datashare-python 0.9.8__tar.gz → 0.10.0.dev0__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.
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/PKG-INFO +4 -3
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/cli/task.py +2 -2
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/cli/worker.py +1 -1
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/config.py +17 -7
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/conftest.py +176 -44
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/constants.py +1 -2
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/dependencies.py +0 -16
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/logging_.py +1 -1
- datashare_python-0.10.0.dev0/datashare_python/mimetypes_.py +1105 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/objects.py +198 -69
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/utils.py +347 -42
- datashare_python-0.10.0.dev0/datashare_python/worker-template.tar.gz +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/worker.py +14 -3
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/pyproject.toml +10 -5
- datashare_python-0.9.8/datashare_python/worker-template.tar.gz +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/.gitignore +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/README.md +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/.gitignore +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/__init__.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/__main__.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/cli/__init__.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/cli/project.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/cli/utils.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/discovery.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/exceptions.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/interceptors.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/task_client.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/template.py +0 -0
- {datashare_python-0.9.8 → datashare_python-0.10.0.dev0}/datashare_python/types_.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datashare-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0.dev0
|
|
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/
|
|
@@ -8,15 +8,16 @@ Project-URL: Repository, https://github.com/ICIJ/datashare-python
|
|
|
8
8
|
Project-URL: Issues, https://github.com/ICIJ/datashare-python/issues
|
|
9
9
|
Author-email: Clément Doumouro <cdoumouro@icij.org>, Clément Doumouro <clement.doumouro@gmail.com>, Lion Summerbell <lsummerbell@icij.org>
|
|
10
10
|
Requires-Python: <4,>=3.11
|
|
11
|
+
Requires-Dist: aiofile~=3.11
|
|
11
12
|
Requires-Dist: aiohttp~=3.11
|
|
12
13
|
Requires-Dist: alive-progress~=3.2
|
|
13
14
|
Requires-Dist: hatchling~=1.27
|
|
14
|
-
Requires-Dist: icij-common[elasticsearch]~=0.8.
|
|
15
|
+
Requires-Dist: icij-common[elasticsearch]~=0.8.3
|
|
15
16
|
Requires-Dist: langcodes~=3.5
|
|
16
17
|
Requires-Dist: lru-dict~=1.4
|
|
17
18
|
Requires-Dist: pydantic-extra-types[pycountry]>=2.11.1
|
|
18
19
|
Requires-Dist: python-json-logger~=4.0
|
|
19
20
|
Requires-Dist: pyyaml~=6.0
|
|
20
|
-
Requires-Dist: temporalio~=1.
|
|
21
|
+
Requires-Dist: temporalio~=1.31
|
|
21
22
|
Requires-Dist: tomlkit~=0.14.0
|
|
22
23
|
Requires-Dist: typer<0.25.1,>=0.15.4
|
|
@@ -28,7 +28,7 @@ _START_HELP = "creates a new task and start it"
|
|
|
28
28
|
_TASK_ID_HELP = "task ID"
|
|
29
29
|
_WATCH_HELP = "watch a task until it's complete"
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
StrTaskArgs = str
|
|
32
32
|
|
|
33
33
|
task_app = AsyncTyper(name="task")
|
|
34
34
|
|
|
@@ -36,7 +36,7 @@ task_app = AsyncTyper(name="task")
|
|
|
36
36
|
@task_app.async_command(help=_START_HELP)
|
|
37
37
|
async def start(
|
|
38
38
|
name: Annotated[str, typer.Argument(help=_NAME_HELP)],
|
|
39
|
-
args: Annotated[
|
|
39
|
+
args: Annotated[StrTaskArgs, typer.Argument(help=_ARGS_HELP)] = None,
|
|
40
40
|
group: Annotated[
|
|
41
41
|
str | None,
|
|
42
42
|
typer.Option("--group", "-g", help=_GROUP_HELP),
|
|
@@ -78,7 +78,7 @@ to the documentation to learn how to do so."""
|
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
@worker_app.async_command(help=_START_WORKER_HELP)
|
|
81
|
-
async def start(
|
|
81
|
+
async def start( # noqa: PLR0917
|
|
82
82
|
queue: Annotated[str, typer.Option("--queue", "-q", help=_WORKER_QUEUE_HELP)],
|
|
83
83
|
workflows: Annotated[
|
|
84
84
|
list[str] | None,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from enum import StrEnum
|
|
2
|
-
from pathlib import Path
|
|
3
2
|
from typing import Literal
|
|
4
3
|
|
|
5
4
|
from icij_common.es import ESClient
|
|
@@ -10,10 +9,10 @@ from temporalio.runtime import PrometheusConfig, Runtime, TelemetryConfig
|
|
|
10
9
|
|
|
11
10
|
import datashare_python
|
|
12
11
|
|
|
13
|
-
from .objects import BaseModel
|
|
12
|
+
from .objects import BaseModel, WorkerPaths
|
|
14
13
|
from .task_client import DatashareTaskClient
|
|
15
14
|
from .types_ import TemporalClient
|
|
16
|
-
from .utils import PYDANTIC_DATA_CONVERTER
|
|
15
|
+
from .utils import PYDANTIC_DATA_CONVERTER, SharedResources, close_cm_callback
|
|
17
16
|
|
|
18
17
|
_ALL_LOGGERS = [datashare_python.__name__]
|
|
19
18
|
|
|
@@ -94,6 +93,19 @@ class LoggingConfig(BaseModel):
|
|
|
94
93
|
loggers: dict[str, LogLevel]
|
|
95
94
|
|
|
96
95
|
|
|
96
|
+
class ResourceCacheConfig(BaseModel):
|
|
97
|
+
size: int = 1
|
|
98
|
+
exit_context_managers: bool = True
|
|
99
|
+
|
|
100
|
+
def to_resource_cache(self) -> SharedResources:
|
|
101
|
+
eviction_callback = None
|
|
102
|
+
if self.exit_context_managers:
|
|
103
|
+
eviction_callback = close_cm_callback
|
|
104
|
+
return SharedResources(
|
|
105
|
+
cache_size=self.size, eviction_callback=eviction_callback
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
97
109
|
_DEFAULT_LOGGERS = {datashare_python.__name__: "INFO"}
|
|
98
110
|
_DEFAULT_LOGGING_CONFIG = LoggingConfig(
|
|
99
111
|
format=LogFormat.DEFAULT, loggers=_DEFAULT_LOGGERS
|
|
@@ -109,11 +121,9 @@ class WorkerConfig(ICIJSettings, BaseModel):
|
|
|
109
121
|
elasticsearch: ESClientConfig = ESClientConfig()
|
|
110
122
|
temporal: TemporalClientConfig = TemporalClientConfig()
|
|
111
123
|
|
|
112
|
-
|
|
124
|
+
max_concurrent_activities: int = 5
|
|
113
125
|
|
|
114
|
-
|
|
115
|
-
artifacts_root: Path | None = None
|
|
116
|
-
workdir: Path | None = None
|
|
126
|
+
paths: WorkerPaths | None = None
|
|
117
127
|
|
|
118
128
|
def to_es_client(self) -> ESClient:
|
|
119
129
|
return self.elasticsearch.to_es_client(self.datashare.api_key)
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import faulthandler
|
|
3
|
+
import logging
|
|
4
|
+
import multiprocessing
|
|
1
5
|
import shutil
|
|
6
|
+
from asyncio import AbstractEventLoop
|
|
2
7
|
from collections.abc import AsyncGenerator, Generator, Sequence
|
|
8
|
+
from contextlib import AbstractAsyncContextManager, asynccontextmanager
|
|
9
|
+
from multiprocessing import Event
|
|
3
10
|
from pathlib import Path
|
|
4
11
|
|
|
5
12
|
import aiohttp
|
|
@@ -10,6 +17,7 @@ from icij_common.es import DOC_ROOT_ID, ES_DOCUMENT_TYPE, ID, ESClient
|
|
|
10
17
|
from icij_common.test_utils import reset_env # noqa: F401
|
|
11
18
|
from pytest_asyncio import is_async_test
|
|
12
19
|
from temporalio import workflow
|
|
20
|
+
from temporalio.runtime import PrometheusConfig, Runtime, TelemetryConfig
|
|
13
21
|
from temporalio.service import RPCError, RPCStatusCode
|
|
14
22
|
|
|
15
23
|
from datashare_python.config import (
|
|
@@ -19,17 +27,14 @@ from datashare_python.config import (
|
|
|
19
27
|
TemporalClientConfig,
|
|
20
28
|
WorkerConfig,
|
|
21
29
|
)
|
|
22
|
-
from datashare_python.
|
|
23
|
-
lifespan_es_client,
|
|
24
|
-
lifespan_task_client,
|
|
25
|
-
set_es_client,
|
|
26
|
-
set_task_client,
|
|
27
|
-
with_dependencies,
|
|
28
|
-
)
|
|
30
|
+
from datashare_python.discovery import discover
|
|
29
31
|
from datashare_python.objects import Document, TaskState
|
|
30
32
|
from datashare_python.task_client import DatashareTaskClient
|
|
31
|
-
from datashare_python.types_ import
|
|
32
|
-
from datashare_python.utils import activity_defn
|
|
33
|
+
from datashare_python.types_ import TemporalClient
|
|
34
|
+
from datashare_python.utils import PYDANTIC_DATA_CONVERTER, activity_defn
|
|
35
|
+
from datashare_python.worker import create_worker_id, worker_context
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
33
38
|
|
|
34
39
|
RABBITMQ_TEST_PORT = 5672
|
|
35
40
|
RABBITMQ_TEST_HOST = "localhost"
|
|
@@ -83,11 +88,6 @@ class MockedWorkflow:
|
|
|
83
88
|
return None
|
|
84
89
|
|
|
85
90
|
|
|
86
|
-
@pytest.fixture(scope="session")
|
|
87
|
-
def test_deps() -> list[ContextManagerFactory]:
|
|
88
|
-
return [set_es_client, set_task_client]
|
|
89
|
-
|
|
90
|
-
|
|
91
91
|
@pytest.fixture(scope="session")
|
|
92
92
|
def test_worker_config() -> WorkerConfig:
|
|
93
93
|
logging_config = LoggingConfig(
|
|
@@ -113,25 +113,8 @@ def test_worker_config_path(test_worker_config: WorkerConfig, tmpdir: Path) -> P
|
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
@pytest.fixture(scope="session")
|
|
116
|
-
async def
|
|
117
|
-
|
|
118
|
-
) -> AsyncGenerator[None, None]:
|
|
119
|
-
worker_id = "test-worker-id"
|
|
120
|
-
ctx = "test application"
|
|
121
|
-
async with with_dependencies(
|
|
122
|
-
test_deps,
|
|
123
|
-
ctx=ctx,
|
|
124
|
-
worker_id=worker_id,
|
|
125
|
-
worker_config=test_worker_config,
|
|
126
|
-
):
|
|
127
|
-
yield
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
@pytest.fixture(scope="session")
|
|
131
|
-
async def test_es_client_session(
|
|
132
|
-
worker_lifetime_deps, # noqa: ANN001, ARG001
|
|
133
|
-
) -> ESClient:
|
|
134
|
-
es = lifespan_es_client()
|
|
116
|
+
async def test_es_client_session(test_worker_config: WorkerConfig) -> ESClient:
|
|
117
|
+
es = test_worker_config.to_es_client()
|
|
135
118
|
await es.indices.delete(index="_all")
|
|
136
119
|
await es.indices.create(index=TEST_PROJECT, body=_INDEX_BODY)
|
|
137
120
|
return es
|
|
@@ -147,9 +130,9 @@ async def test_es_client(test_es_client_session: ESClient) -> ESClient:
|
|
|
147
130
|
|
|
148
131
|
@pytest.fixture(scope="session")
|
|
149
132
|
async def test_task_client_session(
|
|
150
|
-
|
|
133
|
+
test_worker_config: WorkerConfig,
|
|
151
134
|
) -> AsyncGenerator[DatashareTaskClient, None]:
|
|
152
|
-
task_client =
|
|
135
|
+
task_client = test_worker_config.to_task_client()
|
|
153
136
|
async with task_client:
|
|
154
137
|
user, key = await task_client.create_api_key()
|
|
155
138
|
task_client.authenticate(user, key)
|
|
@@ -188,17 +171,24 @@ async def test_temporal_client(
|
|
|
188
171
|
|
|
189
172
|
|
|
190
173
|
@pytest.fixture
|
|
191
|
-
async def
|
|
192
|
-
test_es_client: ESClient,
|
|
174
|
+
async def indexed_docs(
|
|
193
175
|
doc_0: Document,
|
|
194
176
|
doc_1: Document,
|
|
195
177
|
doc_2: Document,
|
|
196
178
|
doc_3: Document,
|
|
197
179
|
) -> list[Document]:
|
|
198
|
-
|
|
199
|
-
|
|
180
|
+
return [doc_0, doc_1, doc_2, doc_3]
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@pytest.fixture
|
|
184
|
+
async def populate_es(
|
|
185
|
+
test_es_client: ESClient, indexed_docs: list[Document]
|
|
186
|
+
) -> list[Document]:
|
|
187
|
+
async for _ in index_docs(
|
|
188
|
+
test_es_client, docs=indexed_docs, index_name=TEST_PROJECT
|
|
189
|
+
):
|
|
200
190
|
pass
|
|
201
|
-
return
|
|
191
|
+
return indexed_docs
|
|
202
192
|
|
|
203
193
|
|
|
204
194
|
def index_docs_ops(
|
|
@@ -313,7 +303,149 @@ def typer_asyncio_patch() -> None:
|
|
|
313
303
|
|
|
314
304
|
|
|
315
305
|
def clear_dirs(config: WorkerConfig) -> None:
|
|
316
|
-
shutil.rmtree(str(config.
|
|
317
|
-
config.
|
|
318
|
-
shutil.rmtree(str(config.
|
|
319
|
-
config.
|
|
306
|
+
shutil.rmtree(str(config.paths.filesystem))
|
|
307
|
+
config.paths.filesystem.mkdir(parents=True, exist_ok=True)
|
|
308
|
+
shutil.rmtree(str(config.paths.artifacts))
|
|
309
|
+
config.paths.artifacts.mkdir(parents=True, exist_ok=True)
|
|
310
|
+
shutil.rmtree(str(config.paths.workdir))
|
|
311
|
+
config.paths.workdir.mkdir(parents=True, exist_ok=True)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def dev_worker_context(
|
|
315
|
+
worker_id_prefix: str,
|
|
316
|
+
*,
|
|
317
|
+
is_async: bool,
|
|
318
|
+
client: TemporalClient,
|
|
319
|
+
activities: list[str] | None = None,
|
|
320
|
+
workflows: list[str] | None = None,
|
|
321
|
+
worker_config: WorkerConfig,
|
|
322
|
+
event_loop: AbstractEventLoop | None = None,
|
|
323
|
+
task_queue: str,
|
|
324
|
+
dependencies: str | None = None,
|
|
325
|
+
sandboxed: bool = True,
|
|
326
|
+
) -> AbstractAsyncContextManager[None]:
|
|
327
|
+
worker_id = create_worker_id(worker_id_prefix)
|
|
328
|
+
if not is_async:
|
|
329
|
+
return _run_worker_in_separate_process(
|
|
330
|
+
worker_id=worker_id,
|
|
331
|
+
activities=activities,
|
|
332
|
+
workflows=workflows,
|
|
333
|
+
worker_config=worker_config.model_dump(),
|
|
334
|
+
task_queue=task_queue,
|
|
335
|
+
dependencies=dependencies,
|
|
336
|
+
sandboxed=sandboxed,
|
|
337
|
+
)
|
|
338
|
+
registered_wfs, registered_acts, registered_deps, worker_config_cls = discover(
|
|
339
|
+
workflows,
|
|
340
|
+
act_names=activities,
|
|
341
|
+
deps_name=dependencies,
|
|
342
|
+
)
|
|
343
|
+
cm = _erase_type(
|
|
344
|
+
worker_context(
|
|
345
|
+
worker_id,
|
|
346
|
+
activities=registered_acts,
|
|
347
|
+
workflows=registered_wfs,
|
|
348
|
+
dependencies=registered_deps,
|
|
349
|
+
worker_config=worker_config,
|
|
350
|
+
client=client,
|
|
351
|
+
event_loop=event_loop,
|
|
352
|
+
task_queue=task_queue,
|
|
353
|
+
)
|
|
354
|
+
)
|
|
355
|
+
return cm
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@asynccontextmanager
|
|
359
|
+
async def _erase_type(cm: AbstractAsyncContextManager) -> AsyncGenerator[None, None]:
|
|
360
|
+
async with cm:
|
|
361
|
+
yield
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
@asynccontextmanager
|
|
365
|
+
async def _run_worker_in_separate_process(
|
|
366
|
+
worker_id: str,
|
|
367
|
+
*,
|
|
368
|
+
activities: list[str] | None = None,
|
|
369
|
+
workflows: list[str] | None = None,
|
|
370
|
+
worker_config: dict,
|
|
371
|
+
task_queue: str,
|
|
372
|
+
dependencies: str | None = None,
|
|
373
|
+
sandboxed: bool = True,
|
|
374
|
+
) -> AsyncGenerator[None, None]:
|
|
375
|
+
ctx = multiprocessing.get_context("spawn")
|
|
376
|
+
shutdown_event = ctx.Event()
|
|
377
|
+
faulthandler.enable()
|
|
378
|
+
kwargs = {
|
|
379
|
+
"worker_id": worker_id,
|
|
380
|
+
"activities": activities,
|
|
381
|
+
"workflows": workflows,
|
|
382
|
+
"worker_config": worker_config,
|
|
383
|
+
"task_queue": task_queue,
|
|
384
|
+
"dependencies": dependencies,
|
|
385
|
+
"sandboxed": sandboxed,
|
|
386
|
+
"shutdown_event": shutdown_event,
|
|
387
|
+
}
|
|
388
|
+
p = ctx.Process(target=_run_worker_process, kwargs=kwargs)
|
|
389
|
+
p.start()
|
|
390
|
+
try:
|
|
391
|
+
yield
|
|
392
|
+
finally:
|
|
393
|
+
shutdown_event.set()
|
|
394
|
+
p.join()
|
|
395
|
+
if p.is_alive():
|
|
396
|
+
p.terminate()
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def _run_worker_process(
|
|
400
|
+
worker_id: str,
|
|
401
|
+
*,
|
|
402
|
+
activities: list[str] | None = None,
|
|
403
|
+
workflows: list[str] | None = None,
|
|
404
|
+
worker_config: dict,
|
|
405
|
+
event_loop: AbstractEventLoop | None = None,
|
|
406
|
+
task_queue: str,
|
|
407
|
+
dependencies: str | None = None,
|
|
408
|
+
sandboxed: bool = True,
|
|
409
|
+
shutdown_event: Event,
|
|
410
|
+
) -> None:
|
|
411
|
+
async def _run() -> None:
|
|
412
|
+
registered_wfs, registered_acts, registered_deps, worker_config_cls = discover(
|
|
413
|
+
workflows,
|
|
414
|
+
act_names=activities,
|
|
415
|
+
deps_name=dependencies,
|
|
416
|
+
)
|
|
417
|
+
loaded_config = worker_config_cls.model_validate(worker_config)
|
|
418
|
+
temporal_config = loaded_config.temporal
|
|
419
|
+
runtime = Runtime(telemetry=TelemetryConfig())
|
|
420
|
+
# We don't use config.to_temporal_client since we get a problem with the
|
|
421
|
+
# temporal runtime not being properly recreated, we create it explicitely
|
|
422
|
+
if temporal_config.prometheus_host is not None:
|
|
423
|
+
telemetry_config = TelemetryConfig(
|
|
424
|
+
metrics=PrometheusConfig(bind_address="0.0.0.0:9000")
|
|
425
|
+
)
|
|
426
|
+
runtime = Runtime(telemetry=telemetry_config)
|
|
427
|
+
client = await TemporalClient.connect(
|
|
428
|
+
target_host=temporal_config.host,
|
|
429
|
+
namespace=temporal_config.namespace,
|
|
430
|
+
runtime=runtime,
|
|
431
|
+
data_converter=PYDANTIC_DATA_CONVERTER,
|
|
432
|
+
)
|
|
433
|
+
worker_ctx = worker_context(
|
|
434
|
+
worker_id,
|
|
435
|
+
activities=registered_acts,
|
|
436
|
+
workflows=registered_wfs,
|
|
437
|
+
worker_config=loaded_config,
|
|
438
|
+
client=client,
|
|
439
|
+
event_loop=event_loop,
|
|
440
|
+
task_queue=task_queue,
|
|
441
|
+
dependencies=registered_deps,
|
|
442
|
+
sandboxed=sandboxed,
|
|
443
|
+
)
|
|
444
|
+
async with worker_ctx as worker:
|
|
445
|
+
aws = [
|
|
446
|
+
asyncio.create_task(asyncio.to_thread(shutdown_event.wait)),
|
|
447
|
+
asyncio.create_task(worker.is_done()),
|
|
448
|
+
]
|
|
449
|
+
await asyncio.wait(aws, return_when=asyncio.FIRST_COMPLETED)
|
|
450
|
+
|
|
451
|
+
asyncio.run(_run())
|
|
@@ -11,7 +11,6 @@ DEFAULT_DS_ADDRESS = "http://localhost:8080"
|
|
|
11
11
|
DEFAULT_NAMESPACE = "datashare-default"
|
|
12
12
|
|
|
13
13
|
METADATA_JSON = "metadata.json"
|
|
14
|
+
MANIFEST_JSON = "manifest.json"
|
|
14
15
|
|
|
15
16
|
TIKA_METADATA_RESOURCENAME = "tika_metadata_resourcename"
|
|
16
|
-
|
|
17
|
-
DEFAULT_SHARED_RESOURCES_SIZE = 1
|
|
@@ -12,7 +12,6 @@ from icij_common.es import ESClient
|
|
|
12
12
|
from .config import LogLevel, WorkerConfig
|
|
13
13
|
from .exceptions import DependencyInjectionError
|
|
14
14
|
from .logging_ import setup_worker_loggers
|
|
15
|
-
from .objects import Shared
|
|
16
15
|
from .task_client import DatashareTaskClient
|
|
17
16
|
from .types_ import ContextManagerFactory, TemporalClient
|
|
18
17
|
|
|
@@ -24,7 +23,6 @@ ES_CLIENT: ContextVar[ESClient] = ContextVar("es_client")
|
|
|
24
23
|
TASK_CLIENT: ContextVar[DatashareTaskClient] = ContextVar("task_client")
|
|
25
24
|
TEMPORAL_CLIENT: ContextVar[TemporalClient] = ContextVar("temporal_client")
|
|
26
25
|
WORKER_CONFIG: ContextVar[WorkerConfig] = ContextVar("worker_config")
|
|
27
|
-
SHARED: ContextVar[Shared] = ContextVar("shared")
|
|
28
26
|
|
|
29
27
|
|
|
30
28
|
def set_event_loop(event_loop: AbstractEventLoop) -> None:
|
|
@@ -101,20 +99,6 @@ def lifespan_temporal_client() -> TemporalClient:
|
|
|
101
99
|
raise DependencyInjectionError("temporal client") from e
|
|
102
100
|
|
|
103
101
|
|
|
104
|
-
# Setup shared resources
|
|
105
|
-
async def set_shared_resources(shared: Shared) -> Shared:
|
|
106
|
-
SHARED.set(shared)
|
|
107
|
-
return shared
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
# Return shared resources
|
|
111
|
-
def lifespan_shared_resources() -> Shared:
|
|
112
|
-
try:
|
|
113
|
-
return SHARED.get()
|
|
114
|
-
except LookupError as e:
|
|
115
|
-
raise DependencyInjectionError("shared resources") from e
|
|
116
|
-
|
|
117
|
-
|
|
118
102
|
@asynccontextmanager
|
|
119
103
|
async def with_dependencies(
|
|
120
104
|
dependencies: list[ContextManagerFactory], **kwargs
|
|
@@ -132,7 +132,7 @@ def _encode_value(value: Any) -> str:
|
|
|
132
132
|
return "true" if value else "false"
|
|
133
133
|
if isinstance(value, numbers.Number):
|
|
134
134
|
return str(value)
|
|
135
|
-
return json.dumps(value)
|
|
135
|
+
return json.dumps(value)
|
|
136
136
|
|
|
137
137
|
|
|
138
138
|
def _json_formatter(datefmt: str) -> BaseJsonFormatter:
|