tilebox-workflows 0.47.0__py3-none-any.whl → 0.48.0__py3-none-any.whl

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.
@@ -1,13 +1,16 @@
1
+ import contextlib
1
2
  import warnings
2
3
  from abc import ABC, abstractmethod
3
4
  from collections.abc import Iterator
4
5
  from io import BytesIO
5
6
  from pathlib import Path
7
+ from pathlib import PurePosixPath as ObjectPath
6
8
 
7
9
  import boto3
8
10
  from botocore.exceptions import ClientError
9
11
  from google.cloud.exceptions import NotFound
10
12
  from google.cloud.storage import Blob, Bucket
13
+ from obstore.store import ObjectStore
11
14
 
12
15
 
13
16
  class JobCache(ABC):
@@ -62,6 +65,53 @@ class NoCache(JobCache):
62
65
  return self
63
66
 
64
67
 
68
+ class ObstoreCache(JobCache):
69
+ def __init__(self, store: ObjectStore, prefix: str | ObjectPath = ObjectPath(".")) -> None:
70
+ """A cache implementation backed by an obstore ObjectStore.
71
+
72
+ This cache implementation is the recommended way of working with the cache, as it provides a unified interface
73
+ for working with different object stores, while also providing a way to transparently work with local files
74
+ as well.
75
+
76
+ Args:
77
+ store: The object store to use for the cache.
78
+ prefix: A path prefix to append to all objects stored in the cache. Defaults to no prefix.
79
+ """
80
+ self.store = store
81
+ self.prefix = ObjectPath(prefix)
82
+
83
+ def __contains__(self, key: str) -> bool:
84
+ with contextlib.suppress(OSError):
85
+ self.store.get(str(self.prefix / key))
86
+ return True # if get is successful, we know the key is in the cache
87
+
88
+ return False
89
+
90
+ def __setitem__(self, key: str, value: bytes) -> None:
91
+ self.store.put(str(self.prefix / key), value)
92
+
93
+ def __delitem__(self, key: str) -> None:
94
+ try:
95
+ self.store.delete(str(self.prefix / key))
96
+ except OSError:
97
+ raise KeyError(f"{key} is not cached!") from None
98
+
99
+ def __getitem__(self, key: str) -> bytes:
100
+ try:
101
+ entry = self.store.get(str(self.prefix / key))
102
+ return bytes(entry.bytes())
103
+ except OSError:
104
+ raise KeyError(f"{key} is not cached!") from None
105
+
106
+ def __iter__(self) -> Iterator[str]:
107
+ for obj in self.store.list_with_delimiter(str(self.prefix))["objects"]:
108
+ path: str = obj["path"]
109
+ yield path.removeprefix(str(self.prefix) + "/")
110
+
111
+ def group(self, key: str) -> "ObstoreCache":
112
+ return ObstoreCache(self.store, prefix=str(self.prefix / key))
113
+
114
+
65
115
  class InMemoryCache(JobCache):
66
116
  def __init__(self) -> None:
67
117
  """A simple in-memory cache implementation.
@@ -153,7 +203,7 @@ class LocalFileSystemCache(JobCache):
153
203
  Args:
154
204
  root: File system path where the cache will be stored. Defaults to "cache" in the current working directory.
155
205
  """
156
- self.root = root if isinstance(root, Path) else Path(root)
206
+ self.root = Path(root)
157
207
 
158
208
  def __contains__(self, key: str) -> bool:
159
209
  return (self.root / key).exists()
@@ -184,7 +234,7 @@ class LocalFileSystemCache(JobCache):
184
234
 
185
235
 
186
236
  class GoogleStorageCache(JobCache):
187
- def __init__(self, bucket: Bucket, prefix: str = "jobs") -> None:
237
+ def __init__(self, bucket: Bucket, prefix: str | ObjectPath = "jobs") -> None:
188
238
  """A cache implementation that stores data in Google Cloud Storage.
189
239
 
190
240
  Args:
@@ -192,7 +242,9 @@ class GoogleStorageCache(JobCache):
192
242
  prefix: A path prefix to append to all objects stored in the cache. Defaults to "jobs".
193
243
  """
194
244
  self.bucket = bucket
195
- self.prefix = Path(prefix) # we still use pathlib here, because it's easier to work with when joining paths
245
+ self.prefix = ObjectPath(
246
+ prefix
247
+ ) # we still use pathlib here, because it's easier to work with when joining paths
196
248
 
