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 @@
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:
@@ -111,11 +114,11 @@ Gen3 Metadata Class
-
async async_delete_alias(guid, alias, _ssl=None, **kwargs)[source]¶
-Asyncronously delete single Aliases for the given guid
+Asynchronously delete single Aliases for the given guid
- Parameters:
-guid (str) – Globally unique ID for the metadata blob
+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
@@ -133,7 +136,7 @@ Gen3 Metadata Class
-
async async_delete_aliases(guid, _ssl=None, **kwargs)[source]¶
-Asyncronously delete all Aliases for the given guid
+Asynchronously delete all Aliases for the given guid
- Parameters:
@@ -215,7 +218,7 @@ Gen3 Metadata Class
-
async async_update_aliases(guid, aliases, merge=False, _ssl=None, **kwargs)[source]¶
-Asyncronously update Aliases for the given guid
+Asynchronously update Aliases for the given guid
- Parameters:
@@ -244,7 +247,7 @@ Gen3 Metadata Class
(List[Dict{"guid" (metadata_list) – “”, “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
@@ -442,7 +445,7 @@ Gen3 Metadata Class
-
-query(query, return_full_metadata=False, limit=10, offset=0, use_agg_mds=False, **kwargs)[source]¶
+query(query=None, return_full_metadata=False, limit=10, offset=0, **kwargs)[source]¶
Query the metadata given a query.