From c79952e57192c5bcc8c75edd9aacf28346aad139 Mon Sep 17 00:00:00 2001 From: Brad Macdonald <52762200+BWMac@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:41:17 -0600 Subject: [PATCH] [SYNPY-1282] Adds Type Hinting to `client.py` (#987) Adds type hints to several functions in `client.py` and a quick note to CONTRIBUTING.md because of an issue getting the `pipenv install` to work properly. --- CONTRIBUTING.md | 1 + synapseclient/client.py | 68 ++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2897bbccf..2335ac2e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,7 @@ Perform the following one-time steps to set up your local environment. 1. This package uses Python, if you have not already, please install [pyenv](https://github.com/pyenv/pyenv#installation) to manage your Python versions. Versions supported by this package are all versions >=3.8 and <=3.11. If you do not install `pyenv` make sure that Python and `pip` are installed correctly and have been added to your PATH by running `python3 --version` and `pip3 --version`. If your installation was successful, your terminal will return the versions of Python and `pip` that you installed. **Note**: If you have `pyenv` it will install a specific version of Python for you. 2. Install `pipenv` by running `pip install pipenv`. + - If you already have `pipenv` installed, ensure that the version is >=2023.9.8 to avoid compatibility issues. 3. Install `synapseclient` locally using pipenv: diff --git a/synapseclient/client.py b/synapseclient/client.py index 508bd2594..8988c555a 100644 --- a/synapseclient/client.py +++ b/synapseclient/client.py @@ -221,16 +221,16 @@ class Synapse(object): # TODO: add additional boolean for write to disk? def __init__( self, - repoEndpoint=None, - authEndpoint=None, - fileHandleEndpoint=None, - portalEndpoint=None, - debug=None, - skip_checks=False, - configPath=CONFIG_FILE, - requests_session=None, - cache_root_dir=None, - silent=None, + repoEndpoint: str = None, + authEndpoint: str = None, + fileHandleEndpoint: str = None, + portalEndpoint: str = None, + debug: bool = None, + skip_checks: bool = False, + configPath: str = CONFIG_FILE, + requests_session: requests.Session = None, + cache_root_dir: str = None, + silent: bool = None, ): self._requests_session = requests_session or requests.Session() @@ -296,7 +296,7 @@ def _init_logger(self): logging.getLogger("py.warnings").handlers = self.logger.handlers @property - def max_threads(self): + def max_threads(self) -> int: return self._max_threads @max_threads.setter @@ -304,12 +304,12 @@ def max_threads(self, value: int): self._max_threads = min(max(value, 1), MAX_THREADS_CAP) @property - def username(self): + def username(self) -> Union[str, None]: # for backwards compatability when username was a part of the Synapse object and not in credentials return self.credentials.username if self.credentials is not None else None @functools.lru_cache() - def getConfigFile(self, configPath): + def getConfigFile(self, configPath: str) -> configparser.RawConfigParser: """ Retrieves the client configuration information. @@ -328,11 +328,11 @@ def getConfigFile(self, configPath): def setEndpoints( self, - repoEndpoint=None, - authEndpoint=None, - fileHandleEndpoint=None, - portalEndpoint=None, - skip_checks=False, + repoEndpoint: str = None, + authEndpoint: str = None, + fileHandleEndpoint: str = None, + portalEndpoint: str = None, + skip_checks: bool = False, ): """ Sets the locations for each of the Synapse services (mostly useful for testing). @@ -385,14 +385,14 @@ def setEndpoints( def login( self, - email=None, - password=None, - apiKey=None, - sessionToken=None, - rememberMe=False, - silent=False, - forced=False, - authToken=None, + email: str = None, + password: str = None, + apiKey: str = None, + sessionToken: str = None, + rememberMe: bool = False, + silent: bool = False, + forced: bool = False, + authToken: str = None, ): """ Valid combinations of login() arguments: @@ -508,7 +508,7 @@ def login( ) ) - def _get_config_section_dict(self, section_name): + def _get_config_section_dict(self, section_name: str) -> dict: config = self.getConfigFile(self.configPath) try: return dict(config.items(section_name)) @@ -516,18 +516,18 @@ def _get_config_section_dict(self, section_name): # section not present return {} - def _get_config_authentication(self): + def _get_config_authentication(self) -> str: return self._get_config_section_dict( config_file_constants.AUTHENTICATION_SECTION_NAME ) - def _get_client_authenticated_s3_profile(self, endpoint, bucket): + def _get_client_authenticated_s3_profile(self, endpoint: str, bucket: str) -> str: config_section = endpoint + "/" + bucket return self._get_config_section_dict(config_section).get( "profile_name", "default" ) - def _get_transfer_config(self): + def _get_transfer_config(self) -> dict: # defaults transfer_config = {"max_threads": DEFAULT_NUM_THREADS, "use_boto_sts": False} @@ -552,7 +552,7 @@ def _get_transfer_config(self): return transfer_config - def _getSessionToken(self, email, password): + def _getSessionToken(self, email: str, password: str) -> str: """Returns a validated session token.""" try: req = {"email": email, "password": password} @@ -572,7 +572,7 @@ def _getSessionToken(self, email, password): raise SynapseAuthenticationError("Invalid username or password.") raise - def _getAPIKey(self, sessionToken): + def _getAPIKey(self, sessionToken: str) -> str: """Uses a session token to fetch an API key.""" headers = {"sessionToken": sessionToken, "Accept": "application/json"} @@ -591,7 +591,7 @@ def _is_logged_in(self) -> bool: return False return True - def logout(self, forgetMe=False): + def logout(self, forgetMe: bool = False): """ Removes authentication information from the Synapse client. @@ -654,7 +654,7 @@ def getUserProfile( ) ) - def _findPrincipals(self, query_string): + def _findPrincipals(self, query_string: str) -> typing.List[UserGroupHeader]: """ Find users or groups by name or email.