From 071734e1e660ff8f1b7437a015e7e98783174c14 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:07:41 +0100 Subject: [PATCH 1/3] use f-strings in server api --- ayon_api/server_api.py | 234 +++++++++++++++++++---------------------- 1 file changed, 107 insertions(+), 127 deletions(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index b6ede5e73..5f0cad048 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -276,7 +276,7 @@ def __contains__(self, key): return key in self.data def __repr__(self): - return "<{} [{}]>".format(self.__class__.__name__, self.status) + return f"<{self.__class__.__name__} [{self.status}]>" def __len__(self): return int(200 <= self.status < 400) @@ -308,10 +308,9 @@ def __len__(self): def __repr__(self): if self.errors: - return "<{} errors={}>".format( - self.__class__.__name__, self.errors[0]['message'] - ) - return "<{}>".format(self.__class__.__name__) + message = self.errors[0]["message"] + return f"<{self.__class__.__name__} errors={message}>" + return f"<{self.__class__.__name__}>" def fill_own_attribs(entity): @@ -469,12 +468,12 @@ def __init__( max_retries: Optional[int] = None, ): if not base_url: - raise ValueError("Invalid server URL {}".format(str(base_url))) + raise ValueError(f"Invalid server URL {str(base_url)}") base_url = base_url.rstrip("/") self._base_url: str = base_url - self._rest_url: str = "{}/api".format(base_url) - self._graphql_url: str = "{}/graphql".format(base_url) + self._rest_url: str = f"{base_url}/api" + self._graphql_url: str = f"{base_url}/graphql" self._log: logging.Logger = logging.getLogger(self.__class__.__name__) self._access_token: Optional[str] = token # Allow to have 'site_id' to 'None' @@ -933,9 +932,9 @@ def has_valid_token(self) -> bool: def validate_server_availability(self): if not self.is_server_available: - raise ServerNotReached("Server \"{}\" can't be reached".format( - self._base_url - )) + raise ServerNotReached( + f"Server \"{self._base_url}\" can't be reached" + ) def validate_token(self) -> bool: try: @@ -1230,7 +1229,7 @@ def get_user( raise UnauthorizedError("User is not authorized.") return output - response = self.get("users/{}".format(username)) + response = self.get(f"users/{username}") response.raise_for_status() return response.data @@ -1264,8 +1263,7 @@ def get_headers( if username: headers["X-as-user"] = username else: - headers["Authorization"] = "Bearer {}".format( - self._access_token) + headers["Authorization"] = f"Bearer {self._access_token}" return headers def login( @@ -1312,9 +1310,9 @@ def login( _detail = response.data.get("detail") details = "" if _detail: - details = " {}".format(_detail) + details = f" {_detail}" - raise AuthenticationError("Login failed {}".format(details)) + raise AuthenticationError(f"Login failed {details}") finally: self._token_validation_started = False @@ -1427,12 +1425,12 @@ def _do_rest_request(self, function, url, **kwargs): else: new_response = RestApiResponse(response) - self.log.debug("Response {}".format(str(new_response))) + self.log.debug(f"Response {str(new_response)}") return new_response def raw_post(self, entrypoint: str, **kwargs): url = self._endpoint_to_url(entrypoint) - self.log.debug("Executing [POST] {}".format(url)) + self.log.debug(f"Executing [POST] {url}") return self._do_rest_request( RequestTypes.post, url, @@ -1441,7 +1439,7 @@ def raw_post(self, entrypoint: str, **kwargs): def raw_put(self, entrypoint: str, **kwargs): url = self._endpoint_to_url(entrypoint) - self.log.debug("Executing [PUT] {}".format(url)) + self.log.debug(f"Executing [PUT] {url}") return self._do_rest_request( RequestTypes.put, url, @@ -1450,7 +1448,7 @@ def raw_put(self, entrypoint: str, **kwargs): def raw_patch(self, entrypoint: str, **kwargs): url = self._endpoint_to_url(entrypoint) - self.log.debug("Executing [PATCH] {}".format(url)) + self.log.debug(f"Executing [PATCH] {url}") return self._do_rest_request( RequestTypes.patch, url, @@ -1459,7 +1457,7 @@ def raw_patch(self, entrypoint: str, **kwargs): def raw_get(self, entrypoint: str, **kwargs): url = self._endpoint_to_url(entrypoint) - self.log.debug("Executing [GET] {}".format(url)) + self.log.debug(f"Executing [GET] {url}") return self._do_rest_request( RequestTypes.get, url, @@ -1468,7 +1466,7 @@ def raw_get(self, entrypoint: str, **kwargs): def raw_delete(self, entrypoint: str, **kwargs): url = self._endpoint_to_url(entrypoint) - self.log.debug("Executing [DELETE] {}".format(url)) + self.log.debug(f"Executing [DELETE] {url}") return self._do_rest_request( RequestTypes.delete, url, @@ -1503,7 +1501,7 @@ def get_event(self, event_id: str) -> Optional[Dict[str, Any]]: dict[str, Any]: Full event data. """ - response = self.get("events/{}".format(event_id)) + response = self.get(f"events/{event_id}") response.raise_for_status() return response.data @@ -1660,16 +1658,16 @@ def update_event( args.append("progress") if retries is not None: args.append("retries") - fields = ", ".join("'{}'".format(f) for f in args) + fields = ", ".join(f"'{f}'" for f in args) ending = "s" if len(args) > 1 else "" - raise ValueError(( - "Your server version '{}' does not support update" - " of {} field{} on event. The fields are supported since" - " server version '0.5'." - ).format(self.get_server_version(), fields, ending)) + raise ValueError( + f"Your server version '{self.server_version}' does not" + f" support update of {fields} field{ending} on event." + " The fields are supported since server version '0.5'." + ) response = self.patch( - "events/{}".format(event_id), + f"events/{event_id}", **kwargs ) response.raise_for_status() @@ -2545,7 +2543,7 @@ def get_server_schema(self) -> Optional[Dict[str, Any]]: dict[str, Any]: Full server schema. """ - url = "{}/openapi.json".format(self._base_url) + url = f"{self._base_url}/openapi.json" response = self._do_rest_request(RequestTypes.get, url) if response: return response.data @@ -2605,7 +2603,7 @@ def set_attribute_config( position = len(attributes) response = self.put( - "attributes/{}".format(attribute_name), + f"attributes/{attribute_name}", data=data, scope=scope, position=position, @@ -2614,9 +2612,8 @@ def set_attribute_config( if response.status_code != 204: # TODO raise different exception raise ValueError( - "Attribute \"{}\" was not created/updated. {}".format( - attribute_name, response.detail - ) + f"Attribute \"{attribute_name}\" was not created/updated." + f" {response.detail}" ) self.reset_attributes_schema() @@ -2630,11 +2627,10 @@ def remove_attribute_config(self, attribute_name: str): attribute_name (str): Name of attribute to remove. """ - response = self.delete("attributes/{}".format(attribute_name)) + response = self.delete(f"attributes/{attribute_name}") response.raise_for_status( - "Attribute \"{}\" was not created/updated. {}".format( - attribute_name, response.detail - ) + f"Attribute \"{attribute_name}\" was not created/updated." + f" {response.detail}" ) self.reset_attributes_schema() @@ -2703,7 +2699,7 @@ def get_attributes_fields_for_type( """ attributes = self.get_attributes_for_type(entity_type) return { - "attrib.{}".format(attr) + f"attrib.{attr}" for attr in attributes } @@ -2777,7 +2773,7 @@ def get_default_fields_for_type(self, entity_type: str) -> Set[str]: entity_type_defaults = set(DEFAULT_USER_FIELDS) else: - raise ValueError("Unknown entity type \"{}\"".format(entity_type)) + raise ValueError(f"Unknown entity type \"{entity_type}\"") return ( entity_type_defaults | self.get_attributes_fields_for_type(entity_type) @@ -2826,11 +2822,7 @@ def get_addon_endpoint( ending = "" if subpaths: ending = "/{}".format("/".join(subpaths)) - return "addons/{}/{}{}".format( - addon_name, - addon_version, - ending - ) + return f"addons/{addon_name}/{addon_version}{ending}" def get_addon_url( self, @@ -3013,7 +3005,7 @@ def update_installer(self, filename: str, sources: List[Dict[str, Any]]): """ response = self.patch( - "desktop/installers/{}".format(filename), + f"desktop/installers/{filename}", sources=sources ) response.raise_for_status() @@ -3025,7 +3017,7 @@ def delete_installer(self, filename: str): filename (str): Installer filename. """ - response = self.delete("desktop/installers/{}".format(filename)) + response = self.delete(f"desktop/installers/{filename}") response.raise_for_status() def download_installer( @@ -3046,7 +3038,7 @@ def download_installer( """ self.download_file( - "desktop/installers/{}".format(filename), + f"desktop/installers/{filename}", dst_filepath, chunk_size=chunk_size, progress=progress @@ -3071,7 +3063,7 @@ def upload_installer( """ return self.upload_file( - "desktop/installers/{}".format(dst_filename), + f"desktop/installers/{dst_filename}", src_filepath, progress=progress ) @@ -3081,7 +3073,7 @@ def _get_dependency_package_route( ) -> str: endpoint = "desktop/dependencyPackages" if filename: - return "{}/{}".format(endpoint, filename) + return f"{endpoint}/{filename}" return endpoint def get_dependency_packages(self) -> "DependencyPackagesDict": @@ -3665,7 +3657,7 @@ def get_project_anatomy_preset( if (major, minor, patch) < (1, 0, 8): preset_name = self.get_default_anatomy_preset_name() - result = self.get("anatomy/presets/{}".format(preset_name)) + result = self.get(f"anatomy/presets/{preset_name}") result.raise_for_status() return result.data @@ -3709,7 +3701,7 @@ def get_project_root_overrides( dict[str, dict[str, str]]: Root values by root name by site id. """ - result = self.get("projects/{}/roots".format(project_name)) + result = self.get(f"projects/{project_name}/roots") result.raise_for_status() return result.data @@ -3842,7 +3834,7 @@ def _get_project_roots_values( for key, value in query_data.items() ])) response = self.get( - "projects/{}/siteRoots{}".format(project_name, query) + f"projects/{project_name}/siteRoots{query}" ) response.raise_for_status() return response.data @@ -3939,9 +3931,9 @@ def get_addon_site_settings_schema( dict[str, Any]: Schema of site settings. """ - result = self.get("addons/{}/{}/siteSettings/schema".format( - addon_name, addon_version - )) + result = self.get( + f"addons/{addon_name}/{addon_version}/siteSettings/schema" + ) result.raise_for_status() return result.data @@ -4031,9 +4023,8 @@ def get_addon_project_settings( query = prepare_query_string(query_items) result = self.get( - "addons/{}/{}/settings/{}{}".format( - addon_name, addon_version, project_name, query - ) + f"addons/{addon_name}/{addon_version}" + f"/settings/{project_name}{query}" ) result.raise_for_status() return result.data @@ -4106,9 +4097,9 @@ def get_addon_site_settings( return {} query = prepare_query_string({"site": site_id}) - result = self.get("addons/{}/{}/siteSettings{}".format( - addon_name, addon_version, query - )) + result = self.get( + f"addons/{addon_name}/{addon_version}/siteSettings{query}" + ) result.raise_for_status() return result.data @@ -4406,7 +4397,7 @@ def delete_secret(self, secret_name: str): secret_name (str): Name of secret to delete. """ - response = self.delete("secrets/{}".format(secret_name)) + response = self.delete(f"secrets/{secret_name}") response.raise_for_status() return response.data @@ -4429,7 +4420,7 @@ def get_rest_project( if not project_name: return None - response = self.get("projects/{}".format(project_name)) + response = self.get(f"projects/{project_name}") # TODO ignore only error about not existing project if response.status != 200: return None @@ -4560,7 +4551,7 @@ def get_rest_folders( "true" if include_attrib else "false" ) response = self.get( - "projects/{}/folders{}".format(project_name, query) + f"projects/{project_name}/folders{query}" ) response.raise_for_status() return response.data["folders"] @@ -4612,12 +4603,7 @@ def get_project_names( if library is not None: query_keys["library"] = "true" if library else "false" - query = "" - if query_keys: - query = "?{}".format(",".join([ - f"{key}={value}" - for key, value in query_keys.items() - ])) + query = prepare_query_string(query_keys) response = self.get(f"projects{query}", **query_keys) response.raise_for_status() @@ -5203,7 +5189,7 @@ def create_folder( create_data[key] = value response = self.post( - "projects/{}/folders".format(project_name), + f"projects/{project_name}/folders", **create_data ) response.raise_for_status() @@ -5289,7 +5275,7 @@ def delete_folder( folder, products, versions and representations. """ - url = "projects/{}/folders/{}".format(project_name, folder_id) + url = f"projects/{project_name}/folders/{folder_id}" if force: url += "?force=true" response = self.delete(url) @@ -5709,7 +5695,7 @@ def create_task( create_data[key] = value response = self.post( - "projects/{}/tasks".format(project_name), + f"projects/{project_name}/tasks", **create_data ) response.raise_for_status() @@ -5781,7 +5767,7 @@ def update_task( update_data[key] = value response = self.patch( - "projects/{}/tasks/{}".format(project_name, task_id), + f"projects/{project_name}/tasks/{task_id}", **update_data ) response.raise_for_status() @@ -5795,7 +5781,7 @@ def delete_task(self, project_name: str, task_id: str): """ response = self.delete( - "projects/{}/tasks/{}".format(project_name, task_id) + f"projects/{project_name}/tasks/{task_id}" ) response.raise_for_status() @@ -6198,7 +6184,7 @@ def create_product( create_data[key] = value response = self.post( - "projects/{}/products".format(project_name), + f"projects/{project_name}/products", **create_data ) response.raise_for_status() @@ -6252,7 +6238,7 @@ def update_product( update_data[key] = value response = self.patch( - "projects/{}/products/{}".format(project_name, product_id), + f"projects/{project_name}/products/{product_id}", **update_data ) response.raise_for_status() @@ -6266,7 +6252,7 @@ def delete_product(self, project_name: str, product_id: str): """ response = self.delete( - "projects/{}/products/{}".format(project_name, product_id) + f"projects/{project_name}/products/{product_id}" ) response.raise_for_status() @@ -6808,7 +6794,7 @@ def create_version( create_data[key] = value response = self.post( - "projects/{}/versions".format(project_name), + f"projects/{project_name}/versions", **create_data ) response.raise_for_status() @@ -7446,7 +7432,7 @@ def get_repre_ids_by_context_filters( """ if not isinstance(context_filters, dict): raise TypeError( - "Expected 'dict' got {}".format(str(type(context_filters))) + f"Expected 'dict' got {str(type(context_filters))}" ) filter_body = {} @@ -7479,7 +7465,7 @@ def get_repre_ids_by_context_filters( }) response = self.post( - "projects/{}/repreContextFilter".format(project_name), + f"projects/{project_name}/repreContextFilter", context=body_context_filters, **filter_body ) @@ -7537,7 +7523,7 @@ def create_representation( create_data[key] = value response = self.post( - "projects/{}/representations".format(project_name), + f"projects/{project_name}/representations", **create_data ) response.raise_for_status() @@ -7592,9 +7578,7 @@ def update_representation( update_data[key] = value response = self.patch( - "projects/{}/representations/{}".format( - project_name, representation_id - ), + f"projects/{project_name}/representations/{representation_id}", **update_data ) response.raise_for_status() @@ -7610,9 +7594,7 @@ def delete_representation( """ response = self.delete( - "projects/{}/representation/{}".format( - project_name, representation_id - ) + f"projects/{project_name}/representation/{representation_id}" ) response.raise_for_status() @@ -7881,11 +7863,9 @@ def get_thumbnail( ): entity_type += "s" - response = self.raw_get("projects/{}/{}/{}/thumbnail".format( - project_name, - entity_type, - entity_id - )) + response = self.raw_get( + f"projects/{project_name}/{entity_type}/{entity_id}/thumbnail" + ) return self._prepare_thumbnail_content(project_name, response) def get_folder_thumbnail( @@ -7993,7 +7973,7 @@ def create_thumbnail( mime_type = get_media_mime_type(src_filepath) response = self.upload_file( - "projects/{}/thumbnails".format(project_name), + f"projects/{project_name}/thumbnails", src_filepath, request_type=RequestTypes.post, headers={"Content-Type": mime_type}, @@ -8064,14 +8044,14 @@ def create_project( """ if self.get_project(project_name): - raise ValueError("Project with name \"{}\" already exists".format( - project_name - )) + raise ValueError( + f"Project with name \"{project_name}\" already exists" + ) if not PROJECT_NAME_REGEX.match(project_name): - raise ValueError(( - "Project name \"{}\" contain invalid characters" - ).format(project_name)) + raise ValueError( + f"Project name \"{project_name}\" contain invalid characters" + ) preset = self.get_project_anatomy_preset(preset_name) @@ -8084,12 +8064,12 @@ def create_project( ) if result.status != 201: - details = "Unknown details ({})".format(result.status) + details = f"Unknown details ({result.status})" if result.data: details = result.data.get("detail") or details - raise ValueError("Failed to create project \"{}\": {}".format( - project_name, details - )) + raise ValueError( + f"Failed to create project \"{project_name}\": {details}" + ) return self.get_project(project_name) @@ -8152,7 +8132,7 @@ def update_project( if value is not None }) response = self.patch( - "projects/{}".format(project_name), + f"projects/{project_name}", **changes ) response.raise_for_status() @@ -8167,16 +8147,15 @@ def delete_project(self, project_name: str): """ if not self.get_project(project_name): - raise ValueError("Project with name \"{}\" was not found".format( - project_name - )) + raise ValueError( + f"Project with name \"{project_name}\" was not found" + ) - result = self.delete("projects/{}".format(project_name)) + result = self.delete(f"projects/{project_name}") if result.status_code != 204: + detail = result.data["detail"] raise ValueError( - "Failed to delete project \"{}\". {}".format( - project_name, result.data["detail"] - ) + f"Failed to delete project \"{project_name}\". {detail}" ) # --- Links --- @@ -8217,7 +8196,7 @@ def get_link_types(self, project_name: str) -> List[Dict[str, Any]]: list[dict[str, Any]]: Link types available on project. """ - response = self.get("projects/{}/links/types".format(project_name)) + response = self.get(f"projects/{project_name}/links/types") response.raise_for_status() return response.data["types"] @@ -8290,7 +8269,7 @@ def create_link_type( link_type_name, input_type, output_type ) response = self.put( - "projects/{}/links/types/{}".format(project_name, full_type_name), + f"projects/{project_name}/links/types/{full_type_name}", **data ) response.raise_for_status() @@ -8318,7 +8297,8 @@ def delete_link_type( link_type_name, input_type, output_type ) response = self.delete( - "projects/{}/links/types/{}".format(project_name, full_type_name)) + f"projects/{project_name}/links/types/{full_type_name}" + ) response.raise_for_status() def make_sure_link_type_exists( @@ -8402,10 +8382,10 @@ def create_link( ): kwargs["link"] = full_link_type_name if link_name: - raise UnsupportedServerVersion(( + raise UnsupportedServerVersion( "Link name is not supported" - " for version of AYON server {}" - ).format(self.server_version)) + f" for version of AYON server {self.server_version}" + ) else: kwargs["linkType"] = full_link_type_name @@ -8413,7 +8393,7 @@ def create_link( kwargs["name"] = link_name response = self.post( - "projects/{}/links".format(project_name), **kwargs + f"projects/{project_name}/links", **kwargs ) response.raise_for_status() return response.data @@ -8430,7 +8410,7 @@ def delete_link(self, project_name: str, link_id: str): """ response = self.delete( - "projects/{}/links/{}".format(project_name, link_id) + f"projects/{project_name}/links/{link_id}" ) response.raise_for_status() @@ -8582,7 +8562,7 @@ def get_entities_links( fields.discard("name") link_fields.discard("links") link_fields |= { - "links.{}".format(field) + f"links.{field}" for field in fields } # --------- @@ -8973,7 +8953,7 @@ def _send_batch_operations( op_results = result.get("operations") if op_results is None: raise FailedOperations( - "Operation failed. Content: {}".format(str(result)) + f"Operation failed. Content: {str(result)}" ) if result.get("success") or not raise_on_fail: @@ -9008,21 +8988,21 @@ def _prepare_fields( if "folderTypes" in fields: fields.remove("folderTypes") fields |= { - "folderTypes.{}".format(name) + f"folderTypes.{name}" for name in self.get_default_fields_for_type("folderType") } if "taskTypes" in fields: fields.remove("taskTypes") fields |= { - "taskTypes.{}".format(name) + f"taskTypes.{name}" for name in self.get_default_fields_for_type("taskType") } if "productTypes" in fields: fields.remove("productTypes") fields |= { - "productTypes.{}".format(name) + f"productTypes.{name}" for name in self.get_default_fields_for_type( "productType" ) From bcdeaee1db2b2784359603a18f5ea4c7dfa3b870 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:09:23 +0100 Subject: [PATCH 2/3] some forgotten format --- ayon_api/server_api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index 5f0cad048..dc6f3311f 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -2936,7 +2936,7 @@ def get_installers( if query_fields: query = "?{}".format(",".join(query_fields)) - response = self.get("desktop/installers{}".format(query)) + response = self.get(f"desktop/installers{query}") response.raise_for_status() return response.data @@ -4158,7 +4158,7 @@ def get_bundle_settings( query_values["site_id"] = site_id query = prepare_query_string(query_values) - response = self.get("settings{}".format(query)) + response = self.get(f"settings{query}") response.raise_for_status() return response.data From 1f94dd21263dc61243147d979f0602e8a1f7a302 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Thu, 23 Jan 2025 12:14:46 +0100 Subject: [PATCH 3/3] better query preparation --- ayon_api/server_api.py | 107 ++++++++++++++--------------------------- ayon_api/utils.py | 14 +++++- 2 files changed, 49 insertions(+), 72 deletions(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index dc6f3311f..b61f2f9b3 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -2479,7 +2479,7 @@ def upload_reviewable( filename = os.path.basename(filepath) headers["x-file-name"] = filename - query = f"?label={label}" if label else "" + query = prepare_query_string({"label": label or None}) endpoint = ( f"/projects/{project_name}" f"/versions/{version_id}/reviewables{query}" @@ -2924,18 +2924,10 @@ def get_installers( InstallersInfoDict: Information about installers known for server. """ - query_fields = [ - "{}={}".format(key, value) - for key, value in ( - ("version", version), - ("platform", platform_name), - ) - if value - ] - query = "" - if query_fields: - query = "?{}".format(",".join(query_fields)) - + query = prepare_query_string({ + "version": version or None, + "platform": platform_name or None, + }) response = self.get(f"desktop/installers{query}") response.raise_for_status() return response.data @@ -3299,10 +3291,9 @@ def delete_addon(self, addon_name: str, purge: Optional[bool] = None): purge (Optional[bool]): Purge all data related to the addon. """ - query_data = {} if purge is not None: - query_data["purge"] = "true" if purge else "false" - query = prepare_query_string(query_data) + purge = "true" if purge else "false" + query = prepare_query_string({"purge": purge}) response = self.delete(f"addons/{addon_name}{query}") response.raise_for_status() @@ -3323,10 +3314,9 @@ def delete_addon_version( purge (Optional[bool]): Purge all data related to the addon. """ - query_data = {} if purge is not None: - query_data["purge"] = "true" if purge else "false" - query = prepare_query_string(query_data) + purge = "true" if purge else "false" + query = prepare_query_string({"purge": purge}) response = self.delete(f"addons/{addon_name}/{addon_version}{query}") response.raise_for_status() @@ -3829,10 +3819,7 @@ def _get_project_roots_values( platform_name = platform.system() query_data["platform"] = platform_name.lower() - query = "?{}".format(",".join([ - "{}={}".format(key, value) - for key, value in query_data.items() - ])) + query = prepare_query_string(query_data) response = self.get( f"projects/{project_name}/siteRoots{query}" ) @@ -3960,10 +3947,7 @@ def get_addon_studio_settings( if variant is None: variant = self.default_settings_variant - query_items = {} - if variant: - query_items["variant"] = variant - query = prepare_query_string(query_items) + query = prepare_query_string({"variant": variant or None}) result = self.get( f"addons/{addon_name}/{addon_version}/settings{query}" @@ -4011,17 +3995,13 @@ def get_addon_project_settings( elif not site_id: site_id = self.site_id - query_items = {} - if site_id: - query_items["site"] = site_id - if variant is None: variant = self.default_settings_variant - if variant: - query_items["variant"] = variant - - query = prepare_query_string(query_items) + query = prepare_query_string({ + "site": site_id or None, + "variant": variant or None, + }) result = self.get( f"addons/{addon_name}/{addon_version}" f"/settings/{project_name}{query}" @@ -4142,22 +4122,17 @@ def get_bundle_settings( dict[str, Any]: All settings for single bundle. """ - query_values = { - key: value - for key, value in ( - ("project_name", project_name), - ("variant", variant or self.default_settings_variant), - ("bundle_name", bundle_name), - ) - if value - } - if use_site: - if not site_id: - site_id = self.site_id - if site_id: - query_values["site_id"] = site_id + if not use_site: + site_id = None + elif not site_id: + site_id = self.site_id - query = prepare_query_string(query_values) + query = prepare_query_string({ + "project_name": project_name or None, + "bundle_name": bundle_name or None, + "variant": variant or self.default_settings_variant or None, + "site_id": site_id, + }) response = self.get(f"settings{query}") response.raise_for_status() return response.data @@ -4547,9 +4522,9 @@ def get_rest_folders( "Function 'get_folders_rest' is supported" " for AYON server 1.0.8 and above." ) - query = "?attrib={}".format( - "true" if include_attrib else "false" - ) + query = prepare_query_string({ + "attrib": "true" if include_attrib else "false" + }) response = self.get( f"projects/{project_name}/folders{query}" ) @@ -4597,15 +4572,15 @@ def get_project_names( list[str]: List of available project names. """ - query_keys = {} if active is not None: - query_keys["active"] = "true" if active else "false" + active = "true" if active else "false" if library is not None: - query_keys["library"] = "true" if library else "false" - query = prepare_query_string(query_keys) + library = "true" if library else "false" - response = self.get(f"projects{query}", **query_keys) + query = prepare_query_string({"active": active, "library": library}) + + response = self.get(f"projects{query}") response.raise_for_status() data = response.data project_names = [] @@ -4759,18 +4734,10 @@ def get_folders_hierarchy( if folder_types: folder_types = ",".join(folder_types) - query_fields = [ - "{}={}".format(key, value) - for key, value in ( - ("search", search_string), - ("types", folder_types), - ) - if value - ] - query = "" - if query_fields: - query = "?{}".format(",".join(query_fields)) - + query = prepare_query_string({ + "search": search_string or None, + "types": folder_types or None, + }) response = self.get( f"projects/{project_name}/hierarchy{query}" ) diff --git a/ayon_api/utils.py b/ayon_api/utils.py index a0033672c..bd391b3cb 100644 --- a/ayon_api/utils.py +++ b/ayon_api/utils.py @@ -139,19 +139,29 @@ def is_valid(self) -> bool: ) -def prepare_query_string(key_values: Dict[str, Any]): +def prepare_query_string( + key_values: Dict[str, Any], skip_none: bool = True +) -> str: """Prepare data to query string. If there are any values a query starting with '?' is returned otherwise an empty string. Args: - dict[str, Any]: Query values. + key_values (dict[str, Any]): Query values. + skip_none (bool): Filter values which are 'None'. Returns: str: Query string. """ + if skip_none: + key_values = { + key: value + for key, value in key_values.items() + if value is not None + } + if not key_values: return "" return "?{}".format(urlencode(key_values))