datashare-python 0.12.7__tar.gz → 0.12.9__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.12.7 → datashare_python-0.12.9}/PKG-INFO +1 -1
  2. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/config.py +4 -1
  3. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/utils.py +38 -12
  4. datashare_python-0.12.9/datashare_python/worker-template.tar.gz +0 -0
  5. {datashare_python-0.12.7 → datashare_python-0.12.9}/pyproject.toml +1 -1
  6. datashare_python-0.12.7/datashare_python/worker-template.tar.gz +0 -0
  7. {datashare_python-0.12.7 → datashare_python-0.12.9}/.gitignore +0 -0
  8. {datashare_python-0.12.7 → datashare_python-0.12.9}/README.md +0 -0
  9. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/.gitignore +0 -0
  10. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/__init__.py +0 -0
  11. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/__main__.py +0 -0
  12. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/cli/__init__.py +0 -0
  13. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/cli/project.py +0 -0
  14. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/cli/task.py +0 -0
  15. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/cli/utils.py +0 -0
  16. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/cli/worker.py +0 -0
  17. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/conftest.py +0 -0
  18. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/constants.py +0 -0
  19. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/dependencies.py +0 -0
  20. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/discovery.py +0 -0
  21. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/exceptions.py +0 -0
  22. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/interceptors.py +0 -0
  23. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/logging_.py +0 -0
  24. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/mimetypes_.py +0 -0
  25. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/objects.py +0 -0
  26. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/task_client.py +0 -0
  27. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/template.py +0 -0
  28. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/types_.py +0 -0
  29. {datashare_python-0.12.7 → datashare_python-0.12.9}/datashare_python/worker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: datashare-python
3
- Version: 0.12.7
3
+ Version: 0.12.9
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/
@@ -114,6 +114,7 @@ class LoggingConfig(BaseModel):
114
114
 
115
115
  class ResourceCacheConfig(BaseModel):
116
116
  size: int = 1
117
+ refresh_interval: int | None = None
117
118
  exit_context_managers: bool = True
118
119
 
119
120
  def to_resource_cache(self) -> "SharedResources":
@@ -123,7 +124,9 @@ class ResourceCacheConfig(BaseModel):
123
124
  if self.exit_context_managers:
124
125
  eviction_callback = close_cm_callback
125
126
  return SharedResources(
126
- cache_size=self.size, eviction_callback=eviction_callback
127
+ cache_size=self.size,
128
+ eviction_callback=eviction_callback,
129
+ refresh_interval=self.refresh_interval,
127
130
  )
128
131
 
129
132
 
@@ -822,9 +822,11 @@ class SharedResources:
822
822
  self,
823
823
  cache_size: int = 1,
824
824
  eviction_callback: Callable[[Any, Any], None] | None = None,
825
+ refresh_interval: int | None = None,
825
826
  ) -> None:
826
827
  self._eviction_callback = eviction_callback
827
828
  self._cache = LRU(cache_size, self._on_evict)
829
+ self._refresh_interval = refresh_interval
828
830
  self._sentinel = object()
829
831
  # Leased resources are tracked by id, evicting a leased resource defers the
830
832
  # eviction callback until its last lease is released
@@ -854,6 +856,14 @@ class SharedResources:
854
856
  """
855
857
  value = self._get_and_acquire(key)
856
858
  if value is self._sentinel:
859
+ # The factory can be long to complete (that's one of the reason we want to
860
+ # cache its results). Because we don't lock the factory call, together with
861
+ # the cache update, in case of concurrent access, quicker factories will
862
+ # complete first and will stay longer in the cache. This is fine, the
863
+ # alternative is to lock factory + cache update to avoid concurrent access
864
+ # but this will mean waiting for the first factory call to complete, this
865
+ # can potentially imply longer waits than no getting the value from the
866
+ # cache
857
867
  value = default_factory()
858
868
  self._cache_and_acquire(key, value)
859
869
  try:
@@ -873,6 +883,14 @@ class SharedResources:
873
883
  """
