datashare-python 0.10.5__tar.gz → 0.10.7__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 (29) hide show
  1. {datashare_python-0.10.5 → datashare_python-0.10.7}/PKG-INFO +1 -1
  2. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/interceptors.py +5 -10
  3. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/objects.py +8 -0
  4. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/utils.py +30 -9
  5. datashare_python-0.10.7/datashare_python/worker-template.tar.gz +0 -0
  6. {datashare_python-0.10.5 → datashare_python-0.10.7}/pyproject.toml +1 -1
  7. datashare_python-0.10.5/datashare_python/worker-template.tar.gz +0 -0
  8. {datashare_python-0.10.5 → datashare_python-0.10.7}/.gitignore +0 -0
  9. {datashare_python-0.10.5 → datashare_python-0.10.7}/README.md +0 -0
  10. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/.gitignore +0 -0
  11. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/__init__.py +0 -0
  12. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/__main__.py +0 -0
  13. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/cli/__init__.py +0 -0
  14. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/cli/project.py +0 -0
  15. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/cli/task.py +0 -0
  16. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/cli/utils.py +0 -0
  17. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/cli/worker.py +0 -0
  18. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/config.py +0 -0
  19. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/conftest.py +0 -0
  20. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/constants.py +0 -0
  21. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/dependencies.py +0 -0
  22. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/discovery.py +0 -0
  23. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/exceptions.py +0 -0
  24. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/logging_.py +0 -0
  25. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/mimetypes_.py +0 -0
  26. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/task_client.py +0 -0
  27. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/template.py +0 -0
  28. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/types_.py +0 -0
  29. {datashare_python-0.10.5 → datashare_python-0.10.7}/datashare_python/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: datashare-python
