Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions crowdin_api/api_resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,21 @@
from .languages.resource import LanguagesResource
from .machine_translation_engines.resource import MachineTranslationEnginesResource
from .projects.resource import ProjectsResource
from .reports.resource import ReportsResource, EnterpriseReportsResource
from .reports.resource import EnterpriseReportsResource, ReportsResource
from .screenshots.resource import ScreenshotsResource
from .security_logs.resource import SecurityLogsResource
from .source_files.resource import SourceFilesResource
from .source_strings.resource import SourceStringsResource
from .storages.resource import StoragesResource
from .string_comments.resource import StringCommentsResource
from .string_translations.resource import StringTranslationsResource
from .tasks.resource import TasksResource, EnterpriseTasksResource
from .style_guides.resource import StyleGuidesResource
from .tasks.resource import EnterpriseTasksResource, TasksResource
from .teams.resource import TeamsResource
from .translation_memory.resource import TranslationMemoryResource
from .translation_status.resource import TranslationStatusResource
from .translations.resource import TranslationsResource
from .users.resource import UsersResource, EnterpriseUsersResource
from .users.resource import EnterpriseUsersResource, UsersResource
from .vendors.resource import VendorsResource
from .webhooks.resource import WebhooksResource
from .workflows.resource import WorkflowsResource
Expand All @@ -50,6 +51,7 @@
"SourceStringsResource",
"StoragesResource",
"StringCommentsResource",
"StyleGuidesResource",
"StringTranslationsResource",
Comment on lines 53 to 55
"TasksResource",
"EnterpriseTasksResource",
Expand Down
1 change: 1 addition & 0 deletions crowdin_api/api_resources/style_guides/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pdoc__ = {"tests": False}
17 changes: 17 additions & 0 deletions crowdin_api/api_resources/style_guides/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from enum import Enum


class ListStyleGuidesOrderBy(Enum):
ID = "id"
NAME = "name"
USER_ID = "userId"
CREATED_AT = "createdAt"


class StyleGuidePatchPath(Enum):
NAME = "/name"
AI_INSTRUCTIONS = "/aiInstructions"
LANGUAGE_IDS = "/languageIds"
PROJECT_IDS = "/projectIds"
IS_SHARED = "/isShared"
STORAGE_ID = "/storageId"
101 changes: 101 additions & 0 deletions crowdin_api/api_resources/style_guides/resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from typing import Iterable, Optional

from crowdin_api.api_resources.abstract.resources import BaseResource
from crowdin_api.api_resources.style_guides.types import (
AddStyleGuideRequest,
StyleGuidePatchRequest,
)
from crowdin_api.sorting import Sorting


class StyleGuidesResource(BaseResource):
"""
Resource for Style Guides.

Link to documentation:
https://support.crowdin.com/developer/api/v2/#tag/Style-Guides
"""

def get_style_guides_path(self, style_guide_id: Optional[int] = None):
if style_guide_id is not None:
return f"style-guides/{style_guide_id}"
return "style-guides"

def list_style_guides(
self,
order_by: Optional[Sorting] = None,
user_id: Optional[int] = None,
limit: Optional[int] = None,
offset: Optional[int] = None,
):
"""
List Style Guides

Link to documentation:
https://support.crowdin.com/developer/api/v2/#operation/api.style-guides.getMany
"""
params = {
"orderBy": order_by,
"userId": user_id,
}
params.update(self.get_page_params(limit=limit, offset=offset))

return self.requester.request(
method="get",
path=self.get_style_guides_path(),
params=params,
)
Comment on lines +43 to +47

def add_style_guide(self, request_data: AddStyleGuideRequest):
"""
Create Style Guide

Link to documentation:
https://support.crowdin.com/developer/api/v2/#operation/api.style-guides.post
"""
return self.requester.request(
method="post",
path=self.get_style_guides_path(),
request_data=request_data,
)

def get_style_guide(self, style_guide_id: int):
"""
Get Style Guide

Link to documentation:
https://support.crowdin.com/developer/api/v2/#operation/api.style-guides.get
"""
return self.requester.request(
method="get",
path=self.get_style_guides_path(style_guide_id),
)

def delete_style_guide(self, style_guide_id: int):
"""
Delete Style Guide

Link to documentation:
https://support.crowdin.com/developer/api/v2/#operation/api.style-guides.delete
"""
return self.requester.request(
method="delete",
path=self.get_style_guides_path(style_guide_id),
)

