From 7be1b3387428b366857c7ab6360770e1c478e9ab Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:15:24 +0100 Subject: [PATCH 1/8] fix routes to download and download things --- ayon_api/_api_helpers/bundles_addons.py | 8 +++++--- ayon_api/_api_helpers/dependency_packages.py | 4 ++-- ayon_api/_api_helpers/installers.py | 4 ++-- ayon_api/_api_helpers/thumbnails.py | 8 ++++---- ayon_api/server_api.py | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/ayon_api/_api_helpers/bundles_addons.py b/ayon_api/_api_helpers/bundles_addons.py index 6355b62eb..9fc5de162 100644 --- a/ayon_api/_api_helpers/bundles_addons.py +++ b/ayon_api/_api_helpers/bundles_addons.py @@ -398,7 +398,7 @@ def upload_addon_zip( """ response = self.upload_file( - "addons/install", + "api/addons/install", src_filepath, progress=progress, request_type=RequestTypes.post, @@ -448,9 +448,11 @@ def download_addon_private_file( "private", filename ) - url = f"{self.get_base_url()}/{endpoint}" self.download_file( - url, dst_filepath, chunk_size=chunk_size, progress=progress + endpoint, + dst_filepath, + chunk_size=chunk_size, + progress=progress, ) return dst_filepath diff --git a/ayon_api/_api_helpers/dependency_packages.py b/ayon_api/_api_helpers/dependency_packages.py index dc1f43e94..a2c72f40a 100644 --- a/ayon_api/_api_helpers/dependency_packages.py +++ b/ayon_api/_api_helpers/dependency_packages.py @@ -189,7 +189,7 @@ def download_dependency_package( route = self._get_dependency_package_route(src_filename) package_filepath = os.path.join(dst_directory, dst_filename) self.download_file( - route, + f"api/{route}", package_filepath, chunk_size=chunk_size, progress=progress @@ -225,7 +225,7 @@ def upload_dependency_package( ) route = self._get_dependency_package_route(dst_filename) - self.upload_file(route, src_filepath, progress=progress) + self.upload_file(f"api/{route}", src_filepath, progress=progress) def _get_dependency_package_route( self, filename: Optional[str] = None diff --git a/ayon_api/_api_helpers/installers.py b/ayon_api/_api_helpers/installers.py index be2bcaaec..72aa5193c 100644 --- a/ayon_api/_api_helpers/installers.py +++ b/ayon_api/_api_helpers/installers.py @@ -143,7 +143,7 @@ def download_installer( """ return self.download_file( - f"desktop/installers/{filename}", + f"api/desktop/installers/{filename}", dst_filepath, chunk_size=chunk_size, progress=progress @@ -168,7 +168,7 @@ def upload_installer( """ return self.upload_file( - f"desktop/installers/{dst_filename}", + f"api/desktop/installers/{dst_filename}", src_filepath, progress=progress ) diff --git a/ayon_api/_api_helpers/thumbnails.py b/ayon_api/_api_helpers/thumbnails.py index 577536e28..9d534fd5e 100644 --- a/ayon_api/_api_helpers/thumbnails.py +++ b/ayon_api/_api_helpers/thumbnails.py @@ -256,7 +256,7 @@ def create_thumbnail( mime_type = get_media_mime_type(src_filepath) response = self.upload_file( - f"projects/{project_name}/thumbnails", + f"api/projects/{project_name}/thumbnails", src_filepath, request_type=RequestTypes.post, headers={"Content-Type": mime_type}, @@ -295,7 +295,7 @@ def create_thumbnail_with_stream( mime_type = get_media_mime_type_for_stream(stream) response = self.upload_file_from_stream( - f"projects/{project_name}/thumbnails", + f"api/projects/{project_name}/thumbnails", stream, request_type=RequestTypes.post, headers={"Content-Type": mime_type}, @@ -325,7 +325,7 @@ def update_thumbnail( mime_type = get_media_mime_type(src_filepath) response = self.upload_file( - f"projects/{project_name}/thumbnails/{thumbnail_id}", + f"api/projects/{project_name}/thumbnails/{thumbnail_id}", src_filepath, request_type=RequestTypes.put, headers={"Content-Type": mime_type}, @@ -351,7 +351,7 @@ def update_thumbnail_from_stream( """ mime_type = get_media_mime_type_for_stream(stream) response = self.upload_file_from_stream( - f"projects/{project_name}/thumbnails/{thumbnail_id}", + f"api/projects/{project_name}/thumbnails/{thumbnail_id}", stream, request_type=RequestTypes.put, headers={"Content-Type": mime_type}, diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index 4dc4b3449..d91e16156 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1813,7 +1813,7 @@ def upload_reviewable( query = prepare_query_string({"label": label or None}) endpoint = ( - f"/projects/{project_name}" + f"api/projects/{project_name}" f"/versions/{version_id}/reviewables{query}" ) return self.upload_file( From a524c2b249f441f5dd133af071c34dc9ee169ef5 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:13:05 +0100 Subject: [PATCH 2/8] set content size only once --- ayon_api/server_api.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index d91e16156..48c0684a1 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1585,13 +1585,7 @@ def _upload_chunks_iter( bytes: Chunk of file. """ - # Get size of file - file_stream.seek(0, io.SEEK_END) - size = file_stream.tell() file_stream.seek(0) - # Set content size to progress object - progress.set_content_size(size) - while True: chunk = file_stream.read(chunk_size) if not chunk: @@ -1643,6 +1637,12 @@ def _upload_file( retries = self.get_default_max_retries() response = None + + # Get size of file + stream.seek(0, io.SEEK_END) + size = stream.tell() + # Set content size to progress object + progress.set_content_size(size) for attempt in range(retries): try: response = post_func( From ee4b45b282e1f303a0ffe025b3eea33c1825b85f Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:14:04 +0100 Subject: [PATCH 3/8] don't use rest by default --- ayon_api/server_api.py | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index 48c0684a1..5cae48bcd 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1595,17 +1595,18 @@ def _upload_chunks_iter( def _upload_file( self, - url: str, + endpoint: str, stream: StreamType, progress: TransferProgress, request_type: Optional[RequestType] = None, chunk_size: Optional[int] = None, + use_rest: bool = False, **kwargs ) -> requests.Response: """Upload file to server. Args: - url (str): Url where file will be uploaded. + endpoint (str): Endpoint used to upload. stream (StreamType): File stream. progress (TransferProgress): Object that gives ability to track progress. @@ -1623,6 +1624,11 @@ def _upload_file( if request_type is None: request_type = RequestTypes.put + endpoint = endpoint.lstrip("/") + url = self._endpoint_to_url(endpoint, use_rest=use_rest) + + progress.set_destination_url(url) + if self._session is None: headers = kwargs.setdefault("headers", {}) for key, value in self.get_headers().items(): @@ -1672,6 +1678,7 @@ def upload_file_from_stream( stream: StreamType, progress: Optional[TransferProgress] = None, request_type: Optional[RequestType] = None, + use_rest: bool = False, **kwargs ) -> requests.Response: """Upload file to server from bytes. @@ -1687,6 +1694,8 @@ def upload_file_from_stream( to track upload progress. request_type (Optional[RequestType]): Type of request that will be used to upload file. + use_rest (bool): Use rest api endpoint (prefix + endpoint with 'api/'). **kwargs (Any): Additional arguments that will be passed to request function. @@ -1694,19 +1703,21 @@ def upload_file_from_stream( requests.Response: Response object """ - url = self._endpoint_to_url(endpoint) - # Create dummy object so the function does not have to check # 'progress' variable everywhere if progress is None: progress = TransferProgress() - progress.set_destination_url(url) progress.set_started() try: return self._upload_file( - url, stream, progress, request_type, **kwargs + endpoint, + stream, + progress, + request_type, + use_rest=use_rest, + **kwargs ) except Exception as exc: @@ -1722,6 +1733,7 @@ def upload_file( filepath: str, progress: Optional[TransferProgress] = None, request_type: Optional[RequestType] = None, + use_rest: bool = False, **kwargs ) -> requests.Response: """Upload file to server. @@ -1737,6 +1749,8 @@ def upload_file( to track upload progress. request_type (Optional[RequestType]): Type of request that will be used to upload file. + use_rest (bool): Use rest api endpoint (prefix + endpoint with 'api/'). **kwargs (Any): Additional arguments that will be passed to request function. @@ -1751,7 +1765,12 @@ def upload_file( with open(filepath, "rb") as stream: return self.upload_file_from_stream( - endpoint, stream, progress, request_type, **kwargs + endpoint, + stream, + progress, + request_type, + use_rest=use_rest, + **kwargs ) def upload_reviewable( From b4c7c1ce26957b4960c8242cc6bb51c25abfa678 Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:17:14 +0100 Subject: [PATCH 4/8] auto-fix endpoint --- ayon_api/server_api.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index 5cae48bcd..16ee138d2 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1600,7 +1600,6 @@ def _upload_file( progress: TransferProgress, request_type: Optional[RequestType] = None, chunk_size: Optional[int] = None, - use_rest: bool = False, **kwargs ) -> requests.Response: """Upload file to server. @@ -1625,8 +1624,7 @@ def _upload_file( request_type = RequestTypes.put endpoint = endpoint.lstrip("/") - url = self._endpoint_to_url(endpoint, use_rest=use_rest) - + url = self._endpoint_to_url(endpoint, use_rest=False) progress.set_destination_url(url) if self._session is None: @@ -1649,6 +1647,8 @@ def _upload_file( size = stream.tell() # Set content size to progress object progress.set_content_size(size) + + api_prepended = False for attempt in range(retries): try: response = post_func( @@ -1658,6 +1658,13 @@ def _upload_file( ), **kwargs ) + # Auto-fix missing 'api/' + if response.status_code == 405 and not api_prepended: + api_prepended = True + if not endpoint.startswith("api/"): + url = self._endpoint_to_url(endpoint, use_rest=True) + progress.set_destination_url(url) + continue break except ( @@ -1670,6 +1677,11 @@ def _upload_file( progress.reset_transferred() response.raise_for_status() + if api_prepended: + self.log.warning( + f"Auto-fixed endpoint '{endpoint}' -> 'api/{endpoint}'." + " Please fix the endpoit passed to the function." + ) return response def upload_file_from_stream( @@ -1678,7 +1690,6 @@ def upload_file_from_stream( stream: StreamType, progress: Optional[TransferProgress] = None, request_type: Optional[RequestType] = None, - use_rest: bool = False, **kwargs ) -> requests.Response: """Upload file to server from bytes. @@ -1694,8 +1705,6 @@ def upload_file_from_stream( to track upload progress. request_type (Optional[RequestType]): Type of request that will be used to upload file. - use_rest (bool): Use rest api endpoint (prefix - endpoint with 'api/'). **kwargs (Any): Additional arguments that will be passed to request function. @@ -1716,7 +1725,6 @@ def upload_file_from_stream( stream, progress, request_type, - use_rest=use_rest, **kwargs ) @@ -1733,7 +1741,6 @@ def upload_file( filepath: str, progress: Optional[TransferProgress] = None, request_type: Optional[RequestType] = None, - use_rest: bool = False, **kwargs ) -> requests.Response: """Upload file to server. @@ -1749,8 +1756,6 @@ def upload_file( to track upload progress. request_type (Optional[RequestType]): Type of request that will be used to upload file. - use_rest (bool): Use rest api endpoint (prefix - endpoint with 'api/'). **kwargs (Any): Additional arguments that will be passed to request function. @@ -1769,7 +1774,6 @@ def upload_file( stream, progress, request_type, - use_rest=use_rest, **kwargs ) From 4c7d27f85513574ec6d888dfe783f4d0b5918c3f Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:19:08 +0100 Subject: [PATCH 5/8] better check --- ayon_api/server_api.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index 16ee138d2..f516301a2 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1661,7 +1661,10 @@ def _upload_file( # Auto-fix missing 'api/' if response.status_code == 405 and not api_prepended: api_prepended = True - if not endpoint.startswith("api/"): + if ( + not endpoint.startswith(self._base_url) + and not endpoint.startswith("api/") + ): url = self._endpoint_to_url(endpoint, use_rest=True) progress.set_destination_url(url) continue From e11c77ca1d5c94b730873486d24ffd5cf908ca6e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:31:30 +0100 Subject: [PATCH 6/8] auto-fix download too --- ayon_api/server_api.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index f516301a2..aeb637d64 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1352,7 +1352,7 @@ def _endpoint_to_url( def _download_file_to_stream( self, - url: str, + endpoint: str, stream: StreamType, chunk_size: int, progress: TransferProgress, @@ -1367,7 +1367,11 @@ def _download_file_to_stream( else: get_func = self._session_functions_mapping[RequestTypes.get] + url = self._endpoint_to_url(endpoint, use_rest=False) + progress.set_source_url(url) + retries = self.get_default_max_retries() + api_prepended = False for attempt in range(retries): # Continue in download offset = progress.get_transferred_size() @@ -1376,6 +1380,18 @@ def _download_file_to_stream( try: with get_func(url, **kwargs) as response: + # Auto-fix missing 'api/' + if response.status_code == 405 and not api_prepended: + api_prepended = True + if ( + not endpoint.startswith(self._base_url) + and not endpoint.startswith("api/") + ): + url = self._endpoint_to_url( + endpoint, use_rest=True + ) + progress.set_destination_url(url) + continue response.raise_for_status() if progress.get_content_size() is None: progress.set_content_size( @@ -1427,17 +1443,14 @@ def download_file_to_stream( if not chunk_size: chunk_size = self.default_download_chunk_size - url = self._endpoint_to_url(endpoint, use_rest=False) - if progress is None: progress = TransferProgress() - progress.set_source_url(url) progress.set_started() try: self._download_file_to_stream( - url, stream, chunk_size, progress + endpoint, stream, chunk_size, progress ) except Exception as exc: @@ -1648,7 +1661,6 @@ def _upload_file( # Set content size to progress object progress.set_content_size(size) - api_prepended = False for attempt in range(retries): try: response = post_func( From 1fbeb0f7be702fc88db0337519930ef206ffda6e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:32:23 +0100 Subject: [PATCH 7/8] added autofix warning --- ayon_api/server_api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index aeb637d64..c9a98fc5d 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1411,6 +1411,12 @@ def _download_file_to_stream( raise progress.next_attempt() + if api_prepended: + self.log.warning( + f"Auto-fixed endpoint '{endpoint}' -> 'api/{endpoint}'." + " Please fix the endpoit passed to the function." + ) + def download_file_to_stream( self, endpoint: str, From 425e5fd79c0a399ee089a3d4ca0e91207d4feb8e Mon Sep 17 00:00:00 2001 From: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:39:39 +0100 Subject: [PATCH 8/8] add missing variable --- ayon_api/server_api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ayon_api/server_api.py b/ayon_api/server_api.py index c9a98fc5d..6705126b2 100644 --- a/ayon_api/server_api.py +++ b/ayon_api/server_api.py @@ -1667,6 +1667,7 @@ def _upload_file( # Set content size to progress object progress.set_content_size(size) + api_prepended = False for attempt in range(retries): try: response = post_func(