datashare-python 0.2.12__tar.gz → 0.2.14__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {datashare_python-0.2.12 → datashare_python-0.2.14}/PKG-INFO +4 -3
  2. {datashare_python-0.2.12 → datashare_python-0.2.14}/pyproject.toml +7 -4
  3. datashare_python-0.2.12/tests/__init__.py +0 -0
  4. datashare_python-0.2.12/tests/cli/test_project.py +0 -23
  5. datashare_python-0.2.12/tests/cli/test_tasks.py +0 -241
  6. datashare_python-0.2.12/tests/cli/test_worker.py +0 -46
  7. datashare_python-0.2.12/tests/conftest.py +0 -14
  8. datashare_python-0.2.12/tests/test_discovery.py +0 -44
  9. datashare_python-0.2.12/tests/test_object.py +0 -28
  10. datashare_python-0.2.12/tests/test_task_client.py +0 -242
  11. datashare_python-0.2.12/tests/test_template.py +0 -40
  12. datashare_python-0.2.12/tests/test_utils.py +0 -17
  13. datashare_python-0.2.12/tests/test_worker.py +0 -68
  14. datashare_python-0.2.12/uv.lock +0 -2379
  15. {datashare_python-0.2.12 → datashare_python-0.2.14}/.gitignore +0 -0
  16. {datashare_python-0.2.12 → datashare_python-0.2.14}/README.md +0 -0
  17. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/.gitignore +0 -0
  18. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/__init__.py +0 -0
  19. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/__main__.py +0 -0
  20. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/cli/__init__.py +0 -0
  21. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/cli/local.py +0 -0
  22. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/cli/project.py +0 -0
  23. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/cli/task.py +0 -0
  24. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/cli/utils.py +0 -0
  25. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/cli/worker.py +0 -0
  26. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/config.py +0 -0
  27. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/conftest.py +0 -0
  28. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/constants.py +0 -0
  29. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/dependencies.py +0 -0
  30. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/discovery.py +0 -0
  31. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/exceptions.py +0 -0
  32. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/local_client.py +0 -0
  33. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/objects.py +0 -0
  34. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/task_client.py +0 -0
  35. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/template.py +0 -0
  36. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/types_.py +0 -0
  37. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/utils.py +0 -0
  38. {datashare_python-0.2.12 → datashare_python-0.2.14}/datashare_python/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: datashare-python
3
- Version: 0.2.12
3
+ Version: 0.2.14
4
4
  Summary: Manage Python tasks and local resources in Datashare
5
5
  Project-URL: Homepage, https://icij.github.io/datashare-python/
6
6
  Project-URL: Documentation, https://icij.github.io/datashare-python/
@@ -11,10 +11,11 @@ Requires-Python: <4,>=3.11
11
11
  Requires-Dist: aiohttp~=3.11.9
12
12
  Requires-Dist: aiostream~=0.6.4
13
13
  Requires-Dist: alive-progress~=3.2.0
14
- Requires-Dist: datashare-worker-template
14
+ Requires-Dist: datashare-worker-template~=0.1
15
+ Requires-Dist: hatchling~=1.27.0
15
16
  Requires-Dist: icij-common[elasticsearch]~=0.7.3
16
17
  Requires-Dist: nest-asyncio~=1.6.0
17
18
  Requires-Dist: python-json-logger~=4.0.0
18
19
  Requires-Dist: temporalio~=1.23.0
19
- Requires-Dist: tomlkit>=0.14.0
20
+ Requires-Dist: tomlkit~=0.14.0
20
21
  Requires-Dist: typer~=0.15.4
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "datashare-python"
3
- version = "0.2.12"
3
+ version = "0.2.14"
4
4
  description = "Manage Python tasks and local resources in Datashare"
