From f5cbddc352871ca94e4e45a30ebbb5aaa6c1b0bd Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Thu, 2 Oct 2025 14:42:43 +0100 Subject: [PATCH 01/13] add TaskCommentsResource with list/get/add/delete/edit endpoints; wire into client and exports; add unit tests --- crowdin_api/api_resources/__init__.py | 2 + .../api_resources/task_comments/__init__.py | 7 + .../api_resources/task_comments/enums.py | 7 + .../api_resources/task_comments/resource.py | 127 ++++++++++++++++++ .../tests/test_task_comments_resources.py | 114 ++++++++++++++++ .../api_resources/task_comments/types.py | 13 ++ crowdin_api/client.py | 13 ++ 7 files changed, 283 insertions(+) create mode 100644 crowdin_api/api_resources/task_comments/__init__.py create mode 100644 crowdin_api/api_resources/task_comments/enums.py create mode 100644 crowdin_api/api_resources/task_comments/resource.py create mode 100644 crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py create mode 100644 crowdin_api/api_resources/task_comments/types.py diff --git a/crowdin_api/api_resources/__init__.py b/crowdin_api/api_resources/__init__.py index 11a5888..c1b7720 100644 --- a/crowdin_api/api_resources/__init__.py +++ b/crowdin_api/api_resources/__init__.py @@ -17,6 +17,7 @@ from .source_strings.resource import SourceStringsResource from .storages.resource import StoragesResource from .string_comments.resource import StringCommentsResource +from .task_comments.resource import TaskCommentsResource from .string_translations.resource import StringTranslationsResource from .tasks.resource import TasksResource, EnterpriseTasksResource from .teams.resource import TeamsResource @@ -51,6 +52,7 @@ "StoragesResource", "StringCommentsResource", "StringTranslationsResource", + "TaskCommentsResource", "TasksResource", "EnterpriseTasksResource", "TeamsResource", diff --git a/crowdin_api/api_resources/task_comments/__init__.py b/crowdin_api/api_resources/task_comments/__init__.py new file mode 100644 index 0000000..e500c30 --- /dev/null +++ b/crowdin_api/api_resources/task_comments/__init__.py @@ -0,0 +1,7 @@ +from .resource import TaskCommentsResource + +__all__ = [ + "TaskCommentsResource", +] + + diff --git a/crowdin_api/api_resources/task_comments/enums.py b/crowdin_api/api_resources/task_comments/enums.py new file mode 100644 index 0000000..fd80888 --- /dev/null +++ b/crowdin_api/api_resources/task_comments/enums.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class TaskCommentPatchPath(Enum): + TEXT = "/text" + + diff --git a/crowdin_api/api_resources/task_comments/resource.py b/crowdin_api/api_resources/task_comments/resource.py new file mode 100644 index 0000000..25a8ec1 --- /dev/null +++ b/crowdin_api/api_resources/task_comments/resource.py @@ -0,0 +1,127 @@ +from typing import Iterable, Optional + +from crowdin_api.api_resources.abstract.resources import BaseResource +from crowdin_api.api_resources.task_comments.types import TaskCommentPatchRequest +from crowdin_api.sorting import Sorting + + +class TaskCommentsResource(BaseResource): + """ + Resource for Task Comments. + + Link to documentation: + https://developer.crowdin.com/api/v2/#tag/Tasks + """ + + def get_task_comments_path( + self, + projectId: int, + taskId: int, + taskCommentId: Optional[int] = None, + ): + if taskCommentId is not None: + return f"projects/{projectId}/tasks/{taskId}/comments/{taskCommentId}" + + return f"projects/{projectId}/tasks/{taskId}/comments" + + def list_task_comments( + self, + taskId: int, + projectId: Optional[int] = None, + orderBy: Optional[Sorting] = None, + page: Optional[int] = None, + offset: Optional[int] = None, + limit: Optional[int] = None, + ): + """ + List Task Comments. + """ + + projectId = projectId or self.get_project_id() + params = {"orderBy": orderBy} + params.update(self.get_page_params(page=page, offset=offset, limit=limit)) + + return self._get_entire_data( + method="get", + path=self.get_task_comments_path(projectId=projectId, taskId=taskId), + params=params, + ) + + def add_task_comment( + self, + text: str, + taskId: int, + projectId: Optional[int] = None, + ): + """ + Add Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="post", + path=self.get_task_comments_path(projectId=projectId, taskId=taskId), + request_data={"text": text}, + ) + + def get_task_comment( + self, + taskCommentId: int, + taskId: int, + projectId: Optional[int] = None, + ): + """ + Get Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="get", + path=self.get_task_comments_path( + projectId=projectId, taskId=taskId, taskCommentId=taskCommentId + ), + ) + + def delete_task_comment( + self, + taskCommentId: int, + taskId: int, + projectId: Optional[int] = None, + ): + """ + Delete Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="delete", + path=self.get_task_comments_path( + projectId=projectId, taskId=taskId, taskCommentId=taskCommentId + ), + ) + + def edit_task_comment( + self, + taskCommentId: int, + data: Iterable[TaskCommentPatchRequest], + taskId: int, + projectId: Optional[int] = None, + ): + """ + Edit Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="patch", + path=self.get_task_comments_path( + projectId=projectId, taskId=taskId, taskCommentId=taskCommentId + ), + request_data=data, + ) + + diff --git a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py new file mode 100644 index 0000000..4a63739 --- /dev/null +++ b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py @@ -0,0 +1,114 @@ +from unittest import mock + +import pytest +from crowdin_api.api_resources.enums import PatchOperation +from crowdin_api.api_resources.task_comments.enums import TaskCommentPatchPath +from crowdin_api.api_resources.task_comments.resource import TaskCommentsResource +from crowdin_api.requester import APIRequester +from crowdin_api.sorting import Sorting + + +class TestTaskCommentsResource: + resource_class = TaskCommentsResource + + 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", + ( + ({"projectId": 1, "taskId": 2}, "projects/1/tasks/2/comments"), + ( + {"projectId": 1, "taskId": 2, "taskCommentId": 3}, + "projects/1/tasks/2/comments/3", + ), + ), + ) + def test_get_task_comments_path(self, incoming_data, path, base_absolut_url): + resource = self.get_resource(base_absolut_url) + assert resource.get_task_comments_path(**incoming_data) == path + + @pytest.mark.parametrize( + "incoming_data, request_params", + ( + ({}, {"orderBy": None, "offset": 0, "limit": 25}), + ({"orderBy": Sorting([])}, {"orderBy": Sorting([]), "offset": 0, "limit": 25}), + ), + ) + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_list_task_comments(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_task_comments(projectId=1, taskId=2, **incoming_data) == "response" + m_request.assert_called_once_with( + method="get", + params=request_params, + path=resource.get_task_comments_path(projectId=1, taskId=2), + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_add_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert resource.add_task_comment(projectId=1, taskId=2, text="hello") == "response" + m_request.assert_called_once_with( + method="post", + path=resource.get_task_comments_path(projectId=1, taskId=2), + request_data={"text": "hello"}, + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_get_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert resource.get_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response" + m_request.assert_called_once_with( + method="get", + path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_delete_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert resource.delete_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response" + m_request.assert_called_once_with( + method="delete", + path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_edit_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + data = [ + { + "value": "new text", + "op": PatchOperation.REPLACE, + "path": TaskCommentPatchPath.TEXT, + } + ] + + resource = self.get_resource(base_absolut_url) + assert ( + resource.edit_task_comment(projectId=1, taskId=2, taskCommentId=3, data=data) + == "response" + ) + m_request.assert_called_once_with( + method="patch", + path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), + request_data=data, + ) + + diff --git a/crowdin_api/api_resources/task_comments/types.py b/crowdin_api/api_resources/task_comments/types.py new file mode 100644 index 0000000..5f1ee0a --- /dev/null +++ b/crowdin_api/api_resources/task_comments/types.py @@ -0,0 +1,13 @@ +from typing import Any + +from crowdin_api.api_resources.enums import PatchOperation +from crowdin_api.api_resources.task_comments.enums import TaskCommentPatchPath +from crowdin_api.typing import TypedDict + + +class TaskCommentPatchRequest(TypedDict): + value: Any + op: PatchOperation + path: TaskCommentPatchPath + + diff --git a/crowdin_api/client.py b/crowdin_api/client.py index d5693da..f5a0e93 100644 --- a/crowdin_api/client.py +++ b/crowdin_api/client.py @@ -360,6 +360,19 @@ def string_translations(self) -> api_resources.StringTranslationsResource: requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) + @property + def task_comments(self) -> api_resources.TaskCommentsResource: + if self.PROJECT_ID: + return api_resources.TaskCommentsResource( + requester=self.get_api_requestor(), + project_id=self.PROJECT_ID, + page_size=self.PAGE_SIZE, + ) + + return api_resources.TaskCommentsResource( + requester=self.get_api_requestor(), page_size=self.PAGE_SIZE + ) + @property def tasks(self) -> Union[api_resources.TasksResource, api_resources.EnterpriseTasksResource]: if self._is_enterprise_platform: From a9689311b41497bd7237238651ec236401f8cd56 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Fri, 3 Oct 2025 23:21:57 +0100 Subject: [PATCH 02/13] chore(lint): fix flake8 W391/W292 in task_comments files --- crowdin_api/api_resources/task_comments/__init__.py | 4 +--- crowdin_api/api_resources/task_comments/enums.py | 1 - crowdin_api/api_resources/task_comments/resource.py | 1 - .../task_comments/tests/test_task_comments_resources.py | 1 - crowdin_api/api_resources/task_comments/types.py | 1 - 5 files changed, 1 insertion(+), 7 deletions(-) diff --git a/crowdin_api/api_resources/task_comments/__init__.py b/crowdin_api/api_resources/task_comments/__init__.py index e500c30..c50cd95 100644 --- a/crowdin_api/api_resources/task_comments/__init__.py +++ b/crowdin_api/api_resources/task_comments/__init__.py @@ -2,6 +2,4 @@ __all__ = [ "TaskCommentsResource", -] - - +] \ No newline at end of file diff --git a/crowdin_api/api_resources/task_comments/enums.py b/crowdin_api/api_resources/task_comments/enums.py index fd80888..2006b5f 100644 --- a/crowdin_api/api_resources/task_comments/enums.py +++ b/crowdin_api/api_resources/task_comments/enums.py @@ -4,4 +4,3 @@ class TaskCommentPatchPath(Enum): TEXT = "/text" - diff --git a/crowdin_api/api_resources/task_comments/resource.py b/crowdin_api/api_resources/task_comments/resource.py index 25a8ec1..76e619c 100644 --- a/crowdin_api/api_resources/task_comments/resource.py +++ b/crowdin_api/api_resources/task_comments/resource.py @@ -124,4 +124,3 @@ def edit_task_comment( request_data=data, ) - diff --git a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py index 4a63739..b3c5dee 100644 --- a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py +++ b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py @@ -111,4 +111,3 @@ def test_edit_task_comment(self, m_request, base_absolut_url): request_data=data, ) - diff --git a/crowdin_api/api_resources/task_comments/types.py b/crowdin_api/api_resources/task_comments/types.py index 5f1ee0a..6619546 100644 --- a/crowdin_api/api_resources/task_comments/types.py +++ b/crowdin_api/api_resources/task_comments/types.py @@ -10,4 +10,3 @@ class TaskCommentPatchRequest(TypedDict): op: PatchOperation path: TaskCommentPatchPath - From 1429d987f4bbe61daed76be6349539ad7203b35a Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Fri, 3 Oct 2025 23:59:17 +0100 Subject: [PATCH 03/13] ci: retrigger after EOF fixes From 47fdfd42df78943b2d4f0bca916db98005b85d3f Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Sat, 4 Oct 2025 01:08:51 +0100 Subject: [PATCH 04/13] chore(lint): fix EOF and whitespace in task_comments files --- crowdin_api/api_resources/task_comments/enums.py | 1 - crowdin_api/api_resources/task_comments/resource.py | 1 - .../task_comments/tests/test_task_comments_resources.py | 1 - crowdin_api/api_resources/task_comments/types.py | 1 - 4 files changed, 4 deletions(-) diff --git a/crowdin_api/api_resources/task_comments/enums.py b/crowdin_api/api_resources/task_comments/enums.py index 2006b5f..6ed3a5c 100644 --- a/crowdin_api/api_resources/task_comments/enums.py +++ b/crowdin_api/api_resources/task_comments/enums.py @@ -3,4 +3,3 @@ class TaskCommentPatchPath(Enum): TEXT = "/text" - diff --git a/crowdin_api/api_resources/task_comments/resource.py b/crowdin_api/api_resources/task_comments/resource.py index 76e619c..3676cdb 100644 --- a/crowdin_api/api_resources/task_comments/resource.py +++ b/crowdin_api/api_resources/task_comments/resource.py @@ -123,4 +123,3 @@ def edit_task_comment( ), request_data=data, ) - diff --git a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py index b3c5dee..8488b09 100644 --- a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py +++ b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py @@ -53,7 +53,6 @@ def test_list_task_comments(self, m_request, incoming_data, request_params, base params=request_params, path=resource.get_task_comments_path(projectId=1, taskId=2), ) - @mock.patch("crowdin_api.requester.APIRequester.request") def test_add_task_comment(self, m_request, base_absolut_url): m_request.return_value = "response" diff --git a/crowdin_api/api_resources/task_comments/types.py b/crowdin_api/api_resources/task_comments/types.py index 6619546..8c630ba 100644 --- a/crowdin_api/api_resources/task_comments/types.py +++ b/crowdin_api/api_resources/task_comments/types.py @@ -9,4 +9,3 @@ class TaskCommentPatchRequest(TypedDict): value: Any op: PatchOperation path: TaskCommentPatchPath - From 4d05606dc52ac6628be0a3465f49bb80e6294af1 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Tue, 7 Oct 2025 23:25:43 +0100 Subject: [PATCH 05/13] style(task_comments): fix EOF newlines and trailing blanks --- crowdin_api/api_resources/task_comments/enums.py | 2 +- crowdin_api/api_resources/task_comments/resource.py | 2 +- crowdin_api/api_resources/task_comments/types.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crowdin_api/api_resources/task_comments/enums.py b/crowdin_api/api_resources/task_comments/enums.py index 6ed3a5c..de8a171 100644 --- a/crowdin_api/api_resources/task_comments/enums.py +++ b/crowdin_api/api_resources/task_comments/enums.py @@ -2,4 +2,4 @@ class TaskCommentPatchPath(Enum): - TEXT = "/text" + TEXT = "/text" \ No newline at end of file diff --git a/crowdin_api/api_resources/task_comments/resource.py b/crowdin_api/api_resources/task_comments/resource.py index 3676cdb..86c84c1 100644 --- a/crowdin_api/api_resources/task_comments/resource.py +++ b/crowdin_api/api_resources/task_comments/resource.py @@ -122,4 +122,4 @@ def edit_task_comment( projectId=projectId, taskId=taskId, taskCommentId=taskCommentId ), request_data=data, - ) + ) \ No newline at end of file diff --git a/crowdin_api/api_resources/task_comments/types.py b/crowdin_api/api_resources/task_comments/types.py index 8c630ba..f016463 100644 --- a/crowdin_api/api_resources/task_comments/types.py +++ b/crowdin_api/api_resources/task_comments/types.py @@ -8,4 +8,4 @@ class TaskCommentPatchRequest(TypedDict): value: Any op: PatchOperation - path: TaskCommentPatchPath + path: TaskCommentPatchPath \ No newline at end of file From 3c1a15e2a523092d477017cd783700c998856ceb Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Tue, 7 Oct 2025 23:37:36 +0100 Subject: [PATCH 06/13] ci: run Codecov upload only on push --- .github/workflows/python-package.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index f6e7ac9..4f1ac8c 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -36,7 +36,8 @@ jobs: - name: Test with pytest run: pytest - - name: Comment coverage + - name: Upload coverage to Codecov + if: github.event_name == 'push' uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} From cd4e0af90e20ca9f46f009ce4a27b000a3420fa2 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Tue, 7 Oct 2025 23:43:25 +0100 Subject: [PATCH 07/13] ci: revert Codecov gating; restore original step name --- .github/workflows/python-package.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 4f1ac8c..f6e7ac9 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -36,8 +36,7 @@ jobs: - name: Test with pytest run: pytest - - name: Upload coverage to Codecov - if: github.event_name == 'push' + - name: Comment coverage uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} From 63fd5617f67016ffcdd9efd1eb4dfafbc8b31e23 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Tue, 7 Oct 2025 23:52:05 +0100 Subject: [PATCH 08/13] style(task_comments): flake8 E301/W292/W391 in package and tests --- .../task_comments/tests/test_task_comments_resources.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py index 8488b09..e80167d 100644 --- a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py +++ b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py @@ -76,6 +76,7 @@ def test_get_task_comment(self, m_request, base_absolut_url): path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), ) + @mock.patch("crowdin_api.requester.APIRequester.request") def test_delete_task_comment(self, m_request, base_absolut_url): m_request.return_value = "response" @@ -87,6 +88,7 @@ def test_delete_task_comment(self, m_request, base_absolut_url): path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), ) + @mock.patch("crowdin_api.requester.APIRequester.request") def test_edit_task_comment(self, m_request, base_absolut_url): m_request.return_value = "response" From 610585da6fc70a6c049b7b1456b900d8494d82c2 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Wed, 8 Oct 2025 00:24:23 +0100 Subject: [PATCH 09/13] style(task_comments): fix flake8 on tests and ensure newline at EOF --- crowdin_api/api_resources/task_comments/__init__.py | 2 +- crowdin_api/api_resources/task_comments/enums.py | 2 +- crowdin_api/api_resources/task_comments/resource.py | 2 +- .../task_comments/tests/test_task_comments_resources.py | 4 +--- crowdin_api/api_resources/task_comments/types.py | 2 +- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/crowdin_api/api_resources/task_comments/__init__.py b/crowdin_api/api_resources/task_comments/__init__.py index c50cd95..60c9616 100644 --- a/crowdin_api/api_resources/task_comments/__init__.py +++ b/crowdin_api/api_resources/task_comments/__init__.py @@ -2,4 +2,4 @@ __all__ = [ "TaskCommentsResource", -] \ No newline at end of file +] diff --git a/crowdin_api/api_resources/task_comments/enums.py b/crowdin_api/api_resources/task_comments/enums.py index de8a171..6ed3a5c 100644 --- a/crowdin_api/api_resources/task_comments/enums.py +++ b/crowdin_api/api_resources/task_comments/enums.py @@ -2,4 +2,4 @@ class TaskCommentPatchPath(Enum): - TEXT = "/text" \ No newline at end of file + TEXT = "/text" diff --git a/crowdin_api/api_resources/task_comments/resource.py b/crowdin_api/api_resources/task_comments/resource.py index 86c84c1..3676cdb 100644 --- a/crowdin_api/api_resources/task_comments/resource.py +++ b/crowdin_api/api_resources/task_comments/resource.py @@ -122,4 +122,4 @@ def edit_task_comment( projectId=projectId, taskId=taskId, taskCommentId=taskCommentId ), request_data=data, - ) \ No newline at end of file + ) diff --git a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py index e80167d..3507dd7 100644 --- a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py +++ b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py @@ -53,6 +53,7 @@ def test_list_task_comments(self, m_request, incoming_data, request_params, base params=request_params, path=resource.get_task_comments_path(projectId=1, taskId=2), ) + @mock.patch("crowdin_api.requester.APIRequester.request") def test_add_task_comment(self, m_request, base_absolut_url): m_request.return_value = "response" @@ -76,7 +77,6 @@ def test_get_task_comment(self, m_request, base_absolut_url): path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), ) - @mock.patch("crowdin_api.requester.APIRequester.request") def test_delete_task_comment(self, m_request, base_absolut_url): m_request.return_value = "response" @@ -88,7 +88,6 @@ def test_delete_task_comment(self, m_request, base_absolut_url): path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), ) - @mock.patch("crowdin_api.requester.APIRequester.request") def test_edit_task_comment(self, m_request, base_absolut_url): m_request.return_value = "response" @@ -111,4 +110,3 @@ def test_edit_task_comment(self, m_request, base_absolut_url): path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), request_data=data, ) - diff --git a/crowdin_api/api_resources/task_comments/types.py b/crowdin_api/api_resources/task_comments/types.py index f016463..8c630ba 100644 --- a/crowdin_api/api_resources/task_comments/types.py +++ b/crowdin_api/api_resources/task_comments/types.py @@ -8,4 +8,4 @@ class TaskCommentPatchRequest(TypedDict): value: Any op: PatchOperation - path: TaskCommentPatchPath \ No newline at end of file + path: TaskCommentPatchPath From 5895026ba416dd20a39281a027f26f22e55d98ea Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Thu, 9 Oct 2025 00:37:32 +0100 Subject: [PATCH 10/13] move task comments under TasksResource; update client and tests --- crowdin_api/api_resources/__init__.py | 2 - .../tests/test_task_comments_resources.py | 6 +- crowdin_api/api_resources/tasks/resource.py | 113 ++++++++++++++++++ crowdin_api/client.py | 7 +- 4 files changed, 120 insertions(+), 8 deletions(-) diff --git a/crowdin_api/api_resources/__init__.py b/crowdin_api/api_resources/__init__.py index c1b7720..11a5888 100644 --- a/crowdin_api/api_resources/__init__.py +++ b/crowdin_api/api_resources/__init__.py @@ -17,7 +17,6 @@ from .source_strings.resource import SourceStringsResource from .storages.resource import StoragesResource from .string_comments.resource import StringCommentsResource -from .task_comments.resource import TaskCommentsResource from .string_translations.resource import StringTranslationsResource from .tasks.resource import TasksResource, EnterpriseTasksResource from .teams.resource import TeamsResource @@ -52,7 +51,6 @@ "StoragesResource", "StringCommentsResource", "StringTranslationsResource", - "TaskCommentsResource", "TasksResource", "EnterpriseTasksResource", "TeamsResource", diff --git a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py index 3507dd7..3eda739 100644 --- a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py +++ b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py @@ -3,13 +3,13 @@ import pytest from crowdin_api.api_resources.enums import PatchOperation from crowdin_api.api_resources.task_comments.enums import TaskCommentPatchPath -from crowdin_api.api_resources.task_comments.resource import TaskCommentsResource +from crowdin_api.api_resources.tasks.resource import TasksResource from crowdin_api.requester import APIRequester from crowdin_api.sorting import Sorting -class TestTaskCommentsResource: - resource_class = TaskCommentsResource +class TestTaskCommentsViaTasksResource: + resource_class = TasksResource def get_resource(self, base_absolut_url): return self.resource_class(requester=APIRequester(base_url=base_absolut_url)) diff --git a/crowdin_api/api_resources/tasks/resource.py b/crowdin_api/api_resources/tasks/resource.py index 589b3bb..14b034a 100644 --- a/crowdin_api/api_resources/tasks/resource.py +++ b/crowdin_api/api_resources/tasks/resource.py @@ -27,6 +27,7 @@ TaskSettingsTemplateLanguages, ) from crowdin_api.sorting import Sorting +from crowdin_api.api_resources.task_comments.types import TaskCommentPatchRequest class TasksResource(BaseResource): @@ -934,6 +935,118 @@ def list_user_tasks( return self._get_entire_data(method="get", path="user/tasks", params=params) + # Task Comments + def get_task_comments_path( + self, + projectId: int, + taskId: int, + taskCommentId: Optional[int] = None, + ): + if taskCommentId is not None: + return f"projects/{projectId}/tasks/{taskId}/comments/{taskCommentId}" + + return f"projects/{projectId}/tasks/{taskId}/comments" + + def list_task_comments( + self, + taskId: int, + projectId: Optional[int] = None, + orderBy: Optional[Sorting] = None, + page: Optional[int] = None, + offset: Optional[int] = None, + limit: Optional[int] = None, + ): + """ + List Task Comments. + """ + + projectId = projectId or self.get_project_id() + params = {"orderBy": orderBy} + params.update(self.get_page_params(page=page, offset=offset, limit=limit)) + + return self._get_entire_data( + method="get", + path=self.get_task_comments_path(projectId=projectId, taskId=taskId), + params=params, + ) + + def add_task_comment( + self, + text: str, + taskId: int, + projectId: Optional[int] = None, + ): + """ + Add Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="post", + path=self.get_task_comments_path(projectId=projectId, taskId=taskId), + request_data={"text": text}, + ) + + def get_task_comment( + self, + taskCommentId: int, + taskId: int, + projectId: Optional[int] = None, + ): + """ + Get Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="get", + path=self.get_task_comments_path( + projectId=projectId, taskId=taskId, taskCommentId=taskCommentId + ), + ) + + def delete_task_comment( + self, + taskCommentId: int, + taskId: int, + projectId: Optional[int] = None, + ): + """ + Delete Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="delete", + path=self.get_task_comments_path( + projectId=projectId, taskId=taskId, taskCommentId=taskCommentId + ), + ) + + def edit_task_comment( + self, + taskCommentId: int, + data: Iterable[TaskCommentPatchRequest], + taskId: int, + projectId: Optional[int] = None, + ): + """ + Edit Task Comment. + """ + + projectId = projectId or self.get_project_id() + + return self.requester.request( + method="patch", + path=self.get_task_comments_path( + projectId=projectId, taskId=taskId, taskCommentId=taskCommentId + ), + request_data=data, + ) + def edit_task_archived_status( self, taskId: int, isArchived: bool = True, projectId: Optional[int] = None ): diff --git a/crowdin_api/client.py b/crowdin_api/client.py index f5a0e93..81c56bb 100644 --- a/crowdin_api/client.py +++ b/crowdin_api/client.py @@ -361,15 +361,16 @@ def string_translations(self) -> api_resources.StringTranslationsResource: ) @property - def task_comments(self) -> api_resources.TaskCommentsResource: + def task_comments(self) -> api_resources.TasksResource: + # Backward-compatible accessor: comments now live under TasksResource if self.PROJECT_ID: - return api_resources.TaskCommentsResource( + return api_resources.TasksResource( requester=self.get_api_requestor(), project_id=self.PROJECT_ID, page_size=self.PAGE_SIZE, ) - return api_resources.TaskCommentsResource( + return api_resources.TasksResource( requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) From 6a235197d3f6593582f777c7d58e185e5c92a375 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Thu, 9 Oct 2025 03:49:11 +0100 Subject: [PATCH 11/13] chore: remove task_comments --- .../api_resources/task_comments/__init__.py | 5 - .../api_resources/task_comments/enums.py | 5 - .../api_resources/task_comments/resource.py | 125 ------------------ .../tests/test_task_comments_resources.py | 112 ---------------- .../api_resources/task_comments/types.py | 11 -- crowdin_api/client.py | 14 -- 6 files changed, 272 deletions(-) delete mode 100644 crowdin_api/api_resources/task_comments/__init__.py delete mode 100644 crowdin_api/api_resources/task_comments/enums.py delete mode 100644 crowdin_api/api_resources/task_comments/resource.py delete mode 100644 crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py delete mode 100644 crowdin_api/api_resources/task_comments/types.py diff --git a/crowdin_api/api_resources/task_comments/__init__.py b/crowdin_api/api_resources/task_comments/__init__.py deleted file mode 100644 index 60c9616..0000000 --- a/crowdin_api/api_resources/task_comments/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .resource import TaskCommentsResource - -__all__ = [ - "TaskCommentsResource", -] diff --git a/crowdin_api/api_resources/task_comments/enums.py b/crowdin_api/api_resources/task_comments/enums.py deleted file mode 100644 index 6ed3a5c..0000000 --- a/crowdin_api/api_resources/task_comments/enums.py +++ /dev/null @@ -1,5 +0,0 @@ -from enum import Enum - - -class TaskCommentPatchPath(Enum): - TEXT = "/text" diff --git a/crowdin_api/api_resources/task_comments/resource.py b/crowdin_api/api_resources/task_comments/resource.py deleted file mode 100644 index 3676cdb..0000000 --- a/crowdin_api/api_resources/task_comments/resource.py +++ /dev/null @@ -1,125 +0,0 @@ -from typing import Iterable, Optional - -from crowdin_api.api_resources.abstract.resources import BaseResource -from crowdin_api.api_resources.task_comments.types import TaskCommentPatchRequest -from crowdin_api.sorting import Sorting - - -class TaskCommentsResource(BaseResource): - """ - Resource for Task Comments. - - Link to documentation: - https://developer.crowdin.com/api/v2/#tag/Tasks - """ - - def get_task_comments_path( - self, - projectId: int, - taskId: int, - taskCommentId: Optional[int] = None, - ): - if taskCommentId is not None: - return f"projects/{projectId}/tasks/{taskId}/comments/{taskCommentId}" - - return f"projects/{projectId}/tasks/{taskId}/comments" - - def list_task_comments( - self, - taskId: int, - projectId: Optional[int] = None, - orderBy: Optional[Sorting] = None, - page: Optional[int] = None, - offset: Optional[int] = None, - limit: Optional[int] = None, - ): - """ - List Task Comments. - """ - - projectId = projectId or self.get_project_id() - params = {"orderBy": orderBy} - params.update(self.get_page_params(page=page, offset=offset, limit=limit)) - - return self._get_entire_data( - method="get", - path=self.get_task_comments_path(projectId=projectId, taskId=taskId), - params=params, - ) - - def add_task_comment( - self, - text: str, - taskId: int, - projectId: Optional[int] = None, - ): - """ - Add Task Comment. - """ - - projectId = projectId or self.get_project_id() - - return self.requester.request( - method="post", - path=self.get_task_comments_path(projectId=projectId, taskId=taskId), - request_data={"text": text}, - ) - - def get_task_comment( - self, - taskCommentId: int, - taskId: int, - projectId: Optional[int] = None, - ): - """ - Get Task Comment. - """ - - projectId = projectId or self.get_project_id() - - return self.requester.request( - method="get", - path=self.get_task_comments_path( - projectId=projectId, taskId=taskId, taskCommentId=taskCommentId - ), - ) - - def delete_task_comment( - self, - taskCommentId: int, - taskId: int, - projectId: Optional[int] = None, - ): - """ - Delete Task Comment. - """ - - projectId = projectId or self.get_project_id() - - return self.requester.request( - method="delete", - path=self.get_task_comments_path( - projectId=projectId, taskId=taskId, taskCommentId=taskCommentId - ), - ) - - def edit_task_comment( - self, - taskCommentId: int, - data: Iterable[TaskCommentPatchRequest], - taskId: int, - projectId: Optional[int] = None, - ): - """ - Edit Task Comment. - """ - - projectId = projectId or self.get_project_id() - - return self.requester.request( - method="patch", - path=self.get_task_comments_path( - projectId=projectId, taskId=taskId, taskCommentId=taskCommentId - ), - request_data=data, - ) diff --git a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py b/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py deleted file mode 100644 index 3eda739..0000000 --- a/crowdin_api/api_resources/task_comments/tests/test_task_comments_resources.py +++ /dev/null @@ -1,112 +0,0 @@ -from unittest import mock - -import pytest -from crowdin_api.api_resources.enums import PatchOperation -from crowdin_api.api_resources.task_comments.enums import TaskCommentPatchPath -from crowdin_api.api_resources.tasks.resource import TasksResource -from crowdin_api.requester import APIRequester -from crowdin_api.sorting import Sorting - - -class TestTaskCommentsViaTasksResource: - resource_class = TasksResource - - 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", - ( - ({"projectId": 1, "taskId": 2}, "projects/1/tasks/2/comments"), - ( - {"projectId": 1, "taskId": 2, "taskCommentId": 3}, - "projects/1/tasks/2/comments/3", - ), - ), - ) - def test_get_task_comments_path(self, incoming_data, path, base_absolut_url): - resource = self.get_resource(base_absolut_url) - assert resource.get_task_comments_path(**incoming_data) == path - - @pytest.mark.parametrize( - "incoming_data, request_params", - ( - ({}, {"orderBy": None, "offset": 0, "limit": 25}), - ({"orderBy": Sorting([])}, {"orderBy": Sorting([]), "offset": 0, "limit": 25}), - ), - ) - @mock.patch("crowdin_api.requester.APIRequester.request") - def test_list_task_comments(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_task_comments(projectId=1, taskId=2, **incoming_data) == "response" - m_request.assert_called_once_with( - method="get", - params=request_params, - path=resource.get_task_comments_path(projectId=1, taskId=2), - ) - - @mock.patch("crowdin_api.requester.APIRequester.request") - def test_add_task_comment(self, m_request, base_absolut_url): - m_request.return_value = "response" - - resource = self.get_resource(base_absolut_url) - assert resource.add_task_comment(projectId=1, taskId=2, text="hello") == "response" - m_request.assert_called_once_with( - method="post", - path=resource.get_task_comments_path(projectId=1, taskId=2), - request_data={"text": "hello"}, - ) - - @mock.patch("crowdin_api.requester.APIRequester.request") - def test_get_task_comment(self, m_request, base_absolut_url): - m_request.return_value = "response" - - resource = self.get_resource(base_absolut_url) - assert resource.get_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response" - m_request.assert_called_once_with( - method="get", - path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), - ) - - @mock.patch("crowdin_api.requester.APIRequester.request") - def test_delete_task_comment(self, m_request, base_absolut_url): - m_request.return_value = "response" - - resource = self.get_resource(base_absolut_url) - assert resource.delete_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response" - m_request.assert_called_once_with( - method="delete", - path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), - ) - - @mock.patch("crowdin_api.requester.APIRequester.request") - def test_edit_task_comment(self, m_request, base_absolut_url): - m_request.return_value = "response" - - data = [ - { - "value": "new text", - "op": PatchOperation.REPLACE, - "path": TaskCommentPatchPath.TEXT, - } - ] - - resource = self.get_resource(base_absolut_url) - assert ( - resource.edit_task_comment(projectId=1, taskId=2, taskCommentId=3, data=data) - == "response" - ) - m_request.assert_called_once_with( - method="patch", - path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), - request_data=data, - ) diff --git a/crowdin_api/api_resources/task_comments/types.py b/crowdin_api/api_resources/task_comments/types.py deleted file mode 100644 index 8c630ba..0000000 --- a/crowdin_api/api_resources/task_comments/types.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Any - -from crowdin_api.api_resources.enums import PatchOperation -from crowdin_api.api_resources.task_comments.enums import TaskCommentPatchPath -from crowdin_api.typing import TypedDict - - -class TaskCommentPatchRequest(TypedDict): - value: Any - op: PatchOperation - path: TaskCommentPatchPath diff --git a/crowdin_api/client.py b/crowdin_api/client.py index 81c56bb..d5693da 100644 --- a/crowdin_api/client.py +++ b/crowdin_api/client.py @@ -360,20 +360,6 @@ def string_translations(self) -> api_resources.StringTranslationsResource: requester=self.get_api_requestor(), page_size=self.PAGE_SIZE ) - @property - def task_comments(self) -> api_resources.TasksResource: - # Backward-compatible accessor: comments now live under TasksResource - if self.PROJECT_ID: - return api_resources.TasksResource( - requester=self.get_api_requestor(), - project_id=self.PROJECT_ID, - page_size=self.PAGE_SIZE, - ) - - return api_resources.TasksResource( - requester=self.get_api_requestor(), page_size=self.PAGE_SIZE - ) - @property def tasks(self) -> Union[api_resources.TasksResource, api_resources.EnterpriseTasksResource]: if self._is_enterprise_platform: From 69b3ac171ae78b53bb4e3d8f259a96d81d5c4e70 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Thu, 9 Oct 2025 09:08:52 +0100 Subject: [PATCH 12/13] feat(tasks): remove task_comments package --- crowdin_api/api_resources/tasks/resource.py | 2 +- crowdin_api/api_resources/tasks/types.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/crowdin_api/api_resources/tasks/resource.py b/crowdin_api/api_resources/tasks/resource.py index 14b034a..500180c 100644 --- a/crowdin_api/api_resources/tasks/resource.py +++ b/crowdin_api/api_resources/tasks/resource.py @@ -27,7 +27,7 @@ TaskSettingsTemplateLanguages, ) from crowdin_api.sorting import Sorting -from crowdin_api.api_resources.task_comments.types import TaskCommentPatchRequest +from crowdin_api.api_resources.tasks.types import TaskCommentPatchRequest class TasksResource(BaseResource): diff --git a/crowdin_api/api_resources/tasks/types.py b/crowdin_api/api_resources/tasks/types.py index d32f6b8..c94e4cc 100644 --- a/crowdin_api/api_resources/tasks/types.py +++ b/crowdin_api/api_resources/tasks/types.py @@ -54,3 +54,11 @@ class EnterpriseTaskSettingsTemplateConfigLanguage(TypedDict): class EnterpriseTaskSettingsTemplateLanguages(TypedDict): languages: Iterable[EnterpriseTaskSettingsTemplateConfigLanguage] + + +# Task comments patch request (moved from removed task_comments package) +class TaskCommentPatchRequest(TypedDict): + value: Any + op: PatchOperation + # For now only /text is supported in edit operations + path: str From bae72f9c3aec1e825f685a9d7c357c0374bf5292 Mon Sep 17 00:00:00 2001 From: Faiza Jibril Date: Sun, 12 Oct 2025 23:46:56 +0100 Subject: [PATCH 13/13] : add task comments tests; docs: add API links to new methods --- crowdin_api/api_resources/tasks/resource.py | 15 +++ .../tasks/tests/test_tasks_resources.py | 91 +++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/crowdin_api/api_resources/tasks/resource.py b/crowdin_api/api_resources/tasks/resource.py index 500180c..6ebef30 100644 --- a/crowdin_api/api_resources/tasks/resource.py +++ b/crowdin_api/api_resources/tasks/resource.py @@ -958,6 +958,9 @@ def list_task_comments( ): """ List Task Comments. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.getMany """ projectId = projectId or self.get_project_id() @@ -978,6 +981,9 @@ def add_task_comment( ): """ Add Task Comment. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.post """ projectId = projectId or self.get_project_id() @@ -996,6 +1002,9 @@ def get_task_comment( ): """ Get Task Comment. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.get """ projectId = projectId or self.get_project_id() @@ -1015,6 +1024,9 @@ def delete_task_comment( ): """ Delete Task Comment. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.delete """ projectId = projectId or self.get_project_id() @@ -1035,6 +1047,9 @@ def edit_task_comment( ): """ Edit Task Comment. + + Link to documentation: + https://developer.crowdin.com/api/v2/#operation/api.projects.tasks.comments.patch """ projectId = projectId or self.get_project_id() 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 68a181e..0a47b46 100644 --- a/crowdin_api/api_resources/tasks/tests/test_tasks_resources.py +++ b/crowdin_api/api_resources/tasks/tests/test_tasks_resources.py @@ -1327,6 +1327,97 @@ def test_edit_task_archived_status(self, m_request, base_absolut_url): request_data=[{"op": "replace", "path": "/isArchived", "value": False}], ) + # --- Task comments --- + @pytest.mark.parametrize( + "incoming_data, path", + ( + ({"projectId": 1, "taskId": 2}, "projects/1/tasks/2/comments"), + ( + {"projectId": 1, "taskId": 2, "taskCommentId": 3}, + "projects/1/tasks/2/comments/3", + ), + ), + ) + def test_get_task_comments_path(self, incoming_data, path, base_absolut_url): + resource = self.get_resource(base_absolut_url) + assert resource.get_task_comments_path(**incoming_data) == path + + @pytest.mark.parametrize( + "incoming_data, request_params", + ( + ({}, {"orderBy": None, "offset": 0, "limit": 25}), + ({"orderBy": Sorting([])}, {"orderBy": Sorting([]), "offset": 0, "limit": 25}), + ), + ) + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_list_task_comments(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_task_comments(projectId=1, taskId=2, **incoming_data) == "response" + m_request.assert_called_once_with( + method="get", + params=request_params, + path=resource.get_task_comments_path(projectId=1, taskId=2), + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_add_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert resource.add_task_comment(projectId=1, taskId=2, text="hello") == "response" + m_request.assert_called_once_with( + method="post", + path=resource.get_task_comments_path(projectId=1, taskId=2), + request_data={"text": "hello"}, + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_get_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert resource.get_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response" + m_request.assert_called_once_with( + method="get", + path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_delete_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + resource = self.get_resource(base_absolut_url) + assert resource.delete_task_comment(projectId=1, taskId=2, taskCommentId=3) == "response" + m_request.assert_called_once_with( + method="delete", + path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), + ) + + @mock.patch("crowdin_api.requester.APIRequester.request") + def test_edit_task_comment(self, m_request, base_absolut_url): + m_request.return_value = "response" + + data = [ + { + "value": "new text", + "op": PatchOperation.REPLACE, + "path": "/text", + } + ] + + resource = self.get_resource(base_absolut_url) + assert ( + resource.edit_task_comment(projectId=1, taskId=2, taskCommentId=3, data=data) + == "response" + ) + m_request.assert_called_once_with( + method="patch", + path=resource.get_task_comments_path(projectId=1, taskId=2, taskCommentId=3), + request_data=data, + ) + class TestEnterpriseTasksResource: resource_class = EnterpriseTasksResource