874
884
  value = self._get_and_acquire(key)
875
885
  if value is self._sentinel:
886
+ # The factory can be long to complete (that's one of the reason we want to
887
+ # cache its results). Because we don't lock the factory call, together with
888
+ # the cache update, in case of concurrent access, quicker factories will
889
+ # complete first and will stay longer in the cache. This is fine, the
890
+ # alternative is to lock factory + cache update to avoid concurrent access
891
+ # but this will mean waiting for the first factory call to complete, this
892
+ # can potentially imply longer waits than no getting the value from the
893
+ # cache
876
894
  value = await default_factory()
877
895
  self._cache_and_acquire(key, value)
878
896
  try:
@@ -884,28 +902,33 @@ class SharedResources:
884
902
  with self._lock:
885
903
  value = self._cache.get(key, self._sentinel)
886
904
  if value is not self._sentinel:
887
- self._acquire(value)
905
+ # If refresh needs to happen, we set the value to the sentinel.
906
+ # The old value will be release with the last user call to _release.
907
+ # Returning the sentinel will trigger the call to the factory
908
+ refresh = (
909
+ self._refresh_interval is not None
910
+ and self._n_leases.get(self._vkey(value), 0)
911
+ >= self._refresh_interval
912
+ )
913
+ if refresh:
914
+ self._pending_evictions[self._vkey(value)] = (key, value)
915
+ value = self._sentinel
916
+ else:
917
+ self._acquire(value)
888
918
  return value
889
919
 
890
920
  def _cache_and_acquire(self, key: str, value: Any) -> None:
891
- # The factory can be long to complete (that's one of the reason we want to
892
- # cache its results). Because we don't lock the factory call, together with
893
- # the cache update, in case of concurrent access, quicker factories will
894
- # complete first and will stay longer in the cache. This is fine, the
895
- # alternative is to lock factory + cache update to avoid concurrent access but
896
- # this will mean waiting for the first factory call to complete, this can
897
- # potentially imply longer waits than no getting the value from the cache
898
921
  with self._lock:
899
922
  self._acquire(value)
900
923
  # Can evict other resources, must be called without holding the lock
901
924
  self._cache[key] = value
902
925
 
903
926
  def _acquire(self, value: Any) -> None:
904
- value_id = id(value)
927
+ value_id = self._vkey(value)
905
928
  self._n_leases[value_id] = self._n_leases.get(value_id, 0) + 1
906
929
 
907
930
  def _release(self, value: Any) -> None:
908
- value_id = id(value)
931
+ value_id = self._vkey(value)
909
932
  with self._lock:
910
933
  self._n_leases[value_id] -= 1
911
934
  if self._n_leases[value_id]:
@@ -917,8 +940,8 @@ class SharedResources:
917
940
 
918
941
  def _on_evict(self, key: Any, value: Any) -> None:
919
942
  with self._lock:
920
- if id(value) in self._n_leases:
921
- self._pending_evictions[id(value)] = (key, value)
943
+ if self._vkey(value) in self._n_leases:
944
+ self._pending_evictions[self._vkey(value)] = (key, value)
922
945
  return
923
946
  self._evict(key, value)
924
947
 
@@ -926,6 +949,9 @@ class SharedResources:
926
949
  if self._eviction_callback is not None:
927
950
  self._eviction_callback(key, value)
928
951
 
952
+ def _vkey(self, value: Any) -> int:
953
+ return id(value)
954
+
929
955
 
930
956
  def close_cm_callback(key: str, value: Any) -> None: # noqa: ARG001
931
957
  if hasattr(value, "__exit__"):
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "datashare-python"
3
- version = "0.12.7"
3
+ version = "0.12.9"
4
4
  description = "Manage Python tasks and local resources in Datashare"
5
5
  authors = [
6
6
  { name = "Clément Doumouro", email = "cdoumouro@icij.org" },