33import os
44import shutil
55import warnings
6- from functools import wraps , cache
7- from typing import Optional , Any
6+ from functools import cache , wraps
7+ from typing import Any , Callable , Optional
88from urllib .parse import urlparse
99
1010import dateutil .parser
1111import requests
1212
1313from marble_client .constants import CACHE_FNAME , NODE_REGISTRY_URL
14- from marble_client .exceptions import UnknownNodeError , JupyterEnvironmentError
14+ from marble_client .exceptions import JupyterEnvironmentError , UnknownNodeError
1515from marble_client .node import MarbleNode
1616
1717__all__ = ["MarbleClient" ]
1818
1919
20- def check_jupyterlab (f ) :
20+ def check_jupyterlab (f : Callable ) -> Callable :
2121 """
22+ Raise an error if not running in a Jupyterlab instance.
23+
2224 Wraps the function f by first checking if the current script is running in a
2325 Marble Jupyterlab environment and raising a JupyterEnvironmentError if not.
2426
@@ -28,22 +30,27 @@ def check_jupyterlab(f):
2830 Note that this checks if either the BIRDHOUSE_HOST_URL or PAVICS_HOST_URL are present to support
2931 versions of birdhouse-deploy prior to 2.4.0.
3032 """
33+
3134 @wraps (f )
32- def wrapper (* args , ** kwargs ):
35+ def wrapper (* args , ** kwargs ) -> Any :
3336 birdhouse_host_var = ("PAVICS_HOST_URL" , "BIRDHOUSE_HOST_URL" )
3437 jupyterhub_env_vars = ("JUPYTERHUB_API_URL" , "JUPYTERHUB_USER" , "JUPYTERHUB_API_TOKEN" )
3538 if any (os .getenv (var ) for var in birdhouse_host_var ) and all (os .getenv (var ) for var in jupyterhub_env_vars ):
3639 return f (* args , ** kwargs )
3740 raise JupyterEnvironmentError ("Not in a Marble jupyterlab environment" )
41+
3842 return wrapper
3943
4044
4145class MarbleClient :
46+ """Client object representing the information in the Marble registry."""
47+
4248 _registry_cache_key = "marble_client_python:cached_registry"
4349 _registry_cache_last_updated_key = "marble_client_python:last_updated"
4450
4551 def __init__ (self , fallback : bool = True ) -> None :
46- """Constructor method
52+ """
53+ Initialize a MarbleClient instance.
4754
4855 :param fallback: If True, then fall back to a cached version of the registry
4956 if the cloud registry cannot be accessed, defaults to True
@@ -64,6 +71,7 @@ def __init__(self, fallback: bool = True) -> None:
6471
6572 @property
6673 def nodes (self ) -> dict [str , MarbleNode ]:
74+ """Return nodes in the current registry."""
6775 return self ._nodes
6876
6977 @property
@@ -87,15 +95,18 @@ def this_node(self) -> MarbleNode:
8795 def this_session (self , session : Optional [requests .Session ] = None ) -> requests .Session :
8896 """
8997 Add the login session cookies of the user who is currently logged in to the session object.
98+
9099 If a session object is not passed as an argument to this function, create a new session
91100 object as well.
92101
93102 Note that this function only works in a Marble Jupyterlab environment.
94103 """
95104 if session is None :
96105 session = requests .Session ()
97- r = requests .get (f"{ os .getenv ('JUPYTERHUB_API_URL' )} /users/{ os .getenv ('JUPYTERHUB_USER' )} " ,
98- headers = {"Authorization" : f"token { os .getenv ('JUPYTERHUB_API_TOKEN' )} " })
106+ r = requests .get (
107+ f"{ os .getenv ('JUPYTERHUB_API_URL' )} /users/{ os .getenv ('JUPYTERHUB_USER' )} " ,
108+ headers = {"Authorization" : f"token { os .getenv ('JUPYTERHUB_API_TOKEN' )} " },
109+ )
99110 try :
100111 r .raise_for_status ()
101112 except requests .HTTPError as err :
@@ -105,17 +116,20 @@ def this_session(self, session: Optional[requests.Session] = None) -> requests.S
105116 return session
106117
107118 @property
108- def registry_uri (self ):
119+ def registry_uri (self ) -> str :
120+ """Return the URL of the currently used Marble registry."""
109121 return self ._registry_uri
110122
111123 def __getitem__ (self , node : str ) -> MarbleNode :
124+ """Return the node with the given name."""
112125 try :
113126 return self .nodes [node ]
114127 except KeyError as err :
115128 raise UnknownNodeError (f"No node named '{ node } ' in the Marble network." ) from err
116129
117130 def __contains__ (self , node : str ) -> bool :
118- """Check if a node is available
131+ """
132+ Check if a node is available.
119133
120134 :param node: ID of the Marble node
121135 :type node: str
@@ -175,8 +189,10 @@ def _save_registry_as_cache(self, registry: dict[str, Any]) -> None:
175189
176190 try :
177191 with open (CACHE_FNAME , "w" ) as f :
178- data = {self ._registry_cache_key : registry ,
179- self ._registry_cache_last_updated_key : datetime .datetime .now (tz = datetime .timezone .utc ).isoformat ()}
192+ data = {
193+ self ._registry_cache_key : registry ,
194+ self ._registry_cache_last_updated_key : datetime .datetime .now (tz = datetime .timezone .utc ).isoformat (),
195+ }
180196 json .dump (data , f )
181197 except OSError :
182198 # If the cache file cannot be written, then restore from backup files
0 commit comments