5
5
  authors = [
6
6
  { name = "Clément Doumouro", email = "cdoumouro@icij.org" },
@@ -18,8 +18,9 @@ dependencies = [
18
18
  "nest-asyncio~=1.6.0",
19
19
  "temporalio~=1.23.0",
20
20
  "typer~=0.15.4",
21
- "datashare-worker-template",
22
- "tomlkit>=0.14.0",
21
+ "datashare-worker-template~=0.1",
22
+ "tomlkit~=0.14.0",
23
+ "hatchling~=1.27.0",
23
24
  ]
24
25
 
25
26
  [project.urls]
@@ -34,13 +35,15 @@ datashare-python = "datashare_python.__main__:main"
34
35
  [build-system]
35
36
  requires = ["hatchling"]
36
37
  build-backend = "hatchling.build"
37
- package = ["datashare_python"]
38
38
 
39
39
  [tool.hatch.build.targets.wheel]
40
40
  artifacts = [
41
41
  "worker-template.tar.gz"
42
42
  ]
43
43
 
44
+ [tool.hatch.build.targets.sdist]
45
+ only-include = ["datashare_python"]
46
+
44
47
  [tool.uv]
45
48
  package = true
46
49
 
File without changes
@@ -1,23 +0,0 @@
1
- from pathlib import Path
2
-
3
- from datashare_python.cli import cli_app
4
- from typer.testing import CliRunner
5
-
6
-
7
- async def test_init_project(
8
- typer_asyncio_patch, # noqa: ANN001, ARG001
9
- local_template_build, # noqa: ANN001, ARG001
10
- tmp_path: Path,
11
- ) -> None:
12
- # Given
13
- runner = CliRunner(mix_stderr=False)
14
- test_worker_project = "test-project"
15
- # When
16
- args = ["project", "init", str(test_worker_project), "-p", str(tmp_path)]
17
- result = runner.invoke(
18
- cli_app,
19
- args,
20
- catch_exceptions=False,
21
- )
22
- # Then
23
- assert result.exit_code == 0
@@ -1,241 +0,0 @@
1
- import logging
2
- from contextlib import AbstractAsyncContextManager
3
- from datetime import UTC, datetime
4
- from typing import Any, Self
5
- from unittest.mock import AsyncMock, MagicMock
6
-
7
- import click
8
- from _pytest.logging import LogCaptureFixture
9
- from _pytest.monkeypatch import MonkeyPatch
10
- from datashare_python.cli import cli_app
11
- from datashare_python.cli import task as cli_task
12
- from datashare_python.objects import StacktraceItem, Task, TaskError, TaskState
13
- from packaging.version import Version
14
- from typer.testing import CliRunner
15
-
16
- BUGGED_CLICK_VERSION = Version("8.1.8")
17
- CLICK_VERSION = Version(click.__version__)
18
-
19
-
20
- async def test_task_create_task(
21
- monkeypatch: MonkeyPatch,
22
- typer_asyncio_patch, # noqa: ANN001, ARG001
23
- caplog: LogCaptureFixture,
24
- ) -> None:
25
- # Given
26
- mock_client_fn = MagicMock()
27
- mock_client = AsyncMock()
28
- task_id = "hello_world-some-id"
29
- mock_client.create_task.return_value = task_id
30
- mock_client_fn.return_value = mock_client
31
-
32
- class MockedClient:
33
- def __init__(self, datashare_url: str, api_key: str | None = None) -> None: # noqa: ARG002
34
- ...
35
-
36
- async def __aenter__(self) -> Self:
37
- return self
38
-
39
- async def __aexit__(self, exc_type, exc_val, exc_tb): ... # noqa: ANN001
40
-
41
- async def create_task(
42
- self, # noqa: ANN001, ARG001
43
- name: str, # noqa: ARG001, ARG002
44
- args: dict[str, Any], # noqa: ARG001, ARG002
45
- *,
46
- id_: str | None = None, # noqa: ARG001, ARG002
47
- group: str | None = None, # noqa: ARG001, ARG002
48
- ) -> str:
49
- return task_id
50
-
51
- monkeypatch.setattr(cli_task, "DatashareTaskClient", MockedClient)
52
- # When
53
- runner = CliRunner(mix_stderr=False)
54
- with caplog.at_level(logging.INFO):
55
- result = runner.invoke(
56
- cli_app, ["task", "start", "hello_world"], catch_exceptions=False
57
- )
58
- # Then
59
- assert result.exit_code == 0
60
- assert result.stdout == task_id + "\n"
61
- assert ("Task(hello_world-some-id) started" in r for r in caplog.records)
62
- assert ("Task(hello_world-some-id) 🛫" in r for r in caplog.records)
63
-
64
-
65
- async def test_task_watch(
66
- monkeypatch: MonkeyPatch,
67
- typer_asyncio_patch, # noqa: ANN001, ARG001
68
- ) -> None:
69
- # Given
70
- task_id = "hello_world-some-id"
71
- created_at = datetime.now(UTC)
72
-
73
- states = [
74
- Task(
75
- id=task_id,
76
- name="hello_world",
77
- progress=0,
78
- state=TaskState.CREATED,
79
- created_at=created_at,
80
- ),
81
- Task(
82
- id=task_id,
83
- name="hello_world",
84
- progress=0,
85
- state=TaskState.QUEUED,
86
- created_at=created_at,
87
- ),
88
- Task(
89
- id=task_id,
90
- name="hello_world",
91
- progress=0,
92
- state=TaskState.RUNNING,
93
- created_at=created_at,
94
- ),
95
- Task(
96
- id=task_id,
97
- name="hello_world",
98
- progress=0.5,
99
- state=TaskState.RUNNING,
100
- created_at=created_at,
101
- ),
102
- Task(
103
- id=task_id,
104
- name="hello_world",
105
- progress=0.99,
106
- state=TaskState.RUNNING,
107
- created_at=created_at,
108
- ),
109
- Task(
110
- id=task_id,
111
- name="hello_world",
112
- progress=1.0,
113
- state=TaskState.DONE,
114
- completed_at=datetime.now(UTC),
115
- created_at=created_at,
116
- ),
117
- ]
118
-
119
- class MockedClient(AbstractAsyncContextManager):
120
- def __init__(self, datashare_url: str, api_key: str | None = None) -> None: # noqa: ARG002
121
- self._state_it = None
122
-
123
- async def get_task(self, task_id: str) -> Task: # noqa: ARG002
124
- return next(self._state_it)
125
-
126
- async def __aenter__(self) -> Self:
127
- self._state_it = iter(states)
128
- return self
129
-
130
- async def __aexit__(self, exc_type, exc_val, exc_tb): ... # noqa: ANN001
131
-
132
- monkeypatch.setattr(cli_task, "DatashareTaskClient", MockedClient)
133
- # When
134
- runner = CliRunner(mix_stderr=False)
135
- result = runner.invoke(
136
- cli_app, ["task", "watch", task_id, "-p", 0.001], catch_exceptions=False
137
- )
138
- # Then
139
- assert result.exit_code == 0
140
- assert result.stdout.endswith(task_id + "\n")
141
- assert "Task(hello_world-some-id) 🛫" in result.stderr
142
- if CLICK_VERSION > BUGGED_CLICK_VERSION:
143
- assert "Task(hello_world-some-id) 🛬" in result.stderr
144
- assert "Task(hello_world-some-id) ✅" in result.stderr
145
- assert "1.0" in result.stderr
146
-
147
-
148
- async def test_task_watch_error(
149
- monkeypatch: MonkeyPatch,
150
- typer_asyncio_patch, # noqa: ANN001, ARG001
151
- ) -> None:
152
- # Given
153
- mock_client_fn = MagicMock()
154
- mock_client = AsyncMock()
155
- task_id = "hello_world-some-id"
156
- mock_client_fn.return_value = mock_client
157
- created_at = datetime.now(UTC)
158
-
159
- class MockedClient(AbstractAsyncContextManager):
160
- def __init__(self, datashare_url: str, api_key: str | None = None) -> None: # noqa: ARG002
161
- self._state_it = None
162
-
163
- async def __aenter__(self) -> Self:
164
- return self
165
-
166
- async def __aexit__(self, exc_type, exc_val, exc_tb): ... # noqa: ANN001
167
-
168
- async def get_task(self, task_id: str) -> Task: # noqa: ARG002
169
- return Task(
170
- id=task_id,
171
- name="hello_world",
172
- progress=0,
173
- state=TaskState.ERROR,
174
- created_at=created_at,
175
- )
176
-
177
- async def get_task_error(self, task_id: str) -> TaskError: # noqa: ARG002
178
- return TaskError(
179
- name="SomeError",
180
- message="some error occurred",
181
- stacktrace=[
182
- StacktraceItem(name="some_func", file="some_file.py", lineno=666)
183
- ],
184
- )
185
-
186
- monkeypatch.setattr(cli_task, "DatashareTaskClient", MockedClient)
187
- # When
188
- runner = CliRunner(mix_stderr=False)
189
- result = runner.invoke(
190
- cli_app, ["task", "watch", task_id, "-p", 0.001], catch_exceptions=False
191
- )
192
- # Then
193
- assert result.exit_code == 1
194
- if CLICK_VERSION > BUGGED_CLICK_VERSION:
195
- assert (
196
- "Task(hello_world-some-id) failed with the following error:"
197
- in result.stderr
198
- )
199
- assert "Task(hello_world-some-id) ❌" in result.stderr
200
-
201
-
202
- async def test_task_watch_cancelled(
203
- monkeypatch: MonkeyPatch,
204
- typer_asyncio_patch, # noqa: ANN001, ARG001
205
- ) -> None:
206
- # Given
207
- mock_client_fn = MagicMock()
208
- mock_client = AsyncMock()
209
- task_id = "hello_world-some-id"
210
- mock_client_fn.return_value = mock_client
211
- created_at = datetime.now(UTC)
212
-
213
- class MockedClient(AbstractAsyncContextManager):
214
- def __init__(self, datashare_url: str, api_key: str | None = None) -> None: # noqa: ARG002
215
- self._state_it = None
216
-
217
- async def __aenter__(self) -> Self:
218
- return self
219
-
220
- async def __aexit__(self, exc_type, exc_val, exc_tb): ... # noqa: ANN001
221
-
222
- async def get_task(self, task_id: str) -> Task: # noqa: ARG002
223
- return Task(
224
- id=task_id,
225
- name="hello_world",
226
- progress=0,
227
- state=TaskState.CANCELLED,
228
- created_at=created_at,
229
- )
230
-
231
- monkeypatch.setattr(cli_task, "DatashareTaskClient", MockedClient)
232
- # When
233
- runner = CliRunner(mix_stderr=False)
234
- result = runner.invoke(
235
- cli_app, ["task", "watch", task_id, "-p", 0.001], catch_exceptions=False
236
- )
237
- # Then
238
- assert result.exit_code == 1
239
- if CLICK_VERSION > BUGGED_CLICK_VERSION:
240
- assert "Task(hello_world-some-id) was cancelled" in result.stderr
241
- assert "Task(hello_world-some-id) 🛑" in result.stderr
@@ -1,46 +0,0 @@
1
- from _pytest.capture import CaptureFixture
2
- from _pytest.monkeypatch import MonkeyPatch
3
- from datashare_python.cli import cli_app
4
- from temporalio.worker import Worker
5
- from typer.testing import CliRunner
6
-
7
-
8
- async def _mock_worker_run(self) -> None: # noqa: ANN001
9
- pass
10
-
11
-
12
- async def test_start_workers(
13
- worker_lifetime_deps, # noqa: ANN001, ARG001
14
- typer_asyncio_patch, # noqa: ANN001, ARG001
15
- monkeypatch: MonkeyPatch,
16
- capsys: CaptureFixture[str],
17
- ) -> None:
18
- # Given
19
- runner = CliRunner(mix_stderr=False)
20
- monkeypatch.setattr(Worker, "run", _mock_worker_run)
21
- with capsys.disabled():
22
- # When
23
- result = runner.invoke(
24
- cli_app,
25
- [
26
- "worker",
27
- "start",
28
- "--queue",
29
- "cpu",
30
- "--activities",
31
- "ping",
32
- "--activities",
33
- "create-translation-batches",
34
- "--workflows",
35
- "ping",
36
- "--temporal-address",
37
- "localhost:7233",
38
- ],
39
- catch_exceptions=False,
40
- )
41
- # Then
42
- assert result.exit_code == 0
43
- expected = """Starting datashare worker running:
44
- - 1 workflow: ping
45
- - 1 activity: create-translation-batches"""
46
- assert expected in result.stderr
@@ -1,14 +0,0 @@
1
- import pytest # noqa: I001
2
- import nest_asyncio
3
- from datashare_python.conftest import * # noqa: F403
4
- from datashare_python.template import build_template_tarball
5
-
6
-
7
- @pytest.fixture # noqa: F405
8
- def typer_asyncio_patch() -> None:
9
- nest_asyncio.apply()
10
-
11
-
12
- @pytest.fixture(scope="session")
13
- def local_template_build() -> None:
14
- build_template_tarball()
@@ -1,44 +0,0 @@
1
- import pytest
2
- from datashare_python.discovery import discover_activities, discover_workflows
3
-
4
-
5
- @pytest.mark.parametrize(
6
- ("names", "expected_workflows"),
7
- [
8
- ([], {"ping", "translate-and-classify"}),
9
- (["ping", "translate-and-classify"], {"ping", "translate-and-classify"}),
10
- (["ping"], {"ping"}),
11
- (["pi.*"], {"ping"}),
12
- (["pong"], set()),
13
- ],
14
- )
15
- def test_discover_workflows(names: list[str], expected_workflows: set[str]) -> None:
16
- # When
17
- workflows = {wf_name for wf_name, _ in discover_workflows(names)}
18
- # Then
19
- assert workflows == expected_workflows
20
-
21
-
22
- @pytest.mark.parametrize(
23
- ("names", "expected_activities"),
24
- [
25
- (
26
- [],
27
- {
28
- "classify-docs",
29
- "create-classification-batches",
30
- "create-translation-batches",
31
- "pong",
32
- "translate-docs",
33
- },
34
- ),
35
- (["translate-docs"], {"translate-docs"}),
36
- ([".*transl.*"], {"create-translation-batches", "translate-docs"}),
37
- (["idontexist"], set()),
38
- ],
39
- )
40
- def test_discover_activities(names: list[str], expected_activities: set[str]) -> None:
41
- # When
42
- activities = {act_name for act_name, _ in discover_activities(names)}
43
- # Then
44
- assert activities == expected_activities
@@ -1,28 +0,0 @@
1
- from datetime import datetime
2
-
3
- from datashare_python.objects import Task, TaskState
4
-
5
-
6
- def test_task_ser() -> None:
7
- # Given
8
- task = Task(id="some_id", name="some_name", args=dict())
9
-
10
- # When
11
- serialized = task.model_dump()
12
-
13
- # Then
14
- assert isinstance(serialized.pop("createdAt"), datetime)
15
- expected = {
16
- "@type": "Task",
17
- "args": {},
18
- "completedAt": None,
19
- "error": None,
20
- "id": "some_id",
21
- "maxRetries": None,
22
- "name": "some_name",
23
- "progress": None,
24
- "result": None,
25
- "retriesLeft": None,
26
- "state": TaskState.CREATED,
27
- }
28
- assert serialized == expected