A HydroShare object for querying HydroShare's REST API. Provide a username and password at initialization or call the sign_in() method to prompt for the username and password.
If using OAuth2 is desired, provide the client_id and token to use. If on CUAHSI JupyterHub or another JupyterHub environment that authenticates with Hydroshare, call the hs_juptyerhub() method to read the credentials from Jupyterhub.
:param username: A HydroShare username
:param password: A HydroShare password associated with the username
:param host: The host to use, defaults to www.hydroshare.org
:param protocol: The protocol to use, defaults to https
:param port: The port to use, defaults to 443
:param client_id: The client id associated with the OAuth2 token
:param token: The OAuth2 token to use
Source code in hsclient\hydroshare.py
class HydroShare:
"""
A HydroShare object for querying HydroShare's REST API. Provide a username and password at initialization or call
the sign_in() method to prompt for the username and password.
If using OAuth2 is desired, provide the client_id and token to use. If on CUAHSI JupyterHub or another JupyterHub
environment that authenticates with Hydroshare, call the hs_juptyerhub() method to read the credentials from
Jupyterhub.
:param username: A HydroShare username
:param password: A HydroShare password associated with the username
:param host: The host to use, defaults to `www.hydroshare.org`
:param protocol: The protocol to use, defaults to `https`
:param port: The port to use, defaults to `443`
:param client_id: The client id associated with the OAuth2 token
:param token: The OAuth2 token to use
"""
default_host = 'www.hydroshare.org'
default_protocol = "https"
default_port = 443
def __init__(
self,
username: str = None,
password: str = None,
host: str = default_host,
protocol: str = default_protocol,
port: int = default_port,
client_id: str = None,
token: Union[Token, Dict[str, str]] = None,
):
if client_id or token:
if not client_id or not token:
raise ValueError("Oauth2 requires a client_id to be paired with a token")
else:
self._hs_session = HydroShareSession(
host=host, protocol=protocol, port=port, client_id=client_id, token=token
)
self.my_user_info() # validate credentials
else:
self._hs_session = HydroShareSession(
username=username, password=password, host=host, protocol=protocol, port=port
)
if username or password:
self.my_user_info() # validate credentials
self._resource_object_cache: Dict[str, Resource] = dict()
def sign_in(self) -> None:
"""Prompts for username/password. Useful for avoiding saving your HydroShare credentials to a notebook"""
username = input("Username: ").strip()
password = getpass.getpass("Password for {}: ".format(username))
self._hs_session.set_auth((username, password))
self.my_user_info() # validate credentials
@classmethod
def hs_juptyerhub(cls, hs_auth_path="/home/jovyan/data/.hs_auth"):
"""
Create a new HydroShare object using OAuth2 credentials stored in a canonical CUAHSI
Jupyterhub OAuth2 pickle file (stored at :param hs_auth_path:).
Provide a non-default (default: `/home/jovyan/data/.hs_auth`) path to the hs_auth file with
:param hs_auth_path:.
"""
if not os.path.isfile(hs_auth_path):
raise ValueError(f"hs_auth_path {hs_auth_path} does not exist.")
with open(hs_auth_path, 'rb') as f:
token, client_id = pickle.load(f)
instance = cls(client_id=client_id, token=token)
instance.my_user_info() # validate credentials
return instance
def search(
self,
creator: str = None,
contributor: str = None,
owner: str = None,
group_name: str = None,
from_date: datetime = None,
to_date: datetime = None,
edit_permission: bool = False,
resource_types: List[str] = [],
subject: List[str] = [],
full_text_search: str = None,
published: bool = False,
spatial_coverage: Union[BoxCoverage, PointCoverage] = None,
):
"""
Query the GET /hsapi/resource/ REST end point of the HydroShare server.
:param creator: Filter results by the HydroShare username or email
:param author: Filter results by the HydroShare username or email
:param owner: Filter results by the HydroShare username or email
:param group_name: Filter results by the HydroShare group name associated with resources
:param from_date: Filter results to those created after from_date. Must be datetime.date.
:param to_date: Filter results to those created before to_date. Must be datetime.date. Because dates have
no time information, you must specify date+1 day to get results for date (e.g. use 2015-05-06 to get
resources created up to and including 2015-05-05)
:param types: Filter results to particular HydroShare resource types (Deprecated, all types are Composite)
:param subject: Filter by comma separated list of subjects
:param full_text_search: Filter by full text search
:param edit_permission: Filter by boolean edit permission
:param published: Filter by boolean published status
:param spatial_coverage: Filtering by spatial coverage raises a 500, do not use
:return: A generator to iterate over a ResourcePreview object
"""
params = {"edit_permission": edit_permission, "published": published}
if creator:
params["creator"] = creator
if contributor:
params["author"] = contributor
if owner:
params["owner"] = owner
if group_name:
params["group"] = group_name
if resource_types:
params["type[]"] = resource_types
if subject:
params["subject"] = ",".join(subject)
if full_text_search:
params["full_text_search"] = full_text_search
if from_date:
params["from_date"] = from_date.strftime('%Y-%m-%d')
if to_date:
params["to_date"] = to_date.strftime('%Y-%m-%d')
if spatial_coverage:
yield Exception(
"Bad Request, status_code 400, spatial_coverage queries are disabled."
)
# TODO: re-enable after resolution of https://github.com/hydroshare/hydroshare/issues/5240
# params["coverage_type"] = spatial_coverage.type
# if spatial_coverage.type == "point":
# params["north"] = spatial_coverage.north
# params["east"] = spatial_coverage.east
# else:
# params["north"] = spatial_coverage.northlimit
# params["east"] = spatial_coverage.eastlimit
# params["south"] = spatial_coverage.southlimit
# params["west"] = spatial_coverage.westlimit
response = self._hs_session.get("/hsapi/resource/", 200, params=params)
res = response.json()
results = res['results']
for item in results:
yield ResourcePreview(**item)
while res['next']:
next_url = res['next']
next_url = urlparse(next_url)
path = next_url.path
params = next_url.query
response = self._hs_session.get(path, 200, params=params)
res = response.json()
results = res['results']
for item in results:
yield ResourcePreview(**item)
def resource(self, resource_id: str, validate: bool = True, use_cache: bool = True) -> Resource:
"""
Creates a resource object from HydroShare with the provided resource_id
:param resource_id: The resource id of the resource to retrieve
:param validate: Defaults to True, set to False to not validate the resource exists
:param use_cache: Defaults to True, set to False to skip the cache, and always retrieve the
resource from HydroShare. This parameter also does not cache the retrieved Resource
object.
:return: A Resource object representing a resource on HydroShare
"""
if resource_id in self._resource_object_cache and use_cache:
return self._resource_object_cache[resource_id]
res = Resource("/resource/{}/data/resourcemap.xml".format(resource_id), self._hs_session)
if validate:
res.metadata
if use_cache:
self._resource_object_cache[resource_id] = res
return res
def create(self, use_cache: bool = True) -> Resource:
"""
Creates a new resource on HydroShare
:param use_cache: Defaults to True, set to False to skip the cache, and always retrieve the
resource from HydroShare. This parameter also does not cache the retrieved Resource
object.
:return: A Resource object representing a resource on HydroShare
"""
response = self._hs_session.post('/hsapi/resource/', status_code=201)
resource_id = response.json()['resource_id']
return self.resource(resource_id, use_cache=use_cache)
def user(self, user_id: int) -> User:
"""
Retrieves the user details of a Hydroshare user
:param user_id: The user id of the user details to retrieve
:return: User object representing the user details
"""
response = self._hs_session.get(f'/hsapi/userDetails/{user_id}/', status_code=200)
return User(**response.json())
def my_user_info(self):
"""
Retrieves the user info of the user's credentials provided
:return: JSON object representing the user info
"""
response = self._hs_session.get('/hsapi/userInfo/', status_code=200)
return response.json()
create(use_cache=True)
Creates a new resource on HydroShare :param use_cache: Defaults to True, set to False to skip the cache, and always retrieve the resource from HydroShare. This parameter also does not cache the retrieved Resource object. :return: A Resource object representing a resource on HydroShare
Source code in hsclient\hydroshare.py
def create(self, use_cache: bool = True) -> Resource:
"""
Creates a new resource on HydroShare
:param use_cache: Defaults to True, set to False to skip the cache, and always retrieve the
resource from HydroShare. This parameter also does not cache the retrieved Resource
object.
:return: A Resource object representing a resource on HydroShare
"""
response = self._hs_session.post('/hsapi/resource/', status_code=201)
resource_id = response.json()['resource_id']
return self.resource(resource_id, use_cache=use_cache)
hs_juptyerhub(hs_auth_path='/home/jovyan/data/.hs_auth')
classmethod
Create a new HydroShare object using OAuth2 credentials stored in a canonical CUAHSI Jupyterhub OAuth2 pickle file (stored at :param hs_auth_path:).
Provide a non-default (default: /home/jovyan/data/.hs_auth
) path to the hs_auth file with
:param hs_auth_path:.
Source code in hsclient\hydroshare.py
@classmethod
def hs_juptyerhub(cls, hs_auth_path="/home/jovyan/data/.hs_auth"):
"""
Create a new HydroShare object using OAuth2 credentials stored in a canonical CUAHSI
Jupyterhub OAuth2 pickle file (stored at :param hs_auth_path:).
Provide a non-default (default: `/home/jovyan/data/.hs_auth`) path to the hs_auth file with
:param hs_auth_path:.
"""
if not os.path.isfile(hs_auth_path):
raise ValueError(f"hs_auth_path {hs_auth_path} does not exist.")
with open(hs_auth_path, 'rb') as f:
token, client_id = pickle.load(f)
instance = cls(client_id=client_id, token=token)
instance.my_user_info() # validate credentials
return instance
my_user_info()
Retrieves the user info of the user's credentials provided :return: JSON object representing the user info
Source code in hsclient\hydroshare.py
def my_user_info(self):
"""
Retrieves the user info of the user's credentials provided
:return: JSON object representing the user info
"""
response = self._hs_session.get('/hsapi/userInfo/', status_code=200)
return response.json()
resource(resource_id, validate=True, use_cache=True)
Creates a resource object from HydroShare with the provided resource_id :param resource_id: The resource id of the resource to retrieve :param validate: Defaults to True, set to False to not validate the resource exists :param use_cache: Defaults to True, set to False to skip the cache, and always retrieve the resource from HydroShare. This parameter also does not cache the retrieved Resource object. :return: A Resource object representing a resource on HydroShare
Source code in hsclient\hydroshare.py
def resource(self, resource_id: str, validate: bool = True, use_cache: bool = True) -> Resource:
"""
Creates a resource object from HydroShare with the provided resource_id
:param resource_id: The resource id of the resource to retrieve
:param validate: Defaults to True, set to False to not validate the resource exists
:param use_cache: Defaults to True, set to False to skip the cache, and always retrieve the
resource from HydroShare. This parameter also does not cache the retrieved Resource
object.
:return: A Resource object representing a resource on HydroShare
"""
if resource_id in self._resource_object_cache and use_cache:
return self._resource_object_cache[resource_id]
res = Resource("/resource/{}/data/resourcemap.xml".format(resource_id), self._hs_session)
if validate:
res.metadata
if use_cache:
self._resource_object_cache[resource_id] = res
return res
search(creator=None, contributor=None, owner=None, group_name=None, from_date=None, to_date=None, edit_permission=False, resource_types=[], subject=[], full_text_search=None, published=False, spatial_coverage=None)
Query the GET /hsapi/resource/ REST end point of the HydroShare server. :param creator: Filter results by the HydroShare username or email :param author: Filter results by the HydroShare username or email :param owner: Filter results by the HydroShare username or email :param group_name: Filter results by the HydroShare group name associated with resources :param from_date: Filter results to those created after from_date. Must be datetime.date. :param to_date: Filter results to those created before to_date. Must be datetime.date. Because dates have no time information, you must specify date+1 day to get results for date (e.g. use 2015-05-06 to get resources created up to and including 2015-05-05) :param types: Filter results to particular HydroShare resource types (Deprecated, all types are Composite) :param subject: Filter by comma separated list of subjects :param full_text_search: Filter by full text search :param edit_permission: Filter by boolean edit permission :param published: Filter by boolean published status :param spatial_coverage: Filtering by spatial coverage raises a 500, do not use
:return: A generator to iterate over a ResourcePreview object
Source code in hsclient\hydroshare.py
def search(
self,
creator: str = None,
contributor: str = None,
owner: str = None,
group_name: str = None,
from_date: datetime = None,
to_date: datetime = None,
edit_permission: bool = False,
resource_types: List[str] = [],
subject: List[str] = [],
full_text_search: str = None,
published: bool = False,
spatial_coverage: Union[BoxCoverage, PointCoverage] = None,
):
"""
Query the GET /hsapi/resource/ REST end point of the HydroShare server.
:param creator: Filter results by the HydroShare username or email
:param author: Filter results by the HydroShare username or email
:param owner: Filter results by the HydroShare username or email
:param group_name: Filter results by the HydroShare group name associated with resources
:param from_date: Filter results to those created after from_date. Must be datetime.date.
:param to_date: Filter results to those created before to_date. Must be datetime.date. Because dates have
no time information, you must specify date+1 day to get results for date (e.g. use 2015-05-06 to get
resources created up to and including 2015-05-05)
:param types: Filter results to particular HydroShare resource types (Deprecated, all types are Composite)
:param subject: Filter by comma separated list of subjects
:param full_text_search: Filter by full text search
:param edit_permission: Filter by boolean edit permission
:param published: Filter by boolean published status
:param spatial_coverage: Filtering by spatial coverage raises a 500, do not use
:return: A generator to iterate over a ResourcePreview object
"""
params = {"edit_permission": edit_permission, "published": published}
if creator:
params["creator"] = creator
if contributor:
params["author"] = contributor
if owner:
params["owner"] = owner
if group_name:
params["group"] = group_name
if resource_types:
params["type[]"] = resource_types
if subject:
params["subject"] = ",".join(subject)
if full_text_search:
params["full_text_search"] = full_text_search
if from_date:
params["from_date"] = from_date.strftime('%Y-%m-%d')
if to_date:
params["to_date"] = to_date.strftime('%Y-%m-%d')
if spatial_coverage:
yield Exception(
"Bad Request, status_code 400, spatial_coverage queries are disabled."
)
# TODO: re-enable after resolution of https://github.com/hydroshare/hydroshare/issues/5240
# params["coverage_type"] = spatial_coverage.type
# if spatial_coverage.type == "point":
# params["north"] = spatial_coverage.north
# params["east"] = spatial_coverage.east
# else:
# params["north"] = spatial_coverage.northlimit
# params["east"] = spatial_coverage.eastlimit
# params["south"] = spatial_coverage.southlimit
# params["west"] = spatial_coverage.westlimit
response = self._hs_session.get("/hsapi/resource/", 200, params=params)
res = response.json()
results = res['results']
for item in results:
yield ResourcePreview(**item)
while res['next']:
next_url = res['next']
next_url = urlparse(next_url)
path = next_url.path
params = next_url.query
response = self._hs_session.get(path, 200, params=params)
res = response.json()
results = res['results']
for item in results:
yield ResourcePreview(**item)
sign_in()
Prompts for username/password. Useful for avoiding saving your HydroShare credentials to a notebook
Source code in hsclient\hydroshare.py
def sign_in(self) -> None:
"""Prompts for username/password. Useful for avoiding saving your HydroShare credentials to a notebook"""
username = input("Username: ").strip()
password = getpass.getpass("Password for {}: ".format(username))
self._hs_session.set_auth((username, password))
self.my_user_info() # validate credentials
user(user_id)
Retrieves the user details of a Hydroshare user :param user_id: The user id of the user details to retrieve :return: User object representing the user details
Source code in hsclient\hydroshare.py
def user(self, user_id: int) -> User:
"""
Retrieves the user details of a Hydroshare user
:param user_id: The user id of the user details to retrieve
:return: User object representing the user details
"""
response = self._hs_session.get(f'/hsapi/userDetails/{user_id}/', status_code=200)
return User(**response.json())