diff --git a/docs/_build/doctrees/metadata.doctree b/docs/_build/doctrees/metadata.doctree index abb2e6912..53c986e5a 100644 Binary files a/docs/_build/doctrees/metadata.doctree and b/docs/_build/doctrees/metadata.doctree differ diff --git a/docs/_build/html/_modules/gen3/metadata.html b/docs/_build/html/_modules/gen3/metadata.html index 7e1dc353c..ca87bc6cd 100644 --- a/docs/_build/html/_modules/gen3/metadata.html +++ b/docs/_build/html/_modules/gen3/metadata.html @@ -37,6 +37,8 @@

Source code for gen3.metadata

 import aiohttp
 import backoff
 from datetime import datetime
+import functools
+import inspect
 import requests
 import json
 import os
@@ -88,12 +90,52 @@ 

Source code for gen3.metadata

 }
 
 
+def _requires_auth(func):
+    """
+    Decorator for Gen3Metadata methods that hit admin endpoints. If the object was
+    created without an auth provider, log a helpful message and return None instead
+    of making a request that is guaranteed to fail.
+    """
+
+    def _log_missing_auth():
+        logging.error(
+            f"'{func.__name__}' calls an /mds-admin endpoint and requires "
+            "authentication. Create a Gen3Auth object, e.g. "
+            "`auth = Gen3Auth(refresh_file='credentials.json')`, and supply it when "
+            "initializing: `Gen3Metadata(auth_provider=auth)`."
+        )
+
+    if inspect.iscoroutinefunction(func):
+
+        @functools.wraps(func)
+        async def async_wrapper(self, *args, **kwargs):
+            if self._auth_provider is None:
+                _log_missing_auth()
+                return None
+            return await func(self, *args, **kwargs)
+
+        return async_wrapper
+
+    @functools.wraps(func)
+    def wrapper(self, *args, **kwargs):
+        if self._auth_provider is None:
+            _log_missing_auth()
+            return None
+        return func(self, *args, **kwargs)
+
+    return wrapper
+
+
 
[docs] class Gen3Metadata: """ A class for interacting with the Gen3 Metadata services. + Open access endpoints work without authentication. Methods that call admin + endpoints (create, update, delete, index management, alias changes) require an + auth_provider; without one they log a message and return directly. + Examples: This generates the Gen3Metadata class pointed at the sandbox commons while using the credentials.json downloaded from the commons profile page. @@ -129,8 +171,13 @@

Source code for gen3.metadata

             endpoint = None
         if auth_provider and isinstance(auth_provider, Gen3Auth):
             endpoint = auth_provider.endpoint
+        if not endpoint:
+            raise ValueError(
+                "Provide either an endpoint or a Gen3Auth object (auth_provider) "
+                "to initialize Gen3Metadata."
+            )
         endpoint = endpoint.strip("/")
-        # if running locally, mds is deployed by itself without a location relative
+        # if running locally, MDS is deployed by itself without a location relative
         # to the commons
         if "http://localhost" in endpoint:
             service_location = ""
@@ -182,6 +229,7 @@ 

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS) + @_requires_auth def get_index_key_paths(self): """ List all the metadata key paths indexed in the database. @@ -199,6 +247,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS) + @_requires_auth def create_index_key_path(self, path): """ Create a metadata key path indexed in the database. @@ -216,6 +265,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS) + @_requires_auth def delete_index_key_path(self, path): """ List all the metadata key paths indexed in the database. @@ -235,11 +285,10 @@

Source code for gen3.metadata

     @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS)
     def query(
         self,
-        query,
+        query=None,
         return_full_metadata=False,
         limit=10,
         offset=0,
-        use_agg_mds=False,
         **kwargs,
     ):
         """
@@ -276,7 +325,8 @@ 

Source code for gen3.metadata

             '''
 
         Args:
-            query (str): mds query as defined by the metadata api
+            query (str, optional): MDS query as defined by the metadata api. If not
+                provided, all records are returned (subject to limit/offset)
             return_full_metadata (bool, optional): if False will just return a list of guids
             limit (int, optional): max num records to return
             offset (int, optional): offset for output
@@ -288,7 +338,11 @@ 

Source code for gen3.metadata

                 metadata JSON blobs as values
         """
 
