Source code for globus_sdk.tokenstorage.v1.file_adapters
from__future__importannotationsimportjsonimportpathlibimporttypingastimportglobus_sdkfromglobus_sdkimport__version__from.baseimportFileAdapter# use the non-annotation form of TypedDict to apply a non-identifier key_JSONFileData_0=t.TypedDict("_JSONFileData_0",{"globus-sdk.version":str})# then inherit from that TypedDict to build the "real" TypedDict with the advantages of# the annotation-based syntaxclass_JSONFileData(_JSONFileData_0):# pylint: disable=inherit-non-classby_rs:dict[str,t.Any]format_version:str
[docs]classSimpleJSONFileAdapter(FileAdapter):""" :param filename: the name of the file to write to and read from A storage adapter for storing tokens in JSON files. """# the version for the current data format used by the file adapter## if the format needs to be changed in the future, the adapter can dispatch on# the declared format version in the file to decide how to handle the dataformat_version="1.0"# the supported versions (data not in these versions causes an error)supported_versions=("1.0",)def__init__(self,filename:pathlib.Path|str)->None:self.filename=str(filename)def_invalid(self,msg:str)->t.NoReturn:raiseValueError(f"{msg} while loading from '{self.filename}' for JSON File Adapter")def_raw_load(self)->dict[str,t.Any]:""" Load the file contents as JSON and return the resulting dict object. If a dict is not found, raises an error. """withopen(self.filename,encoding="utf-8")asf:val=json.load(f)ifnotisinstance(val,dict):self._invalid("Found non-dict root data")returnvaldef_handle_formats(self,read_data:dict[str,t.Any])->_JSONFileData:"""Handle older data formats supported by globus_sdk.tokenstorage if the data is not in a known/recognized format, this will error otherwise, reshape the data to the current supported format and return it """format_version=read_data.get("format_version")ifformat_versionnotinself.supported_versions:raiseValueError(f"cannot store data using SimpleJSONFileAdapter({self.filename} ""existing data file is in an unknown format "f"(format_version={format_version})")ifnotisinstance(read_data.get("by_rs"),dict):raiseValueError(f"cannot store data using SimpleJSONFileAdapter({self.filename} ""existing data file is malformed")ifany(knotinread_dataforkin("by_rs","format_version","globus-sdk.version")):self._invalid("Missing required keys")ifnotisinstance(by_rs_dict:=read_data["by_rs"],dict)orany(notisinstance(k,str)forkinby_rs_dict):self._invalid("Invalid 'by_rs'")ifnotisinstance(read_data["format_version"],str):self._invalid("Invalid 'format_version'")ifnotisinstance(read_data["globus-sdk.version"],str):self._invalid("Invalid 'globus-sdk.version'")returnread_data# type: ignore[return-value]def_load(self)->_JSONFileData:""" Load data from the file and ensure that the data is in a modern format which can be handled by the rest of the adapter. If the file is missing, this will return a "skeleton" for new data. """try:data=self._raw_load()exceptFileNotFoundError:return{"by_rs":{},"format_version":self.format_version,"globus-sdk.version":__version__,}returnself._handle_formats(data)
[docs]defstore(self,token_response:globus_sdk.OAuthTokenResponse)->None:""" By default, ``self.on_refresh`` is just an alias for this function. Given a token response, extract all the token data and write it to ``self.filename`` as JSON data. Additionally will write the version of ``globus_sdk.tokenstorage`` which was in use. Under the assumption that this may be running on a system with multiple local users, this sets the umask such that only the owner of the resulting file can read or write it. :param token_response: The token data received from the refresh """to_write=self._load()# copy the data from the by_resource_server attribute## if the file did not exist and we're handling the initial token response, this# is a full copy of all of the token data## if the file already exists and we're handling a token refresh, we only modify# newly received tokensto_write["by_rs"].update(token_response.by_resource_server)# deny rwx to Group and World, exec to Userwithself.user_only_umask():withopen(self.filename,"w",encoding="utf-8")asf:json.dump(to_write,f)
[docs]defget_by_resource_server(self)->dict[str,t.Any]:""" Read only the by_resource_server formatted data from the file, discarding any other keys. This returns a dict in the same format as ``OAuthTokenResponse.by_resource_server`` """returnself._load()["by_rs"]