197
249
  def _blob(self, key: str) -> Blob:
198
250
  return self.bucket.blob(str(self.prefix / key))
@@ -228,14 +280,14 @@ class GoogleStorageCache(JobCache):
228
280
 
229
281
  # make the names relative to the cache prefix (but including the key in the name)
230
282
  for blob in blobs:
231
- yield str(Path(blob.name).relative_to(self.prefix))
283
+ yield str(ObjectPath(blob.name).relative_to(self.prefix))
232
284
 
233
285
  def group(self, key: str) -> "GoogleStorageCache":
234
286
  return GoogleStorageCache(self.bucket, prefix=str(self.prefix / key))
235
287
 
236
288
 
237
289
  class AmazonS3Cache(JobCache):
238
- def __init__(self, bucket: str, prefix: str = "jobs") -> None:
290
+ def __init__(self, bucket: str, prefix: str | ObjectPath = "jobs") -> None:
239
291
  """A cache implementation that stores data in Amazon S3.
240
292
 
241
293
  Args:
@@ -243,7 +295,7 @@ class AmazonS3Cache(JobCache):
243
295
  prefix: A path prefix to append to all objects stored in the cache. Defaults to "jobs".
244
296
  """
245
297
  self.bucket = bucket
246
- self.prefix = Path(prefix)
298
+ self.prefix = ObjectPath(prefix)
247
299
  with warnings.catch_warnings():
248
300
  # https://github.com/boto/boto3/issues/3889
249
301
  warnings.filterwarnings("ignore", category=DeprecationWarning, message=".*datetime.utcnow.*")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tilebox-workflows
3
- Version: 0.47.0
3
+ Version: 0.48.0
4
4
  Summary: Workflow client and task runner for Tilebox
5
5
  Project-URL: Homepage, https://tilebox.com
6
6
  Project-URL: Documentation, https://docs.tilebox.com/workflows/introduction
@@ -1,5 +1,5 @@
1
1
  tilebox/workflows/__init__.py,sha256=D6NXvTUjWv0YWN5tYD09p1cFkGs8nGrZ9V7agtjvp8c,636
2
- tilebox/workflows/cache.py,sha256=GK0lOIuAEhHya4jCe5PNc1T72xuCrs62AhD6zIoNPQk,11253
2
+ tilebox/workflows/cache.py,sha256=ZgVUm2O4Qr1nPXvUVx82YGtiDg4IjUbHpnm5KTfrKvo,13233
3
3
  tilebox/workflows/client.py,sha256=L8MZXZ-yDutu91sD1am24yfANLCaasRXO8ITJHg5UgE,5680
4
4
  tilebox/workflows/data.py,sha256=8DBWZJonsLKCMMF02jpD0xfEENbrSUqANFvBYzMb1eY,29559
5
5
  tilebox/workflows/interceptors.py,sha256=yfo6pCxUdhb0EC1J506k1ge4S_BAl83TAFYxCcxu8sU,1799
@@ -42,6 +42,6 @@ tilebox/workflows/workflows/v1/task_pb2_grpc.py,sha256=nkQjtsDiql1ofbSxhDXbPkySd
42
42
  tilebox/workflows/workflows/v1/workflows_pb2.py,sha256=rGwIydUP4osLD_fG3QmHaqs42mKmRoCqtwihJTLJ314,3990
43
43
  tilebox/workflows/workflows/v1/workflows_pb2.pyi,sha256=qiDQUM2Vlu_izQvaSDlK5GqKYGsNJgtm0bo9zW-qNjU,1633
44
44
  tilebox/workflows/workflows/v1/workflows_pb2_grpc.py,sha256=36Vp_TIxtS-MRBZHECf84fHFbnrm3-UizCsMOlz7qfo,8529
45
- tilebox_workflows-0.47.0.dist-info/METADATA,sha256=SccnKvYADXLBSRIokW3HK4nbqdz4l7IbRkAhXlziZns,3948
46
- tilebox_workflows-0.47.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
47
- tilebox_workflows-0.47.0.dist-info/RECORD,,
45
+ tilebox_workflows-0.48.0.dist-info/METADATA,sha256=g_7EhTNi4DXYUYheJjhks2sGQU4hwdFcUCFhhwxu6fU,3948
46
+ tilebox_workflows-0.48.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
47
+ tilebox_workflows-0.48.0.dist-info/RECORD,,