volcano-sdk-python 0.7.0__py3-none-any.whl → 0.7.2__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.
volcano_sdk/auth.py CHANGED
@@ -1007,12 +1007,20 @@ class Auth:
1007
1007
  )
1008
1008
 
1009
1009
  def _session_request(
1010
- self, operation: Callable[[str], TransportResponse]
1010
+ self,
1011
+ operation: Callable[[str], TransportResponse],
1012
+ *,
1013
+ binding: tuple[int, int, Session | None] | None = None,
1011
1014
  ) -> TransportResponse:
1012
- binding = self._client._capture_session_binding()
1015
+ if binding is None:
1016
+ binding = self._client._capture_session_binding()
1013
1017
  if binding[2] is None:
1014
1018
  raise RuntimeError(_NO_ACTIVE_SESSION)
1015
- response = operation(binding[2].access_token)
1019
+ binding = self._owned_refresh_session(binding)
1020
+ current = binding[2]
1021
+ if current is None:
1022
+ raise SessionChangedError
1023
+ response = operation(current.access_token)
1016
1024
  if response.status_code != HTTPStatus.UNAUTHORIZED:
1017
1025
  return response
1018
1026
  try:
volcano_sdk/py.typed ADDED
@@ -0,0 +1 @@
1
+
volcano_sdk/storage.py CHANGED
@@ -11,7 +11,7 @@ from dataclasses import dataclass
11
11
  from datetime import datetime
12
12
  from io import SEEK_END, BytesIO
13
13
  from tempfile import TemporaryFile
14
- from typing import Any, BinaryIO, Protocol, cast
14
+ from typing import TYPE_CHECKING, Any, BinaryIO, Protocol, cast
15
15
  from urllib.parse import quote
16
16
 
17
17
  from ._transport import (
@@ -25,6 +25,7 @@ from ._transport import (
25
25
  )
26
26
  from .models import (
27
27
  JSONValue,
28
+ Session,
28
29
  StorageObject,
29
30
  StoragePage,
30
31
  UploadPart,
@@ -33,6 +34,9 @@ from .models import (
33
34
  UploadSessionStatus,
34
35
  )
35
36
 
37
+ if TYPE_CHECKING:
38
+ from .auth import Auth
39
+
36
40
  _INVALID_STORAGE_PAGE = "Expected a complete storage page"
37
41
  _INVALID_CONTENT_TYPE = "content_type must be a non-blank printable ASCII string"
38
42
  _INVALID_STORAGE_PATH = "Storage path must be a non-empty string"
@@ -280,6 +284,7 @@ class StorageContext(Protocol):
280
284
  """Client capabilities required by object storage."""
281
285
 
282
286
  _transport: Transport
287
+ auth: Auth
283
288
 
284
289
  def _anon_token(self) -> str: ...
285
290
 
@@ -287,6 +292,8 @@ class StorageContext(Protocol):
287
292
 
288
293
  def _session_token(self) -> str: ...
289
294
 
295
+ def _capture_session_binding(self) -> tuple[int, int, Session | None]: ...
296
+
290
297
 
291
298
  class StorageListTransport(Protocol):
292
299
  """Transport capability required to list storage objects."""
@@ -462,25 +469,33 @@ class StorageBucket:
462
469
  ) -> dict[str, Any]:
463
470
  """Upload bytes or the remaining contents of a binary stream."""
464
471
  mime_type = _upload_content_type(content_type)
465
- response = invoke(
466
- self._client._transport.upload_storage_object,
467
- authorization=self._client._session_token(),
468
- bucket_name=self._name,
469
- path=path,
470
- data=_simple_upload_bytes(data),
471
- content_type=mime_type,
472
+ binding = self._client._capture_session_binding()
473
+ self._client._session_token()
474
+ content = _simple_upload_bytes(data)
475
+ response = self._client.auth._session_request(
476
+ lambda token: invoke(
477
+ self._client._transport.upload_storage_object,
478
+ authorization=token,
479
+ bucket_name=self._name,
480
+ path=path,
481
+ data=content,
482
+ content_type=mime_type,
483
+ ),
484
+ binding=binding,
472
485
  )
473
486
  payload = response_payload(response, 201)
474
487
  return dict(payload)
475
488
 
476
489
  def download(self, path: str, *, byte_range: str | None = None) -> bytes:
477
490
  """Download bytes from a path in this bucket."""
478
- response = invoke(
479
- self._client._transport.download_storage_object,
480
- authorization=self._client._session_token(),
481
- bucket_name=self._name,
482
- path=path,
483
- byte_range=byte_range,
491
+ response = self._client.auth._session_request(
492
+ lambda token: invoke(
493
+ self._client._transport.download_storage_object,
494
+ authorization=token,
495
+ bucket_name=self._name,
496
+ path=path,
497
+ byte_range=byte_range,
498
+ )
484
499
  )
485
500
  expected_status = (
486
501
  _HTTP_PARTIAL_CONTENT
@@ -500,16 +515,18 @@ class StorageBucket:
500
515
  ) -> UploadSession:
501
516
  """Create server state for a resumable upload."""
502
517
  transport = cast("StorageUploadSessionTransport", self._client._transport)
503
- response = invoke(
504
- transport.create_upload_session,
505
- authorization=self._client._session_token(),
506
- bucket_name=self._name,
507
- request=StorageUploadSessionRequest(
508
- path=_storage_path(path),
509
- content_type=content_type,
510
- total_size=total_size,
511
- part_size=part_size,
512
- ),
518
+ response = self._client.auth._session_request(
519
+ lambda token: invoke(
520
+ transport.create_upload_session,
521
+ authorization=token,
522
+ bucket_name=self._name,
523
+ request=StorageUploadSessionRequest(
524
+ path=_storage_path(path),
525
+ content_type=content_type,
526
+ total_size=total_size,
527
+ part_size=part_size,
528
+ ),
529
+ )
513
530
  )
514
531
  return _upload_session(response_payload(response, 201))
515
532
 
@@ -523,16 +540,18 @@ class StorageBucket:
523
540
  ) -> UploadPart:
524
541
  """Upload one part of a resumable upload session."""
525
542
  transport = cast("StorageUploadPartTransport", self._client._transport)
526
- response = invoke(
527
- transport.upload_part,
528
- authorization=self._client._session_token(),
529
- bucket_name=self._name,
530
- request=StorageUploadPartRequest(
531
- path=_storage_path(path),
532
- session_id=session_id,
533
- part_number=part_number,
534
- data=data,
535
- ),
543
+ response = self._client.auth._session_request(
544
+ lambda token: invoke(
545
+ transport.upload_part,
546
+ authorization=token,
547
+ bucket_name=self._name,
548
+ request=StorageUploadPartRequest(
549
+ path=_storage_path(path),
550
+ session_id=session_id,
551
+ part_number=part_number,
552
+ data=data,
553
+ ),
554
+ )
536
555
  )
537
556
  return _upload_part(response_payload(response, 200))
538
557
 
@@ -544,14 +563,16 @@ class StorageBucket:
544
563
  ) -> StorageObject:
545
564
  """Complete a resumable upload and return the stored object."""
546
565
  transport = cast("StorageCompleteUploadTransport", self._client._transport)
547
- response = invoke(
548
- transport.complete_upload_session,
549
- authorization=self._client._session_token(),
550
- bucket_name=self._name,
551
- request=StorageUploadSessionReference(
552
- path=_storage_path(path),
553
- session_id=session_id,
554
- ),
566
+ response = self._client.auth._session_request(
567
+ lambda token: invoke(
568
+ transport.complete_upload_session,
569
+ authorization=token,
570
+ bucket_name=self._name,
571
+ request=StorageUploadSessionReference(
572
+ path=_storage_path(path),
573
+ session_id=session_id,
574
+ ),
575
+ )
555
576
  )
556
577
  payload = cast("Mapping[str, object]", response_payload(response, 200))
557
578
  return _storage_object(payload["object"])
@@ -564,14 +585,16 @@ class StorageBucket:
564
585
  ) -> UploadSessionStatus:
565
586
  """Get resumable upload progress and uploaded part metadata."""
566
587
  transport = cast("StorageUploadStatusTransport", self._client._transport)
567
- response = invoke(
568
- transport.get_upload_session,
569
- authorization=self._client._session_token(),
570
- bucket_name=self._name,
571
- request=StorageUploadSessionReference(
572
- path=_storage_path(path),
573
- session_id=session_id,
574
- ),
588
+ response = self._client.auth._session_request(
589
+ lambda token: invoke(
590
+ transport.get_upload_session,
591
+ authorization=token,
592
+ bucket_name=self._name,
593
+ request=StorageUploadSessionReference(
594
+ path=_storage_path(path),
595
+ session_id=session_id,
596
+ ),
597
+ )
575
598
  )
576
599
  return _upload_session_status(response_payload(response, 200))
577
600
 
@@ -583,14 +606,16 @@ class StorageBucket:
583
606
  ) -> None:
584
607
  """Abort a resumable upload and discard its uploaded parts."""
585
608
  transport = cast("StorageAbortUploadTransport", self._client._transport)
586
- response = invoke(
587
- transport.abort_upload_session,
588
- authorization=self._client._session_token(),
589
- bucket_name=self._name,
590
- request=StorageUploadSessionReference(
591
- path=_storage_path(path),
592
- session_id=session_id,
593
- ),
609
+ response = self._client.auth._session_request(
610
+ lambda token: invoke(
611
+ transport.abort_upload_session,
612
+ authorization=token,
613
+ bucket_name=self._name,
614
+ request=StorageUploadSessionReference(
615
+ path=_storage_path(path),
616
+ session_id=session_id,
617
+ ),
618
+ )
594
619
  )
595
620
  response_payload(response, 200)
596
621
 
@@ -662,41 +687,51 @@ class StorageBucket:
662
687
  ) -> StoragePage:
663
688
  """List objects under a prefix and return the next-page cursor."""
664
689
  transport = cast("StorageListTransport", self._client._transport)
665
- response = invoke(
666
- transport.list_storage_objects,
667
- authorization=self._client._session_token(),
668
- bucket_name=self._name,
669
- prefix=prefix,
670
- limit=limit,
671
- cursor=cursor,
690
+ response = self._client.auth._session_request(
691
+ lambda token: invoke(
692
+ transport.list_storage_objects,
693
+ authorization=token,
694
+ bucket_name=self._name,
695
+ prefix=prefix,
696
+ limit=limit,
697
+ cursor=cursor,
698
+ )
672
699
  )
673
700
  return _storage_page(response_payload(response, 200))
674
701
 
675
702
  def remove(self, paths: str | Sequence[str]) -> tuple[str, ...]:
676
703
  """Delete one or more object paths and return their immutable snapshot."""
677
704
  path_list = _storage_paths(paths)
678
- transport = cast("StorageDeleteTransport", self._client._transport)
679
- authorization = self._client._session_token()
705
+ binding = self._client._capture_session_binding()
680
706
  for path in path_list:
681
- response = invoke(
707
+ self._remove_path(path, binding)
708
+ return path_list
709
+
710
+ def _remove_path(self, path: str, binding: tuple[int, int, Session | None]) -> None:
711
+ transport = cast("StorageDeleteTransport", self._client._transport)
712
+ response = self._client.auth._session_request(
713
+ lambda token: invoke(
682
714
  transport.delete_storage_object,
683
- authorization=authorization,
715
+ authorization=token,
684
716
  bucket_name=self._name,
685
717
  path=path,
686
- )
687
- response_payload(response, 200)
688
- return path_list
718
+ ),
719
+ binding=binding,
720
+ )
721
+ response_payload(response, 200)
689
722
 
690
723
  def move(self, from_path: str, to_path: str) -> StorageObject:
691
724
  """Move or rename an object within this bucket."""
692
725
  source, destination = _storage_paths((from_path, to_path))
693
726
  transport = cast("StorageMoveTransport", self._client._transport)
694
- response = invoke(
695
- transport.move_storage_object,
696
- authorization=self._client._session_token(),
697
- bucket_name=self._name,
698
- from_path=source,
699
- to_path=destination,
727
+ response = self._client.auth._session_request(
728
+ lambda token: invoke(
729
+ transport.move_storage_object,
730
+ authorization=token,
731
+ bucket_name=self._name,
732
+ from_path=source,
733
+ to_path=destination,
734
+ )
700
735
  )
701
736
  return _storage_object(response_payload(response, 200))
702
737
 
@@ -704,12 +739,14 @@ class StorageBucket:
704
739
  """Copy an object to another path within this bucket."""
705
740
  source, destination = _storage_paths((from_path, to_path))
706
741
  transport = cast("StorageCopyTransport", self._client._transport)
707
- response = invoke(
708
- transport.copy_storage_object,
709
- authorization=self._client._session_token(),
710
- bucket_name=self._name,
711
- from_path=source,
712
- to_path=destination,
742
+ response = self._client.auth._session_request(
743
+ lambda token: invoke(
744
+ transport.copy_storage_object,
745
+ authorization=token,
746
+ bucket_name=self._name,
747
+ from_path=source,
748
+ to_path=destination,
749
+ )
713
750
  )
714
751
  return _storage_object(response_payload(response, 201))
715
752
 
@@ -718,12 +755,14 @@ class StorageBucket:
718
755
  object_path = _storage_paths(path)[0]
719
756
  visibility = _storage_visibility(is_public)
720
757
  transport = cast("StorageVisibilityTransport", self._client._transport)
721
- response = invoke(
722
- transport.update_storage_object_visibility,
723
- authorization=self._client._session_token(),
724
- bucket_name=self._name,
725
- path=object_path,
726
- is_public=visibility,
758
+ response = self._client.auth._session_request(
759
+ lambda token: invoke(
760
+ transport.update_storage_object_visibility,
761
+ authorization=token,
762
+ bucket_name=self._name,
763
+ path=object_path,
764
+ is_public=visibility,
765
+ )
727
766
  )
728
767
  return _storage_object(response_payload(response, 200))
729
768
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: volcano-sdk-python
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: Official Python SDK for Volcano
5
5
  Project-URL: Homepage, https://volcano.dev
6
6
  Project-URL: Repository, https://github.com/Kong/volcano-sdk-python
@@ -33,6 +33,8 @@ python -m pip install volcano-sdk-python
33
33
 
34
34
  The [PyPI distribution](https://pypi.org/project/volcano-sdk-python/) is named
35
35
  `volcano-sdk-python`; import it as `volcano_sdk`.
36
+ The installed package includes inline type information for mypy and other
37
+ PEP 561-compatible type checkers.
36
38
 
37
39
  ## Try the contract facade
38
40
 
@@ -217,7 +219,8 @@ events. Pass `next_cursor` back as `cursor` to continue a search. `logs.activity
217
219
  returns immutable time buckets using the same resource selector and query syntax.
218
220
  Both methods require an active user session.
219
221
 
220
- Database selects, inserts, updates, deletes, and log reads refresh the captured
222
+ Database selects, inserts, updates, deletes, log reads, and authenticated storage
223
+ requests (including upload sessions and parts) refresh the captured
221
224
  session after an HTTP 401 and retry the same request once. Concurrent requests reuse a successful
222
225
  refresh for that session.
223
226
  Replacing or signing out the session before replay, or while replay is in flight,
@@ -5,7 +5,7 @@ volcano_sdk/_lock_renewer.py,sha256=tFo1ZeRiPKB5VSbW61uoMpNR67ZDYyMEe-dCjpAM3As,
5
5
  volcano_sdk/_lock_worker.py,sha256=QhSmwR0WcwgT-7ueJMlbCogLqOakQ5eRAtyWV74fgV0,3057
6
6
  volcano_sdk/_realtime_fetch_worker.py,sha256=zQTgFF4cIUBeAL4J2OpWAlz_sIynv2BLfu588EogAdo,9269
7
7
  volcano_sdk/_transport.py,sha256=apXZLuT9W17vO-7Ag2E289o2B-uL-Rndv_wRPm69x0I,55481
8
- volcano_sdk/auth.py,sha256=6TXpCZ0mPqluPh-nJSYUbjcryJTwZBz03zDSHuP1eZA,42262
8
+ volcano_sdk/auth.py,sha256=Uhw_jDQvE7AyAjAJ2Tf6qAgT7N0QLDyx8OkJ_u0fE8Q,42525
9
9
  volcano_sdk/client.py,sha256=KutjBUOEJyK73OibKilrcWazpWeXKEZYUehSAH8qxUE,10366
10
10
  volcano_sdk/connection_string.py,sha256=LlTZigsrCF4IfAqQ8SDTWJv35hnnzNu1MfeVv5JW-Kk,2331
11
11
  volcano_sdk/database.py,sha256=p_5OaqlBjKAtIUfKQCflXM_CGqokrVmpOMsp6KHiJ8A,9493
@@ -14,8 +14,9 @@ volcano_sdk/functions.py,sha256=zDeAKyCieNnI6wzb9iZMlg9_cbjaYWXYbXHb7jzCle4,1012
14
14
  volcano_sdk/locks.py,sha256=iWMhdbZQDw44ZNwENaZWu7WelakjpHhjYzKzufD7SNU,6932
15
15
  volcano_sdk/logs.py,sha256=lxORRQBvsnJ0BdMau19MXrIeig5_mEucQSyJ4F1CZxU,4666
16
16
  volcano_sdk/models.py,sha256=43zM6LQ9eJ3Hn6q9PiVSozSmOzPSr4m4OL8G8KVb-gg,8619
17
+ volcano_sdk/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
17
18
  volcano_sdk/realtime.py,sha256=VkxZyrC7PlddnCSv8wBBLVg4nPWjpyuGo1FoBWhpf6M,59295
18
- volcano_sdk/storage.py,sha256=bY4yNYPnavVeQtjZ99hCOFNuR_gPRg5a785lUu_MLXo,24724
19
+ volcano_sdk/storage.py,sha256=1bAgzGO-dhUCVG8B-5x40jenHeh68Id2csIJF57KSGk,26126
19
20
  volcano_sdk/_generated/__init__.py,sha256=ZlB8wMYdN6EjpUS5W_lX3jsxq9G1kOcmUr-j3Fccfn8,164
20
21
  volcano_sdk/_generated/client.py,sha256=GDzw6T2uRmPlUb1DImpBGxwy0dNbhmBknfvvIQW0GuU,12387
21
22
  volcano_sdk/_generated/errors.py,sha256=trp-p5qn1_JLRxGZhdHtICaNPaCrcDCe4TgIihBravk,546
@@ -772,7 +773,7 @@ volcano_sdk/_generated/models/usage_data_point.py,sha256=d4U08JbVTiIMM_l2BmRILL1
772
773
  volcano_sdk/_generated/models/variable.py,sha256=tvGDOMv77gW6j5skufnfrlNAhzCzA1F7nuPCQWx79yY,5926
773
774
  volcano_sdk/_generated/models/variable_deploy_source.py,sha256=G_aCiFHzQx8WhJFs0GvYZEFclfTrfkDvd3kT1e3vty8,463
774
775
  volcano_sdk/_generated/models/variable_status.py,sha256=THSsKBSiAYG4kAtBzGA4TZqxjgx8hdL0Q4qCdZfOj00,391
775
- volcano_sdk_python-0.7.0.dist-info/METADATA,sha256=UvxuStKj4B3uX6BtRlrXlfjXNQw4GaOe6vDVN6nKF9c,33273
776
- volcano_sdk_python-0.7.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
777
- volcano_sdk_python-0.7.0.dist-info/licenses/LICENSE,sha256=AIHJy-5MFqM8fHfuGFTTb9a8rvJGypcVgN4aZ-7XTWw,11387
778
- volcano_sdk_python-0.7.0.dist-info/RECORD,,
776
+ volcano_sdk_python-0.7.2.dist-info/METADATA,sha256=5NJwDw5xHBhxDWTB3V__IEGWbB49s8hj06lh7wnhYpA,33451
777
+ volcano_sdk_python-0.7.2.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
778
+ volcano_sdk_python-0.7.2.dist-info/licenses/LICENSE,sha256=AIHJy-5MFqM8fHfuGFTTb9a8rvJGypcVgN4aZ-7XTWw,11387
779
+ volcano_sdk_python-0.7.2.dist-info/RECORD,,