datashare-python 0.10.1__tar.gz → 0.10.5__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.10.1 → datashare_python-0.10.5}/PKG-INFO +2 -2
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/interceptors.py +48 -5
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/objects.py +11 -1
- datashare_python-0.10.5/datashare_python/worker-template.tar.gz +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/pyproject.toml +1 -1
- datashare_python-0.10.1/datashare_python/worker-template.tar.gz +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/.gitignore +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/README.md +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/.gitignore +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/__init__.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/__main__.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/cli/__init__.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/cli/project.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/cli/task.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/cli/utils.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/cli/worker.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/config.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/conftest.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/constants.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/dependencies.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/discovery.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/exceptions.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/logging_.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/mimetypes_.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/task_client.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/template.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/types_.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/utils.py +0 -0
- {datashare_python-0.10.1 → datashare_python-0.10.5}/datashare_python/worker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: datashare-python
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.5
|
|
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/
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import dataclasses
|
|
3
3
|
import datetime
|
|
4
|
+
import logging
|
|
4
5
|
import secrets
|
|
5
6
|
from collections.abc import Callable, Generator, Mapping
|
|
6
7
|
from contextlib import contextmanager
|
|
7
8
|
from contextvars import ContextVar
|
|
8
9
|
from copy import deepcopy
|
|
9
10
|
from functools import wraps
|
|
10
|
-
from inspect import signature
|
|
11
|
+
from inspect import iscoroutinefunction, signature
|
|
11
12
|
from types import UnionType
|
|
12
13
|
from typing import (
|
|
13
14
|
Annotated,
|
|
14
15
|
Any,
|
|
15
16
|
NoReturn,
|
|
17
|
+
ParamSpec,
|
|
16
18
|
Self,
|
|
17
19
|
TypeVar,
|
|
18
20
|
get_args,
|
|
@@ -27,6 +29,7 @@ from temporalio.activity import _Definition
|
|
|
27
29
|
from temporalio.api.common.v1 import Payload
|
|
28
30
|
from temporalio.client import WorkflowHandle
|
|
29
31
|
from temporalio.converter import DataConverter
|
|
32
|
+
from temporalio.service import RPCError
|
|
30
33
|
from temporalio.worker import (
|
|
31
34
|
ActivityInboundInterceptor,
|
|
32
35
|
ActivityOutboundInterceptor,
|
|
@@ -66,6 +69,8 @@ from .utils import (
|
|
|
66
69
|
ProgressSignal,
|
|
67
70
|
)
|
|
68
71
|
|
|
72
|
+
logger = logging.getLogger(__name__)
|
|
73
|
+
|
|
69
74
|
_TRACEPARENT = "traceparent"
|
|
70
75
|
_DEFAULT_PAYLOAD_CONVERTER = DataConverter.default.payload_converter
|
|
71
76
|
_PROGRESS_TYPES = {
|
|
@@ -190,6 +195,8 @@ class _TraceContextWorkflowOutboundInterceptor(WorkflowOutboundInterceptor):
|
|
|
190
195
|
|
|
191
196
|
class _TraceContextActivityInboundInterceptor(ActivityInboundInterceptor):
|
|
192
197
|
async def execute_activity(self, input: ExecuteActivityInput) -> Any: # noqa: A002
|
|
198
|
+
info = activity.info()
|
|
199
|
+
logger.info("start executing activity: %s", info.activity_id)
|
|
193
200
|
with _trace_context(input.headers):
|
|
194
201
|
return await super().execute_activity(input)
|
|
195
202
|
|
|
@@ -327,7 +334,8 @@ def _get_progress_handler(
|
|
|
327
334
|
weight=weight,
|
|
328
335
|
min_progress_interval_s=min_progress_interval_s,
|
|
329
336
|
)
|
|
330
|
-
|
|
337
|
+
handler = _fail_safe(handler.progress, "emit progress", excs=(RPCError,))
|
|
338
|
+
return handler
|
|
331
339
|
|
|
332
340
|
|
|
333
341
|
def _is_progress(t: type) -> bool:
|
|
@@ -431,9 +439,10 @@ class _HeartbeatInboundInterceptor(ActivityInboundInterceptor):
|
|
|
431
439
|
heartbeat_task = None
|
|
432
440
|
if heartbeat_timeout:
|
|
433
441
|
period = heartbeat_timeout.total_seconds() / self._n_missed_before_timeout
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
)
|
|
442
|
+
# We don't want a failing hearbeat to fail the worker task so we just
|
|
443
|
+
# ignore any exception
|
|
444
|
+
heartbeat_fn = _fail_safe(self._outbound.heartbeat, "heartbeat")
|
|
445
|
+
heartbeat_task = asyncio.create_task(_heartbeat_every(heartbeat_fn, period))
|
|
437
446
|
try:
|
|
438
447
|
activity.heartbeat()
|
|
439
448
|
return await super().execute_activity(input)
|
|
@@ -443,6 +452,40 @@ class _HeartbeatInboundInterceptor(ActivityInboundInterceptor):
|
|
|
443
452
|
await asyncio.wait([heartbeat_task])
|
|
444
453
|
|
|
445
454
|
|
|
455
|
+
P = ParamSpec("P")
|
|
456
|
+
T = TypeVar("T")
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def _fail_safe[P, T](
|
|
460
|
+
fn: Callable[P, T],
|
|
461
|
+
action: str,
|
|
462
|
+
excs: tuple[type[Exception]] | None = None,
|
|
463
|
+
) -> Callable[P, T]:
|
|
464
|
+
if excs is None:
|
|
465
|
+
excs = (Exception,)
|
|
466
|
+
if iscoroutinefunction(fn):
|
|
467
|
+
|
|
468
|
+
@wraps(fn)
|
|
469
|
+
async def wrapper(*args, **kwargs) -> None:
|
|
470
|
+
try:
|
|
471
|
+
await fn(*args, **kwargs)
|
|
472
|
+
except excs as exc:
|
|
473
|
+
msg = f"failed to {action} due to {exc}"
|
|
474
|
+
logger.exception(msg)
|
|
475
|
+
|
|
476
|
+
else:
|
|
477
|
+
|
|
478
|
+
@wraps(fn)
|
|
479
|
+
def wrapper(*args, **kwargs) -> None:
|
|
480
|
+
try:
|
|
481
|
+
fn(*args, **kwargs)
|
|
482
|
+
except excs as exc:
|
|
483
|
+
msg = f"failed to {action} due to {exc}"
|
|
484
|
+
logger.exception(msg)
|
|
485
|
+
|
|
486
|
+
return wrapper
|
|
487
|
+
|
|
488
|
+
|
|
446
489
|
def _sync_progress(
|
|
447
490
|
progress_handler: AsyncProgressRateHandler,
|
|
448
491
|
) -> SyncProgressRateHandler:
|
|
@@ -14,7 +14,7 @@ from icij_common.registrable import Registrable
|
|
|
14
14
|
from pydantic_core import PydanticCustomError, ValidationError, core_schema
|
|
15
15
|
from pydantic_core.core_schema import PlainValidatorFunctionSchema
|
|
16
16
|
from pydantic_extra_types.language_code import LanguageName
|
|
17
|
-
from temporalio import workflow
|
|
17
|
+
from temporalio import activity, workflow
|
|
18
18
|
|
|
19
19
|
from .constants import TIKA_METADATA_RESOURCENAME
|
|
20
20
|
|
|
@@ -325,6 +325,8 @@ A = TypeVar("A", bound=TaskArgs)
|
|
|
325
325
|
|
|
326
326
|
class ManifestEntry[A](DatashareModel, ABC):
|
|
327
327
|
status: ManifestEntryStatus
|
|
328
|
+
# TODO: make this one non optional in the next major !
|
|
329
|
+
task_id: str | None
|
|
328
330
|
label: str | None = None
|
|
329
331
|
input: Annotated[
|
|
330
332
|
dict[str, Any] | None,
|
|
@@ -336,7 +338,11 @@ class ManifestEntry[A](DatashareModel, ABC):
|
|
|
336
338
|
|
|
337
339
|
@classmethod
|
|
338
340
|
def complete(cls, args: A, label: str | None = None, **kwargs) -> Self:
|
|
341
|
+
task_id = None
|
|
342
|
+
if activity.in_activity():
|
|
343
|
+
task_id = activity.info().workflow_id
|
|
339
344
|
return cls(
|
|
345
|
+
task_id=task_id,
|
|
340
346
|
input=args.as_manifest_task_input(),
|
|
341
347
|
label=label,
|
|
342
348
|
status=ManifestEntryStatus.COMPLETE,
|
|
@@ -345,7 +351,11 @@ class ManifestEntry[A](DatashareModel, ABC):
|
|
|
345
351
|
|
|
346
352
|
@classmethod
|
|
347
353
|
def partial(cls, args: A, label: str | None = None, **kwargs) -> Self:
|
|
354
|
+
task_id = None
|
|
355
|
+
if activity.in_activity():
|
|
356
|
+
task_id = activity.info().workflow_id
|
|
348
357
|
return cls(
|
|
358
|
+
task_id=task_id,
|
|
349
359
|
input=args.as_manifest_task_input(),
|
|
350
360
|
label=label,
|
|
351
361
|
status=ManifestEntryStatus.PARTIAL,
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|