From d0eff8e7c998b9b2d250701e3270680308921924 Mon Sep 17 00:00:00 2001 From: Abram Booth Date: Fri, 26 Jan 2024 10:58:43 -0500 Subject: [PATCH] wip --- gravyladle_toolkit/capability.py | 20 +++++++++++++++++--- gravyladle_toolkit/gatherstorage_class.py | 17 +++++++++++++---- gravyladle_toolkit/storage.py | 22 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/gravyladle_toolkit/capability.py b/gravyladle_toolkit/capability.py index 45fc95f7..ba7f3c6a 100644 --- a/gravyladle_toolkit/capability.py +++ b/gravyladle_toolkit/capability.py @@ -1,11 +1,16 @@ import inspect +import logging from gravyvalet.namespaces import GRAVY +_logger = logging.getLogger(__name__) + + ### # ONE OPTION: use decorators to declare capability identifiers on interface methods + def immediate_capability(capability_iri, *, requires): # decorator for capabilities that can be computed immediately, # without sending any requests or waiting on external resources @@ -40,6 +45,7 @@ def _decorator(fn): ### # helpers for capability methods + def get_supported_capabilities(interface): return set(_get_capability_method_map(interface).keys()) @@ -47,12 +53,14 @@ def get_supported_capabilities(interface): def get_capability_method(interface_instance, capability_iri): _methodname = _get_capability_method_map(interface_instance).get(capability_iri) if _methodname is not None: - return getattr(interface_instance, _methodname) + _method = getattr(interface_instance, _methodname) + # TODO: check whether it's abstract ### # module-private helpers + def _get_capability_method_map(obj): try: return getattr(obj, GRAVY.capability_map) @@ -63,16 +71,22 @@ def _get_capability_method_map(obj): def _compute_capability_method_map(obj): _capability_method_map = {} for _methodname, _fn in inspect.getmembers(obj, inspect.ismethod): + # TODO: intent is to make it easy to implement the capabilities you are + # trying to support while ignoring all the rest (until you want them). + # on the base class, declare and decorate methods for each supported + # capability, then implementers may implement (or not implement) any or + # all of them -- this doesn't quite do all that, maybe try from __new__? try: _capability_iri = getattr(_fn, GRAVY.capability) except AttributeError: pass # not a capability implementation else: assert _capability_iri not in _capability_method_map, ( - f'duplicate implementations of capability <{_capability_iri}>' - f'(conflicting: {_fn}, {_capability_method_map[_capability_iri]})' + f"duplicate implementations of capability <{_capability_iri}>" + f"(conflicting: {_fn}, {_capability_method_map[_capability_iri]})" ) _capability_method_map[_capability_iri] = _methodname + _logger.info("found capability methods on %r: %r", obj, _capability_method_map) setattr(obj, GRAVY.capability_map, _capability_method_map) return _capability_method_map diff --git a/gravyladle_toolkit/gatherstorage_class.py b/gravyladle_toolkit/gatherstorage_class.py index c32db5ad..a2b72165 100644 --- a/gravyladle_toolkit/gatherstorage_class.py +++ b/gravyladle_toolkit/gatherstorage_class.py @@ -8,13 +8,22 @@ proxy_act_capability, proxy_read_capability, ) -from .interfaces import ( - BaseAddonInterface, - PagedResult, -) +from .interfaces import PagedResult # what an example gravy:StorageInterface implementation could be like (class-based) +STORAGE_INTERFACE_NORMS = gather.GatheringNorms( + namestory=( + rdf.Literal("Storage interface norms", language="en"), + rdf.Literal("Norms for an interface with a storage service", language="en"), + ), + focustype_iris={}, +) + + +class StorageInterfaceOrganizer(gather.GatheringOrganizer): + norms = STORAGE_INTERFACE_NORMS + thesaurus = {} class StorageInterface(BaseAddonInterface): diff --git a/gravyladle_toolkit/storage.py b/gravyladle_toolkit/storage.py index 48ff6b89..1d0d8ae7 100644 --- a/gravyladle_toolkit/storage.py +++ b/gravyladle_toolkit/storage.py @@ -86,3 +86,25 @@ async def get_version_ids(self, item_id: str) -> PagedResult[str]: ) async def pls_restore_version(self, item_id: str, version_id: str): raise NotImplementedError + + +if __debug__: # examples + + class _ExampleStorageImplementation(StorageInterface): + def item_download_url(self, item_id: str) -> str: + return self._waterbutler_download_url(item_id) + + async def get_item_description(self, item_id: str) -> dict: + return item_id # stub + + def item_upload_url(self, item_id: str) -> str: + return self._waterbutler_upload_url(item_id) + + async def pls_delete_item(self, item_id: str): + raise NotImplementedError + + def _waterbutler_download_url(self, item_id): + raise NotImplementedError + + def _waterbutler_upload_url(self, item_id): + raise NotImplementedError