diff --git a/README.md b/README.md index 9716565..6c9fd1f 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ from crowdin_api import CrowdinClient class FirstCrowdinClient(CrowdinClient): TOKEN = "__token__" + PROJECT_ID = 1 # Optional, set project id for all API's ORGANIZATION = "organizationName" # Optional, for Crowdin Enterprise only TIMEOUT = 60 # Optional, sets http request timeout. RETRY_DELAY = 0.1 # Optional, sets the delay between failed requests diff --git a/crowdin_api/api_resources/abstract/resources.py b/crowdin_api/api_resources/abstract/resources.py index 353e86c..b3b2892 100644 --- a/crowdin_api/api_resources/abstract/resources.py +++ b/crowdin_api/api_resources/abstract/resources.py @@ -5,12 +5,20 @@ class BaseResource(metaclass=ABCMeta): - def __init__(self, requester: APIRequester, page_size=25): + def __init__( + self, requester: APIRequester, project_id: Optional[int] = None, page_size=25 + ): self.requester = requester + self.project_id = project_id self.page_size = page_size self._flag_fetch_all = None self._max_limit = None + def get_project_id(self): + if self.project_id is None: + raise ValueError("You must set project id for client") + return self.project_id + def _get_page_params(self, page: int): if page < 1: raise ValueError("The page number must be greater than or equal to 1.") diff --git a/crowdin_api/api_resources/abstract/tests/test_resources.py b/crowdin_api/api_resources/abstract/tests/test_resources.py index e8b0d8e..cac1916 100644 --- a/crowdin_api/api_resources/abstract/tests/test_resources.py +++ b/crowdin_api/api_resources/abstract/tests/test_resources.py @@ -7,6 +7,14 @@ class TestBaseResource: + def test_get_project_id(self, base_absolut_url): + project_id = 1 + resource = BaseResource( + requester=APIRequester(base_url=base_absolut_url), + project_id=project_id, + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "in_params,out_params", ( diff --git a/crowdin_api/api_resources/bundles/resource.py b/crowdin_api/api_resources/bundles/resource.py index 0335409..fe305e1 100644 --- a/crowdin_api/api_resources/bundles/resource.py +++ b/crowdin_api/api_resources/bundles/resource.py @@ -28,7 +28,7 @@ def get_bundles_exports_path(self, projectId: int, bundleId: int, exportId: Opti def list_bundles( self, - projectId: int, + projectId: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, ): @@ -43,6 +43,7 @@ def list_bundles( """ params = self.get_page_params(offset=offset, limit=limit) + projectId = projectId or self.get_project_id() return self._get_entire_data( method="get", @@ -52,11 +53,11 @@ def list_bundles( def add_bundle( self, - projectId: int, name: str, format: str, sourcePatterns: Iterable[str], exportPattern: str, + projectId: Optional[int] = None, ignorePatterns: Optional[Iterable[str]] = None, isMultilingual: Optional[bool] = None, includeProjectSourceLanguage: Optional[bool] = None, @@ -73,6 +74,8 @@ def add_bundle( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.bundles.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_bundles_path(projectId=projectId), @@ -89,7 +92,7 @@ def add_bundle( } ) - def get_bundle(self, projectId: int, bundleId: int): + def get_bundle(self, bundleId: int, projectId: Optional[int] = None): """ Get Bundle. @@ -100,12 +103,14 @@ def get_bundle(self, projectId: int, bundleId: int): https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.bundles.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_bundles_path(projectId=projectId, bundleId=bundleId), ) - def delete_bundle(self, projectId: int, bundleId: int): + def delete_bundle(self, bundleId: int, projectId: Optional[int] = None): """ Delete Bundle. @@ -116,12 +121,19 @@ def delete_bundle(self, projectId: int, bundleId: int): https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.bundles.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_bundles_path(projectId=projectId, bundleId=bundleId), ) - def edit_bundle(self, projectId: int, bundleId: int, data: Iterable[BundlePatchRequest]): + def edit_bundle( + self, + bundleId: int, + data: Iterable[BundlePatchRequest], + projectId: Optional[int] = None, + ): """ Edit Bundle. @@ -132,6 +144,8 @@ def edit_bundle(self, projectId: int, bundleId: int, data: Iterable[BundlePatchR https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.bundles.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_bundles_path(projectId=projectId, bundleId=bundleId), @@ -139,10 +153,7 @@ def edit_bundle(self, projectId: int, bundleId: int, data: Iterable[BundlePatchR ) def download_bundle( - self, - projectId: int, - bundleId: int, - exportId: str + self, bundleId: int, exportId: str, projectId: Optional[int] = None ): """ Download bundle. @@ -154,16 +165,14 @@ def download_bundle( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.bundles.exports.download.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=f"{self.get_bundles_exports_path(projectId=projectId, bundleId=bundleId, exportId=exportId)}/download", ) - def export_bundle( - self, - projectId: int, - bundleId: int - ): + def export_bundle(self, bundleId: int, projectId: Optional[int] = None): """ Export bundle. @@ -174,16 +183,15 @@ def export_bundle( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.bundles.exports.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_bundles_exports_path(projectId=projectId, bundleId=bundleId), ) def check_bundle_export_status( - self, - projectId: int, - bundleId: int, - exportId: str + self, bundleId: int, exportId: str, projectId: Optional[int] = None ): """ Check Bundle Export Status. @@ -195,6 +203,8 @@ def check_bundle_export_status( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.bundles.exports.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_bundles_exports_path(projectId=projectId, bundleId=bundleId, exportId=exportId), @@ -202,8 +212,8 @@ def check_bundle_export_status( def get_bundle_list_files( self, - projectId: int, bundleId: int, + projectId: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, ): @@ -218,6 +228,7 @@ def get_bundle_list_files( """ params = self.get_page_params(offset=offset, limit=limit) + projectId = projectId or self.get_project_id() return self._get_entire_data( method="get", diff --git a/crowdin_api/api_resources/bundles/tests/test_bundles_resources.py b/crowdin_api/api_resources/bundles/tests/test_bundles_resources.py index 17b9e37..5b56a20 100644 --- a/crowdin_api/api_resources/bundles/tests/test_bundles_resources.py +++ b/crowdin_api/api_resources/bundles/tests/test_bundles_resources.py @@ -14,6 +14,13 @@ class TestBundlesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( diff --git a/crowdin_api/api_resources/dictionaries/resource.py b/crowdin_api/api_resources/dictionaries/resource.py index 497cee4..6a13466 100644 --- a/crowdin_api/api_resources/dictionaries/resource.py +++ b/crowdin_api/api_resources/dictionaries/resource.py @@ -18,7 +18,7 @@ class DictionariesResource(BaseResource): def list_dictionaries( self, - projectId: int, + projectId: Optional[int] = None, languageIds: Optional[Iterable[str]] = None, page: Optional[int] = None, offset: Optional[int] = None, @@ -33,6 +33,7 @@ def list_dictionaries( params = self.get_page_params(page=page, offset=offset, limit=limit) params["languageIds"] = None if languageIds is None else ",".join(languageIds) + projectId = projectId or self.get_project_id() return self._get_entire_data( method="get", @@ -40,7 +41,12 @@ def list_dictionaries( params=params, ) - def edit_dictionary(self, projectId: int, languageId: str, data: Iterable[DictionaryPatchPath]): + def edit_dictionary( + self, + languageId: str, + data: Iterable[DictionaryPatchPath], + projectId: Optional[int] = None, + ): """ Edit Dictionary. @@ -48,6 +54,8 @@ def edit_dictionary(self, projectId: int, languageId: str, data: Iterable[Dictio https://developer.crowdin.com/api/v2/#operation/api.projects.dictionaries.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=f"projects/{projectId}/dictionaries/{languageId}", diff --git a/crowdin_api/api_resources/dictionaries/tests/test_dictionaries_resources.py b/crowdin_api/api_resources/dictionaries/tests/test_dictionaries_resources.py index 668c8bd..3bf8d90 100644 --- a/crowdin_api/api_resources/dictionaries/tests/test_dictionaries_resources.py +++ b/crowdin_api/api_resources/dictionaries/tests/test_dictionaries_resources.py @@ -12,6 +12,13 @@ class TestDictionariesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_project_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, request_params", ( diff --git a/crowdin_api/api_resources/distributions/resource.py b/crowdin_api/api_resources/distributions/resource.py index 26b9267..bbf719d 100644 --- a/crowdin_api/api_resources/distributions/resource.py +++ b/crowdin_api/api_resources/distributions/resource.py @@ -21,7 +21,7 @@ def get_distributions_path(self, projectId: int, hash: Optional[str] = None): def list_distributions( self, - projectId: int, + projectId: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, ): @@ -32,6 +32,8 @@ def list_distributions( https://developer.crowdin.com/api/v2/#operation/api.projects.distributions.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_distributions_path(projectId=projectId), @@ -39,12 +41,12 @@ def list_distributions( ) def add_distribution( - self, - projectId: int, - name: str, - fileIds: Optional[Iterable[int]] = None, - bundleIds: Optional[Iterable[int]] = None, - exportMode: Optional[ExportMode] = ExportMode.DEFAULT + self, + name: str, + projectId: Optional[int] = None, + fileIds: Optional[Iterable[int]] = None, + bundleIds: Optional[Iterable[int]] = None, + exportMode: Optional[ExportMode] = ExportMode.DEFAULT, ): """ Add Distribution. @@ -53,6 +55,8 @@ def add_distribution( https://developer.crowdin.com/api/v2/#operation/api.projects.distributions.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_distributions_path(projectId=projectId), @@ -64,7 +68,7 @@ def add_distribution( }, ) - def get_distribution(self, projectId: int, hash: str): + def get_distribution(self, hash: str, projectId: Optional[int] = None): """ Get Distribution. @@ -72,12 +76,14 @@ def get_distribution(self, projectId: int, hash: str): https://developer.crowdin.com/api/v2/#operation/api.projects.distributions.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_distributions_path(projectId=projectId, hash=hash), ) - def delete_distribution(self, projectId: int, hash: str): + def delete_distribution(self, hash: str, projectId: Optional[int] = None): """ Delete Distribution. @@ -85,13 +91,18 @@ def delete_distribution(self, projectId: int, hash: str): https://developer.crowdin.com/api/v2/#operation/api.projects.distributions.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_distributions_path(projectId=projectId, hash=hash), ) def edit_distribution( - self, projectId: int, hash: str, data: Iterable[DistributionPatchRequest] + self, + hash: str, + data: Iterable[DistributionPatchRequest], + projectId: Optional[int] = None, ): """ Edit Distribution. @@ -100,13 +111,15 @@ def edit_distribution( https://developer.crowdin.com/api/v2/#operation/api.projects.distributions.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_distributions_path(projectId=projectId, hash=hash), request_data=data, ) - def get_distribution_release(self, projectId: int, hash: str): + def get_distribution_release(self, hash: str, projectId: Optional[int] = None): """ Get Distribution Release. @@ -114,12 +127,14 @@ def get_distribution_release(self, projectId: int, hash: str): https://developer.crowdin.com/api/v2/#operation/api.projects.distributions.release.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=f"{self.get_distributions_path(projectId=projectId, hash=hash)}/release", ) - def release_distribution(self, projectId: int, hash: str): + def release_distribution(self, hash: str, projectId: Optional[int] = None): """ Release Distribution. @@ -127,6 +142,8 @@ def release_distribution(self, projectId: int, hash: str): https://developer.crowdin.com/api/v2/#operation/api.projects.distributions.release.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"{self.get_distributions_path(projectId=projectId, hash=hash)}/release", diff --git a/crowdin_api/api_resources/distributions/tests/test_distributions_resources.py b/crowdin_api/api_resources/distributions/tests/test_distributions_resources.py index 0bb7fd1..60da7a4 100644 --- a/crowdin_api/api_resources/distributions/tests/test_distributions_resources.py +++ b/crowdin_api/api_resources/distributions/tests/test_distributions_resources.py @@ -13,6 +13,13 @@ class TestLanguagesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_project_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( diff --git a/crowdin_api/api_resources/glossaries/resource.py b/crowdin_api/api_resources/glossaries/resource.py index d955a46..5d117ef 100644 --- a/crowdin_api/api_resources/glossaries/resource.py +++ b/crowdin_api/api_resources/glossaries/resource.py @@ -204,10 +204,10 @@ def check_glossary_import_status(self, glossaryId: int, importId: str): def concordance_search_in_glossaries( self, - projectId: int, sourceLanguageId: str, targetLanguageId: str, expressions: Iterable[str], + projectId: Optional[int] = None, ): """ Concordance search in Glossaries @@ -221,6 +221,8 @@ def concordance_search_in_glossaries( "expressions": expressions, } + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"projects/{projectId}/glossaries/concordance", diff --git a/crowdin_api/api_resources/glossaries/tests/test_glossaries_resources.py b/crowdin_api/api_resources/glossaries/tests/test_glossaries_resources.py index e0fedbd..c67fd70 100644 --- a/crowdin_api/api_resources/glossaries/tests/test_glossaries_resources.py +++ b/crowdin_api/api_resources/glossaries/tests/test_glossaries_resources.py @@ -22,6 +22,13 @@ class TestGlossariesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_project_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + # Glossaries @pytest.mark.parametrize( "in_params, path", @@ -237,7 +244,7 @@ def test_concordance_search_in_glossaries(self, m_request, base_absolut_url): ], } - assert resource.concordance_search_in_glossaries(1, **data) == "response" + assert resource.concordance_search_in_glossaries(projectId=1, **data) == "response" m_request.assert_called_once_with( method="post", path="projects/1/glossaries/concordance", diff --git a/crowdin_api/api_resources/labels/resource.py b/crowdin_api/api_resources/labels/resource.py index 2d9f528..5f4c3ac 100644 --- a/crowdin_api/api_resources/labels/resource.py +++ b/crowdin_api/api_resources/labels/resource.py @@ -20,7 +20,7 @@ def get_labels_path(self, projectId: int, labelId: Optional[int] = None): def list_labels( self, - projectId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -32,13 +32,15 @@ def list_labels( https://developer.crowdin.com/api/v2/#operation/api.projects.labels.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_labels_path(projectId=projectId), params=self.get_page_params(page=page, offset=offset, limit=limit), ) - def add_label(self, projectId: int, title: str): + def add_label(self, title: str, projectId: Optional[int] = None): """ Add Label. @@ -46,13 +48,15 @@ def add_label(self, projectId: int, title: str): https://developer.crowdin.com/api/v2/#operation/api.projects.labels.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_labels_path(projectId=projectId), request_data={"title": title}, ) - def get_label(self, projectId: int, labelId: int): + def get_label(self, labelId: int, projectId: Optional[int] = None): """ Get Label. @@ -60,12 +64,14 @@ def get_label(self, projectId: int, labelId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.labels.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_labels_path(projectId=projectId, labelId=labelId), ) - def delete_label(self, projectId: int, labelId: int): + def delete_label(self, labelId: int, projectId: Optional[int] = None): """ Delete Label. @@ -73,12 +79,19 @@ def delete_label(self, projectId: int, labelId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.labels.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_labels_path(projectId=projectId, labelId=labelId), ) - def edit_label(self, projectId: int, labelId: int, data: Iterable[LabelsPatchRequest]): + def edit_label( + self, + labelId: int, + data: Iterable[LabelsPatchRequest], + projectId: Optional[int] = None, + ): """ Edit Label. @@ -86,6 +99,8 @@ def edit_label(self, projectId: int, labelId: int, data: Iterable[LabelsPatchReq https://developer.crowdin.com/api/v2/#operation/api.projects.labels.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_labels_path(projectId=projectId, labelId=labelId), @@ -95,7 +110,12 @@ def edit_label(self, projectId: int, labelId: int, data: Iterable[LabelsPatchReq def get_screenshots_path(self, project_id: int, label_id: int): return f"projects/{project_id}/labels/{label_id}/screenshots" - def assign_label_to_screenshots(self, project_id: int, label_id: int, screenshot_ids: Iterable[int]): + def assign_label_to_screenshots( + self, + label_id: int, + screenshot_ids: Iterable[int], + project_id: Optional[int] = None, + ): """ Assign Label to Screenshots @@ -104,6 +124,8 @@ def assign_label_to_screenshots(self, project_id: int, label_id: int, screenshot https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.labels.screenshots.post """ + project_id = project_id or self.get_project_id() + return self.requester.request( method="post", path=self.get_screenshots_path(project_id, label_id), @@ -112,7 +134,12 @@ def assign_label_to_screenshots(self, project_id: int, label_id: int, screenshot } ) - def unassign_label_from_screenshots(self, project_id: int, label_id: int, screenshot_ids: Iterable[int]): + def unassign_label_from_screenshots( + self, + label_id: int, + screenshot_ids: Iterable[int], + project_id: Optional[int] = None, + ): """ Unassign Label from Screenshots @@ -121,6 +148,7 @@ def unassign_label_from_screenshots(self, project_id: int, label_id: int, screen https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.labels.screenshots.deleteMany """ + project_id = project_id or self.get_project_id() query = ",".join(str(screenshot_id) for screenshot_id in screenshot_ids) return self.requester.request( @@ -128,7 +156,9 @@ def unassign_label_from_screenshots(self, project_id: int, label_id: int, screen path=f"{self.get_screenshots_path(project_id, label_id)}?screenshotIds={query}" ) - def assign_label_to_strings(self, projectId: int, labelId: int, stringIds: Iterable[int]): + def assign_label_to_strings( + self, labelId: int, stringIds: Iterable[int], projectId: Optional[int] = None + ): """ Assign Label to Strings. @@ -136,13 +166,17 @@ def assign_label_to_strings(self, projectId: int, labelId: int, stringIds: Itera https://developer.crowdin.com/api/v2/#operation/api.projects.labels.strings.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", request_data={"stringIds": stringIds}, path=f"{self.get_labels_path(projectId=projectId, labelId=labelId)}/strings", ) - def unassign_label_from_strings(self, projectId: int, labelId: int, stringIds: Iterable[int]): + def unassign_label_from_strings( + self, labelId: int, stringIds: Iterable[int], projectId: Optional[int] = None + ): """ Unassign Label from Strings. @@ -150,6 +184,8 @@ def unassign_label_from_strings(self, projectId: int, labelId: int, stringIds: I https://developer.crowdin.com/api/v2/#operation/api.projects.labels.strings.deleteMany """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", params={"stringIds": ",".join(str(stringId) for stringId in stringIds)}, diff --git a/crowdin_api/api_resources/labels/tests/test_labels_resources.py b/crowdin_api/api_resources/labels/tests/test_labels_resources.py index 239b13f..846c0b2 100644 --- a/crowdin_api/api_resources/labels/tests/test_labels_resources.py +++ b/crowdin_api/api_resources/labels/tests/test_labels_resources.py @@ -13,6 +13,13 @@ class TestLabelsResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "in_params, path", ( diff --git a/crowdin_api/api_resources/notifications/resource.py b/crowdin_api/api_resources/notifications/resource.py index fc69c11..8d1013a 100644 --- a/crowdin_api/api_resources/notifications/resource.py +++ b/crowdin_api/api_resources/notifications/resource.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Union, Optional from crowdin_api.api_resources.abstract.resources import BaseResource from crowdin_api.api_resources.notifications.types import ( @@ -28,8 +28,8 @@ def send_notification_to_authenticated_user(self, message: str): def send_notification_to_project_members( self, - projectId: int, request_data: Union[ByUserIdsRequestScheme, ByRoleRequestScehme], + projectId: Optional[int] = None, ): """ Send Notification To Project Members @@ -41,6 +41,9 @@ def send_notification_to_project_members( Link to documentation (Enterprise): https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.notify.post """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"projects/{projectId}/notify", diff --git a/crowdin_api/api_resources/notifications/tests/test_notification_resources.py b/crowdin_api/api_resources/notifications/tests/test_notification_resources.py index afc0e96..f619b4b 100644 --- a/crowdin_api/api_resources/notifications/tests/test_notification_resources.py +++ b/crowdin_api/api_resources/notifications/tests/test_notification_resources.py @@ -12,6 +12,13 @@ class TestNotificationResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @mock.patch("crowdin_api.requester.APIRequester.request") def test_send_notification_to_authenticated_user(self, m_request, base_absolut_url): m_request.return_value = "response" diff --git a/crowdin_api/api_resources/projects/resource.py b/crowdin_api/api_resources/projects/resource.py index 8192d85..ff9907c 100644 --- a/crowdin_api/api_resources/projects/resource.py +++ b/crowdin_api/api_resources/projects/resource.py @@ -200,7 +200,7 @@ def add_strings_based_project( }, ) - def get_project(self, projectId: int): + def get_project(self, projectId: Optional[int] = None): """ Get Project. @@ -208,11 +208,13 @@ def get_project(self, projectId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_projects_path(projectId=projectId) ) - def delete_project(self, projectId: int): + def delete_project(self, projectId: Optional[int] = None): """ Delete Project. @@ -220,17 +222,24 @@ def delete_project(self, projectId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_projects_path(projectId=projectId) ) - def edit_project(self, projectId: int, data: Iterable[ProjectPatchRequest]): + def edit_project( + self, data: Iterable[ProjectPatchRequest], projectId: Optional[int] = None + ): """ Edit Project. Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.patch """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_projects_path(projectId=projectId), @@ -247,13 +256,18 @@ def get_project_file_format_settings_path( return f"projects/{projectId}/file-format-settings" - def download_project_file_custom_segmentation(self, projectId: int, fileFormatSettingsId: int): + def download_project_file_custom_segmentation( + self, fileFormatSettingsId: int, projectId: Optional[int] = None + ): """ Download Project File Format Settings Custom Segmentation. Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.file-format-settings.custom-segmentations.get """ + + projectId = projectId or self.get_project_id() + path = self.get_project_file_format_settings_path( projectId=projectId, fileFormatSettingsId=fileFormatSettingsId @@ -264,13 +278,17 @@ def download_project_file_custom_segmentation(self, projectId: int, fileFormatSe path=f"{path}/custom-segmentations", ) - def reset_project_file_custom_segmentation(self, projectId: int, fileFormatSettingsId: int): + def reset_project_file_custom_segmentation( + self, fileFormatSettingsId: int, projectId: Optional[int] = None + ): """ Reset Project File Format Settings Custom Segmentation. Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.file-format-settings.custom-segmentations.delete """ + + projectId = projectId or self.get_project_id() path = self.get_project_file_format_settings_path( projectId=projectId, fileFormatSettingsId=fileFormatSettingsId @@ -283,7 +301,7 @@ def reset_project_file_custom_segmentation(self, projectId: int, fileFormatSetti def list_project_file_format_settings( self, - projectId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -294,6 +312,8 @@ def list_project_file_format_settings( Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.file-format-settings.getMany """ + + projectId = projectId or self.get_project_id() params = self.get_page_params(page=page, offset=offset, limit=limit) return self._get_entire_data( @@ -304,13 +324,13 @@ def list_project_file_format_settings( def add_project_file_format_settings( self, - projectId: int, format: str, settings: Union[ PropertyFileFormatSettings, XmlFileFormatSettings, SpecificFileFormatSettings, DocxFileFormatSettings, MediaWikiFileFormatSettings, TxtFileFormatSettings, OtherFileFormatSettings - ] + ], + projectId: Optional[int] = None, ): """ Add Project File Format Settings. @@ -319,13 +339,17 @@ def add_project_file_format_settings( https://developer.crowdin.com/api/v2/#operation/api.projects.file-format-settings.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_project_file_format_settings_path(projectId=projectId), request_data={"format": format, "settings": settings} ) - def get_project_file_format_settings(self, projectId: int, fileFormatSettingsId: int): + def get_project_file_format_settings( + self, fileFormatSettingsId: int, projectId: Optional[int] = None + ): """ Get Project File Format Settings. @@ -333,6 +357,8 @@ def get_project_file_format_settings(self, projectId: int, fileFormatSettingsId: https://developer.crowdin.com/api/v2/#operation/api.projects.file-format-settings.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_project_file_format_settings_path( @@ -341,7 +367,9 @@ def get_project_file_format_settings(self, projectId: int, fileFormatSettingsId: ), ) - def delete_project_file_format_settings(self, projectId: int, fileFormatSettingsId: int): + def delete_project_file_format_settings( + self, fileFormatSettingsId: int, projectId: Optional[int] = None + ): """ Delete Project File Format Settings. @@ -349,6 +377,8 @@ def delete_project_file_format_settings(self, projectId: int, fileFormatSettings https://developer.crowdin.com/api/v2/#operation/api.projects.file-format-settings.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_project_file_format_settings_path( @@ -359,9 +389,9 @@ def delete_project_file_format_settings(self, projectId: int, fileFormatSettings def edit_project_file_format_settings( self, - projectId: int, fileFormatSettingsId: int, - data: Iterable[ProjectFilePatchRequest] + data: Iterable[ProjectFilePatchRequest], + projectId: Optional[int] = None, ): """ Edit Project File Format Settings. @@ -370,6 +400,8 @@ def edit_project_file_format_settings( https://developer.crowdin.com/api/v2/#operation/api.projects.file-format-settings.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_project_file_format_settings_path( @@ -390,7 +422,7 @@ def get_strings_exporter_path( def list_project_strings_exporter_settings( self, - projectId: int, + projectId: Optional[int] = None, ): """ List Project Strings Exporter Settings. @@ -398,6 +430,9 @@ def list_project_strings_exporter_settings( Link to documetation: https://developer.crowdin.com/api/v2/#operation/api.projects.strings-exporter-settings.getMany """ + + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_strings_exporter_path(projectId=projectId), @@ -405,13 +440,13 @@ def list_project_strings_exporter_settings( def add_project_strings_exporter_settings( self, - projectId: int, format: str, settings: Union[ AndroidStringsExporterSettings, MacOSXStringsExporterSettings, XliffStringsExporterSettings, ], + projectId: Optional[int] = None, ): """ Add Project Strings Exporter Settings. @@ -419,6 +454,9 @@ def add_project_strings_exporter_settings( Link to documetation: https://developer.crowdin.com/api/v2/#operation/api.projects.strings-exporter-settings.post """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_strings_exporter_path(projectId=projectId), @@ -426,7 +464,7 @@ def add_project_strings_exporter_settings( ) def get_project_strings_exporter_settings( - self, projectId: int, systemStringExporterSettingsId: int + self, systemStringExporterSettingsId: int, projectId: Optional[int] = None ): """ Get Project Strings Exporter Settings @@ -434,6 +472,9 @@ def get_project_strings_exporter_settings( Link to documetation: https://developer.crowdin.com/api/v2/#operation/api.projects.strings-exporter-settings.get """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_strings_exporter_path( @@ -443,7 +484,7 @@ def get_project_strings_exporter_settings( ) def delete_project_strings_exporter_settings( - self, projectId: int, systemStringExporterSettingsId: int + self, systemStringExporterSettingsId: int, projectId: Optional[int] = None ): """ Delete Project Strings Exporter Settings. @@ -451,6 +492,9 @@ def delete_project_strings_exporter_settings( Link to documetation: https://developer.crowdin.com/api/v2/#operation/api.projects.strings-exporter-settings.delete """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_strings_exporter_path( @@ -461,7 +505,6 @@ def delete_project_strings_exporter_settings( def edit_project_strings_exporter_settings( self, - projectId: int, systemStringExporterSettingsId: int, format: str, settings: Union[ @@ -469,6 +512,7 @@ def edit_project_strings_exporter_settings( MacOSXStringsExporterSettings, XliffStringsExporterSettings, ], + projectId: Optional[int] = None, ): """ Edit Project Strings Exporter Settings. @@ -476,6 +520,9 @@ def edit_project_strings_exporter_settings( Link to documetation: https://developer.crowdin.com/api/v2/#operation/api.projects.strings-exporter-settings.patch """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_strings_exporter_path( diff --git a/crowdin_api/api_resources/projects/tests/test_projects_resources.py b/crowdin_api/api_resources/projects/tests/test_projects_resources.py index 0264035..a3f38b9 100644 --- a/crowdin_api/api_resources/projects/tests/test_projects_resources.py +++ b/crowdin_api/api_resources/projects/tests/test_projects_resources.py @@ -26,6 +26,13 @@ class TestProjectsResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "projectId, path", ( diff --git a/crowdin_api/api_resources/reports/resource.py b/crowdin_api/api_resources/reports/resource.py index 11a5794..9e3821e 100644 --- a/crowdin_api/api_resources/reports/resource.py +++ b/crowdin_api/api_resources/reports/resource.py @@ -39,7 +39,7 @@ def get_reports_path(self, projectId: int, reportId: Optional[str] = None): return f"projects/{projectId}/reports" - def generate_report(self, projectId: int, request_data: Dict): + def generate_report(self, request_data: Dict, projectId: Optional[int] = None): """ Generate Report. @@ -50,6 +50,8 @@ def generate_report(self, projectId: int, request_data: Dict): https://developer.crowdin.com/enterprise/api/v2/#operation/api.reports.download.download """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_reports_path(projectId=projectId), @@ -58,27 +60,35 @@ def generate_report(self, projectId: int, request_data: Dict): @abc.abstractmethod @deprecated("Use other methods instead") - def generate_simple_cost_estimate_report(self, projectId: int, **kwargs): + def generate_simple_cost_estimate_report( + self, projectId: Optional[int] = None, **kwargs + ): raise NotImplementedError("Not implemented") @abc.abstractmethod @deprecated("Use other methods instead") - def generate_fuzzy_cost_estimate_report(self, projectId: int, **kwargs): + def generate_fuzzy_cost_estimate_report( + self, projectId: Optional[int] = None, **kwargs + ): raise NotImplementedError("Not implemented") @abc.abstractmethod @deprecated("Use other methods instead") - def generate_simple_translation_cost_report(self, projectId: int, **kwargs): + def generate_simple_translation_cost_report( + self, projectId: Optional[int] = None, **kwargs + ): raise NotImplementedError("Not implemented") @abc.abstractmethod @deprecated("Use other methods instead") - def generate_fuzzy_translation_cost_report(self, projectId: int, **kwargs): + def generate_fuzzy_translation_cost_report( + self, projectId: Optional[int] = None, **kwargs + ): raise NotImplementedError("Not implemented") def generate_top_members_report( self, - projectId: int, + projectId: Optional[int] = None, unit: Optional[Unit] = None, languageId: Optional[str] = None, format: Optional[Format] = Format.XLSX, @@ -94,6 +104,9 @@ def generate_top_members_report( Link to documentation for enterprise: https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + + projectId = projectId or self.get_project_id() + return self.generate_report( projectId=projectId, request_data={ @@ -110,8 +123,8 @@ def generate_top_members_report( def generate_contribution_raw_data_report( self, - projectId: int, mode: ContributionMode, + projectId: Optional[int] = None, unit: Optional[Unit] = None, languageId: Optional[str] = None, userId: Optional[int] = None, @@ -128,6 +141,8 @@ def generate_contribution_raw_data_report( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() + return self.generate_report( projectId=projectId, request_data={ @@ -145,10 +160,10 @@ def generate_contribution_raw_data_report( def generate_costs_estimation_post_editing_general_report( self, - project_id: int, base_rates: BaseRates, individual_rates: Iterable[CostEstimationPeIndividualRate], net_rate_schemes: CostEstimationPeNetRateSchemes, + project_id: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = None, @@ -173,6 +188,8 @@ def generate_costs_estimation_post_editing_general_report( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + project_id = project_id or self.get_project_id() + return self.generate_report( projectId=project_id, request_data={ @@ -200,7 +217,7 @@ def generate_costs_estimation_post_editing_general_report( def generate_costs_estimation_post_editing_by_task_report( self, - project_id: int, + project_id: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = None, @@ -221,6 +238,8 @@ def generate_costs_estimation_post_editing_by_task_report( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + project_id = project_id or self.get_project_id() + return self.generate_report( projectId=project_id, request_data={ @@ -241,10 +260,10 @@ def generate_costs_estimation_post_editing_by_task_report( def generate_translation_costs_post_editing_general_report( self, - project_id: int, base_rates: BaseRates, individual_rates: Iterable[CostEstimationPeIndividualRate], net_rate_schemes: CostEstimationPeNetRateSchemes, + project_id: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = None, @@ -267,6 +286,8 @@ def generate_translation_costs_post_editing_general_report( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + project_id = project_id or self.get_project_id() + return self.generate_report( projectId=project_id, request_data={ @@ -292,10 +313,10 @@ def generate_translation_costs_post_editing_general_report( def generate_translation_costs_post_editing_by_task_report( self, - project_id: int, base_rates: BaseRates, individual_rates: Iterable[CostEstimationPeIndividualRate], net_rate_schemes: CostEstimationPeNetRateSchemes, + project_id: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = None, @@ -311,6 +332,8 @@ def generate_translation_costs_post_editing_by_task_report( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + project_id = project_id or self.get_project_id() + return self.generate_report( projectId=project_id, request_data={ @@ -327,7 +350,9 @@ def generate_translation_costs_post_editing_by_task_report( } ) - def check_report_generation_status(self, projectId: int, reportId: str): + def check_report_generation_status( + self, reportId: str, projectId: Optional[int] = None + ): """ Check Report Generation Status. @@ -338,12 +363,14 @@ def check_report_generation_status(self, projectId: int, reportId: str): https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_reports_path(projectId=projectId, reportId=reportId), ) - def download_report(self, projectId: int, reportId: str): + def download_report(self, reportId: str, projectId: Optional[int] = None): """ Download Report. @@ -354,6 +381,8 @@ def download_report(self, projectId: int, reportId: str): https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.download.download """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=f"{self.get_reports_path(projectId=projectId, reportId=reportId)}/download", @@ -373,7 +402,7 @@ def get_report_settings_templates_path( def list_report_settings_template( self, - projectId: int, + projectId: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None ): @@ -387,6 +416,8 @@ def list_report_settings_template( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.settings-templates.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_report_settings_templates_path(projectId=projectId), @@ -395,11 +426,11 @@ def list_report_settings_template( def add_report_settings_template( self, - projectId: int, name: str, currency: Currency, unit: Unit, config: Config, + projectId: Optional[int] = None, ): """ Add Report Settings Templates. @@ -411,6 +442,8 @@ def add_report_settings_template( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.settings-templates.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_report_settings_templates_path( @@ -427,8 +460,8 @@ def add_report_settings_template( def get_report_settings_template( self, - projectId: int, reportSettingsTemplateId: int, + projectId: Optional[int] = None, ): """ Get Report Settings Templates. @@ -440,6 +473,8 @@ def get_report_settings_template( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.settings-templates.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_report_settings_templates_path( @@ -450,10 +485,9 @@ def get_report_settings_template( def edit_report_settings_template( self, - projectId: int, reportSettingsTemplateId: int, - data: Iterable[ReportSettingsTemplatesPatchRequest] - + data: Iterable[ReportSettingsTemplatesPatchRequest], + projectId: Optional[int] = None, ): """ Edit Report Settings Templates. @@ -465,6 +499,8 @@ def edit_report_settings_template( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.settings-templates.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_report_settings_templates_path( @@ -476,8 +512,8 @@ def edit_report_settings_template( def delete_report_settings_template( self, - projectId: int, reportSettingsTemplateId: int, + projectId: Optional[int] = None, ): """ Delete Report Settings Templates. @@ -489,6 +525,8 @@ def delete_report_settings_template( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.settings-templates.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_report_settings_templates_path( @@ -515,7 +553,7 @@ class ReportsResource(BaseReportsResource, BaseReportSettingsTemplatesResource): @deprecated("Use other methods instead") def generate_simple_cost_estimate_report( self, - projectId: int, + projectId: Optional[int] = None, # Schema unit: Optional[Unit] = None, currency: Optional[Currency] = None, @@ -534,6 +572,8 @@ def generate_simple_cost_estimate_report( https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() + return self.generate_report( projectId=projectId, request_data={ @@ -556,7 +596,7 @@ def generate_simple_cost_estimate_report( @deprecated("Use other methods instead") def generate_fuzzy_cost_estimate_report( self, - projectId: int, + projectId: Optional[int] = None, # Schema unit: Optional[Unit] = None, currency: Optional[Currency] = None, @@ -576,6 +616,8 @@ def generate_fuzzy_cost_estimate_report( https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() + return self.generate_report( projectId=projectId, request_data={ @@ -599,7 +641,7 @@ def generate_fuzzy_cost_estimate_report( @deprecated("Use other methods instead") def generate_simple_translation_cost_report( self, - projectId: int, + projectId: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = Format.XLSX, @@ -616,6 +658,8 @@ def generate_simple_translation_cost_report( https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() + return self.generate_report( projectId=projectId, request_data={ @@ -637,7 +681,7 @@ def generate_simple_translation_cost_report( @deprecated("Use other methods instead") def generate_fuzzy_translation_cost_report( self, - projectId: int, + projectId: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = Format.XLSX, @@ -654,6 +698,8 @@ def generate_fuzzy_translation_cost_report( https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() + return self.generate_report( projectId=projectId, request_data={ @@ -699,7 +745,7 @@ def _prepare_stepTypes(step_types_const: dict, stepTypes: Optional[Iterable[Step @deprecated("Use other methods instead") def generate_simple_cost_estimate_report( self, - projectId: int, + projectId: Optional[int] = None, # Schema unit: Optional[Unit] = None, currency: Optional[Currency] = None, @@ -716,6 +762,7 @@ def generate_simple_cost_estimate_report( Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() step_types_const = { "type": "Translate", "mode": "simple", @@ -742,7 +789,7 @@ def generate_simple_cost_estimate_report( @deprecated("Use other methods instead") def generate_fuzzy_cost_estimate_report( self, - projectId: int, + projectId: Optional[int] = None, # Schema unit: Optional[Unit] = None, currency: Optional[Currency] = None, @@ -759,6 +806,7 @@ def generate_fuzzy_cost_estimate_report( Links to documentation: https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() step_types_const = { "type": "Translate", "mode": "fuzzy", @@ -786,7 +834,7 @@ def generate_fuzzy_cost_estimate_report( @deprecated("Use other methods instead") def generate_simple_translation_cost_report( self, - projectId: int, + projectId: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = Format.XLSX, @@ -801,6 +849,7 @@ def generate_simple_translation_cost_report( Link to documentation: https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() step_types_const = { "type": "Translate", "mode": "simple", @@ -826,7 +875,7 @@ def generate_simple_translation_cost_report( @deprecated("Use other methods instead") def generate_fuzzy_translation_cost_report( self, - projectId: int, + projectId: Optional[int] = None, unit: Optional[Unit] = None, currency: Optional[Currency] = None, format: Optional[Format] = Format.XLSX, @@ -841,6 +890,7 @@ def generate_fuzzy_translation_cost_report( Link to documentation: https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.reports.post """ + projectId = projectId or self.get_project_id() step_types_const = { "type": "Translate", "mode": "fuzzy", diff --git a/crowdin_api/api_resources/reports/tests/test_reports_resources.py b/crowdin_api/api_resources/reports/tests/test_reports_resources.py index e350779..ea815df 100644 --- a/crowdin_api/api_resources/reports/tests/test_reports_resources.py +++ b/crowdin_api/api_resources/reports/tests/test_reports_resources.py @@ -39,6 +39,13 @@ class TestReportsResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( @@ -1428,6 +1435,13 @@ class TestBaseReportSettingsTemplatesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( diff --git a/crowdin_api/api_resources/screenshots/resource.py b/crowdin_api/api_resources/screenshots/resource.py index 8b5665e..d8c6551 100644 --- a/crowdin_api/api_resources/screenshots/resource.py +++ b/crowdin_api/api_resources/screenshots/resource.py @@ -30,7 +30,7 @@ def get_screenshots_path(self, projectId: int, screenshotId: Optional[int] = Non def list_screenshots( self, - projectId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -42,6 +42,8 @@ def list_screenshots( https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_screenshots_path(projectId=projectId), @@ -50,9 +52,9 @@ def list_screenshots( def add_screenshot( self, - projectId: int, storageId: int, name: str, + projectId: Optional[int] = None, autoTag: Optional[bool] = None, ): """ @@ -62,6 +64,8 @@ def add_screenshot( https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_screenshots_path(projectId=projectId), @@ -72,7 +76,7 @@ def add_screenshot( }, ) - def get_screenshot(self, projectId: int, screenshotId: int): + def get_screenshot(self, screenshotId: int, projectId: Optional[int] = None): """ Get Screenshot. @@ -80,12 +84,20 @@ def get_screenshot(self, projectId: int, screenshotId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_screenshots_path(projectId=projectId, screenshotId=screenshotId), ) - def update_screenshot(self, projectId: int, screenshotId: int, storageId: int, name: str): + def update_screenshot( + self, + screenshotId: int, + storageId: int, + name: str, + projectId: Optional[int] = None, + ): """ Update Screenshot. @@ -93,6 +105,8 @@ def update_screenshot(self, projectId: int, screenshotId: int, storageId: int, n https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.put """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="put", request_data={ @@ -102,7 +116,7 @@ def update_screenshot(self, projectId: int, screenshotId: int, storageId: int, n path=self.get_screenshots_path(projectId=projectId, screenshotId=screenshotId), ) - def delete_screenshot(self, projectId: int, screenshotId: int): + def delete_screenshot(self, screenshotId: int, projectId: Optional[int] = None): """ Delete Screenshot. @@ -110,13 +124,18 @@ def delete_screenshot(self, projectId: int, screenshotId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_screenshots_path(projectId=projectId, screenshotId=screenshotId), ) def edit_screenshot( - self, projectId: int, screenshotId: int, data: Iterable[ScreenshotPatchRequest] + self, + screenshotId: int, + data: Iterable[ScreenshotPatchRequest], + projectId: Optional[int] = None, ): """ Edit Screenshot. @@ -125,6 +144,8 @@ def edit_screenshot( https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", request_data=data, @@ -140,8 +161,8 @@ def get_tags_path(self, projectId: int, screenshotId: int, tagId: Optional[int] def list_tags( self, - projectId: int, screenshotId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -153,13 +174,20 @@ def list_tags( https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_tags_path(projectId=projectId, screenshotId=screenshotId), params=self.get_page_params(page=page, offset=offset, limit=limit), ) - def replace_tags(self, projectId: int, screenshotId: int, data: Iterable[AddTagRequest]): + def replace_tags( + self, + screenshotId: int, + data: Iterable[AddTagRequest], + projectId: Optional[int] = None, + ): """ Replace Tags. @@ -167,13 +195,17 @@ def replace_tags(self, projectId: int, screenshotId: int, data: Iterable[AddTagR https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.putMany """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="put", path=self.get_tags_path(projectId=projectId, screenshotId=screenshotId), request_data=data, ) - def auto_tag(self, projectId: int, screenshotId: int, autoTag: bool): + def auto_tag( + self, screenshotId: int, autoTag: bool, projectId: Optional[int] = None + ): """ Auto Tag. @@ -181,13 +213,20 @@ def auto_tag(self, projectId: int, screenshotId: int, autoTag: bool): https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.putMany """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="put", path=self.get_tags_path(projectId=projectId, screenshotId=screenshotId), request_data={"autoTag": autoTag}, ) - def add_tag(self, projectId: int, screenshotId: int, data: Iterable[AddTagRequest]): + def add_tag( + self, + screenshotId: int, + data: Iterable[AddTagRequest], + projectId: Optional[int] = None, + ): """ Add Tag. @@ -195,13 +234,15 @@ def add_tag(self, projectId: int, screenshotId: int, data: Iterable[AddTagReques https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_tags_path(projectId=projectId, screenshotId=screenshotId), request_data=data, ) - def clear_tags(self, projectId: int, screenshotId: int): + def clear_tags(self, screenshotId: int, projectId: Optional[int] = None): """ Clear Tags. @@ -209,12 +250,14 @@ def clear_tags(self, projectId: int, screenshotId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.deleteMany """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_tags_path(projectId=projectId, screenshotId=screenshotId), ) - def get_tag(self, projectId: int, screenshotId: int, tagId: int): + def get_tag(self, screenshotId: int, tagId: int, projectId: Optional[int] = None): """ Get Tag. @@ -222,12 +265,16 @@ def get_tag(self, projectId: int, screenshotId: int, tagId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_tags_path(projectId=projectId, screenshotId=screenshotId, tagId=tagId), ) - def delete_tag(self, projectId: int, screenshotId: int, tagId: int): + def delete_tag( + self, screenshotId: int, tagId: int, projectId: Optional[int] = None + ): """ Delete Tag. @@ -235,6 +282,8 @@ def delete_tag(self, projectId: int, screenshotId: int, tagId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_tags_path(projectId=projectId, screenshotId=screenshotId, tagId=tagId), @@ -242,10 +291,10 @@ def delete_tag(self, projectId: int, screenshotId: int, tagId: int): def edit_tag( self, - projectId: int, screenshotId: int, tagId: int, data: Iterable[TagPatchRequest], + projectId: Optional[int] = None, ): """ Edit Tag. @@ -254,6 +303,8 @@ def edit_tag( https://developer.crowdin.com/api/v2/#operation/api.projects.screenshots.tags.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", request_data=data, diff --git a/crowdin_api/api_resources/screenshots/tests/test_screenshots_resources.py b/crowdin_api/api_resources/screenshots/tests/test_screenshots_resources.py index ff52572..a328d5a 100644 --- a/crowdin_api/api_resources/screenshots/tests/test_screenshots_resources.py +++ b/crowdin_api/api_resources/screenshots/tests/test_screenshots_resources.py @@ -13,6 +13,13 @@ class TestSourceFilesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + # Screenshots @pytest.mark.parametrize( "in_params, path", diff --git a/crowdin_api/api_resources/source_files/resource.py b/crowdin_api/api_resources/source_files/resource.py index 1996168..2e23e77 100644 --- a/crowdin_api/api_resources/source_files/resource.py +++ b/crowdin_api/api_resources/source_files/resource.py @@ -50,7 +50,7 @@ def get_branch_path(self, projectId: int, branchId: Optional[int] = None): def list_project_branches( self, - projectId: int, + projectId: Optional[int] = None, name: Optional[str] = None, page: Optional[int] = None, offset: Optional[int] = None, @@ -63,6 +63,7 @@ def list_project_branches( https://developer.crowdin.com/api/v2/#operation/api.projects.branches.getMany """ + projectId = projectId or self.get_project_id() params = {"name": name} params.update(self.get_page_params(page=page, offset=offset, limit=limit)) @@ -72,8 +73,8 @@ def list_project_branches( def add_branch( self, - projectId: int, name: str, + projectId: Optional[int] = None, title: Optional[str] = None, exportPattern: Optional[str] = None, priority: Optional[Priority] = None, @@ -85,6 +86,8 @@ def add_branch( https://developer.crowdin.com/api/v2/#operation/api.projects.branches.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_branch_path(projectId=projectId), @@ -96,7 +99,7 @@ def add_branch( }, ) - def get_branch(self, projectId: int, branchId: int): + def get_branch(self, branchId: int, projectId: Optional[int] = None): """ Get Branch. @@ -104,12 +107,14 @@ def get_branch(self, projectId: int, branchId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.branches.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_branch_path(projectId=projectId, branchId=branchId), ) - def delete_branch(self, projectId: int, branchId: int): + def delete_branch(self, branchId: int, projectId: Optional[int] = None): """ Delete Branch. @@ -117,13 +122,18 @@ def delete_branch(self, projectId: int, branchId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.branches.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=f"projects/{projectId}/branches/{branchId}", ) def edit_branch( - self, projectId: int, branchId: int, data: Iterable[BranchPatchRequest] + self, + branchId: int, + data: Iterable[BranchPatchRequest], + projectId: Optional[int] = None, ): """ Edit Branch. @@ -132,6 +142,8 @@ def edit_branch( https://developer.crowdin.com/api/v2/#operation/api.projects.branches.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_branch_path(projectId=projectId, branchId=branchId), @@ -147,7 +159,7 @@ def get_directory_path(self, projectId: int, directoryId: Optional[int] = None): def list_directories( self, - projectId: int, + projectId: Optional[int] = None, branchId: Optional[int] = None, directoryId: Optional[int] = None, filter: Optional[str] = None, @@ -163,6 +175,7 @@ def list_directories( https://developer.crowdin.com/api/v2/#operation/api.projects.directories.getMany """ + projectId = projectId or self.get_project_id() params = { "branchId": branchId, "directoryId": directoryId, @@ -179,8 +192,8 @@ def list_directories( def add_directory( self, - projectId: int, name: str, + projectId: Optional[int] = None, branchId: Optional[int] = None, directoryId: Optional[int] = None, title: Optional[int] = None, @@ -194,6 +207,8 @@ def add_directory( https://developer.crowdin.com/api/v2/#operation/api.projects.directories.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_directory_path(projectId=projectId), @@ -207,7 +222,7 @@ def add_directory( }, ) - def get_directory(self, projectId: int, directoryId: int): + def get_directory(self, directoryId: int, projectId: Optional[int] = None): """ Get Directory. @@ -215,12 +230,14 @@ def get_directory(self, projectId: int, directoryId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.directories.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_directory_path(projectId=projectId, directoryId=directoryId), ) - def delete_directory(self, projectId: int, directoryId: int): + def delete_directory(self, directoryId: int, projectId: Optional[int] = None): """ Delete Directory. @@ -228,13 +245,18 @@ def delete_directory(self, projectId: int, directoryId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.directories.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_directory_path(projectId=projectId, directoryId=directoryId), ) def edit_directory( - self, projectId: int, directoryId: int, data: Iterable[DirectoryPatchRequest] + self, + directoryId: int, + data: Iterable[DirectoryPatchRequest], + projectId: Optional[int] = None, ): """ Edit Directory. @@ -243,6 +265,8 @@ def edit_directory( https://developer.crowdin.com/api/v2/#operation/api.projects.directories.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_directory_path(projectId=projectId, directoryId=directoryId), @@ -258,7 +282,7 @@ def get_file_path(self, projectId: int, fileId: Optional[int] = None): def list_files( self, - projectId: int, + projectId: Optional[int] = None, branchId: Optional[int] = None, directoryId: Optional[int] = None, filter: Optional[str] = None, @@ -274,6 +298,7 @@ def list_files( https://developer.crowdin.com/api/v2/#operation/api.projects.files.getMany """ + projectId = projectId or self.get_project_id() params = { "branchId": branchId, "directoryId": directoryId, @@ -288,9 +313,9 @@ def list_files( def add_file( self, - projectId: int, storageId: int, name: str, + projectId: Optional[int] = None, branchId: Optional[int] = None, directoryId: Optional[int] = None, title: Optional[int] = None, @@ -321,6 +346,8 @@ def add_file( https://developer.crowdin.com/api/v2/#operation/api.projects.files.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_file_path(projectId=projectId), @@ -339,7 +366,7 @@ def add_file( }, ) - def get_file(self, projectId: int, fileId: int): + def get_file(self, fileId: int, projectId: Optional[int] = None): """ Get File. @@ -347,12 +374,16 @@ def get_file(self, projectId: int, fileId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.files.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_file_path(projectId=projectId, fileId=fileId), ) - def restore_file(self, projectId: int, fileId: int, revisionId: int): + def restore_file( + self, fileId: int, revisionId: int, projectId: Optional[int] = None + ): """ Restore File. @@ -360,6 +391,8 @@ def restore_file(self, projectId: int, fileId: int, revisionId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.files.put """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="put", path=self.get_file_path(projectId=projectId, fileId=fileId), @@ -368,9 +401,9 @@ def restore_file(self, projectId: int, fileId: int, revisionId: int): def update_file( self, - projectId: int, fileId: int, storageId: int, + projectId: Optional[int] = None, updateOption: Optional[FileUpdateOption] = None, importOptions: Optional[ Union[ @@ -397,6 +430,8 @@ def update_file( https://developer.crowdin.com/api/v2/#operation/api.projects.files.put """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="put", path=self.get_file_path(projectId=projectId, fileId=fileId), @@ -410,7 +445,7 @@ def update_file( }, ) - def delete_file(self, projectId: int, fileId: int): + def delete_file(self, fileId: int, projectId: Optional[int] = None): """ Delete File. @@ -418,12 +453,19 @@ def delete_file(self, projectId: int, fileId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.files.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_file_path(projectId=projectId, fileId=fileId), ) - def edit_file(self, projectId: int, fileId: int, data: Iterable[FilePatchRequest]): + def edit_file( + self, + fileId: int, + data: Iterable[FilePatchRequest], + projectId: Optional[int] = None, + ): """ Edit File. @@ -431,24 +473,29 @@ def edit_file(self, projectId: int, fileId: int, data: Iterable[FilePatchRequest https://developer.crowdin.com/api/v2/#operation/api.projects.files.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_file_path(projectId=projectId, fileId=fileId), request_data=data, ) - def download_file_preview(self, projectId: int, fileId: int): + def download_file_preview(self, fileId: int, projectId: Optional[int] = None): """ Download File Preview. Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.files.preview.get """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=f"{self.get_file_path(projectId, fileId)}/preview" ) - def download_file(self, projectId: int, fileId: int): + def download_file(self, fileId: int, projectId: Optional[int] = None): """ Download File. @@ -456,6 +503,8 @@ def download_file(self, projectId: int, fileId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.files.download.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=f"{self.get_file_path(projectId=projectId, fileId=fileId)}/download", @@ -474,8 +523,8 @@ def get_file_revisions_path( def list_file_revisions( self, - projectId: int, fileId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -487,13 +536,17 @@ def list_file_revisions( https://developer.crowdin.com/api/v2/#operation/api.projects.files.revisions.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_file_revisions_path(projectId=projectId, fileId=fileId), params=self.get_page_params(page=page, offset=offset, limit=limit), ) - def get_file_revision(self, projectId: int, fileId: int, revisionId: int): + def get_file_revision( + self, fileId: int, revisionId: int, projectId: Optional[int] = None + ): """ Get File Revision. @@ -501,6 +554,8 @@ def get_file_revision(self, projectId: int, fileId: int, revisionId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.files.revisions.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_file_revisions_path( diff --git a/crowdin_api/api_resources/source_files/tests/test_source_files_resources.py b/crowdin_api/api_resources/source_files/tests/test_source_files_resources.py index f442cff..36f19e6 100644 --- a/crowdin_api/api_resources/source_files/tests/test_source_files_resources.py +++ b/crowdin_api/api_resources/source_files/tests/test_source_files_resources.py @@ -19,6 +19,13 @@ class TestSourceFilesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + # Branches @pytest.mark.parametrize( "in_params, path", diff --git a/crowdin_api/api_resources/source_strings/resource.py b/crowdin_api/api_resources/source_strings/resource.py index 95a3561..48c0c1e 100644 --- a/crowdin_api/api_resources/source_strings/resource.py +++ b/crowdin_api/api_resources/source_strings/resource.py @@ -32,7 +32,7 @@ def get_source_strings_path(self, projectId: int, stringId: Optional[int] = None def list_strings( self, - projectId: int, + projectId: Optional[int] = None, fileId: Optional[int] = None, branchId: Optional[int] = None, denormalizePlaceholders: Optional[DenormalizePlaceholders] = None, @@ -51,6 +51,7 @@ def list_strings( https://developer.crowdin.com/api/v2/#operation/api.projects.strings.getMany """ + projectId = projectId or self.get_project_id() params = { "branchId": branchId, "fileId": fileId, @@ -70,8 +71,8 @@ def list_strings( def add_string( self, - projectId: int, text: str, + projectId: Optional[int] = None, identifier: Optional[str] = None, fileId: Optional[int] = None, context: Optional[str] = None, @@ -86,6 +87,8 @@ def add_string( https://developer.crowdin.com/api/v2/#operation/api.projects.strings.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_source_strings_path(projectId=projectId), @@ -100,7 +103,7 @@ def add_string( }, ) - def get_string(self, projectId: int, stringId: int): + def get_string(self, stringId: int, projectId: Optional[int] = None): """ Get String. @@ -108,12 +111,14 @@ def get_string(self, projectId: int, stringId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.strings.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_source_strings_path(projectId=projectId, stringId=stringId), ) - def delete_string(self, projectId: int, stringId: int): + def delete_string(self, stringId: int, projectId: Optional[int] = None): """ Delete String. @@ -121,12 +126,19 @@ def delete_string(self, projectId: int, stringId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.strings.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_source_strings_path(projectId=projectId, stringId=stringId), ) - def edit_string(self, projectId: int, stringId: int, data: Iterable[SourceStringsPatchRequest]): + def edit_string( + self, + stringId: int, + data: Iterable[SourceStringsPatchRequest], + projectId: Optional[int] = None, + ): """ Edit String. @@ -134,6 +146,8 @@ def edit_string(self, projectId: int, stringId: int, data: Iterable[SourceString https://developer.crowdin.com/api/v2/#operation/api.projects.strings.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_source_strings_path(projectId=projectId, stringId=stringId), @@ -142,8 +156,8 @@ def edit_string(self, projectId: int, stringId: int, data: Iterable[SourceString def string_batch_operation( self, - projectId: int, data: Iterable[StringBatchOperationPatchRequest], + projectId: Optional[int] = None, ): """ String Batch Operations. @@ -151,6 +165,9 @@ def string_batch_operation( Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.strings.batchPatch """ + + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_source_strings_path(projectId=projectId), diff --git a/crowdin_api/api_resources/source_strings/tests/test_source_strings_resources.py b/crowdin_api/api_resources/source_strings/tests/test_source_strings_resources.py index f903fdd..2449c45 100644 --- a/crowdin_api/api_resources/source_strings/tests/test_source_strings_resources.py +++ b/crowdin_api/api_resources/source_strings/tests/test_source_strings_resources.py @@ -18,6 +18,13 @@ class TestSourceFilesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "in_params, path", ( @@ -193,7 +200,7 @@ def test_string_batch_operation(self, m_request, base_absolut_url): }, ] resource = self.get_resource(base_absolut_url) - assert resource.string_batch_operation(1, data=data) == "response" + assert resource.string_batch_operation(projectId=1, data=data) == "response" m_request.assert_called_once_with( method="patch", path=resource.get_source_strings_path(1), diff --git a/crowdin_api/api_resources/string_comments/resource.py b/crowdin_api/api_resources/string_comments/resource.py index 7e642a6..feeebb1 100644 --- a/crowdin_api/api_resources/string_comments/resource.py +++ b/crowdin_api/api_resources/string_comments/resource.py @@ -27,7 +27,7 @@ def get_string_comments_path(self, projectId: int, stringCommentId: Optional[int def list_string_comments( self, - projectId: int, + projectId: Optional[int] = None, stringId: Optional[int] = None, type: Optional[StringCommentType] = None, issueType: Optional[Iterable[StringCommentIssueType]] = None, @@ -43,6 +43,7 @@ def list_string_comments( https://developer.crowdin.com/api/v2/#operation/api.projects.comments.getMany """ + projectId = projectId or self.get_project_id() params = { "stringId": stringId, "type": type, @@ -59,11 +60,11 @@ def list_string_comments( def add_string_comment( self, - projectId: int, text: str, stringId: int, targetLanguageId: str, type: StringCommentType, + projectId: Optional[int] = None, issueType: Optional[StringCommentIssueType] = None, ): """ @@ -73,6 +74,8 @@ def add_string_comment( https://developer.crowdin.com/api/v2/#operation/api.projects.comments.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_string_comments_path(projectId=projectId), @@ -85,7 +88,7 @@ def add_string_comment( }, ) - def get_string_comment(self, projectId: int, stringCommentId: int): + def get_string_comment(self, stringCommentId: int, projectId: Optional[int] = None): """ Get String Comment. @@ -93,6 +96,8 @@ def get_string_comment(self, projectId: int, stringCommentId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.comments.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_string_comments_path( @@ -100,7 +105,9 @@ def get_string_comment(self, projectId: int, stringCommentId: int): ), ) - def delete_string_comment(self, projectId: int, stringCommentId: int): + def delete_string_comment( + self, stringCommentId: int, projectId: Optional[int] = None + ): """ Delete String Comment. @@ -108,6 +115,8 @@ def delete_string_comment(self, projectId: int, stringCommentId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.comments.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_string_comments_path( @@ -117,9 +126,9 @@ def delete_string_comment(self, projectId: int, stringCommentId: int): def edit_string_comment( self, - projectId: int, stringCommentId: int, data: Iterable[StringCommentPatchRequest], + projectId: Optional[int] = None, ): """ Edit String Comment. @@ -128,6 +137,8 @@ def edit_string_comment( https://developer.crowdin.com/api/v2/#operation/api.projects.comments.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", request_data=data, diff --git a/crowdin_api/api_resources/string_comments/tests/test_string_comments_resources.py b/crowdin_api/api_resources/string_comments/tests/test_string_comments_resources.py index 4d0d204..f480de2 100644 --- a/crowdin_api/api_resources/string_comments/tests/test_string_comments_resources.py +++ b/crowdin_api/api_resources/string_comments/tests/test_string_comments_resources.py @@ -18,6 +18,13 @@ class TestSourceFilesResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "in_params, path", ( diff --git a/crowdin_api/api_resources/string_translations/resource.py b/crowdin_api/api_resources/string_translations/resource.py index 8b02c80..b750892 100644 --- a/crowdin_api/api_resources/string_translations/resource.py +++ b/crowdin_api/api_resources/string_translations/resource.py @@ -24,7 +24,7 @@ def get_approvals_path(self, projectId: int, approvalId: Optional[int] = None): def list_translation_approvals( self, - projectId: int, + projectId: Optional[int] = None, fileId: Optional[int] = None, stringId: Optional[int] = None, languageId: Optional[str] = None, @@ -40,6 +40,7 @@ def list_translation_approvals( https://developer.crowdin.com/api/v2/#operation/api.projects.approvals.getMany """ + projectId = projectId or self.get_project_id() params = { "fileId": fileId, "stringId": stringId, @@ -56,8 +57,8 @@ def list_translation_approvals( def add_approval( self, - projectId: int, translationId: int, + projectId: Optional[int] = None, ): """ Add Approval. @@ -66,13 +67,15 @@ def add_approval( https://developer.crowdin.com/api/v2/#operation/api.projects.approvals.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_approvals_path(projectId=projectId), request_data={"translationId": translationId}, ) - def get_approval(self, projectId: int, approvalId: int): + def get_approval(self, approvalId: int, projectId: Optional[int] = None): """ Get Approval. @@ -80,12 +83,14 @@ def get_approval(self, projectId: int, approvalId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.approvals.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_approvals_path(projectId=projectId, approvalId=approvalId), ) - def remove_approval(self, projectId: int, approvalId: int): + def remove_approval(self, approvalId: int, projectId: Optional[int] = None): """ Remove Approvall. @@ -93,6 +98,8 @@ def remove_approval(self, projectId: int, approvalId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.approvals.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_approvals_path(projectId=projectId, approvalId=approvalId), @@ -101,8 +108,8 @@ def remove_approval(self, projectId: int, approvalId: int): # Language Translations def list_language_translations( self, - projectId: int, languageId: str, + projectId: Optional[int] = None, stringIds: Optional[Iterable[int]] = None, labelIds: Optional[Iterable[int]] = None, fileId: Optional[int] = None, @@ -119,6 +126,7 @@ def list_language_translations( https://developer.crowdin.com/api/v2/#operation/api.projects.languages.translations.getMany """ + projectId = projectId or self.get_project_id() params = { "stringIds": None if stringIds is None @@ -140,10 +148,10 @@ def list_language_translations( def translation_alignment( self, - projectId: int, sourceLanguageId: str, targetLanguageId: str, text: str, + projectId: Optional[int] = None, ): """ Translation Alignment @@ -152,6 +160,7 @@ def translation_alignment( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.alignment.post """ + projectId = projectId or self.get_project_id() data = { "sourceLanguageId": sourceLanguageId, "targetLanguageId": targetLanguageId, @@ -173,7 +182,7 @@ def get_translations_path(self, projectId: int, translationId: Optional[int] = N def list_string_translations( self, - projectId: int, + projectId: Optional[int] = None, stringId: Optional[int] = None, languageId: Optional[str] = None, denormalizePlaceholders: Optional[DenormalizePlaceholders] = None, @@ -188,6 +197,7 @@ def list_string_translations( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.getMany """ + projectId = projectId or self.get_project_id() params = { "stringId": stringId, "languageId": languageId, @@ -203,10 +213,10 @@ def list_string_translations( def add_translation( self, - projectId: int, stringId: int, languageId: str, text: str, + projectId: Optional[int] = None, pluralCategoryName: Optional[PluralCategoryName] = None, ): """ @@ -216,6 +226,8 @@ def add_translation( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_translations_path(projectId=projectId), @@ -227,7 +239,9 @@ def add_translation( }, ) - def delete_string_translations(self, projectId: int, stringId: int, languageId: str): + def delete_string_translations( + self, stringId: int, languageId: str, projectId: Optional[int] = None + ): """ Delete String Translations. @@ -235,13 +249,15 @@ def delete_string_translations(self, projectId: int, stringId: int, languageId: https://developer.crowdin.com/api/v2/#operation/api.projects.translations.deleteMany """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", params={"stringId": stringId, "languageId": languageId}, path=self.get_translations_path(projectId=projectId), ) - def get_translation(self, projectId: int, translationId: int): + def get_translation(self, translationId: int, projectId: Optional[int] = None): """ Get Translation. @@ -249,12 +265,14 @@ def get_translation(self, projectId: int, translationId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.translations.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_translations_path(projectId=projectId, translationId=translationId), ) - def restore_translation(self, projectId: int, translationId: int): + def restore_translation(self, translationId: int, projectId: Optional[int] = None): """ Restore Translation. @@ -262,12 +280,14 @@ def restore_translation(self, projectId: int, translationId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.translations.put """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="put", path=self.get_translations_path(projectId=projectId, translationId=translationId), ) - def delete_translation(self, projectId: int, translationId: int): + def delete_translation(self, translationId: int, projectId: Optional[int] = None): """ Delete Translation. @@ -275,6 +295,8 @@ def delete_translation(self, projectId: int, translationId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.translations.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_translations_path(projectId=projectId, translationId=translationId), @@ -289,7 +311,7 @@ def get_translation_votes_path(self, projectId: int, voteId: Optional[int] = Non def list_translation_votes( self, - projectId: int, + projectId: Optional[int] = None, stringId: Optional[int] = None, languageId: Optional[str] = None, translationId: Optional[int] = None, @@ -304,6 +326,8 @@ def list_translation_votes( https://developer.crowdin.com/api/v2/#operation/api.projects.votes.getMany """ + projectId = projectId or self.get_project_id() + params = { "stringId": stringId, "languageId": languageId, @@ -317,7 +341,9 @@ def list_translation_votes( params=params, ) - def add_vote(self, projectId: int, mark: VoteMark, translationId: int): + def add_vote( + self, mark: VoteMark, translationId: int, projectId: Optional[int] = None + ): """ Add Vote. @@ -325,13 +351,15 @@ def add_vote(self, projectId: int, mark: VoteMark, translationId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.votes.pos """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_translation_votes_path(projectId=projectId), request_data={"translationId": translationId, "mark": mark}, ) - def get_vote(self, projectId: int, voteId: int): + def get_vote(self, voteId: int, projectId: Optional[int] = None): """ Get Vote. @@ -339,12 +367,14 @@ def get_vote(self, projectId: int, voteId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.votes.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_translation_votes_path(projectId=projectId, voteId=voteId), ) - def cancel_vote(self, projectId: int, voteId: int): + def cancel_vote(self, voteId: int, projectId: Optional[int] = None): """ Cancel Vote. @@ -352,6 +382,8 @@ def cancel_vote(self, projectId: int, voteId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.votes.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_translation_votes_path(projectId=projectId, voteId=voteId), diff --git a/crowdin_api/api_resources/string_translations/tests/test_string_translations_resources.py b/crowdin_api/api_resources/string_translations/tests/test_string_translations_resources.py index 78ee34c..0ea6505 100644 --- a/crowdin_api/api_resources/string_translations/tests/test_string_translations_resources.py +++ b/crowdin_api/api_resources/string_translations/tests/test_string_translations_resources.py @@ -13,6 +13,13 @@ class TestStringTranslationsResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + # Approval @pytest.mark.parametrize( "in_params, path", @@ -172,7 +179,7 @@ def test_translation_alignment(self, m_request, base_absolut_url): "text": "Your password has been reset successfully!" } - assert resource.translation_alignment(1, **data) + assert resource.translation_alignment(projectId=1, **data) m_request.assert_called_once_with( method="post", path="projects/1/translations/alignment", diff --git a/crowdin_api/api_resources/tasks/resource.py b/crowdin_api/api_resources/tasks/resource.py index efde67b..b3dc0d4 100644 --- a/crowdin_api/api_resources/tasks/resource.py +++ b/crowdin_api/api_resources/tasks/resource.py @@ -51,7 +51,7 @@ def get_task_settings_templates_path( def list_task_settings_templates( self, - projectId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -66,6 +66,7 @@ def list_task_settings_templates( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.tasks.settings-templates.getMany """ + projectId = projectId or self.get_project_id() params = self.get_page_params(page=page, offset=offset, limit=limit) return self._get_entire_data( @@ -76,9 +77,9 @@ def list_task_settings_templates( def add_task_settings_template( self, - projectId: int, name: str, - config: TaskSettingsTemplateLanguages + config: TaskSettingsTemplateLanguages, + projectId: Optional[int] = None, ): """ Add Task Settings Template. @@ -87,13 +88,17 @@ def add_task_settings_template( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.settings-templates.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_task_settings_templates_path(projectId=projectId), request_data={"name": name, "config": config}, ) - def get_task_settings_template(self, projectId: int, taskSettingsTemplateId: int): + def get_task_settings_template( + self, taskSettingsTemplateId: int, projectId: Optional[int] = None + ): """ Get Task Settings Template. @@ -104,6 +109,8 @@ def get_task_settings_template(self, projectId: int, taskSettingsTemplateId: int https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.tasks.settings-templates.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_task_settings_templates_path( projectId=projectId, @@ -111,7 +118,9 @@ def get_task_settings_template(self, projectId: int, taskSettingsTemplateId: int ) ) - def delete_task_settings_template(self, projectId: int, taskSettingsTemplateId: int): + def delete_task_settings_template( + self, taskSettingsTemplateId: int, projectId: Optional[int] = None + ): """ Delete Task Settings Template. @@ -122,6 +131,8 @@ def delete_task_settings_template(self, projectId: int, taskSettingsTemplateId: https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.tasks.settings-templates.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_task_settings_templates_path( @@ -132,9 +143,9 @@ def delete_task_settings_template(self, projectId: int, taskSettingsTemplateId: def edit_task_settings_template( self, - projectId: int, taskSettingsTemplateId: int, data: Iterable[ConfigPatchRequest], + projectId: Optional[int] = None, ): """ Edit Task Settings Template. @@ -146,6 +157,8 @@ def edit_task_settings_template( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.tasks.settings-templates.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_task_settings_templates_path( @@ -163,7 +176,7 @@ def get_tasks_path(self, projectId: int, taskId: Optional[int] = None): def list_tasks( self, - projectId: int, + projectId: Optional[int] = None, assigneeId: Optional[int] = None, status: Optional[CrowdinTaskStatus] = None, page: Optional[int] = None, @@ -177,6 +190,7 @@ def list_tasks( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.getMany """ + projectId = projectId or self.get_project_id() params = {"assigneeId": assigneeId, "status": status} params.update(self.get_page_params(page=page, offset=offset, limit=limit)) @@ -186,7 +200,7 @@ def list_tasks( params=params, ) - def add_task(self, projectId: int, request_data: Dict): + def add_task(self, request_data: Dict, projectId: Optional[int] = None): """ Add Task. @@ -194,6 +208,8 @@ def add_task(self, projectId: int, request_data: Dict): https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_tasks_path(projectId=projectId), @@ -202,11 +218,11 @@ def add_task(self, projectId: int, request_data: Dict): def add_general_task( self, - projectId: int, title: str, languageId: str, fileIds: Iterable[int], type: CrowdinGeneralTaskType, + projectId: Optional[int] = None, status: Optional[CrowdinTaskStatus] = None, description: Optional[str] = None, splitFiles: Optional[bool] = None, @@ -228,6 +244,8 @@ def add_general_task( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.post """ + projectId = projectId or self.get_project_id() + return self.add_task( projectId=projectId, request_data={ @@ -253,11 +271,11 @@ def add_general_task( def add_language_service_task( self, - projectId: int, title: str, languageId: str, fileIds: Iterable[str], type: LanguageServiceTaskType, + projectId: Optional[int] = None, status: Optional[CrowdinTaskStatus] = None, description: Optional[str] = None, labelIds: Optional[Iterable[int]] = None, @@ -275,6 +293,8 @@ def add_language_service_task( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.post """ + projectId = projectId or self.get_project_id() + return self.add_task( projectId=projectId, request_data={ @@ -297,11 +317,11 @@ def add_language_service_task( def add_vendor_oht_task( self, - projectId: int, title: str, languageId: str, fileIds: Iterable[int], type: OhtCrowdinTaskType, + projectId: Optional[int] = None, status: Optional[CrowdinTaskStatus] = None, description: Optional[str] = None, expertise: Optional[OhtCrowdinTaskExpertise] = None, @@ -320,6 +340,8 @@ def add_vendor_oht_task( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.post """ + projectId = projectId or self.get_project_id() + return self.add_task( projectId=projectId, request_data={ @@ -343,11 +365,11 @@ def add_vendor_oht_task( def add_vendor_gengo_task( self, - projectId: int, title: str, languageId: str, fileIds: Iterable[int], type: GengoCrowdinTaskType, + projectId: Optional[int] = None, status: Optional[CrowdinTaskStatus] = None, description: Optional[str] = None, expertise: Optional[GengoCrowdinTaskExpertise] = None, @@ -368,6 +390,8 @@ def add_vendor_gengo_task( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.post """ + projectId = projectId or self.get_project_id() + return self.add_task( projectId=projectId, request_data={ @@ -393,11 +417,11 @@ def add_vendor_gengo_task( def add_vendor_translated_task( self, - projectId: int, title: str, languageId: str, fileIds: Iterable[int], type: TranslatedCrowdinTaskType, + projectId: Optional[int] = None, status: Optional[CrowdinTaskStatus] = None, description: Optional[str] = None, expertise: Optional[TranslatedCrowdinTaskExpertise] = None, @@ -413,6 +437,9 @@ def add_vendor_translated_task( Link to documentation: https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.post """ + + projectId = projectId or self.get_project_id() + return self.add_task( projectId=projectId, request_data={ @@ -434,12 +461,12 @@ def add_vendor_translated_task( def add_vendor_manual_task( self, - projectId: int, title: str, languageId: str, fileIds: Iterable[int], type: ManualCrowdinTaskType, vendor: ManualCrowdinVendors, + projectId: Optional[int] = None, status: Optional[CrowdinTaskStatus] = None, description: Optional[str] = None, skipAssignedStrings: Optional[bool] = None, @@ -460,6 +487,8 @@ def add_vendor_manual_task( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.post """ + projectId = projectId or self.get_project_id() + return self.add_task( projectId=projectId, request_data={ @@ -480,10 +509,10 @@ def add_vendor_manual_task( "startedAt": startedAt, "dateFrom": dateFrom, "dateTo": dateTo, - } + }, ) - def export_task_strings(self, projectId: int, taskId: int): + def export_task_strings(self, taskId: int, projectId: Optional[int] = None): """ Export Task Strings. @@ -491,12 +520,14 @@ def export_task_strings(self, projectId: int, taskId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.exports.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"{self.get_tasks_path(projectId=projectId, taskId=taskId)}/exports", ) - def get_task(self, projectId: int, taskId: int): + def get_task(self, taskId: int, projectId: Optional[int] = None): """ Get Task. @@ -504,11 +535,13 @@ def get_task(self, projectId: int, taskId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_tasks_path(projectId=projectId, taskId=taskId) ) - def delete_task(self, projectId: int, taskId: int): + def delete_task(self, taskId: int, projectId: Optional[int] = None): """ Delete Task. @@ -516,6 +549,8 @@ def delete_task(self, projectId: int, taskId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_tasks_path(projectId=projectId, taskId=taskId), @@ -523,9 +558,9 @@ def delete_task(self, projectId: int, taskId: int): def edit_task( self, - projectId: int, taskId: int, data: Union[Iterable[VendorPatchRequest], Iterable[TaskPatchRequest]], + projectId: Optional[int] = None, ): """ Edit Task. @@ -534,6 +569,8 @@ def edit_task( https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_tasks_path(projectId=projectId, taskId=taskId), @@ -564,7 +601,9 @@ def list_user_tasks( return self._get_entire_data(method="get", path="user/tasks", params=params) - def edit_task_archived_status(self, taskId: int, projectId: int, isArchived: bool = True): + def edit_task_archived_status( + self, taskId: int, isArchived: bool = True, projectId: Optional[int] = None + ): """ Edit Task Archived Status. @@ -572,6 +611,8 @@ def edit_task_archived_status(self, taskId: int, projectId: int, isArchived: boo https://developer.crowdin.com/api/v2/#operation/api.user.tasks.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=f"user/tasks/{taskId}", @@ -596,9 +637,9 @@ class EnterpriseTasksResource(TasksResource): def add_task_settings_template( self, - projectId: int, name: str, - config: EnterpriseTaskSettingsTemplateLanguages + config: EnterpriseTaskSettingsTemplateLanguages, + projectId: Optional[int] = None, ): """ Add Task Settings Template. @@ -607,6 +648,8 @@ def add_task_settings_template( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.tasks.settings-templates.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_task_settings_templates_path(projectId=projectId), diff --git a/crowdin_api/api_resources/tasks/tests/test_tasks_resources.py b/crowdin_api/api_resources/tasks/tests/test_tasks_resources.py index f3c98d4..518392b 100644 --- a/crowdin_api/api_resources/tasks/tests/test_tasks_resources.py +++ b/crowdin_api/api_resources/tasks/tests/test_tasks_resources.py @@ -31,6 +31,13 @@ class TestTasksResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( diff --git a/crowdin_api/api_resources/teams/resource.py b/crowdin_api/api_resources/teams/resource.py index 4895f1d..6e7a777 100644 --- a/crowdin_api/api_resources/teams/resource.py +++ b/crowdin_api/api_resources/teams/resource.py @@ -30,8 +30,8 @@ def get_members_path(self, teamId: int, memberId: Optional[int] = None): def add_team_to_project( self, - projectId: int, teamId: int, + projectId: Optional[int] = None, accessToAllWorkflowSteps: bool = True, managerAccess: bool = False, permissions: Optional[Permissions] = None, @@ -44,6 +44,8 @@ def add_team_to_project( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.teams.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"projects/{projectId}/teams", diff --git a/crowdin_api/api_resources/teams/tests/test_teams_resources.py b/crowdin_api/api_resources/teams/tests/test_teams_resources.py index 0769c26..66c58e6 100644 --- a/crowdin_api/api_resources/teams/tests/test_teams_resources.py +++ b/crowdin_api/api_resources/teams/tests/test_teams_resources.py @@ -14,6 +14,13 @@ class TestTeamsResources: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( diff --git a/crowdin_api/api_resources/translation_memory/resource.py b/crowdin_api/api_resources/translation_memory/resource.py index 0939803..0e65f04 100644 --- a/crowdin_api/api_resources/translation_memory/resource.py +++ b/crowdin_api/api_resources/translation_memory/resource.py @@ -256,12 +256,12 @@ def download_tm(self, tmId: int, exportId: str): def concordance_search_in_tms( self, - projectId: int, sourceLanguageId: str, targetLanguageId: str, autoSubstitution: bool, minRelevant: int, expressions: Iterable[str], + projectId: Optional[int] = None, ): """ Concordance search in TMs @@ -270,6 +270,7 @@ def concordance_search_in_tms( https://developer.crowdin.com/api/v2/#operation/api.projects.tms.concordance.post """ + projectId = projectId or self.get_project_id() data = { "sourceLanguageId": sourceLanguageId, "targetLanguageId": targetLanguageId, diff --git a/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py b/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py index ed68eda..73753e5 100644 --- a/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py +++ b/crowdin_api/api_resources/translation_memory/tests/test_translation_memory_resources.py @@ -19,6 +19,13 @@ class TestTranslationMemoryResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + # Translation Memory @pytest.mark.parametrize( "in_params, path", @@ -293,7 +300,7 @@ def test_concordance_search_in_tms(self, m_reqeust, base_absolut_url): ], } - assert resource.concordance_search_in_tms(1, **data) == "response" + assert resource.concordance_search_in_tms(projectId=1, **data) == "response" m_reqeust.assert_called_once_with( method="post", path="projects/1/tms/concordance", diff --git a/crowdin_api/api_resources/translation_status/resource.py b/crowdin_api/api_resources/translation_status/resource.py index 96adbc4..afc36f1 100644 --- a/crowdin_api/api_resources/translation_status/resource.py +++ b/crowdin_api/api_resources/translation_status/resource.py @@ -19,8 +19,8 @@ class TranslationStatusResource(BaseResource): def get_branch_progress( self, - projectId: int, branchId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -32,6 +32,8 @@ def get_branch_progress( https://developer.crowdin.com/api/v2/#operation/api.projects.branches.languages.progress.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=f"projects/{projectId}/branches/{branchId}/languages/progress", @@ -40,8 +42,8 @@ def get_branch_progress( def get_directory_progress( self, - projectId: int, directoryId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -53,6 +55,8 @@ def get_directory_progress( https://developer.crowdin.com/api/v2/#operation/api.projects.directories.languages.progress.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=f"projects/{projectId}/directories/{directoryId}/languages/progress", @@ -61,8 +65,8 @@ def get_directory_progress( def get_file_progress( self, - projectId: int, fileId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -74,6 +78,8 @@ def get_file_progress( https://developer.crowdin.com/api/v2/#operation/api.projects.files.languages.progress.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=f"projects/{projectId}/files/{fileId}/languages/progress", @@ -82,8 +88,8 @@ def get_file_progress( def get_language_progress( self, - projectId: int, languageId: str, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -95,6 +101,8 @@ def get_language_progress( https://developer.crowdin.com/api/v2/#operation/api.projects.languages.files.progress.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=f"projects/{projectId}/languages/{languageId}/progress", @@ -103,7 +111,7 @@ def get_language_progress( def get_project_progress( self, - projectId: int, + projectId: Optional[int] = None, languageIds: Optional[Iterable[str]] = None, page: Optional[int] = None, offset: Optional[int] = None, @@ -116,6 +124,7 @@ def get_project_progress( https://developer.crowdin.com/api/v2/#operation/api.projects.languages.progress.getMany """ + projectId = projectId or self.get_project_id() params = {"languageIds": None if languageIds is None else ",".join(languageIds)} params.update(self.get_page_params(page=page, offset=offset, limit=limit)) @@ -127,7 +136,7 @@ def get_project_progress( def list_qa_check_issues( self, - projectId: int, + projectId: Optional[int] = None, category: Optional[Iterable[Category]] = None, validation: Optional[Iterable[Validation]] = None, languageIds: Optional[Iterable[str]] = None, @@ -142,6 +151,7 @@ def list_qa_check_issues( https://developer.crowdin.com/api/v2/#operation/api.projects.qa-checks.getMany """ + projectId = projectId or self.get_project_id() params = { "languageIds": None if languageIds is None else ",".join(languageIds), "category": ",".join((item.value for item in category)) if category else None, diff --git a/crowdin_api/api_resources/translation_status/tests/test_translation_status_resources.py b/crowdin_api/api_resources/translation_status/tests/test_translation_status_resources.py index 9487924..83dcab0 100644 --- a/crowdin_api/api_resources/translation_status/tests/test_translation_status_resources.py +++ b/crowdin_api/api_resources/translation_status/tests/test_translation_status_resources.py @@ -12,6 +12,13 @@ class TestTranslationStatusResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @mock.patch("crowdin_api.requester.APIRequester.request") def test_get_branch_progress(self, m_request, base_absolut_url): m_request.return_value = "response" diff --git a/crowdin_api/api_resources/translations/resource.py b/crowdin_api/api_resources/translations/resource.py index 226b467..f478d46 100644 --- a/crowdin_api/api_resources/translations/resource.py +++ b/crowdin_api/api_resources/translations/resource.py @@ -30,7 +30,9 @@ def get_builds_path(self, projectId: int, buildId: Optional[int] = None): return f"projects/{projectId}/translations/builds" - def pre_translation_status(self, projectId: int, preTranslationId: str): + def pre_translation_status( + self, preTranslationId: str, projectId: Optional[int] = None + ): """ Pre-Translation Status. @@ -38,6 +40,8 @@ def pre_translation_status(self, projectId: int, preTranslationId: str): https://developer.crowdin.com/api/v2/#tag/Translations/paths/~1projects~1{projectId}~1pre-translations~1{preTranslationId}/get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=f"projects/{projectId}/pre-translations/{preTranslationId}", @@ -45,9 +49,9 @@ def pre_translation_status(self, projectId: int, preTranslationId: str): def apply_pre_translation( self, - projectId: int, languageIds: Iterable[str], fileIds: Iterable[int], + projectId: Optional[int] = None, method: Optional[PreTranslationApplyMethod] = None, engineId: Optional[int] = None, autoApproveOption: Optional[PreTranslationAutoApproveOption] = None, @@ -69,6 +73,8 @@ def apply_pre_translation( if excludeLabelIds is None: excludeLabelIds = [] + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"projects/{projectId}/pre-translations", @@ -88,8 +94,8 @@ def apply_pre_translation( def build_project_directory_translation( self, - projectId: int, directoryId: int, + projectId: Optional[int] = None, targetLanguageIds: Optional[Iterable[str]] = None, skipUntranslatedStrings: Optional[bool] = None, skipUntranslatedFiles: Optional[bool] = None, @@ -102,6 +108,8 @@ def build_project_directory_translation( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.directories.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"{self.get_builds_path(projectId=projectId)}/directories/{directoryId}", @@ -115,9 +123,9 @@ def build_project_directory_translation( def build_project_file_translation( self, - projectId: int, fileId: int, targetLanguageId: str, + projectId: Optional[int] = None, skipUntranslatedStrings: Optional[bool] = None, skipUntranslatedFiles: Optional[bool] = None, exportApprovedOnly: Optional[bool] = None, @@ -135,6 +143,8 @@ def build_project_file_translation( else: headers = None + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", headers=headers, @@ -149,7 +159,7 @@ def build_project_file_translation( def list_project_builds( self, - projectId: int, + projectId: Optional[int] = None, branchId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, @@ -162,6 +172,7 @@ def list_project_builds( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.getMany """ + projectId = projectId or self.get_project_id() params = {"branchId": branchId} params.update(self.get_page_params(page=page, offset=offset, limit=limit)) @@ -171,7 +182,9 @@ def list_project_builds( params=params, ) - def build_project_translation(self, projectId: int, request_data: Dict): + def build_project_translation( + self, request_data: Dict, projectId: Optional[int] = None + ): """ Build Project Translation. @@ -179,6 +192,8 @@ def build_project_translation(self, projectId: int, request_data: Dict): https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_builds_path(projectId=projectId), @@ -187,7 +202,7 @@ def build_project_translation(self, projectId: int, request_data: Dict): def build_crowdin_project_translation( self, - projectId: int, + projectId: Optional[int] = None, branchId: Optional[int] = None, targetLanguageIds: Optional[Iterable[str]] = None, skipUntranslatedStrings: Optional[bool] = None, @@ -202,6 +217,8 @@ def build_crowdin_project_translation( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.post """ + projectId = projectId or self.get_project_id() + return self.build_project_translation( projectId=projectId, request_data={ @@ -216,8 +233,8 @@ def build_crowdin_project_translation( def build_pseudo_project_translation( self, - projectId: int, pseudo: bool, + projectId: Optional[int] = None, prefix: Optional[str] = None, suffix: Optional[str] = None, lengthTransformation: Optional[int] = None, @@ -230,6 +247,8 @@ def build_pseudo_project_translation( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.post """ + projectId = projectId or self.get_project_id() + return self.build_project_translation( projectId=projectId, request_data={ @@ -243,10 +262,10 @@ def build_pseudo_project_translation( def upload_translation( self, - projectId: int, languageId: str, storageId: int, fileId: int, + projectId: Optional[int] = None, importEqSuggestions: Optional[bool] = None, autoApproveImported: Optional[bool] = None, translateHidden: Optional[bool] = None, @@ -258,6 +277,8 @@ def upload_translation( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.postOnLanguage """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"projects/{projectId}/translations/{languageId}", @@ -270,7 +291,9 @@ def upload_translation( }, ) - def download_project_translations(self, projectId: int, buildId: int): + def download_project_translations( + self, buildId: int, projectId: Optional[int] = None + ): """ Download Project Translations. @@ -278,12 +301,14 @@ def download_project_translations(self, projectId: int, buildId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.download.download """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=f"{self.get_builds_path(projectId=projectId, buildId=buildId)}/download", ) - def check_project_build_status(self, projectId: int, buildId: int): + def check_project_build_status(self, buildId: int, projectId: Optional[int] = None): """ Check Project Build Status. @@ -291,12 +316,14 @@ def check_project_build_status(self, projectId: int, buildId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_builds_path(projectId=projectId, buildId=buildId), ) - def cancel_build(self, projectId: int, buildId: int): + def cancel_build(self, buildId: int, projectId: Optional[int] = None): """ Cancel Build. @@ -304,6 +331,8 @@ def cancel_build(self, projectId: int, buildId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.translations.builds.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_builds_path(projectId=projectId, buildId=buildId), @@ -311,8 +340,8 @@ def cancel_build(self, projectId: int, buildId: int): def export_project_translation( self, - projectId: int, targetLanguageId: str, + projectId: Optional[int] = None, format: Optional[ExportProjectTranslationFormat] = None, labelIds: Optional[Iterable[int]] = None, branchIds: Optional[Iterable[int]] = None, @@ -329,6 +358,8 @@ def export_project_translation( https://developer.crowdin.com/api/v2/#operation/api.projects.translations.exports.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=f"projects/{projectId}/translations/exports", diff --git a/crowdin_api/api_resources/translations/tests/test_translations_resources.py b/crowdin_api/api_resources/translations/tests/test_translations_resources.py index e49a409..264b160 100644 --- a/crowdin_api/api_resources/translations/tests/test_translations_resources.py +++ b/crowdin_api/api_resources/translations/tests/test_translations_resources.py @@ -17,6 +17,13 @@ class TestTranslationsResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @mock.patch("crowdin_api.requester.APIRequester.request") def test_list_project_branches(self, m_request, base_absolut_url): m_request.return_value = "response" diff --git a/crowdin_api/api_resources/users/resource.py b/crowdin_api/api_resources/users/resource.py index 0db66cb..23f870a 100644 --- a/crowdin_api/api_resources/users/resource.py +++ b/crowdin_api/api_resources/users/resource.py @@ -18,7 +18,7 @@ def get_members_path(self, projectId: int, memberId: Optional[int] = None): def list_project_members( self, - projectId: int, + projectId: Optional[int] = None, search: Optional[str] = None, role: Optional[UserRole] = None, languageId: Optional[str] = None, @@ -36,6 +36,7 @@ def list_project_members( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.members.getMany """ + projectId = projectId or self.get_project_id() params = {"search": search, "role": role, "languageId": languageId} params.update(self.get_page_params(page=page, offset=offset, limit=limit)) @@ -57,7 +58,7 @@ class UsersResource(BaseUsersResource): https://developer.crowdin.com/api/v2/#tag/Users """ - def get_member_info(self, projectId: int, memberId: int): + def get_member_info(self, memberId: int, projectId: Optional[int] = None): """ Get Member Info. @@ -65,6 +66,8 @@ def get_member_info(self, projectId: int, memberId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.members.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_members_path(projectId=projectId, memberId=memberId) @@ -89,8 +92,8 @@ def get_users_path(self, userId: Optional[int] = None): def add_project_member( self, - projectId: int, userIds: Iterable[int], + projectId: Optional[int] = None, accessToAllWorkflowSteps: Optional[bool] = None, managerAccess: Optional[bool] = None, permissions: Optional[Dict] = None, @@ -103,6 +106,8 @@ def add_project_member( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.members.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_members_path(projectId=projectId), @@ -117,8 +122,8 @@ def add_project_member( def replace_project_member_permissions( self, - projectId: int, memberId: int, + projectId: Optional[int] = None, accessToAllWorkflowSteps: Optional[bool] = None, managerAccess: Optional[bool] = None, permissions: Optional[Dict] = None, @@ -131,6 +136,8 @@ def replace_project_member_permissions( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.members.put """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="put", path=self.get_members_path(projectId=projectId, memberId=memberId), @@ -144,8 +151,8 @@ def replace_project_member_permissions( def delete_member_from_project( self, - projectId: int, memberId: int, + projectId: Optional[int] = None, ): """ Delete Member From Project. @@ -154,6 +161,8 @@ def delete_member_from_project( https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.members.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_members_path(projectId=projectId, memberId=memberId) ) diff --git a/crowdin_api/api_resources/users/tests/test_users_resources.py b/crowdin_api/api_resources/users/tests/test_users_resources.py index 2afd155..0ae619d 100644 --- a/crowdin_api/api_resources/users/tests/test_users_resources.py +++ b/crowdin_api/api_resources/users/tests/test_users_resources.py @@ -18,6 +18,13 @@ class TestBaseUsersResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( diff --git a/crowdin_api/api_resources/webhooks/resource.py b/crowdin_api/api_resources/webhooks/resource.py index 8ed86a4..d344d2f 100644 --- a/crowdin_api/api_resources/webhooks/resource.py +++ b/crowdin_api/api_resources/webhooks/resource.py @@ -46,7 +46,7 @@ def get_webhooks_path(self, projectId: int, webhookId: Optional[int] = None): def list_webhooks( self, - projectId: int, + projectId: Optional[int] = None, page: Optional[int] = None, offset: Optional[int] = None, limit: Optional[int] = None, @@ -58,6 +58,8 @@ def list_webhooks( https://developer.crowdin.com/api/v2/#tag/Webhooks """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_webhooks_path(projectId=projectId), @@ -66,11 +68,11 @@ def list_webhooks( def add_webhook( self, - projectId: int, name: str, url: str, events: Iterable[WebhookEvents], requestType: WebhookRequestType, + projectId: Optional[int] = None, isActive: Optional[bool] = None, batchingEnabled: Optional[bool] = None, contentType: Optional[WebhookContentType] = None, @@ -84,6 +86,8 @@ def add_webhook( https://developer.crowdin.com/api/v2/#operation/api.projects.webhooks.post """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="post", path=self.get_webhooks_path(projectId=projectId), @@ -100,7 +104,7 @@ def add_webhook( }, ) - def get_webhook(self, projectId: int, webhookId: int): + def get_webhook(self, webhookId: int, projectId: Optional[int] = None): """ Get Webhook. @@ -108,12 +112,14 @@ def get_webhook(self, projectId: int, webhookId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.webhooks.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_webhooks_path(projectId=projectId, webhookId=webhookId), ) - def delete_webhook(self, projectId: int, webhookId: int): + def delete_webhook(self, webhookId: int, projectId: Optional[int] = None): """ Delete Webhook. @@ -121,12 +127,19 @@ def delete_webhook(self, projectId: int, webhookId: int): https://developer.crowdin.com/api/v2/#operation/api.projects.webhooks.delete """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="delete", path=self.get_webhooks_path(projectId=projectId, webhookId=webhookId), ) - def edit_webhook(self, projectId: int, webhookId: int, data: Iterable[WebhookPatchRequest]): + def edit_webhook( + self, + webhookId: int, + data: Iterable[WebhookPatchRequest], + projectId: Optional[int] = None, + ): """ Edit Custom Language. @@ -134,6 +147,8 @@ def edit_webhook(self, projectId: int, webhookId: int, data: Iterable[WebhookPat https://developer.crowdin.com/api/v2/#operation/api.projects.webhooks.patch """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="patch", path=self.get_webhooks_path(projectId=projectId, webhookId=webhookId), diff --git a/crowdin_api/api_resources/webhooks/tests/test_webhooks_resources.py b/crowdin_api/api_resources/webhooks/tests/test_webhooks_resources.py index 13b1f66..5a8e37b 100644 --- a/crowdin_api/api_resources/webhooks/tests/test_webhooks_resources.py +++ b/crowdin_api/api_resources/webhooks/tests/test_webhooks_resources.py @@ -18,6 +18,13 @@ class TestWebhooksResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @mock.patch("crowdin_api.requester.APIRequester.request") def test_list_webhooks(self, m_request, base_absolut_url): m_request.return_value = "response" diff --git a/crowdin_api/api_resources/workflows/resource.py b/crowdin_api/api_resources/workflows/resource.py index 6f80b21..5edf853 100644 --- a/crowdin_api/api_resources/workflows/resource.py +++ b/crowdin_api/api_resources/workflows/resource.py @@ -30,7 +30,7 @@ def get_workflow_templates_path(self, templateId: Optional[int] = None): return "workflow-templates" - def list_workflow_steps(self, projectId: int): + def list_workflow_steps(self, projectId: Optional[int] = None): """ List Workflow Steps. @@ -38,12 +38,14 @@ def list_workflow_steps(self, projectId: int): https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.workflow-steps.getMany """ + projectId = projectId or self.get_project_id() + return self._get_entire_data( method="get", path=self.get_workflow_steps_path(projectId=projectId), ) - def get_workflow_step(self, projectId: int, stepId: int): + def get_workflow_step(self, stepId: int, projectId: Optional[int] = None): """ Get Workflow Step. @@ -51,6 +53,8 @@ def get_workflow_step(self, projectId: int, stepId: int): https://developer.crowdin.com/enterprise/api/v2/#operation/api.projects.workflow-steps.get """ + projectId = projectId or self.get_project_id() + return self.requester.request( method="get", path=self.get_workflow_steps_path(projectId=projectId, stepId=stepId), diff --git a/crowdin_api/api_resources/workflows/tests/test_workflows_resources.py b/crowdin_api/api_resources/workflows/tests/test_workflows_resources.py index 31f49da..e8eb1f2 100644 --- a/crowdin_api/api_resources/workflows/tests/test_workflows_resources.py +++ b/crowdin_api/api_resources/workflows/tests/test_workflows_resources.py @@ -12,6 +12,13 @@ class TestWorkflowsResource: def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) + def test_resource_with_id(self, base_absolut_url): + project_id = 1 + resource = self.resource_class( + requester=APIRequester(base_url=base_absolut_url), project_id=project_id + ) + assert resource.get_project_id() == project_id + @pytest.mark.parametrize( "incoming_data, path", ( diff --git a/crowdin_api/client.py b/crowdin_api/client.py index 4d120e6..f5654de 100644 --- a/crowdin_api/client.py +++ b/crowdin_api/client.py @@ -10,6 +10,7 @@ class CrowdinClient: API_REQUESTER_CLASS: Type[APIRequester] = APIRequester + PROJECT_ID = None TIMEOUT = 60 RETRY_DELAY = 0.1 # 100ms MAX_RETRIES = 5 @@ -26,6 +27,7 @@ def __init__( self, # TODO: replace this with union type expressions # once we do not have to support <3.10 anymore + project_id: Optional[int] = None, organization: Optional[str] = None, token: Optional[str] = None, base_url: Optional[str] = None, @@ -38,6 +40,7 @@ def __init__( headers: Optional[dict] = None, extended_request_params: Optional[dict] = None ): + self.PROJECT_ID = project_id or self.PROJECT_ID self.ORGANIZATION = organization or self.ORGANIZATION self.TOKEN = token or self.TOKEN self.BASE_URL = base_url or self.BASE_URL @@ -91,24 +94,52 @@ def get_api_requestor(self) -> APIRequester: @property def bundles(self) -> api_resources.BundlesResource: + if self.PROJECT_ID: + return api_resources.BundlesResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.BundlesResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def dictionaries(self) -> api_resources.DictionariesResource: + if self.PROJECT_ID: + return api_resources.DictionariesResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.DictionariesResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def distributions(self) -> api_resources.DistributionsResource: + if self.PROJECT_ID: + return api_resources.DistributionsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.DistributionsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def glossaries(self) -> api_resources.GlossariesResource: + if self.PROJECT_ID: + return api_resources.GlossariesResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.GlossariesResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @@ -118,24 +149,52 @@ def groups(self) -> api_resources.GroupsResource: if not self._is_enterprise_platform: raise CrowdinException(detail="Not implemented for the base API") + if self.PROJECT_ID: + return api_resources.GroupsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.GroupsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def labels(self) -> api_resources.LabelsResource: + if self.PROJECT_ID: + return api_resources.LabelsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.LabelsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def languages(self) -> api_resources.LanguagesResource: + if self.PROJECT_ID: + return api_resources.LanguagesResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.LanguagesResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def projects(self) -> api_resources.ProjectsResource: + if self.PROJECT_ID: + return api_resources.ProjectsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.ProjectsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @@ -149,6 +208,13 @@ def reports(self) -> Union[api_resources.ReportsResource, else: report_class = api_resources.ReportsResource + if self.PROJECT_ID: + return report_class( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return report_class( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE, @@ -156,36 +222,78 @@ def reports(self) -> Union[api_resources.ReportsResource, @property def screenshots(self) -> api_resources.ScreenshotsResource: + if self.PROJECT_ID: + return api_resources.ScreenshotsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.ScreenshotsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def source_files(self) -> api_resources.SourceFilesResource: + if self.PROJECT_ID: + return api_resources.SourceFilesResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.SourceFilesResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def source_strings(self) -> api_resources.SourceStringsResource: + if self.PROJECT_ID: + return api_resources.SourceStringsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.SourceStringsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def storages(self) -> api_resources.StoragesResource: + if self.PROJECT_ID: + return api_resources.StoragesResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.StoragesResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def string_comments(self) -> api_resources.StringCommentsResource: + if self.PROJECT_ID: + return api_resources.StringCommentsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.StringCommentsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def string_translations(self) -> api_resources.StringTranslationsResource: + if self.PROJECT_ID: + return api_resources.StringTranslationsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.StringTranslationsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @@ -197,6 +305,13 @@ def tasks(self) -> Union[api_resources.TasksResource, api_resources.EnterpriseTa else: report_class = api_resources.TasksResource + if self.PROJECT_ID: + return report_class( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return report_class( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE, @@ -207,30 +322,65 @@ def teams(self) -> api_resources.TeamsResource: if not self._is_enterprise_platform: raise CrowdinException(detail="Not implemented for the base API") + if self.PROJECT_ID: + return api_resources.TeamsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.TeamsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def translation_memory(self) -> api_resources.TranslationMemoryResource: + if self.PROJECT_ID: + return api_resources.TranslationMemoryResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.TranslationMemoryResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def translation_status(self) -> api_resources.TranslationStatusResource: + if self.PROJECT_ID: + return api_resources.TranslationStatusResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.TranslationStatusResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def translations(self) -> api_resources.TranslationsResource: + if self.PROJECT_ID: + return api_resources.TranslationsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.TranslationsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def machine_translations(self) -> api_resources.MachineTranslationEnginesResource: + if self.PROJECT_ID: + return api_resources.MachineTranslationEnginesResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.MachineTranslationEnginesResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @@ -242,6 +392,13 @@ def users(self) -> Union[api_resources.UsersResource, api_resources.EnterpriseUs else: user_class = api_resources.UsersResource + if self.PROJECT_ID: + return user_class( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return user_class( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @@ -251,12 +408,26 @@ def vendors(self) -> api_resources.VendorsResource: if not self._is_enterprise_platform: raise CrowdinException(detail="Not implemented for the base API") + if self.PROJECT_ID: + return api_resources.VendorsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.VendorsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @property def webhooks(self) -> api_resources.WebhooksResource: + if self.PROJECT_ID: + return api_resources.WebhooksResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.WebhooksResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) @@ -266,6 +437,13 @@ def workflows(self) -> api_resources.WorkflowsResource: if not self._is_enterprise_platform: raise CrowdinException(detail="Not implemented for the base API") + if self.PROJECT_ID: + return api_resources.WorkflowsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + return api_resources.WorkflowsResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) diff --git a/crowdin_api/tests/test_client.py b/crowdin_api/tests/test_client.py index 65c6a46..c3cdd33 100644 --- a/crowdin_api/tests/test_client.py +++ b/crowdin_api/tests/test_client.py @@ -164,6 +164,7 @@ def test_api_requestor(self, m_APIRequester): return_value="api_requestor", ) def test_storages(self, _m_api_requestor, property_name, class_name): + # Without `project_id` with mock.patch( f"crowdin_api.api_resources.{class_name}", return_value=class_name, @@ -172,6 +173,17 @@ def test_storages(self, _m_api_requestor, property_name, class_name): assert getattr(client, property_name) == class_name m_resource.assert_called_once_with(requester="api_requestor", page_size=25) + # With `project_id` + with mock.patch( + f"crowdin_api.api_resources.{class_name}", + return_value=class_name, + ) as m_resource: + client = CrowdinClient(project_id=1) + assert getattr(client, property_name) == class_name + m_resource.assert_called_once_with( + requester="api_requestor", project_id=1, page_size=25 + ) + class TestCrowdinClientEnterprise: @pytest.mark.parametrize( @@ -209,6 +221,7 @@ class TestCrowdinClientEnterprise: return_value="api_requestor", ) def test_storages_with_organization(self, _m_api_requestor, property_name, class_name): + # Without `project_id` with mock.patch( f"crowdin_api.api_resources.{class_name}", return_value=class_name, @@ -216,3 +229,14 @@ def test_storages_with_organization(self, _m_api_requestor, property_name, class client = MockCrowdinClientEnterprise() assert getattr(client, property_name) == class_name m_resource.assert_called_once_with(requester="api_requestor", page_size=25) + + # With `project_id` + with mock.patch( + f"crowdin_api.api_resources.{class_name}", + return_value=class_name, + ) as m_resource: + client = MockCrowdinClientEnterprise(project_id=1) + assert getattr(client, property_name) == class_name + m_resource.assert_called_once_with( + requester="api_requestor", project_id=1, page_size=25 + )