kiarina-lib-google-cloud-storage 1.5.0__tar.gz → 1.6.1__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 (19) hide show
  1. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/CHANGELOG.md +16 -0
  2. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/PKG-INFO +85 -27
  3. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/README.md +84 -26
  4. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/pyproject.toml +1 -1
  5. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/src/kiarina/lib/google/cloud_storage/_get_blob.py +6 -2
  6. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/src/kiarina/lib/google/cloud_storage/_get_bucket.py +7 -2
  7. kiarina_lib_google_cloud_storage-1.6.1/src/kiarina/lib/google/cloud_storage/_get_storage_client.py +12 -0
  8. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/src/kiarina/lib/google/cloud_storage/settings.py +0 -2
  9. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/tests/test_get_blob.py +28 -8
  10. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/tests/test_get_bucket.py +32 -10
  11. kiarina_lib_google_cloud_storage-1.6.1/tests/test_get_storage_client.py +57 -0
  12. kiarina_lib_google_cloud_storage-1.5.0/src/kiarina/lib/google/cloud_storage/_get_storage_client.py +0 -12
  13. kiarina_lib_google_cloud_storage-1.5.0/tests/test_get_storage_client.py +0 -34
  14. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/.gitignore +0 -0
  15. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/.vscode/settings.json +0 -0
  16. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/src/kiarina/lib/google/cloud_storage/__init__.py +0 -0
  17. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/src/kiarina/lib/google/cloud_storage/py.typed +0 -0
  18. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/tests/__init__.py +0 -0
  19. {kiarina_lib_google_cloud_storage-1.5.0 → kiarina_lib_google_cloud_storage-1.6.1}/tests/conftest.py +0 -0
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.6.1] - 2025-10-10
11
+
12
+ ### Changed
13
+ - No changes
14
+
15
+ ## [1.6.0] - 2025-10-10
16
+
17
+ ### Changed
18
+ - **BREAKING**: Separated authentication configuration from storage configuration
19
+ - Removed `google_auth_config_key` field from `GoogleCloudStorageSettings`
20
+ - Added `auth_config_key` parameter to `get_storage_client()`, `get_bucket()`, and `get_blob()`
21
+ - Authentication is now configured separately through kiarina-lib-google-auth
22
+ - **Migration**: Replace `google_auth_config_key` in settings with `auth_config_key` parameter in function calls
23
+ - **Rationale**: Clear separation of concerns - storage settings define "where", authentication defines "who"
24
+ - **Benefits**: More flexible configuration, easier to reuse authentication across different storage configurations
25
+
10
26
  ## [1.5.0] - 2025-10-10
11
27
 
12
28
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kiarina-lib-google-cloud-storage
3
- Version: 1.5.0
3
+ Version: 1.6.1
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
@@ -105,7 +105,6 @@ from kiarina.lib.google.cloud_storage import get_blob, settings_manager
105
105
  # Configure once (typically in your app initialization)
106
106
  settings_manager.user_config = {
107
107
  "default": {
108
- "google_auth_config_key": "default",
109
108
  "bucket_name": "my-app-data",
110
109
  "blob_name_prefix": "production/v1"
111
110
  }
@@ -126,7 +125,6 @@ content = blob.download_as_text()
126
125
  # Set once in your deployment environment
127
126
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BUCKET_NAME="my-app-data"
128
127
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BLOB_NAME_PREFIX="production/v1"
129
- export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_GOOGLE_AUTH_CONFIG_KEY="default"
130
128
  ```
131
129
 
132
130
  ```python
@@ -145,23 +143,35 @@ Deploy the same application code to different environments with different config
145
143
 
146
144
  ```yaml
147
145
  # config/production.yaml
146
+ google_auth:
147
+ default:
148
+ type: "service_account"
149
+ service_account_file: "/secrets/prod-sa-key.json"
150
+
148
151
  google_cloud_storage:
149
152
  default:
150
- google_auth_config_key: "production"
151
153
  bucket_name: "prod-us-west1-app-data"
152
154
  blob_name_prefix: "v2/production"
153
155
 
154
156
  # config/staging.yaml
157
+ google_auth:
158
+ default:
159
+ type: "service_account"
160
+ service_account_file: "/secrets/staging-sa-key.json"
161
+
155
162
  google_cloud_storage:
156
163
  default:
157
- google_auth_config_key: "staging"
158
164
  bucket_name: "staging-app-data"
159
165
  blob_name_prefix: "v2/staging"
160
166
 
161
167
  # config/development.yaml
168
+ google_auth:
169
+ default:
170
+ type: "user_account"
171
+ authorized_user_file: "~/.config/gcloud/application_default_credentials.json"
172
+
162
173
  google_cloud_storage:
163
174
  default:
164
- google_auth_config_key: "development"
165
175
  bucket_name: "dev-local-data"
166
176
  blob_name_prefix: "v2/dev"
167
177
  ```
@@ -193,15 +203,28 @@ Support multiple tenants with isolated storage, without changing application cod
193
203
  ```python
194
204
  from kiarina.lib.google.cloud_storage import settings_manager, get_blob
195
205
 
196
- # Configure tenant-specific storage
206
+ # Configure tenant-specific storage and authentication
207
+ from kiarina.lib.google.auth import settings_manager as auth_settings_manager
208
+
209
+ # Authentication configuration (separate from storage)
210
+ auth_settings_manager.user_config = {
211
+ "tenant_acme": {
212
+ "type": "service_account",
213
+ "service_account_file": "/secrets/acme-sa-key.json"
214
+ },
215
+ "tenant_globex": {
216
+ "type": "service_account",
217
+ "service_account_file": "/secrets/globex-sa-key.json"
218
+ }
219
+ }
220
+
221
+ # Storage configuration (separate from authentication)
197
222
  settings_manager.user_config = {
198
223
  "tenant_acme": {
199
- "google_auth_config_key": "tenant_acme",
200
224
  "bucket_name": "acme-corp-data",
201
225
  "blob_name_prefix": "app-data"
202
226
  },
203
227
  "tenant_globex": {
204
- "google_auth_config_key": "tenant_globex",
205
228
  "bucket_name": "globex-data",
206
229
  "blob_name_prefix": "app-data"
207
230
  }
@@ -211,7 +234,11 @@ settings_manager.user_config = {
211
234
  def save_document(tenant_id: str, doc_id: str, content: bytes):
212
235
  """Save document for any tenant"""
213
236
  config_key = f"tenant_{tenant_id}"
214
- blob = get_blob(config_key=config_key, blob_name=f"documents/{doc_id}.pdf")
237
+ blob = get_blob(
238
+ blob_name=f"documents/{doc_id}.pdf",
239
+ config_key=config_key,
240
+ auth_config_key=config_key
241
+ )
215
242
  blob.upload_from_string(content)
216
243
 
217
244
  def list_documents(tenant_id: str) -> list[str]:
@@ -219,7 +246,7 @@ def list_documents(tenant_id: str) -> list[str]:
219
246
  from kiarina.lib.google.cloud_storage import get_bucket
220
247
 
221
248
  config_key = f"tenant_{tenant_id}"
222
- bucket = get_bucket(config_key=config_key)
249
+ bucket = get_bucket(config_key=config_key, auth_config_key=config_key)
223
250
 
224
251
  # Get prefix from settings
225
252
  settings = settings_manager.get_settings_by_key(config_key)
@@ -247,7 +274,6 @@ def mock_storage_config():
247
274
  """Configure test storage"""
248
275
  settings_manager.user_config = {
249
276
  "test": {
250
- "google_auth_config_key": "test",
251
277
  "bucket_name": "test-bucket",
252
278
  "blob_name_prefix": f"test-run-{datetime.now().isoformat()}"
253
279
  }
@@ -312,13 +338,14 @@ This library uses [pydantic-settings-manager](https://github.com/kiarina/pydanti
312
338
 
313
339
  | Field | Type | Required | Description |
314
340
  |-------|------|----------|-------------|
315
- | `google_auth_config_key` | `str \| None` | No | Configuration key for kiarina-lib-google-auth |
316
341
  | `bucket_name` | `str \| None` | Yes* | Google Cloud Storage bucket name |
317
342
  | `blob_name_prefix` | `str \| None` | No | Prefix for blob names (e.g., "production/v1") |
318
343
  | `blob_name` | `str \| None` | No | Default blob name (rarely used) |
319
344
 
320
345
  *Required when using `get_bucket()` or `get_blob()`
321
346
 
347
+ **Note:** Authentication is configured separately through `auth_config_key` parameters in the API functions, which reference configurations in [kiarina-lib-google-auth](../kiarina-lib-google-auth/).
348
+
322
349
  ### Configuration Methods
323
350
 
324
351
  #### 1. Programmatic Configuration
@@ -328,7 +355,6 @@ from kiarina.lib.google.cloud_storage import settings_manager
328
355
 
329
356
  settings_manager.user_config = {
330
357
  "default": {
331
- "google_auth_config_key": "default",
332
358
  "bucket_name": "my-bucket",
333
359
  "blob_name_prefix": "app-data"
334
360
  }
@@ -340,11 +366,12 @@ settings_manager.user_config = {
340
366
  All settings can be configured via environment variables with the `KIARINA_LIB_GOOGLE_CLOUD_STORAGE_` prefix:
341
367
 
342
368
  ```bash
343
- export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_GOOGLE_AUTH_CONFIG_KEY="default"
344
369
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BUCKET_NAME="my-bucket"
345
370
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BLOB_NAME_PREFIX="app-data"
346
371
  ```
347
372
 
373
+ **Note:** Authentication is configured separately via `KIARINA_LIB_GOOGLE_AUTH_*` environment variables. See [kiarina-lib-google-auth](../kiarina-lib-google-auth/) for details.
374
+
348
375
  #### 3. Configuration Files (with YAML)
349
376
 
350
377
  ```python
@@ -360,33 +387,50 @@ settings_manager.user_config = config["google_cloud_storage"]
360
387
 
361
388
  ### Integration with kiarina-lib-google-auth
362
389
 
363
- This library integrates seamlessly with [kiarina-lib-google-auth](../kiarina-lib-google-auth/) for authentication:
390
+ This library integrates seamlessly with [kiarina-lib-google-auth](../kiarina-lib-google-auth/) for authentication.
391
+
392
+ **Key Design:** Authentication and storage configurations are **completely separate**, allowing flexible combinations.
364
393
 
365
394
  ```python
366
395
  from kiarina.lib.google.auth import settings_manager as auth_settings_manager
367
396
  from kiarina.lib.google.cloud_storage import settings_manager as storage_settings_manager
368
397
 
369
- # Configure authentication
398
+ # Configure authentication (separate)
370
399
  auth_settings_manager.user_config = {
371
400
  "default": {
372
401
  "type": "service_account",
373
402
  "service_account_file": "~/service-account-key.json"
403
+ },
404
+ "user_auth": {
405
+ "type": "user_account",
406
+ "authorized_user_file": "~/.config/gcloud/application_default_credentials.json"
374
407
  }
375
408
  }
376
409
 
377
- # Configure storage (references auth config)
410
+ # Configure storage (separate)
378
411
  storage_settings_manager.user_config = {
379
412
  "default": {
380
- "google_auth_config_key": "default", # References auth config above
381
413
  "bucket_name": "my-bucket"
414
+ },
415
+ "backup": {
416
+ "bucket_name": "my-backup-bucket"
382
417
  }
383
418
  }
384
419
 
385
- # Use authenticated storage
420
+ # Use with default authentication
386
421
  from kiarina.lib.google.cloud_storage import get_bucket
387
- bucket = get_bucket() # Automatically authenticated
422
+ bucket = get_bucket() # Uses default auth + default storage
423
+
424
+ # Mix and match configurations
425
+ bucket = get_bucket(config_key="backup", auth_config_key="user_auth")
426
+ # Uses user_auth authentication + backup storage configuration
388
427
  ```
389
428
 
429
+ **Benefits of Separation:**
430
+ - **Flexibility**: Use same auth with multiple buckets, or multiple auths with same bucket
431
+ - **Clarity**: Clear distinction between "who" (auth) and "where" (storage)
432
+ - **Reusability**: Share authentication across different storage configurations
433
+
390
434
  ## API Reference
391
435
 
392
436
  ### get_storage_client()
@@ -395,13 +439,13 @@ Get a Google Cloud Storage client with credentials from kiarina-lib-google-auth.
395
439
 
396
440
  ```python
397
441
  def get_storage_client(
398
- config_key: str | None = None,
442
+ auth_config_key: str | None = None,
399
443
  **kwargs: Any
400
444
  ) -> storage.Client
401
445
  ```
402
446
 
403
447
  **Parameters:**
404
- - `config_key`: Configuration key to use (default: None uses active key)
448
+ - `auth_config_key`: Configuration key for kiarina-lib-google-auth (default: None uses active key)
405
449
  - `**kwargs`: Additional arguments passed to `storage.Client()`
406
450
 
407
451
  **Returns:**
@@ -410,7 +454,7 @@ def get_storage_client(
410
454
  **Example:**
411
455
  ```python
412
456
  client = get_storage_client()
413
- client = get_storage_client(config_key="production")
457
+ client = get_storage_client(auth_config_key="production")
414
458
  client = get_storage_client(project="my-project") # Override project
415
459
  ```
416
460
 
@@ -421,12 +465,15 @@ Get a Google Cloud Storage bucket.
421
465
  ```python
422
466
  def get_bucket(
423
467
  config_key: str | None = None,
468
+ *,
469
+ auth_config_key: str | None = None,
424
470
  **kwargs: Any
425
471
  ) -> storage.Bucket
426
472
  ```
427
473
 
428
474
  **Parameters:**
429
- - `config_key`: Configuration key to use (default: None uses active key)
475
+ - `config_key`: Configuration key for storage settings (default: None uses active key)
476
+ - `auth_config_key`: Configuration key for authentication (default: None uses active key)
430
477
  - `**kwargs`: Additional arguments passed to `get_storage_client()`
431
478
 
432
479
  **Returns:**
@@ -439,6 +486,7 @@ def get_bucket(
439
486
  ```python
440
487
  bucket = get_bucket()
441
488
  bucket = get_bucket(config_key="production")
489
+ bucket = get_bucket(config_key="production", auth_config_key="prod_auth")
442
490
 
443
491
  # Use native google-cloud-storage API
444
492
  for blob in bucket.list_blobs(prefix="users/"):
@@ -451,15 +499,18 @@ Get a Google Cloud Storage blob.
451
499
 
452
500
  ```python
453
501
  def get_blob(
454
- config_key: str | None = None,
455
502
  blob_name: str | None = None,
503
+ *,
504
+ config_key: str | None = None,
505
+ auth_config_key: str | None = None,
456
506
  **kwargs: Any
457
507
  ) -> storage.Blob
458
508
  ```
459
509
 
460
510
  **Parameters:**
461
- - `config_key`: Configuration key to use (default: None uses active key)
462
511
  - `blob_name`: Blob name (default: None uses settings.blob_name)
512
+ - `config_key`: Configuration key for storage settings (default: None uses active key)
513
+ - `auth_config_key`: Configuration key for authentication (default: None uses active key)
463
514
  - `**kwargs`: Additional arguments passed to `get_bucket()`
464
515
 
465
516
  **Returns:**
@@ -478,6 +529,13 @@ blob = get_blob(blob_name="data.json")
478
529
  # Actual blob name will be "production/v1/data.json"
479
530
  blob = get_blob(blob_name="data.json")
480
531
 
532
+ # With custom configurations
533
+ blob = get_blob(
534
+ blob_name="data.json",
535
+ config_key="production",
536
+ auth_config_key="prod_auth"
537
+ )
538
+
481
539
  # Use native google-cloud-storage API
482
540
  blob.upload_from_string("content")
483
541
  content = blob.download_as_text()
@@ -77,7 +77,6 @@ from kiarina.lib.google.cloud_storage import get_blob, settings_manager
77
77
  # Configure once (typically in your app initialization)
78
78
  settings_manager.user_config = {
79
79
  "default": {
80
- "google_auth_config_key": "default",
81
80
  "bucket_name": "my-app-data",
82
81
  "blob_name_prefix": "production/v1"
83
82
  }
@@ -98,7 +97,6 @@ content = blob.download_as_text()
98
97
  # Set once in your deployment environment
99
98
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BUCKET_NAME="my-app-data"
100
99
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BLOB_NAME_PREFIX="production/v1"
101
- export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_GOOGLE_AUTH_CONFIG_KEY="default"
102
100
  ```
103
101
 
104
102
  ```python
@@ -117,23 +115,35 @@ Deploy the same application code to different environments with different config
117
115
 
118
116
  ```yaml
119
117
  # config/production.yaml
118
+ google_auth:
119
+ default:
120
+ type: "service_account"
121
+ service_account_file: "/secrets/prod-sa-key.json"
122
+
120
123
  google_cloud_storage:
121
124
  default:
122
- google_auth_config_key: "production"
123
125
  bucket_name: "prod-us-west1-app-data"
124
126
  blob_name_prefix: "v2/production"
125
127
 
126
128
  # config/staging.yaml
129
+ google_auth:
130
+ default:
131
+ type: "service_account"
132
+ service_account_file: "/secrets/staging-sa-key.json"
133
+
127
134
  google_cloud_storage:
128
135
  default:
129
- google_auth_config_key: "staging"
130
136
  bucket_name: "staging-app-data"
131
137
  blob_name_prefix: "v2/staging"
132
138
 
133
139
  # config/development.yaml
140
+ google_auth:
141
+ default:
142
+ type: "user_account"
143
+ authorized_user_file: "~/.config/gcloud/application_default_credentials.json"
144
+
134
145
  google_cloud_storage:
135
146
  default:
136
- google_auth_config_key: "development"
137
147
  bucket_name: "dev-local-data"
138
148
  blob_name_prefix: "v2/dev"
139
149
  ```
@@ -165,15 +175,28 @@ Support multiple tenants with isolated storage, without changing application cod
165
175
  ```python
166
176
  from kiarina.lib.google.cloud_storage import settings_manager, get_blob
167
177
 
168
- # Configure tenant-specific storage
178
+ # Configure tenant-specific storage and authentication
179
+ from kiarina.lib.google.auth import settings_manager as auth_settings_manager
180
+
181
+ # Authentication configuration (separate from storage)
182
+ auth_settings_manager.user_config = {
183
+ "tenant_acme": {
184
+ "type": "service_account",
185
+ "service_account_file": "/secrets/acme-sa-key.json"
186
+ },
187
+ "tenant_globex": {
188
+ "type": "service_account",
189
+ "service_account_file": "/secrets/globex-sa-key.json"
190
+ }
191
+ }
192
+
193
+ # Storage configuration (separate from authentication)
169
194
  settings_manager.user_config = {
170
195
  "tenant_acme": {
171
- "google_auth_config_key": "tenant_acme",
172
196
  "bucket_name": "acme-corp-data",
173
197
  "blob_name_prefix": "app-data"
174
198
  },
175
199
  "tenant_globex": {
176
- "google_auth_config_key": "tenant_globex",
177
200
  "bucket_name": "globex-data",
178
201
  "blob_name_prefix": "app-data"
179
202
  }
@@ -183,7 +206,11 @@ settings_manager.user_config = {
183
206
  def save_document(tenant_id: str, doc_id: str, content: bytes):
184
207
  """Save document for any tenant"""
185
208
  config_key = f"tenant_{tenant_id}"
186
- blob = get_blob(config_key=config_key, blob_name=f"documents/{doc_id}.pdf")
209
+ blob = get_blob(
210
+ blob_name=f"documents/{doc_id}.pdf",
211
+ config_key=config_key,
212
+ auth_config_key=config_key
213
+ )
187
214
  blob.upload_from_string(content)
188
215
 
189
216
  def list_documents(tenant_id: str) -> list[str]:
@@ -191,7 +218,7 @@ def list_documents(tenant_id: str) -> list[str]:
191
218
  from kiarina.lib.google.cloud_storage import get_bucket
192
219
 
193
220
  config_key = f"tenant_{tenant_id}"
194
- bucket = get_bucket(config_key=config_key)
221
+ bucket = get_bucket(config_key=config_key, auth_config_key=config_key)
195
222
 
196
223
  # Get prefix from settings
197
224
  settings = settings_manager.get_settings_by_key(config_key)
@@ -219,7 +246,6 @@ def mock_storage_config():
219
246
  """Configure test storage"""
220
247
  settings_manager.user_config = {
221
248
  "test": {
222
- "google_auth_config_key": "test",
223
249
  "bucket_name": "test-bucket",
224
250
  "blob_name_prefix": f"test-run-{datetime.now().isoformat()}"
225
251
  }
@@ -284,13 +310,14 @@ This library uses [pydantic-settings-manager](https://github.com/kiarina/pydanti
284
310
 
285
311
  | Field | Type | Required | Description |
286
312
  |-------|------|----------|-------------|
287
- | `google_auth_config_key` | `str \| None` | No | Configuration key for kiarina-lib-google-auth |
288
313
  | `bucket_name` | `str \| None` | Yes* | Google Cloud Storage bucket name |
289
314
  | `blob_name_prefix` | `str \| None` | No | Prefix for blob names (e.g., "production/v1") |
290
315
  | `blob_name` | `str \| None` | No | Default blob name (rarely used) |
291
316
 
292
317
  *Required when using `get_bucket()` or `get_blob()`
293
318
 
319
+ **Note:** Authentication is configured separately through `auth_config_key` parameters in the API functions, which reference configurations in [kiarina-lib-google-auth](../kiarina-lib-google-auth/).
320
+
294
321
  ### Configuration Methods
295
322
 
296
323
  #### 1. Programmatic Configuration
@@ -300,7 +327,6 @@ from kiarina.lib.google.cloud_storage import settings_manager
300
327
 
301
328
  settings_manager.user_config = {
302
329
  "default": {
303
- "google_auth_config_key": "default",
304
330
  "bucket_name": "my-bucket",
305
331
  "blob_name_prefix": "app-data"
306
332
  }
@@ -312,11 +338,12 @@ settings_manager.user_config = {
312
338
  All settings can be configured via environment variables with the `KIARINA_LIB_GOOGLE_CLOUD_STORAGE_` prefix:
313
339
 
314
340
  ```bash
315
- export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_GOOGLE_AUTH_CONFIG_KEY="default"
316
341
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BUCKET_NAME="my-bucket"
317
342
  export KIARINA_LIB_GOOGLE_CLOUD_STORAGE_BLOB_NAME_PREFIX="app-data"
318
343
  ```
319
344
 
345
+ **Note:** Authentication is configured separately via `KIARINA_LIB_GOOGLE_AUTH_*` environment variables. See [kiarina-lib-google-auth](../kiarina-lib-google-auth/) for details.
346
+
320
347
  #### 3. Configuration Files (with YAML)
321
348
 
322
349
  ```python
@@ -332,33 +359,50 @@ settings_manager.user_config = config["google_cloud_storage"]
332
359
 
333
360
  ### Integration with kiarina-lib-google-auth
334
361
 
335
- This library integrates seamlessly with [kiarina-lib-google-auth](../kiarina-lib-google-auth/) for authentication:
362
+ This library integrates seamlessly with [kiarina-lib-google-auth](../kiarina-lib-google-auth/) for authentication.
363
+
364
+ **Key Design:** Authentication and storage configurations are **completely separate**, allowing flexible combinations.
336
365
 
337
366
  ```python
338
367
  from kiarina.lib.google.auth import settings_manager as auth_settings_manager
339
368
  from kiarina.lib.google.cloud_storage import settings_manager as storage_settings_manager
340
369
 
341
- # Configure authentication
370
+ # Configure authentication (separate)
342
371
  auth_settings_manager.user_config = {
343
372
  "default": {
344
373
  "type": "service_account",
345
374
  "service_account_file": "~/service-account-key.json"
375
+ },
376
+ "user_auth": {
377
+ "type": "user_account",
378
+ "authorized_user_file": "~/.config/gcloud/application_default_credentials.json"
346
379
  }
347
380
  }
348
381
 
349
- # Configure storage (references auth config)
382
+ # Configure storage (separate)
350
383
  storage_settings_manager.user_config = {
351
384
  "default": {
352
- "google_auth_config_key": "default", # References auth config above
353
385
  "bucket_name": "my-bucket"
386
+ },
387
+ "backup": {
388
+ "bucket_name": "my-backup-bucket"
354
389
  }
355
390
  }
356
391
 
357
- # Use authenticated storage
392
+ # Use with default authentication
358
393
  from kiarina.lib.google.cloud_storage import get_bucket
359
- bucket = get_bucket() # Automatically authenticated
394
+ bucket = get_bucket() # Uses default auth + default storage
395
+
396
+ # Mix and match configurations
397
+ bucket = get_bucket(config_key="backup", auth_config_key="user_auth")
398
+ # Uses user_auth authentication + backup storage configuration
360
399
  ```
361
400
 
401
+ **Benefits of Separation:**
402
+ - **Flexibility**: Use same auth with multiple buckets, or multiple auths with same bucket
403
+ - **Clarity**: Clear distinction between "who" (auth) and "where" (storage)
404
+ - **Reusability**: Share authentication across different storage configurations
405
+
362
406
  ## API Reference
363
407
 
364
408
  ### get_storage_client()
@@ -367,13 +411,13 @@ Get a Google Cloud Storage client with credentials from kiarina-lib-google-auth.
367
411
 
368
412
  ```python
369
413
  def get_storage_client(
370
- config_key: str | None = None,
414
+ auth_config_key: str | None = None,
371
415
  **kwargs: Any
372
416
  ) -> storage.Client
373
417
  ```
374
418
 
375
419
  **Parameters:**
376
- - `config_key`: Configuration key to use (default: None uses active key)
420
+ - `auth_config_key`: Configuration key for kiarina-lib-google-auth (default: None uses active key)
377
421
  - `**kwargs`: Additional arguments passed to `storage.Client()`
378
422
 
379
423
  **Returns:**
@@ -382,7 +426,7 @@ def get_storage_client(
382
426
  **Example:**
383
427
  ```python
384
428
  client = get_storage_client()
385
- client = get_storage_client(config_key="production")
429
+ client = get_storage_client(auth_config_key="production")
386
430
  client = get_storage_client(project="my-project") # Override project
387
431
  ```
388
432
 
@@ -393,12 +437,15 @@ Get a Google Cloud Storage bucket.
393
437
  ```python
394
438
  def get_bucket(
395
439
  config_key: str | None = None,
440
+ *,
441
+ auth_config_key: str | None = None,
396
442
  **kwargs: Any
397
443
  ) -> storage.Bucket
398
444
  ```
399
445
 
400
446
  **Parameters:**
401
- - `config_key`: Configuration key to use (default: None uses active key)
447
+ - `config_key`: Configuration key for storage settings (default: None uses active key)
448
+ - `auth_config_key`: Configuration key for authentication (default: None uses active key)
402
449
  - `**kwargs`: Additional arguments passed to `get_storage_client()`
403
450
 
404
451
  **Returns:**
@@ -411,6 +458,7 @@ def get_bucket(
411
458
  ```python
412
459
  bucket = get_bucket()
413
460
  bucket = get_bucket(config_key="production")
461
+ bucket = get_bucket(config_key="production", auth_config_key="prod_auth")
414
462
 
415
463
  # Use native google-cloud-storage API
416
464
  for blob in bucket.list_blobs(prefix="users/"):
@@ -423,15 +471,18 @@ Get a Google Cloud Storage blob.
423
471
 
424
472
  ```python
425
473
  def get_blob(
426
- config_key: str | None = None,
427
474
  blob_name: str | None = None,
475
+ *,
476
+ config_key: str | None = None,
477
+ auth_config_key: str | None = None,
428
478
  **kwargs: Any
429
479
  ) -> storage.Blob
430
480
  ```
431
481
 
432
482
  **Parameters:**
433
- - `config_key`: Configuration key to use (default: None uses active key)
434
483
  - `blob_name`: Blob name (default: None uses settings.blob_name)
484
+ - `config_key`: Configuration key for storage settings (default: None uses active key)
485
+ - `auth_config_key`: Configuration key for authentication (default: None uses active key)
435
486
  - `**kwargs`: Additional arguments passed to `get_bucket()`
436
487
 
437
488
  **Returns:**
@@ -450,6 +501,13 @@ blob = get_blob(blob_name="data.json")
450
501
  # Actual blob name will be "production/v1/data.json"
451
502
  blob = get_blob(blob_name="data.json")
452
503
 
504
+ # With custom configurations
505
+ blob = get_blob(
506
+ blob_name="data.json",
507
+ config_key="production",
508
+ auth_config_key="prod_auth"
509
+ )
510
+
453
511
  # Use native google-cloud-storage API
454
512
  blob.upload_from_string("content")
455
513
  content = blob.download_as_text()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kiarina-lib-google-cloud-storage"
3
- version = "1.5.0"
3
+ version = "1.6.1"
4
4
  description = "Google Cloud Storage client library for kiarina namespace"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -7,7 +7,11 @@ from .settings import settings_manager
7
7
 
8
8
 
9
9
  def get_blob(
10
- config_key: str | None = None, blob_name: str | None = None, **kwargs: Any
10
+ blob_name: str | None = None,
11
+ *,
12
+ config_key: str | None = None,
13
+ auth_config_key: str | None = None,
14
+ **kwargs: Any,
11
15
  ) -> storage.Blob:
12
16
  settings = settings_manager.get_settings_by_key(config_key)
13
17
 
@@ -20,5 +24,5 @@ def get_blob(
20
24
  if settings.blob_name_prefix:
21
25
  blob_name = f"{settings.blob_name_prefix}/{blob_name}"
22
26
 
23
- bucket = get_bucket(config_key, **kwargs)
27
+ bucket = get_bucket(config_key, auth_config_key=auth_config_key, **kwargs)
24
28
  return bucket.blob(blob_name)
@@ -6,11 +6,16 @@ from ._get_storage_client import get_storage_client
6
6
  from .settings import settings_manager
7
7
 
8
8
 
9
- def get_bucket(config_key: str | None = None, **kwargs: Any) -> storage.Bucket:
9
+ def get_bucket(
10
+ config_key: str | None = None,
11
+ *,
12
+ auth_config_key: str | None = None,
13
+ **kwargs: Any,
14
+ ) -> storage.Bucket:
10
15
  settings = settings_manager.get_settings_by_key(config_key)
11
16
 
12
17
  if settings.bucket_name is None:
13
18
  raise ValueError("bucket_name is not set in the settings")
14
19
 
15
- client = get_storage_client(config_key, **kwargs)
20
+ client = get_storage_client(auth_config_key, **kwargs)
16
21
  return client.bucket(settings.bucket_name)
@@ -0,0 +1,12 @@
1
+ from typing import Any
2
+
3
+ from google.cloud import storage # type: ignore[import-untyped]
4
+ from kiarina.lib.google.auth import get_credentials
5
+
6
+
7
+ def get_storage_client(
8
+ auth_config_key: str | None = None,
9
+ **kwargs: Any,
10
+ ) -> storage.Client:
11
+ credentials = get_credentials(auth_config_key)
12
+ return storage.Client(credentials=credentials, **kwargs)
@@ -3,8 +3,6 @@ from pydantic_settings_manager import SettingsManager
3
3
 
4
4
 
5
5
  class GoogleCloudStorageSettings(BaseSettings):
6
- google_auth_config_key: str | None = None
7
-
8
6
  bucket_name: str | None = None
9
7
 
10
8
  blob_name_prefix: str | None = None
@@ -9,7 +9,6 @@ def test_get_blob():
9
9
  # Setup settings
10
10
  settings_manager.user_config = {
11
11
  "default": {
12
- "google_auth_config_key": "test_auth",
13
12
  "bucket_name": "test-bucket",
14
13
  "blob_name": "test-blob.txt",
15
14
  }
@@ -36,7 +35,6 @@ def test_get_blob_with_blob_name_parameter():
36
35
  # Setup settings
37
36
  settings_manager.user_config = {
38
37
  "default": {
39
- "google_auth_config_key": "test_auth",
40
38
  "bucket_name": "test-bucket",
41
39
  }
42
40
  }
@@ -62,7 +60,6 @@ def test_get_blob_with_blob_name_prefix():
62
60
  # Setup settings with blob_name_prefix
63
61
  settings_manager.user_config = {
64
62
  "default": {
65
- "google_auth_config_key": "test_auth",
66
63
  "bucket_name": "test-bucket",
67
64
  "blob_name_prefix": "prefix",
68
65
  "blob_name": "test-blob.txt",
@@ -90,7 +87,6 @@ def test_get_blob_with_blob_name_prefix_and_parameter():
90
87
  # Setup settings with blob_name_prefix
91
88
  settings_manager.user_config = {
92
89
  "default": {
93
- "google_auth_config_key": "test_auth",
94
90
  "bucket_name": "test-bucket",
95
91
  "blob_name_prefix": "prefix",
96
92
  }
@@ -117,7 +113,6 @@ def test_get_blob_without_blob_name():
117
113
  # Setup settings without blob_name
118
114
  settings_manager.user_config = {
119
115
  "default": {
120
- "google_auth_config_key": "test_auth",
121
116
  "bucket_name": "test-bucket",
122
117
  }
123
118
  }
@@ -132,7 +127,6 @@ def test_get_blob_with_custom_config_key():
132
127
  # Setup settings with custom config key
133
128
  settings_manager.user_config = {
134
129
  "custom": {
135
- "google_auth_config_key": "custom_auth",
136
130
  "bucket_name": "custom-bucket",
137
131
  "blob_name": "custom-blob.txt",
138
132
  }
@@ -151,5 +145,31 @@ def test_get_blob_with_custom_config_key():
151
145
  blob = get_blob(config_key="custom")
152
146
  assert blob.name == "custom-blob.txt"
153
147
 
154
- # Verify get_bucket was called with custom config key
155
- mock_get_bucket.assert_called_once_with("custom")
148
+ # Verify get_bucket was called with custom config key and no auth_config_key
149
+ mock_get_bucket.assert_called_once_with("custom", auth_config_key=None)
150
+
151
+
152
+ def test_get_blob_with_auth_config_key():
153
+ # Setup settings
154
+ settings_manager.user_config = {
155
+ "default": {
156
+ "bucket_name": "test-bucket",
157
+ "blob_name": "test-blob.txt",
158
+ }
159
+ }
160
+
161
+ # Mock get_bucket and blob
162
+ mock_bucket = MagicMock()
163
+ mock_blob = MagicMock()
164
+ mock_blob.name = "test-blob.txt"
165
+ mock_bucket.blob.return_value = mock_blob
166
+
167
+ with patch(
168
+ "kiarina.lib.google.cloud_storage._get_blob.get_bucket",
169
+ return_value=mock_bucket,
170
+ ) as mock_get_bucket:
171
+ blob = get_blob(auth_config_key="custom_auth")
172
+ assert blob.name == "test-blob.txt"
173
+
174
+ # Verify get_bucket was called with custom auth config key
175
+ mock_get_bucket.assert_called_once_with(None, auth_config_key="custom_auth")
@@ -9,7 +9,6 @@ def test_get_bucket():
9
9
  # Setup settings
10
10
  settings_manager.user_config = {
11
11
  "default": {
12
- "google_auth_config_key": "test_auth",
13
12
  "bucket_name": "test-bucket",
14
13
  }
15
14
  }
@@ -23,21 +22,20 @@ def test_get_bucket():
23
22
  with patch(
24
23
  "kiarina.lib.google.cloud_storage._get_bucket.get_storage_client",
25
24
  return_value=mock_client,
26
- ):
25
+ ) as mock_get_client:
27
26
  bucket = get_bucket()
28
27
  assert bucket.name == "test-bucket"
29
28
 
29
+ # Verify get_storage_client was called with None (default)
30
+ mock_get_client.assert_called_once_with(None)
31
+
30
32
  # Verify bucket was called with correct bucket name
31
33
  mock_client.bucket.assert_called_once_with("test-bucket")
32
34
 
33
35
 
34
36
  def test_get_bucket_without_bucket_name():
35
37
  # Setup settings without bucket_name
36
- settings_manager.user_config = {
37
- "default": {
38
- "google_auth_config_key": "test_auth",
39
- }
40
- }
38
+ settings_manager.user_config = {"default": {}}
41
39
 
42
40
  with pytest.raises(ValueError, match="bucket_name is not set in the settings"):
43
41
  get_bucket()
@@ -47,7 +45,6 @@ def test_get_bucket_with_custom_config_key():
47
45
  # Setup settings with custom config key
48
46
  settings_manager.user_config = {
49
47
  "custom": {
50
- "google_auth_config_key": "custom_auth",
51
48
  "bucket_name": "custom-bucket",
52
49
  }
53
50
  }
@@ -65,5 +62,30 @@ def test_get_bucket_with_custom_config_key():
65
62
  bucket = get_bucket(config_key="custom")
66
63
  assert bucket.name == "custom-bucket"
67
64
 
68
- # Verify get_storage_client was called with custom config key
69
- mock_get_client.assert_called_once_with("custom")
65
+ # Verify get_storage_client was called with None (no auth_config_key specified)
66
+ mock_get_client.assert_called_once_with(None)
67
+
68
+
69
+ def test_get_bucket_with_auth_config_key():
70
+ # Setup settings
71
+ settings_manager.user_config = {
72
+ "default": {
73
+ "bucket_name": "test-bucket",
74
+ }
75
+ }
76
+
77
+ # Mock get_storage_client and bucket
78
+ mock_client = MagicMock()
79
+ mock_bucket = MagicMock()
80
+ mock_bucket.name = "test-bucket"
81
+ mock_client.bucket.return_value = mock_bucket
82
+
83
+ with patch(
84
+ "kiarina.lib.google.cloud_storage._get_bucket.get_storage_client",
85
+ return_value=mock_client,
86
+ ) as mock_get_client:
87
+ bucket = get_bucket(auth_config_key="custom_auth")
88
+ assert bucket.name == "test-bucket"
89
+
90
+ # Verify get_storage_client was called with custom auth config key
91
+ mock_get_client.assert_called_once_with("custom_auth")
@@ -0,0 +1,57 @@
1
+ from unittest.mock import MagicMock, patch
2
+
3
+ from kiarina.lib.google.cloud_storage import get_storage_client
4
+
5
+
6
+ def test_get_storage_client():
7
+ # Mock get_credentials and storage.Client
8
+ mock_credentials = MagicMock()
9
+ mock_credentials.project_id = "test-project"
10
+ mock_client = MagicMock()
11
+ mock_client.project = "test-project"
12
+
13
+ with (
14
+ patch(
15
+ "kiarina.lib.google.cloud_storage._get_storage_client.get_credentials",
16
+ return_value=mock_credentials,
17
+ ) as mock_get_credentials,
18
+ patch(
19
+ "kiarina.lib.google.cloud_storage._get_storage_client.storage.Client",
20
+ return_value=mock_client,
21
+ ) as mock_client_class,
22
+ ):
23
+ client = get_storage_client()
24
+ assert client.project == "test-project"
25
+
26
+ # Verify get_credentials was called with None (default)
27
+ mock_get_credentials.assert_called_once_with(None)
28
+
29
+ # Verify Client was called with correct credentials
30
+ mock_client_class.assert_called_once_with(credentials=mock_credentials)
31
+
32
+
33
+ def test_get_storage_client_with_auth_config_key():
34
+ # Mock get_credentials and storage.Client
35
+ mock_credentials = MagicMock()
36
+ mock_credentials.project_id = "custom-project"
37
+ mock_client = MagicMock()
38
+ mock_client.project = "custom-project"
39
+
40
+ with (
41
+ patch(
42
+ "kiarina.lib.google.cloud_storage._get_storage_client.get_credentials",
43
+ return_value=mock_credentials,
44
+ ) as mock_get_credentials,
45
+ patch(
46
+ "kiarina.lib.google.cloud_storage._get_storage_client.storage.Client",
47
+ return_value=mock_client,
48
+ ) as mock_client_class,
49
+ ):
50
+ client = get_storage_client(auth_config_key="custom_auth")
51
+ assert client.project == "custom-project"
52
+
53
+ # Verify get_credentials was called with custom auth config key
54
+ mock_get_credentials.assert_called_once_with("custom_auth")
55
+
56
+ # Verify Client was called with correct credentials
57
+ mock_client_class.assert_called_once_with(credentials=mock_credentials)
@@ -1,12 +0,0 @@
1
- from typing import Any
2
-
3
- from google.cloud import storage # type: ignore[import-untyped]
4
- from kiarina.lib.google.auth import get_credentials
5
-
6
- from .settings import settings_manager
7
-
8
-
9
- def get_storage_client(config_key: str | None = None, **kwargs: Any) -> storage.Client:
10
- settings = settings_manager.get_settings_by_key(config_key)
11
- credentials = get_credentials(settings.google_auth_config_key)
12
- return storage.Client(credentials=credentials, **kwargs)
@@ -1,34 +0,0 @@
1
- from unittest.mock import MagicMock, patch
2
-
3
- from kiarina.lib.google.cloud_storage import get_storage_client, settings_manager
4
-
5
-
6
- def test_get_storage_client():
7
- # Setup settings
8
- settings_manager.user_config = {
9
- "default": {
10
- "google_auth_config_key": "test_auth",
11
- }
12
- }
13
-
14
- # Mock get_credentials and storage.Client
15
- mock_credentials = MagicMock()
16
- mock_credentials.project_id = "test-project"
17
- mock_client = MagicMock()
18
- mock_client.project = "test-project"
19
-
20
- with (
21
- patch(
22
- "kiarina.lib.google.cloud_storage._get_storage_client.get_credentials",
23
- return_value=mock_credentials,
24
- ),
25
- patch(
26
- "kiarina.lib.google.cloud_storage._get_storage_client.storage.Client",
27
- return_value=mock_client,
28
- ) as mock_client_class,
29
- ):
30
- client = get_storage_client()
31
- assert client.project == "test-project"
32
-
33
- # Verify Client was called with correct credentials
34
- mock_client_class.assert_called_once_with(credentials=mock_credentials)