-        url = self.endpoint + f"/metadata?{query}"
+        url = (
+            self.endpoint + f"/metadata?{query}"
+            if query
+            else self.endpoint + "/metadata"
+        )
 
         url_with_params = append_query_params(
             url, data=return_full_metadata, limit=limit, offset=offset, **kwargs
@@ -351,6 +405,7 @@ 

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS) + @_requires_auth def batch_create(self, metadata_list, overwrite=True, **kwargs): """ Create the list of metadata associated with the list of guids @@ -358,10 +413,10 @@

Source code for gen3.metadata

         Args:
             metadata_list (List[Dict{"guid": "", "data": {}}]): list of metadata
                 objects in a specific format. Expects a dict with "guid" and "data"
-                fields where "data" is another JSON blob to add to the mds
+                fields where "data" is another JSON blob to add to the MDS
             overwrite (bool, optional): whether or not to overwrite existing data
         """
-        url = self.admin_endpoint + f"/metadata"
+        url = self.admin_endpoint + "/metadata"
 
         if len(metadata_list) > 1 and (
             "guid" not in metadata_list[0] and "data" not in metadata_list[0]
@@ -387,6 +442,7 @@ 

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth def create(self, guid, metadata, aliases=None, overwrite=False, **kwargs): """ Create the metadata associated with the guid @@ -426,6 +482,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth async def async_create( self, guid, @@ -483,6 +540,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS) + @_requires_auth def update(self, guid, metadata, aliases=None, merge=False, **kwargs): """ Update the metadata associated with the guid @@ -521,6 +579,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS) + @_requires_auth async def async_update( self, guid, metadata, aliases=None, merge=False, _ssl=None, **kwargs ): @@ -572,6 +631,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **DEFAULT_BACKOFF_SETTINGS) + @_requires_auth def delete(self, guid, **kwargs): """ Delete the metadata associated with the guid @@ -638,7 +698,11 @@

Source code for gen3.metadata

 
             # aiohttp only allows basic auth with their built in auth, so we
             # need to manually add JWT auth header
-            headers = {"Authorization": self._auth_provider._get_auth_value()}
+            headers = (
+                {"Authorization": self._auth_provider._get_auth_value()}
+                if self._auth_provider
+                else {}
+            )
 
             logging.debug(f"hitting: {url_with_params}")
             async with session.get(
@@ -649,13 +713,17 @@ 

Source code for gen3.metadata

             return await response.json()
+
+[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth def delete_alias(self, guid, alias, **kwargs): """ Delete single Alias for the given guid Args: guid (TYPE): Globally unique ID for the metadata blob + alias (str): alternative identifier (alias) to delete **kwargs: additional query params Returns: @@ -668,15 +736,20 @@

Source code for gen3.metadata

         response = requests.delete(url_with_params, auth=self._auth_provider)
         response.raise_for_status()
 
