chuk-artifacts 0.4__py3-none-any.whl → 0.4.1__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.
@@ -12,6 +12,7 @@ from dotenv import load_dotenv
12
12
 
13
13
  # Core classes
14
14
  from .store import ArtifactStore
15
+ from .models import ArtifactEnvelope
15
16
 
16
17
  # Exception classes
17
18
  from .exceptions import (
@@ -42,6 +43,9 @@ __all__ = [
42
43
  # Main class
43
44
  "ArtifactStore",
44
45
 
46
+ # Models
47
+ "ArtifactEnvelope",
48
+
45
49
  # Exceptions
46
50
  "ArtifactStoreError",
47
51
  "ArtifactNotFoundError",
@@ -146,4 +150,4 @@ def configure_logging(level: str = "INFO"):
146
150
  "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
147
151
  )
148
152
  handler.setFormatter(formatter)
149
- logger.addHandler(handler)
153
+ logger.addHandler(handler)
chuk_artifacts/core.py CHANGED
@@ -19,7 +19,7 @@ from typing import Any, Dict, Optional, TYPE_CHECKING
19
19
  if TYPE_CHECKING:
20
20
  from .store import ArtifactStore
21
21
 
22
- from .exceptions import ArtifactStoreError, ProviderError, SessionError
22
+ from .exceptions import ArtifactStoreError, ProviderError, SessionError, ArtifactNotFoundError
23
23
 
24
24
  logger = logging.getLogger(__name__)
25
25
 
@@ -102,44 +102,55 @@ class CoreStorageOperations:
102
102
  raise ProviderError(f"Storage failed: {e}") from e
103
103
 
104
104
  async def update_file(
105
- self,
106
- artifact_id: str,
107
- new_data: bytes,
108
- *,
109
- mime: Optional[str] = None,
110
- summary: Optional[str] = None,
111
- meta: Optional[Dict[str, Any]] = None,
112
- filename: Optional[str] = None,
113
- ttl: Optional[int] = None,
114
- ) -> None:
115
- """
116
- Update the contents of an existing artifact.
105
+ self,
106
+ artifact_id: str,
107
+ new_data: Optional[bytes] = None,
108
+ *,
109
+ mime: Optional[str] = None,
110
+ summary: Optional[str] = None,
111
+ meta: Optional[Dict[str, Any]] = None,
112
+ filename: Optional[str] = None,
113
+ ttl: Optional[int] = None,
114
+ ) -> bool:
115
+ """
116
+ Update an artifact's content, metadata, filename, summary, or mime type.
117
+
118
+ Parameters
119
+ ----------
120
+ artifact_id : str
121
+ ID of the artifact to update
122
+ new_data : bytes, optional
123
+ New data to overwrite the existing artifact
124
+ mime : str, optional
125
+ New MIME type
126
+ summary : str, optional
127
+ New summary
128
+ meta : dict, optional
129
+ Updated metadata
130
+ filename : str, optional
131
+ New filename
132
+ ttl : int, optional
133
+ New TTL
134
+
135
+ Returns
136
+ -------
137
+ bool
138
+ True if update was successful
139
+ """
140
+ if self.artifact_store._closed:
141
+ raise ArtifactStoreError("Store is closed")
117
142
 
118
- Parameters
119
- ----------
120
- artifact_id : str
121
- ID of the artifact to update.
122
- new_data : bytes
123
- New data to overwrite the existing artifact.
124
- mime : Optional[str]
125
- Optional new MIME type.
126
- summary : Optional[str]
127
- Optional new summary.
128
- meta : Optional[Dict[str, Any]]
129
- Optional updated metadata.
130
- filename : Optional[str]
131
- Optional new filename.
132
- ttl : Optional[int]
133
- Optional TTL to reset (if provided).
134
- """
135
- if self.artifact_store._closed:
136
- raise ArtifactStoreError("Store is closed")
143
+ if not any([new_data is not None, meta is not None, filename is not None,
144
+ summary is not None, mime is not None, ttl is not None]):
145
+ raise ValueError("At least one update parameter must be provided.")
137
146
 
138
- try:
139
- record = await self._get_record(artifact_id)
140
- key = record["key"]
141
- session_id = record["session_id"]
147
+ try:
148
+ record = await self._get_record(artifact_id)
149
+ key = record["key"]
150
+ session_id = record["session_id"]
142
151
 
152
+ # Update data if provided
153
+ if new_data is not None:
143
154
  # Overwrite in object storage
144
155
  await self._store_with_retry(
145
156
  new_data,
@@ -148,31 +159,37 @@ class CoreStorageOperations:
148
159
  filename or record.get("filename"),
149
160
  session_id,
150
161
  )
162
+
163
+ # Update size and hash in metadata
164
+ record["bytes"] = len(new_data)
165
+ record["sha256"] = hashlib.sha256(new_data).hexdigest()
151
166
 
152
- # Update metadata
153
- record.update({
154
- "mime": mime or record["mime"],
155
- "summary": summary or record["summary"],
156
- "meta": meta or record["meta"],
157
- "filename": filename or record.get("filename"),
158
- "bytes": len(new_data),
159
- "sha256": hashlib.sha256(new_data).hexdigest(),
160
- "updated_at": datetime.utcnow().isoformat() + "Z",
161
- "ttl": ttl or record["ttl"],
162
- })
167
+ # Update metadata fields
168
+ if mime is not None:
169
+ record["mime"] = mime
170
+ if summary is not None:
171
+ record["summary"] = summary
172
+ if filename is not None:
173
+ record["filename"] = filename
174
+ if meta is not None:
175
+ record["meta"] = meta
176
+ if ttl is not None:
177
+ record["ttl"] = ttl
163
178
 
164
- if ttl is not None:
165
- record["ttl"] = ttl
179
+ # Add update timestamp
180
+ record["updated_at"] = datetime.utcnow().isoformat() + "Z"
166
181
 
167
- session_ctx_mgr = self.artifact_store._session_factory()
168
- async with session_ctx_mgr as session:
169
- await session.setex(artifact_id, record["ttl"], json.dumps(record))
182
+ # Store updated metadata
183
+ session_ctx_mgr = self.artifact_store._session_factory()
184
+ async with session_ctx_mgr as session:
185
+ await session.setex(artifact_id, record["ttl"], json.dumps(record))
170
186
 
171
- logger.info("Artifact updated successfully", extra={"artifact_id": artifact_id})
187
+ logger.info("Artifact updated successfully", extra={"artifact_id": artifact_id})
188
+ return True
172
189
 
173
- except Exception as e:
174
- logger.error(f"Update failed for artifact {artifact_id}: {e}")
175
- raise ProviderError(f"Artifact update failed: {e}") from e
190
+ except Exception as e:
191
+ logger.error(f"Update failed for artifact {artifact_id}: {e}")
192
+ raise ProviderError(f"Artifact update failed: {e}") from e
176
193
 
177
194
  async def retrieve(self, artifact_id: str) -> bytes:
178
195
  """Retrieve artifact data."""
@@ -246,7 +263,7 @@ class CoreStorageOperations:
246
263
  raise last_exception
247
264
 
248
265
  async def _get_record(self, artifact_id: str) -> Dict[str, Any]:
249
- """Get artifact metadata."""
266
+ """Get artifact metadata record from session provider."""
250
267
  try:
251
268
  session_ctx_mgr = self.artifact_store._session_factory()
252
269
  async with session_ctx_mgr as session:
@@ -255,7 +272,7 @@ class CoreStorageOperations:
255
272
  raise SessionError(f"Session error for {artifact_id}: {e}") from e
256
273
 
257
274
  if raw is None:
258
- raise ProviderError(f"Artifact {artifact_id} not found")
275
+ raise ArtifactNotFoundError(f"Artifact {artifact_id} not found")
259
276
 
260
277
  try:
261
278
  return json.loads(raw)
chuk_artifacts/store.py CHANGED
@@ -172,21 +172,24 @@ class ArtifactStore:
172
172
  filename: Optional[str] = None,
173
173
  summary: Optional[str] = None,
174
174
  mime: Optional[str] = None,
175
+ ttl: Optional[int] = None,
175
176
  ) -> bool:
176
177
  """
177
178
  Update an artifact's content, metadata, filename, summary, or mime type.
178
179
  All parameters are optional. At least one must be provided.
179
180
  """
180
- if not any([data, meta, filename, summary, mime]):
181
+ if not any([data is not None, meta is not None, filename is not None,
182
+ summary is not None, mime is not None, ttl is not None]):
181
183
  raise ValueError("At least one update parameter must be provided.")
182
184
 
183
185
  return await self._core.update_file(
184
186
  artifact_id=artifact_id,
185
187
  new_data=data,
188
+ mime=mime,
189
+ summary=summary,
186
190
  meta=meta,
187
191
  filename=filename,
188
- summary=summary,
189
- mime=mime,
192
+ ttl=ttl,
190
193
  )
191
194
 
192
195
  async def retrieve(self, artifact_id: str) -> bytes:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chuk-artifacts
3
- Version: 0.4
3
+ Version: 0.4.1
4
4
  Summary: Chuk Artifacts provides a production-ready, modular artifact storage system that works seamlessly across multiple storage backends (memory, filesystem, AWS S3, IBM Cloud Object Storage) with Redis or memory-based metadata caching and strict session-based security.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,23 +1,23 @@
1
- chuk_artifacts/__init__.py,sha256=-4S9FWKVcQSa2ZD3GVbmbpGZPcl0cTQN_TFZLSqV7lQ,3605
1
+ chuk_artifacts/__init__.py,sha256=9HIUqLd14M4CGcQvTsa4XEd8SBCjYRIqoKfTh_GEG4w,3683
2
2
  chuk_artifacts/admin.py,sha256=lUgmKBPxJh-0FYrGWjkACXQOl8lbVEDPJaeGVsWZmC4,6071
3
3
  chuk_artifacts/base.py,sha256=BtuVnC9M8QI1znyTdBxjZ6knIKP_k0yUfLfh7inGJUc,2559
4
4
  chuk_artifacts/batch.py,sha256=x8ARrWJ24I9fAXXodzvh31uMxYrvwZCGGJhUCM4vMJ4,5099
5
5
  chuk_artifacts/config.py,sha256=MaUzHzKPoBUyERviEpv8JVvPybMzSksgLyj0b7AO3Sc,7664
6
- chuk_artifacts/core.py,sha256=u1w0A-DZUoTvnnTrtYNMNxqLdKqvRHJZBaXHsjIHQ8E,9465
6
+ chuk_artifacts/core.py,sha256=K23Z9WtbHXCaacWV5mVRPYYCF13qfB0cnG-x3wxXyDs,9893
7
7
  chuk_artifacts/exceptions.py,sha256=f-s7Mg7c8vMXsbgqO2B6lMHdXcJQNvsESAY4GhJaV4g,814
8
8
  chuk_artifacts/grid.py,sha256=PqDQGPSyxzDkQp7X-JKJvUmVmrmjdVv1wbzQ6Ysj6gg,4328
9
9
  chuk_artifacts/metadata.py,sha256=KSWZxaIxpOP_SdxUVXLttQ65aXJGx9ylqkW4n3997fI,7845
10
10
  chuk_artifacts/models.py,sha256=XlI-PATNO67vlGVEOnphCx78mfmofcBRAiVU79Ohs9o,881
11
11
  chuk_artifacts/presigned.py,sha256=-GE8r0CfUZuPNA_jnSGTfX7kuws6kYCPe7C4y6FItdo,11491
12
12
  chuk_artifacts/provider_factory.py,sha256=T0IXx1C8gygJzp417oB44_DxEaZoZR7jcdwQy8FghRE,3398
13
- chuk_artifacts/store.py,sha256=86PmXrjg4so-Dy492HPLTasGA5wT8T2AyGOUa21o2UQ,27380
13
+ chuk_artifacts/store.py,sha256=IAXRQbtvR5jw4GVZKOT_P9_g1B5Kr912NLlESQXUUQI,27533
14
14
  chuk_artifacts/providers/__init__.py,sha256=3lN1lAy1ETT1mQslJo1f22PPR1W4CyxmsqJBclzH4NE,317
15
15
  chuk_artifacts/providers/filesystem.py,sha256=fj8p2SVq8V8GQCnqId77Fkwn_PgOquIj6UEaGTiqUe0,15949
16
16
  chuk_artifacts/providers/ibm_cos.py,sha256=Kf4ZqxP7aHeYKm6gM03aponMzx-lIyWn2_TL8_X4A_U,3677
17
17
  chuk_artifacts/providers/ibm_cos_iam.py,sha256=7mDs0VvVh1OOUmSc-fgghbTa_euongazwZ0QG3wjdJo,5068
18
18
  chuk_artifacts/providers/memory.py,sha256=QpJFxJuZGf548ulctmNGtUpHlRzyx1_PW5F1XNVIKrE,12002
19
19
  chuk_artifacts/providers/s3.py,sha256=QSSiYjNENQfwxJ2-Yw-CJrO8lNZcIrsfdn2Vo_DD-b4,2931
20
- chuk_artifacts-0.4.dist-info/METADATA,sha256=BiPcDJkHk8XcsY-mUVUc8G1ywbmfiT2rWmqjHYcGjdQ,18706
21
- chuk_artifacts-0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
- chuk_artifacts-0.4.dist-info/top_level.txt,sha256=1_PVMtWXR0A-ZmeH6apF9mPaMtU0i23JE6wmN4GBRDI,15
23
- chuk_artifacts-0.4.dist-info/RECORD,,
20
+ chuk_artifacts-0.4.1.dist-info/METADATA,sha256=sDw8-dWWFBngeUNzXYD3s7t7D-5_Pa5szsh5clfucPA,18708
21
+ chuk_artifacts-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
+ chuk_artifacts-0.4.1.dist-info/top_level.txt,sha256=1_PVMtWXR0A-ZmeH6apF9mPaMtU0i23JE6wmN4GBRDI,15
23
+ chuk_artifacts-0.4.1.dist-info/RECORD,,