3
- Version: 0.10.5
3
+ Version: 0.10.7
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/
@@ -14,7 +14,6 @@ from typing import (
14
14
  Annotated,
15
15
  Any,
16
16
  NoReturn,
17
- ParamSpec,
18
17
  Self,
19
18
  TypeVar,
20
19
  get_args,
@@ -452,11 +451,7 @@ class _HeartbeatInboundInterceptor(ActivityInboundInterceptor):
452
451
  await asyncio.wait([heartbeat_task])
453
452
 
454
453
 
455
- P = ParamSpec("P")
456
- T = TypeVar("T")
457
-
458
-
459
- def _fail_safe[P, T](
454
+ def _fail_safe[**P, T](
460
455
  fn: Callable[P, T],
461
456
  action: str,
462
457
  excs: tuple[type[Exception]] | None = None,
@@ -466,9 +461,9 @@ def _fail_safe[P, T](
466
461
  if iscoroutinefunction(fn):
467
462
 
468
463
  @wraps(fn)
469
- async def wrapper(*args, **kwargs) -> None:
464
+ async def wrapper(*args: P.args, **kwargs: P.kwargs) -> None:
470
465
  try:
471
- await fn(*args, **kwargs)
466
+ return await fn(*args, **kwargs)
472
467
  except excs as exc:
473
468
  msg = f"failed to {action} due to {exc}"
474
469
  logger.exception(msg)
@@ -476,9 +471,9 @@ def _fail_safe[P, T](
476
471
  else:
477
472
 
478
473
  @wraps(fn)
479
- def wrapper(*args, **kwargs) -> None:
474
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> None:
480
475
  try:
481
- fn(*args, **kwargs)
476
+ return fn(*args, **kwargs)
482
477
  except excs as exc:
483
478
  msg = f"failed to {action} due to {exc}"
484
479
  logger.exception(msg)
@@ -1,3 +1,5 @@
1
+ import hashlib
2
+ import json
1
3
  import logging
2
4
  import os
3
5
  from abc import ABC
@@ -63,6 +65,12 @@ Predicate = Callable[[T], bool] | Callable[[T], Awaitable[bool]]
63
65
  class BaseModel(_BaseModel):
64
66
  model_config = merge_configs(icij_config(), no_enum_values_config())
65
67
 
68
+ def __hash__(self) -> int:
69
+ digest = hashlib.md5(
70
+ json.dumps(self.model_dump(mode="json"), sort_keys=True).encode()
71
+ ).digest()
72
+ return int.from_bytes(digest[:8])
73
+
66
74
 
67
75
  class DatashareModel(BaseModel):
68
76
  model_config = merge_configs(BaseModel.model_config, lowercamel_case_config())
@@ -32,6 +32,7 @@ import temporalio
32
32
  from aiofile import async_open
33
33
  from lru import LRU
34
34
  from pydantic import ValidationError
35
+ from pydantic.alias_generators import to_snake
35
36
  from temporalio import activity, workflow
36
37
  from temporalio.api.common.v1 import Payload
37
38
  from temporalio.client import Client
@@ -62,6 +63,8 @@ from .objects import (
62
63
  )
63
64
  from .types_ import RawAsyncProgressHandler
64
65
 
66
+ _CACHE_DIR = "__cache__"
67
+
65
68
  logger = logging.getLogger(__name__)
66
69
 
67
70
  DependencyLabel = str | None
@@ -533,7 +536,11 @@ activity_contextual_id = contextual_id
533
536
 
534
537
 
535
538
  def _contextual_path(
536
- *, wf_context: bool = True, act_context: bool = True, run_context: bool = False
539
+ *,
540
+ wf_context: bool = True,
541
+ act_context: bool = True,
542
+ run_context: bool = False,
543
+ caching_key: str | None = None,
537
544
  ) -> Path:
538
545
  act_info = activity.info()
539
546
  path = []
@@ -541,14 +548,18 @@ def _contextual_path(
541
548
  raise ValueError("at least one of wf_context and act_context must be True")
542
549
  if wf_context:
543
550
  path = [act_info.workflow_type]
544
- path.append(act_info.workflow_id)
545
- if run_context:
546
- path.append(act_info.workflow_run_id)
551
+ if not caching_key:
552
+ path.append(act_info.workflow_id)
553
+ if run_context:
554
+ path.append(act_info.workflow_run_id)
547
555
  if act_context:
548
556
  path.append(act_info.activity_type)
549
- path.append(act_info.activity_id)
550
- if run_context:
551
- path.append(act_info.activity_run_id)
557
+ if not caching_key:
558
+ path.append(act_info.activity_id)
559
+ if run_context:
560
+ path.append(act_info.activity_run_id)
561
+ if caching_key:
562
+ path += [_CACHE_DIR, caching_key]
552
563
  return Path(*path)
553
564
 
554
565
 
@@ -559,9 +570,13 @@ def activity_workdir(
559
570
  wf_context: bool = True,
560
571
  act_context: bool = True,
561
572
  run_context: bool = False,
573
+ caching_key: str | None = None,
562
574
  ) -> Path:
563
575
  ctx_path = _contextual_path(
564
- wf_context=wf_context, act_context=act_context, run_context=run_context
576
+ wf_context=wf_context,
577
+ act_context=act_context,
578
+ run_context=run_context,
579
+ caching_key=caching_key,
565
580
  )
566
581
  return workdir.joinpath(project, ctx_path)
567
582
 
@@ -808,4 +823,10 @@ def async_enter_cm(
808
823
 
809
824
 
810
825
  def config_cache_key(config: BaseModel) -> str:
811
- return str(hash(config))
826
+ # BaseModel support deterministic hash we can call hash on it
827
+ config_label = (
828
+ to_snake(config.__class__.__name__.replace("Config", ""))
829
+ .lower()
830
+ .replace("_", "-")
831
+ )
832
+ return f"{config_label}-{str(hash(config))}"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "datashare-python"
3
- version = "0.10.5"
3
+ version = "0.10.7"
4
4
  description = "Manage Python tasks and local resources in Datashare"
5
5
  authors = [
6
6
  { name = "Clément Doumouro", email = "cdoumouro@icij.org" },