-        return response.json()
+        return response.text
+ +
+[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth async def async_delete_alias(self, guid, alias, _ssl=None, **kwargs): """ - Asyncronously delete single Aliases for the given guid + Asynchronously delete single Aliases for the given guid Args: guid (TYPE): Globally unique ID for the metadata blob + alias (str): alternative identifier (alias) to delete _ssl (None, optional): whether or not to use ssl **kwargs: additional query params @@ -697,11 +770,13 @@

Source code for gen3.metadata

             ) as response:
                 response.raise_for_status()
 
-            return await response.json()
+                return await response.text()
+
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth def create_aliases(self, guid, aliases, **kwargs): """ Create Aliases for the given guid @@ -730,9 +805,10 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth async def async_create_aliases(self, guid, aliases, _ssl=None, **kwargs): """ - Asyncronously create Aliases for the given guid + Asynchronously create Aliases for the given guid Args: guid (TYPE): Globally unique ID for the metadata blob @@ -765,6 +841,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth def update_aliases(self, guid, aliases, merge=False, **kwargs): """ Update Aliases for the given guid @@ -794,11 +871,12 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth async def async_update_aliases( self, guid, aliases, merge=False, _ssl=None, **kwargs ): """ - Asyncronously update Aliases for the given guid + Asynchronously update Aliases for the given guid Args: guid (TYPE): Globally unique ID for the metadata blob @@ -833,6 +911,7 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth def delete_aliases(self, guid, **kwargs): """ Delete all Aliases for the given guid @@ -857,9 +936,10 @@

Source code for gen3.metadata

 
[docs] @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) + @_requires_auth async def async_delete_aliases(self, guid, _ssl=None, **kwargs): """ - Asyncronously delete all Aliases for the given guid + Asynchronously delete all Aliases for the given guid Args: guid (TYPE): Globally unique ID for the metadata blob @@ -886,64 +966,6 @@

Source code for gen3.metadata

                 return await response.text
-
-[docs] - @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) - def delete_alias(self, guid, alias, **kwargs): - """ - Delete single Alias for the given guid - - Args: - guid (TYPE): Globally unique ID for the metadata blob - alias (str): alternative identifier (alias) to delete - **kwargs: additional query params - - Returns: - requests.Response: response from the request to delete aliases - """ - url = self.admin_endpoint + f"/metadata/{guid}/aliases/{alias}" - url_with_params = append_query_params(url, **kwargs) - - logging.debug(f"hitting: {url_with_params}") - response = requests.delete(url_with_params, auth=self._auth_provider) - response.raise_for_status() - - return response.text
- - -
-[docs] - @backoff.on_exception(backoff.expo, Exception, **BACKOFF_NO_LOG_IF_NOT_RETRIED) - async def async_delete_alias(self, guid, alias, _ssl=None, **kwargs): - """ - Asyncronously delete single Aliases for the given guid - - Args: - guid (str): Globally unique ID for the metadata blob - alias (str): alternative identifier (alias) to delete - _ssl (None, optional): whether or not to use ssl - **kwargs: additional query params - - Returns: - requests.Response: response from the request to delete aliases - """ - async with aiohttp.ClientSession() as session: - url = self.admin_endpoint + f"/metadata/{guid}/aliases/{alias}" - url_with_params = append_query_params(url, **kwargs) - - # aiohttp only allows basic auth with their built in auth, so we - # need to manually add JWT auth header - headers = {"Authorization": self._auth_provider._get_auth_value()} - - logging.debug(f"hitting: {url_with_params}") - async with session.delete( - url_with_params, headers=headers, ssl=_ssl - ) as response: - response.raise_for_status() - - return await response.text
- - def _prepare_metadata( self, metadata, indexd_doc, force_metadata_columns_even_if_empty ): diff --git a/docs/_build/html/metadata.html b/docs/_build/html/metadata.html index 868e4e436..cd2655cf4 100644 --- a/docs/_build/html/metadata.html +++ b/docs/_build/html/metadata.html @@ -40,6 +40,9 @@

Gen3 Metadata Classclass gen3.metadata.Gen3Metadata(endpoint=None, auth_provider=None, service_location='mds', admin_endpoint_suffix='-admin')[source]

Bases: object

A class for interacting with the Gen3 Metadata services.

+

Open access endpoints work without authentication. Methods that call admin +endpoints (create, update, delete, index management, alias changes) require an +auth_provider; without one they log a message and return directly.

Examples

This generates the Gen3Metadata class pointed at the sandbox commons while using the credentials.json downloaded from the commons profile page.

@@ -89,7 +92,7 @@

Gen3 Metadata Class
async async_create_aliases(guid, aliases, _ssl=None, **kwargs)[source]
-

Asyncronously create Aliases for the given guid

+

Asynchronously create Aliases for the given guid

Parameters: