kiarina-lib-google-cloud-storage 1.6.2__py3-none-any.whl → 1.6.3__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.
- kiarina/lib/google/cloud_storage/_get_blob.py +16 -4
- kiarina/lib/google/cloud_storage/_get_bucket.py +1 -5
- kiarina/lib/google/cloud_storage/settings.py +3 -3
- {kiarina_lib_google_cloud_storage-1.6.2.dist-info → kiarina_lib_google_cloud_storage-1.6.3.dist-info}/METADATA +26 -25
- kiarina_lib_google_cloud_storage-1.6.3.dist-info/RECORD +9 -0
- kiarina_lib_google_cloud_storage-1.6.2.dist-info/RECORD +0 -9
- {kiarina_lib_google_cloud_storage-1.6.2.dist-info → kiarina_lib_google_cloud_storage-1.6.3.dist-info}/WHEEL +0 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
import re
|
1
2
|
from typing import Any
|
2
3
|
|
3
4
|
from google.cloud import storage # type: ignore[import-untyped]
|
@@ -38,10 +39,10 @@ def get_blob(
|
|
38
39
|
blob = get_blob(placeholders={"user_id": "123", "basename": "profile.json"})
|
39
40
|
# With pattern "users/{user_id}/{basename}" -> "users/123/profile.json"
|
40
41
|
|
41
|
-
# Using
|
42
|
-
blob = get_blob() # Uses settings.blob_name_pattern
|
42
|
+
# Using fixed pattern from settings (no placeholders)
|
43
|
+
blob = get_blob() # Uses settings.blob_name_pattern if it has no placeholders
|
43
44
|
"""
|
44
|
-
settings = settings_manager.
|
45
|
+
settings = settings_manager.get_settings(config_key)
|
45
46
|
|
46
47
|
# Priority 1: Explicit blob_name
|
47
48
|
if blob_name is not None:
|
@@ -65,7 +66,6 @@ def get_blob(
|
|
65
66
|
|
66
67
|
# Priority 3: Default pattern from settings
|
67
68
|
elif settings.blob_name_pattern is not None:
|
68
|
-
# Pattern without placeholders (fixed name)
|
69
69
|
final_blob_name = settings.blob_name_pattern
|
70
70
|
|
71
71
|
else:
|
@@ -74,5 +74,17 @@ def get_blob(
|
|
74
74
|
"and blob_name_pattern is not set in settings"
|
75
75
|
)
|
76
76
|
|
77
|
+
# Safety check: Ensure no unresolved placeholders remain
|
78
|
+
if _has_placeholders(final_blob_name):
|
79
|
+
raise ValueError(
|
80
|
+
f"Unresolved placeholders found in blob name: {final_blob_name}. "
|
81
|
+
f"Please provide placeholders argument to resolve them."
|
82
|
+
)
|
83
|
+
|
77
84
|
bucket = get_bucket(config_key, auth_config_key=auth_config_key, **kwargs)
|
78
85
|
return bucket.blob(final_blob_name)
|
86
|
+
|
87
|
+
|
88
|
+
def _has_placeholders(pattern: str) -> bool:
|
89
|
+
"""Check if a pattern contains placeholders like {key}."""
|
90
|
+
return bool(re.search(r"\{[^}]+\}", pattern))
|
@@ -12,10 +12,6 @@ def get_bucket(
|
|
12
12
|
auth_config_key: str | None = None,
|
13
13
|
**kwargs: Any,
|
14
14
|
) -> storage.Bucket:
|
15
|
-
settings = settings_manager.
|
16
|
-
|
17
|
-
if settings.bucket_name is None:
|
18
|
-
raise ValueError("bucket_name is not set in the settings")
|
19
|
-
|
15
|
+
settings = settings_manager.get_settings(config_key)
|
20
16
|
client = get_storage_client(auth_config_key, **kwargs)
|
21
17
|
return client.bucket(settings.bucket_name)
|
@@ -3,16 +3,16 @@ from pydantic_settings_manager import SettingsManager
|
|
3
3
|
|
4
4
|
|
5
5
|
class GoogleCloudStorageSettings(BaseSettings):
|
6
|
-
bucket_name: str
|
6
|
+
bucket_name: str
|
7
7
|
|
8
8
|
blob_name_pattern: str | None = None
|
9
9
|
"""
|
10
10
|
Blob name pattern with placeholders.
|
11
|
-
|
11
|
+
|
12
12
|
Examples:
|
13
13
|
- "data.json" (fixed name)
|
14
14
|
- "files/{basename}" (single placeholder)
|
15
|
-
- "
|
15
|
+
- "my-service/{tenant_id}/users/{user_id}/files/{basename}" (multiple placeholders)
|
16
16
|
"""
|
17
17
|
|
18
18
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: kiarina-lib-google-cloud-storage
|
3
|
-
Version: 1.6.
|
3
|
+
Version: 1.6.3
|
4
4
|
Summary: Google Cloud Storage client library for kiarina namespace
|
5
5
|
Project-URL: Homepage, https://github.com/kiarina/kiarina-python
|
6
6
|
Project-URL: Repository, https://github.com/kiarina/kiarina-python
|
@@ -22,7 +22,7 @@ Classifier: Typing :: Typed
|
|
22
22
|
Requires-Python: >=3.12
|
23
23
|
Requires-Dist: google-cloud-storage>=2.19.0
|
24
24
|
Requires-Dist: kiarina-lib-google-auth>=1.4.0
|
25
|
-
Requires-Dist: pydantic-settings-manager>=2.
|
25
|
+
Requires-Dist: pydantic-settings-manager>=2.3.0
|
26
26
|
Requires-Dist: pydantic-settings>=2.10.1
|
27
27
|
Description-Content-Type: text/markdown
|
28
28
|
|
@@ -115,18 +115,18 @@ New requirement: Add agent-level isolation for multi-tenancy.
|
|
115
115
|
|
116
116
|
**Updated Security Rules:**
|
117
117
|
```javascript
|
118
|
-
match /
|
119
|
-
allow read, write: if request.auth.uid == user_id
|
120
|
-
&& request.auth.token.
|
118
|
+
match /my-service/{tenant_id}/users/{user_id}/files/{basename} {
|
119
|
+
allow read, write: if request.auth.uid == user_id
|
120
|
+
&& request.auth.token.tenant_id == tenant_id;
|
121
121
|
}
|
122
122
|
```
|
123
123
|
|
124
124
|
**Problem**: You must now update **every place** in your application code that constructs these paths:
|
125
125
|
```python
|
126
126
|
# Must change all of these
|
127
|
-
blob_name = f"
|
128
|
-
blob_name = f"
|
129
|
-
blob_name = f"
|
127
|
+
blob_name = f"my-service/{tenant_id}/users/{user_id}/files/{file_name}" # Changed!
|
128
|
+
blob_name = f"my-service/{tenant_id}/users/{user_id}/thumbnails/{file_name}" # Changed!
|
129
|
+
blob_name = f"my-service/{tenant_id}/users/{user_id}/exports/{file_name}" # Changed!
|
130
130
|
# ... and many more
|
131
131
|
```
|
132
132
|
|
@@ -138,14 +138,14 @@ blob_name = f"web/{user_id}/{agent_id}/exports/{file_name}" # Changed!
|
|
138
138
|
google_cloud_storage:
|
139
139
|
default:
|
140
140
|
bucket_name: "my-app-data"
|
141
|
-
blob_name_pattern: "
|
141
|
+
blob_name_pattern: "my-service/{tenant_id}/users/{user_id}/files/{basename}"
|
142
142
|
```
|
143
143
|
|
144
144
|
**GCS Security Rules (Infrastructure Concern):**
|
145
145
|
```javascript
|
146
|
-
match /
|
147
|
-
allow read, write: if request.auth.uid == user_id
|
148
|
-
&& request.auth.token.
|
146
|
+
match /my-service/{tenant_id}/users/{user_id}/files/{basename} {
|
147
|
+
allow read, write: if request.auth.uid == user_id
|
148
|
+
&& request.auth.token.tenant_id == tenant_id;
|
149
149
|
}
|
150
150
|
```
|
151
151
|
|
@@ -368,14 +368,14 @@ def save_document(tenant_id: str, doc_id: str, content: bytes):
|
|
368
368
|
def list_documents(tenant_id: str) -> list[str]:
|
369
369
|
"""List documents for any tenant"""
|
370
370
|
from kiarina.lib.google.cloud_storage import get_bucket
|
371
|
-
|
371
|
+
|
372
372
|
config_key = f"tenant_{tenant_id}"
|
373
373
|
bucket = get_bucket(config_key=config_key, auth_config_key=config_key)
|
374
|
-
|
374
|
+
|
375
375
|
# Get prefix from settings
|
376
|
-
settings = settings_manager.
|
376
|
+
settings = settings_manager.get_settings(config_key)
|
377
377
|
prefix = f"{settings.blob_name_prefix}/documents/" if settings.blob_name_prefix else "documents/"
|
378
|
-
|
378
|
+
|
379
379
|
blobs = bucket.list_blobs(prefix=prefix)
|
380
380
|
return [blob.name for blob in blobs]
|
381
381
|
```
|
@@ -409,10 +409,10 @@ def mock_storage_config():
|
|
409
409
|
def test_save_user_profile(mock_storage_config):
|
410
410
|
"""Test user profile saving"""
|
411
411
|
from myapp.services import save_user_profile
|
412
|
-
|
412
|
+
|
413
413
|
# Application code uses test configuration automatically
|
414
414
|
save_user_profile("user123", {"name": "Alice"})
|
415
|
-
|
415
|
+
|
416
416
|
# Verify using the same configuration
|
417
417
|
from kiarina.lib.google.cloud_storage import get_blob
|
418
418
|
blob = get_blob(blob_name="users/user123/profile.json")
|
@@ -428,20 +428,20 @@ from kiarina.lib.google.cloud_storage import settings_manager
|
|
428
428
|
|
429
429
|
def debug_storage_config(config_key: str | None = None):
|
430
430
|
"""Show actual storage paths for debugging"""
|
431
|
-
settings = settings_manager.
|
432
|
-
|
431
|
+
settings = settings_manager.get_settings(config_key)
|
432
|
+
|
433
433
|
print(f"Configuration: {config_key or 'default'}")
|
434
434
|
print(f" Bucket: {settings.bucket_name}")
|
435
435
|
print(f" Prefix: {settings.blob_name_prefix or '(none)'}")
|
436
436
|
print(f" Auth: {settings.google_auth_config_key}")
|
437
|
-
|
437
|
+
|
438
438
|
# Example paths
|
439
439
|
example_blob = "users/123/profile.json"
|
440
440
|
if settings.blob_name_prefix:
|
441
441
|
full_path = f"{settings.blob_name_prefix}/{example_blob}"
|
442
442
|
else:
|
443
443
|
full_path = example_blob
|
444
|
-
|
444
|
+
|
445
445
|
print(f" Example: gs://{settings.bucket_name}/{full_path}")
|
446
446
|
|
447
447
|
# Usage
|
@@ -665,13 +665,14 @@ blob = get_blob()
|
|
665
665
|
# Actual: gs://bucket/data/fixed.json
|
666
666
|
|
667
667
|
# Complex pattern
|
668
|
-
# If blob_name_pattern="
|
668
|
+
# If blob_name_pattern="my-service/{tenant_id}/users/{user_id}/files/{basename}"
|
669
669
|
blob = get_blob(placeholders={
|
670
|
+
"tenant_id": "tenant123",
|
670
671
|
"user_id": "user123",
|
671
672
|
"agent_id": "agent456",
|
672
673
|
"basename": "document.pdf"
|
673
674
|
})
|
674
|
-
# Actual: gs://bucket/
|
675
|
+
# Actual: gs://bucket/my-service/tenant123/users/user123/files/document.pdf
|
675
676
|
|
676
677
|
# With custom configurations
|
677
678
|
blob = get_blob(
|
@@ -700,7 +701,7 @@ settings_manager: SettingsManager[GoogleCloudStorageSettings]
|
|
700
701
|
- `active_key`: Get/set active configuration key
|
701
702
|
|
702
703
|
**Methods:**
|
703
|
-
- `
|
704
|
+
- `get_settings(key: str)`: Get settings by specific key
|
704
705
|
- `clear()`: Clear cached settings
|
705
706
|
|
706
707
|
## Common Operations
|
@@ -0,0 +1,9 @@
|
|
1
|
+
kiarina/lib/google/cloud_storage/__init__.py,sha256=q2AdOOOHUj_D-eot8_1-atrIaCKsCg0YatUOdq3kVVE,1184
|
2
|
+
kiarina/lib/google/cloud_storage/_get_blob.py,sha256=j74xGy9ZlAFs2EwywQBVACprRcGOU63wd9FKWlE39dk,3065
|
3
|
+
kiarina/lib/google/cloud_storage/_get_bucket.py,sha256=1fBIuohwQzpsxaANpVTExQly3smwaYD2wtnDe7yg6Uo,484
|
4
|
+
kiarina/lib/google/cloud_storage/_get_storage_client.py,sha256=lmBR2I9_vcyb0PfsiSz0BPFYBwQ6zVci75cmk9GUN5U,359
|
5
|
+
kiarina/lib/google/cloud_storage/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
+
kiarina/lib/google/cloud_storage/settings.py,sha256=vKYeiVRL0qOPCJEbwJfdEUPU8KwpgMLLBzJ3eGpaqOI,536
|
7
|
+
kiarina_lib_google_cloud_storage-1.6.3.dist-info/METADATA,sha256=PByhsHVLVhbX9IwQdDhSqSo48ThFkC5H-T7rB2gA6JM,27553
|
8
|
+
kiarina_lib_google_cloud_storage-1.6.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
+
kiarina_lib_google_cloud_storage-1.6.3.dist-info/RECORD,,
|
@@ -1,9 +0,0 @@
|
|
1
|
-
kiarina/lib/google/cloud_storage/__init__.py,sha256=q2AdOOOHUj_D-eot8_1-atrIaCKsCg0YatUOdq3kVVE,1184
|
2
|
-
kiarina/lib/google/cloud_storage/_get_blob.py,sha256=J8GFQIx_xQWgqvd2LscI83u6xmzS7uPBIshyUDgBZEI,2644
|
3
|
-
kiarina/lib/google/cloud_storage/_get_bucket.py,sha256=SaGIQqRb9UOJaosGf2pXduAEYscE_T21AHCNTaZtRGo,597
|
4
|
-
kiarina/lib/google/cloud_storage/_get_storage_client.py,sha256=lmBR2I9_vcyb0PfsiSz0BPFYBwQ6zVci75cmk9GUN5U,359
|
5
|
-
kiarina/lib/google/cloud_storage/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
kiarina/lib/google/cloud_storage/settings.py,sha256=2ZG2AmWe6mM8wq-OHTqSneTIvoraIxh2Q1W7umLOFvI,540
|
7
|
-
kiarina_lib_google_cloud_storage-1.6.2.dist-info/METADATA,sha256=y16n-HD2RzseJezOZHujIS4xhzrds78eWEXKJK-p3-E,27462
|
8
|
-
kiarina_lib_google_cloud_storage-1.6.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
9
|
-
kiarina_lib_google_cloud_storage-1.6.2.dist-info/RECORD,,
|
File without changes
|