def edit_style_guide(
self,
style_guide_id: int,
request_data: Iterable[StyleGuidePatchRequest],
):
"""
Edit Style Guide

Link to documentation:
https://support.crowdin.com/developer/api/v2/#operation/api.style-guides.patch
"""
return self.requester.request(
method="patch",
path=self.get_style_guides_path(style_guide_id),
request_data=request_data,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
from unittest import mock

import pytest
from crowdin_api.api_resources.enums import PatchOperation
from crowdin_api.api_resources.style_guides.enums import (
ListStyleGuidesOrderBy,
StyleGuidePatchPath,
)
from crowdin_api.api_resources.style_guides.resource import StyleGuidesResource
from crowdin_api.api_resources.style_guides.types import AddStyleGuideRequest
from crowdin_api.requester import APIRequester
from crowdin_api.sorting import Sorting, SortingOrder, SortingRule


class TestStyleGuidesResource:
resource_class = StyleGuidesResource

def get_resource(self, base_absolut_url):
return self.resource_class(requester=APIRequester(base_url=base_absolut_url))

@pytest.mark.parametrize(
"in_params, path",
(
({}, "style-guides"),
({"style_guide_id": 2}, "style-guides/2"),
),
)
def test_get_style_guides_path(self, in_params, path, base_absolut_url):
resource = self.get_resource(base_absolut_url)
assert resource.get_style_guides_path(**in_params) == path

@pytest.mark.parametrize(
"incoming_data, request_params",
(
(
{},
{
"orderBy": None,
"userId": None,
"limit": 25,
"offset": 0,
},
),
(
{
"order_by": Sorting(
[SortingRule(ListStyleGuidesOrderBy.CREATED_AT, SortingOrder.DESC)]
),
"user_id": 2,
"limit": 25,
"offset": 0,
},
{
"orderBy": Sorting(
[SortingRule(ListStyleGuidesOrderBy.CREATED_AT, SortingOrder.DESC)]
),
"userId": 2,
"limit": 25,
"offset": 0,
},
),
),
)
@mock.patch("crowdin_api.requester.APIRequester.request")
def test_list_style_guides(self, m_request, incoming_data, request_params, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.list_style_guides(**incoming_data) == "response"

m_request.assert_called_once_with(
method="get",
path="style-guides",
params=request_params,
)

@pytest.mark.parametrize(
"incoming_data, request_data",
(
(
AddStyleGuideRequest(
name="Be My Eyes iOS's Style Guide",
storageId=1,
),
{
"name": "Be My Eyes iOS's Style Guide",
"storageId": 1,
},
),
(
AddStyleGuideRequest(
name="Be My Eyes iOS's Style Guide",
storageId=1,
aiInstructions="Rules to be used by AI models",
languageIds=["uk", "fr", "de"],
projectIds=[1, 2, 3],
isShared=False,
),
{
"name": "Be My Eyes iOS's Style Guide",
"storageId": 1,
"aiInstructions": "Rules to be used by AI models",
"languageIds": ["uk", "fr", "de"],
"projectIds": [1, 2, 3],
"isShared": False,
},
),
),
)
@mock.patch("crowdin_api.requester.APIRequester.request")
def test_add_style_guide(self, m_request, incoming_data, request_data, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.add_style_guide(incoming_data) == "response"

m_request.assert_called_once_with(
method="post",
path="style-guides",
request_data=request_data,
)

@mock.patch("crowdin_api.requester.APIRequester.request")
def test_get_style_guide(self, m_request, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.get_style_guide(style_guide_id=2) == "response"

m_request.assert_called_once_with(
method="get",
path="style-guides/2",
)

@mock.patch("crowdin_api.requester.APIRequester.request")
def test_delete_style_guide(self, m_request, base_absolut_url):
m_request.return_value = "response"

resource = self.get_resource(base_absolut_url)
assert resource.delete_style_guide(style_guide_id=2) == "response"

m_request.assert_called_once_with(
method="delete",
path="style-guides/2",
)

@mock.patch("crowdin_api.requester.APIRequester.request")
def test_edit_style_guide(self, m_request, base_absolut_url):
m_request.return_value = "response"

request_data = [
{
"op": PatchOperation.REPLACE,
"path": StyleGuidePatchPath.NAME,
"value": "Be My Eyes iOS's Style Guide",
}
]

resource = self.get_resource(base_absolut_url)
assert resource.edit_style_guide(style_guide_id=2, request_data=request_data) == "response"

m_request.assert_called_once_with(
method="patch",
path="style-guides/2",
request_data=request_data,
)
20 changes: 20 additions & 0 deletions crowdin_api/api_resources/style_guides/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Any, Iterable, Optional

from crowdin_api.api_resources.enums import PatchOperation
from crowdin_api.api_resources.style_guides.enums import StyleGuidePatchPath
from crowdin_api.typing import TypedDict


class AddStyleGuideRequest(TypedDict):
name: str
storageId: int
aiInstructions: Optional[str]
languageIds: Optional[Iterable[str]]
projectIds: Optional[Iterable[int]]
isShared: Optional[bool]


class StyleGuidePatchRequest(TypedDict):
op: PatchOperation
path: StyleGuidePatchPath
value: Any
6 changes: 6 additions & 0 deletions crowdin_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,12 @@ def string_translations(self) -> api_resources.StringTranslationsResource:
requester=self.get_api_requestor(), page_size=self.PAGE_SIZE
)

@property
def style_guides(self) -> api_resources.StyleGuidesResource:
return api_resources.StyleGuidesResource(
requester=self.get_api_requestor(), page_size=self.PAGE_SIZE
)
Comment on lines +363 to +367

@property
def tasks(self) -> Union[api_resources.TasksResource, api_resources.EnterpriseTasksResource]:
if self._is_enterprise_platform:
Expand Down
Loading