volcano-sdk-python 0.11.1__py3-none-any.whl → 0.11.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.
@@ -14,12 +14,12 @@ INVALID_LOG_RESPONSE = "Expected a complete log response"
14
14
  def response_values(payload: object) -> Mapping[str, object]:
15
15
  """Require a JSON object for the response envelope.
16
16
 
17
- Raises:
18
- TypeError: The response envelope is not an object.
19
-
20
17
  Returns:
21
18
  The response fields without normalizing their values.
22
19
 
20
+ Raises:
21
+ TypeError: The response envelope is not an object.
22
+
23
23
  """
24
24
  if not isinstance(payload, Mapping):
25
25
  raise TypeError(INVALID_LOG_RESPONSE)
@@ -29,12 +29,12 @@ def response_values(payload: object) -> Mapping[str, object]:
29
29
  def response_data(values: Mapping[str, object]) -> tuple[Mapping[str, JSONValue], ...]:
30
30
  """Require a list of objects without coercing empty mappings into lists.
31
31
 
32
- Raises:
33
- TypeError: The rows are not a list of objects.
34
-
35
32
  Returns:
36
33
  The validated rows in their original order.
37
34
 
35
+ Raises:
36
+ TypeError: The rows are not a list of objects.
37
+
38
38
  """
39
39
  raw_data = values.get("data")
40
40
  if not isinstance(raw_data, list):
@@ -48,12 +48,12 @@ def response_data(values: Mapping[str, object]) -> tuple[Mapping[str, JSONValue]
48
48
  def search_metadata(values: Mapping[str, object]) -> tuple[int, bool, str | None]:
49
49
  """Require search pagination fields without coercing their values.
50
50
 
51
- Raises:
52
- TypeError: Required metadata is missing or has an invalid type.
53
-
54
51
  Returns:
55
52
  The page limit, continuation flag, and optional cursor.
56
53
 
54
+ Raises:
55
+ TypeError: Required metadata is missing or has an invalid type.
56
+
57
57
  """
58
58
  limit = values.get("limit")
59
59
  has_more = values.get("has_more")
@@ -71,12 +71,12 @@ def search_metadata(values: Mapping[str, object]) -> tuple[int, bool, str | None
71
71
  def activity_total(values: Mapping[str, object]) -> int:
72
72
  """Require the activity total without treating booleans as integers.
73
73
 
74
- Raises:
75
- TypeError: The total is missing or is not an integer.
76
-
77
74
  Returns:
78
75
  The total reported by the server.
79
76
 
77
+ Raises:
78
+ TypeError: The total is missing or is not an integer.
79
+
80
80
  """
81
81
  total = values.get("total")
82
82
  if not isinstance(total, int) or isinstance(total, bool):
volcano_sdk/_transport.py CHANGED
@@ -7,7 +7,15 @@ from collections.abc import Mapping
7
7
  from dataclasses import dataclass
8
8
  from io import BytesIO
9
9
  from pathlib import PurePosixPath
10
- from typing import TYPE_CHECKING, Any, ParamSpec, Protocol, TypeVar, cast
10
+ from typing import (
11
+ TYPE_CHECKING,
12
+ Any,
13
+ ParamSpec,
14
+ Protocol,
15
+ TypeVar,
16
+ cast,
17
+ runtime_checkable,
18
+ )
11
19
  from uuid import UUID, uuid4
12
20
 
13
21
  import httpx
@@ -375,6 +383,7 @@ class _GeneratedTransportResponse:
375
383
  headers: Mapping[str, str]
376
384
 
377
385
 
386
+ @runtime_checkable
378
387
  class AuthRefreshTransport(Protocol):
379
388
  def auth_refresh(
380
389
  self,
@@ -384,6 +393,7 @@ class AuthRefreshTransport(Protocol):
384
393
  ) -> TransportResponse: ...
385
394
 
386
395
 
396
+ @runtime_checkable
387
397
  class AuthLogoutTransport(Protocol):
388
398
  def auth_logout(
389
399
  self,
@@ -393,6 +403,7 @@ class AuthLogoutTransport(Protocol):
393
403
  ) -> TransportResponse: ...
394
404
 
395
405
 
406
+ @runtime_checkable
396
407
  class AuthSignUpTransport(Protocol):
397
408
  def auth_signup(
398
409
  self,
@@ -404,6 +415,7 @@ class AuthSignUpTransport(Protocol):
404
415
  ) -> TransportResponse: ...
405
416
 
406
417
 
418
+ @runtime_checkable
407
419
  class AuthSignUpAnonymousTransport(Protocol):
408
420
  def auth_signup_anonymous(
409
421
  self,
@@ -413,6 +425,7 @@ class AuthSignUpAnonymousTransport(Protocol):
413
425
  ) -> TransportResponse: ...
414
426
 
415
427
 
428
+ @runtime_checkable
416
429
  class AuthConvertAnonymousTransport(Protocol):
417
430
  def auth_convert_anonymous(
418
431
  self,
@@ -424,6 +437,7 @@ class AuthConvertAnonymousTransport(Protocol):
424
437
  ) -> TransportResponse: ...
425
438
 
426
439
 
440
+ @runtime_checkable
427
441
  class AuthForgotPasswordTransport(Protocol):
428
442
  def auth_forgot_password(
429
443
  self,
@@ -433,6 +447,7 @@ class AuthForgotPasswordTransport(Protocol):
433
447
  ) -> TransportResponse: ...
434
448
 
435
449
 
450
+ @runtime_checkable
436
451
  class AuthConfirmEmailTransport(Protocol):
437
452
  def auth_confirm_email(
438
453
  self,
@@ -442,6 +457,7 @@ class AuthConfirmEmailTransport(Protocol):
442
457
  ) -> TransportResponse: ...
443
458
 
444
459
 
460
+ @runtime_checkable
445
461
  class AuthResetPasswordTransport(Protocol):
446
462
  def auth_reset_password(
447
463
  self,
@@ -452,6 +468,7 @@ class AuthResetPasswordTransport(Protocol):
452
468
  ) -> TransportResponse: ...
453
469
 
454
470
 
471
+ @runtime_checkable
455
472
  class AuthResendConfirmationTransport(Protocol):
456
473
  def auth_resend_confirmation(
457
474
  self,
@@ -461,6 +478,7 @@ class AuthResendConfirmationTransport(Protocol):
461
478
  ) -> TransportResponse: ...
462
479
 
463
480
 
481
+ @runtime_checkable
464
482
  class AuthRequestEmailChangeTransport(Protocol):
465
483
  def auth_request_email_change(
466
484
  self,
@@ -470,6 +488,7 @@ class AuthRequestEmailChangeTransport(Protocol):
470
488
  ) -> TransportResponse: ...
471
489
 
472
490
 
491
+ @runtime_checkable
473
492
  class AuthCancelEmailChangeTransport(Protocol):
474
493
  def auth_cancel_email_change(
475
494
  self,
@@ -478,6 +497,7 @@ class AuthCancelEmailChangeTransport(Protocol):
478
497
  ) -> TransportResponse: ...
479
498
 
480
499
 
500
+ @runtime_checkable
481
501
  class AuthConfirmEmailChangeTransport(Protocol):
482
502
  def auth_confirm_email_change(
483
503
  self,
@@ -487,6 +507,7 @@ class AuthConfirmEmailChangeTransport(Protocol):
487
507
  ) -> TransportResponse: ...
488
508
 
489
509
 
510
+ @runtime_checkable
490
511
  class AuthDeleteAllMySessionsTransport(Protocol):
491
512
  def auth_delete_all_my_sessions(
492
513
  self,
@@ -495,6 +516,7 @@ class AuthDeleteAllMySessionsTransport(Protocol):
495
516
  ) -> TransportResponse: ...
496
517
 
497
518
 
519
+ @runtime_checkable
498
520
  class AuthDeleteMySessionTransport(Protocol):
499
521
  def auth_delete_my_session(
500
522
  self,
@@ -504,6 +526,7 @@ class AuthDeleteMySessionTransport(Protocol):
504
526
  ) -> TransportResponse: ...
505
527
 
506
528
 
529
+ @runtime_checkable
507
530
  class AuthGetMySessionsTransport(Protocol):
508
531
  def auth_get_my_sessions(
509
532
  self,
@@ -514,6 +537,7 @@ class AuthGetMySessionsTransport(Protocol):
514
537
  ) -> TransportResponse: ...
515
538
 
516
539
 
540
+ @runtime_checkable
517
541
  class AuthListOAuthProvidersTransport(Protocol):
518
542
  def auth_list_oauth_providers(
519
543
  self,
@@ -522,6 +546,7 @@ class AuthListOAuthProvidersTransport(Protocol):
522
546
  ) -> TransportResponse: ...
523
547
 
524
548
 
549
+ @runtime_checkable
525
550
  class AuthOAuthAuthorizationURLTransport(Protocol):
526
551
  def auth_oauth_authorization_url(
527
552
  self,
@@ -533,6 +558,7 @@ class AuthOAuthAuthorizationURLTransport(Protocol):
533
558
  ) -> str: ...
534
559
 
535
560
 
561
+ @runtime_checkable
536
562
  class AuthOAuthExchangeTransport(Protocol):
537
563
  def auth_oauth_exchange(
538
564
  self,
@@ -543,6 +569,7 @@ class AuthOAuthExchangeTransport(Protocol):
543
569
  ) -> TransportResponse: ...
544
570
 
545
571
 
572
+ @runtime_checkable
546
573
  class AuthLinkOAuthProviderTransport(Protocol):
547
574
  def auth_link_oauth_provider(
548
575
  self,
@@ -552,6 +579,7 @@ class AuthLinkOAuthProviderTransport(Protocol):
552
579
  ) -> TransportResponse: ...
553
580
 
554
581
 
582
+ @runtime_checkable
555
583
  class AuthUnlinkOAuthProviderTransport(Protocol):
556
584
  def auth_unlink_oauth_provider(
557
585
  self,
@@ -561,6 +589,7 @@ class AuthUnlinkOAuthProviderTransport(Protocol):
561
589
  ) -> TransportResponse: ...
562
590
 
563
591
 
592
+ @runtime_checkable
564
593
  class AuthGetOAuthProviderTokenTransport(Protocol):
565
594
  def auth_get_oauth_provider_token(
566
595
  self,
@@ -570,6 +599,7 @@ class AuthGetOAuthProviderTokenTransport(Protocol):
570
599
  ) -> TransportResponse: ...
571
600
 
572
601
 
602
+ @runtime_checkable
573
603
  class AuthRefreshOAuthProviderTokenTransport(Protocol):
574
604
  def auth_refresh_oauth_provider_token(
575
605
  self,
@@ -579,6 +609,7 @@ class AuthRefreshOAuthProviderTokenTransport(Protocol):
579
609
  ) -> TransportResponse: ...
580
610
 
581
611
 
612
+ @runtime_checkable
582
613
  class AuthCallOAuthAPITransport(Protocol):
583
614
  def auth_call_oauth_api(
584
615
  self,
@@ -591,10 +622,12 @@ class AuthCallOAuthAPITransport(Protocol):
591
622
  ) -> TransportResponse: ...
592
623
 
593
624
 
625
+ @runtime_checkable
594
626
  class AuthGetUserTransport(Protocol):
595
627
  def auth_get_user(self, *, authorization: str) -> TransportResponse: ...
596
628
 
597
629
 
630
+ @runtime_checkable
598
631
  class AuthUpdateUserTransport(Protocol):
599
632
  def auth_update_user(
600
633
  self,
@@ -685,6 +718,7 @@ class Transport(Protocol):
685
718
  ) -> TransportResponse: ...
686
719
 
687
720
 
721
+ @runtime_checkable
688
722
  class AsyncDatabaseSelectTransport(Protocol):
689
723
  """Async database query capability used by cancellable realtime fetches."""
690
724
 
volcano_sdk/auth.py CHANGED
@@ -108,6 +108,7 @@ _INVALID_LINKED_OAUTH_PROVIDERS = "Expected complete linked OAuth providers"
108
108
  _INVALID_OAUTH_LINK = "Expected an OAuth authorization URL"
109
109
  _INVALID_OAUTH_STATUS = "Expected complete OAuth provider token status"
110
110
  _INVALID_OAUTH_API_RESPONSE = "Expected OAuth provider API response data"
111
+ _INVALID_AUTH_TRANSPORT = "Transport does not support the requested auth operation"
111
112
  _INVALID_AUTH_CALLBACK = "callback must be callable"
112
113
  _INVALID_HOSTED_AUTH_PARAMETER = "Hosted auth parameters must be non-empty strings"
113
114
  _HOSTED_AUTH_STATE_MISMATCH = "Hosted auth state mismatch"
@@ -490,7 +491,7 @@ class Auth:
490
491
 
491
492
  def __init__(self, client: AuthContext) -> None:
492
493
  """Create an authentication facade backed by a client."""
493
- self._client = client
494
+ self._client: AuthContext = client
494
495
  self._rejected_refresh: tuple[int, SessionOperations] | None = None
495
496
 
496
497
  def get_session(self) -> Session | None:
@@ -542,9 +543,14 @@ class Auth:
542
543
  Returns:
543
544
  The sign-up acknowledgement, including a session if signed in.
544
545
 
546
+ Raises:
547
+ TypeError: The transport does not support this authentication operation.
548
+
545
549
  """
546
550
  generation, _ = self._client._capture_session()
547
- transport = cast("AuthSignUpTransport", self._client._transport)
551
+ transport = self._client._transport
552
+ if not isinstance(transport, AuthSignUpTransport):
553
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
548
554
  response = invoke(
549
555
  transport.auth_signup,
550
556
  authorization=self._client._anon_token(),
@@ -570,10 +576,13 @@ class Auth:
570
576
 
571
577
  Raises:
572
578
  SessionChangedError: The local session changed during sign-up.
579
+ TypeError: The transport does not support this authentication operation.
573
580
 
574
581
  """
575
582
  generation, _ = self._client._capture_session()
576
- transport = cast("AuthSignUpAnonymousTransport", self._client._transport)
583
+ transport = self._client._transport
584
+ if not isinstance(transport, AuthSignUpAnonymousTransport):
585
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
577
586
  response = invoke(
578
587
  transport.auth_signup_anonymous,
579
588
  authorization=self._client._anon_token(),
@@ -598,12 +607,15 @@ class Auth:
598
607
 
599
608
  Raises:
600
609
  AuthenticationError: There is no active session.
610
+ TypeError: The transport does not support this authentication operation.
601
611
 
602
612
  """
603
613
  binding = self._client._capture_session_binding()
604
614
  if binding[2] is None:
605
615
  raise AuthenticationError(_NO_ACTIVE_SESSION)
606
- transport = cast("AuthConvertAnonymousTransport", self._client._transport)
616
+ transport = self._client._transport
617
+ if not isinstance(transport, AuthConvertAnonymousTransport):
618
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
607
619
  request_metadata = deepcopy(dict(metadata or {}))
608
620
  response = self._session_request(
609
621
  lambda access_token: invoke(
@@ -618,14 +630,21 @@ class Auth:
618
630
  return self._update_current_user(response_payload(response, 200), binding)
619
631
 
620
632
  def reset_password_for_email(self, *, email: str) -> None:
621
- """Request a reset email without revealing whether the account exists."""
622
- transport = cast("AuthForgotPasswordTransport", self._client._transport)
633
+ """Request a reset email without revealing whether the account exists.
634
+
635
+ Raises:
636
+ TypeError: The transport does not support this authentication operation.
637
+
638
+ """
639
+ transport = self._client._transport
640
+ if not isinstance(transport, AuthForgotPasswordTransport):
641
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
623
642
  response = invoke(
624
643
  transport.auth_forgot_password,
625
644
  authorization=self._client._anon_token(),
626
645
  email=email,
627
646
  )
628
- response_payload(response, 200)
647
+ _ = response_payload(response, 200)
629
648
 
630
649
  def request_email_change(self, *, new_email: str) -> EmailChangeResult:
631
650
  """Request a confirmation email without changing the current session.
@@ -635,12 +654,15 @@ class Auth:
635
654
 
636
655
  Raises:
637
656
  AuthenticationError: There is no active session.
657
+ TypeError: The transport does not support this authentication operation.
638
658
 
639
659
  """
640
660
  binding = self._client._capture_session_binding()
641
661
  if binding[2] is None:
642
662
  raise AuthenticationError(_NO_ACTIVE_SESSION)
643
- transport = cast("AuthRequestEmailChangeTransport", self._client._transport)
663
+ transport = self._client._transport
664
+ if not isinstance(transport, AuthRequestEmailChangeTransport):
665
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
644
666
  response = self._session_request(
645
667
  lambda access_token: invoke(
646
668
  transport.auth_request_email_change,
@@ -650,7 +672,7 @@ class Auth:
650
672
  binding=binding,
651
673
  )
652
674
  result = _email_change_result_from_payload(response_payload(response, 200))
653
- self._owned_refresh_session(binding)
675
+ _ = self._owned_refresh_session(binding)
654
676
  return result
655
677
 
656
678
  def cancel_email_change(self) -> None:
@@ -658,12 +680,15 @@ class Auth:
658
680
 
659
681
  Raises:
660
682
  AuthenticationError: There is no active session.
683
+ TypeError: The transport does not support this authentication operation.
661
684
 
662
685
  """
663
686
  binding = self._client._capture_session_binding()
664
687
  if binding[2] is None:
665
688
  raise AuthenticationError(_NO_ACTIVE_SESSION)
666
- transport = cast("AuthCancelEmailChangeTransport", self._client._transport)
689
+ transport = self._client._transport
690
+ if not isinstance(transport, AuthCancelEmailChangeTransport):
691
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
667
692
  response = self._session_request(
668
693
  lambda access_token: invoke(
669
694
  transport.auth_cancel_email_change,
@@ -671,8 +696,8 @@ class Auth:
671
696
  ),
672
697
  binding=binding,
673
698
  )
674
- response_payload(response, 200)
675
- self._owned_refresh_session(binding)
699
+ _ = response_payload(response, 200)
700
+ _ = self._owned_refresh_session(binding)
676
701
 
677
702
  def confirm_email_change(self, *, token: str) -> User:
678
703
  """Confirm a pending email change and return the updated user.
@@ -682,12 +707,15 @@ class Auth:
682
707
 
683
708
  Raises:
684
709
  AuthenticationError: There is no active session.
710
+ TypeError: The transport does not support this authentication operation.
685
711
 
686
712
  """
687
713
  binding = self._client._capture_session_binding()
688
714
  if binding[2] is None:
689
715
  raise AuthenticationError(_NO_ACTIVE_SESSION)
690
- transport = cast("AuthConfirmEmailChangeTransport", self._client._transport)
716
+ transport = self._client._transport
717
+ if not isinstance(transport, AuthConfirmEmailChangeTransport):
718
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
691
719
  response = self._session_request(
692
720
  lambda access_token: invoke(
693
721
  transport.auth_confirm_email_change,
@@ -703,12 +731,15 @@ class Auth:
703
731
 
704
732
  Raises:
705
733
  AuthenticationError: There is no active session.
734
+ TypeError: The transport does not support this authentication operation.
706
735
 
707
736
  """
708
737
  binding = self._client._capture_session_binding()
709
738
  if binding[2] is None:
710
739
  raise AuthenticationError(_NO_ACTIVE_SESSION)
711
- transport = cast("AuthDeleteAllMySessionsTransport", self._client._transport)
740
+ transport = self._client._transport
741
+ if not isinstance(transport, AuthDeleteAllMySessionsTransport):
742
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
712
743
  response = self._session_request(
713
744
  lambda access_token: invoke(
714
745
  transport.auth_delete_all_my_sessions,
@@ -716,8 +747,8 @@ class Auth:
716
747
  ),
717
748
  binding=binding,
718
749
  )
719
- response_payload(response, 204)
720
- self._owned_refresh_session(binding)
750
+ _ = response_payload(response, 204)
751
+ _ = self._owned_refresh_session(binding)
721
752
 
722
753
  def list_sessions(self, *, page: int = 1, limit: int = 20) -> SessionPage:
723
754
  """List sessions in the stable offset-paginated activity order.
@@ -727,12 +758,15 @@ class Auth:
727
758
 
728
759
  Raises:
729
760
  AuthenticationError: There is no active session.
761
+ TypeError: The transport does not support this authentication operation.
730
762
 
731
763
  """
732
764
  binding = self._client._capture_session_binding()
733
765
  if binding[2] is None:
734
766
  raise AuthenticationError(_NO_ACTIVE_SESSION)
735
- transport = cast("AuthGetMySessionsTransport", self._client._transport)
767
+ transport = self._client._transport
768
+ if not isinstance(transport, AuthGetMySessionsTransport):
769
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
736
770
  response = self._session_request(
737
771
  lambda access_token: invoke(
738
772
  transport.auth_get_my_sessions,
@@ -743,7 +777,7 @@ class Auth:
743
777
  binding=binding,
744
778
  )
745
779
  result = _session_page_from_payload(response_payload(response, 200))
746
- self._owned_refresh_session(binding)
780
+ _ = self._owned_refresh_session(binding)
747
781
  return result
748
782
 
749
783
  def list_linked_oauth_providers(self) -> tuple[LinkedOAuthProvider, ...]:
@@ -754,12 +788,15 @@ class Auth:
754
788
 
755
789
  Raises:
756
790
  AuthenticationError: There is no active session.
791
+ TypeError: The transport does not support this authentication operation.
757
792
 
758
793
  """
759
794
  binding = self._client._capture_session_binding()
760
795
  if binding[2] is None:
761
796
  raise AuthenticationError(_NO_ACTIVE_SESSION)
762
- transport = cast("AuthListOAuthProvidersTransport", self._client._transport)
797
+ transport = self._client._transport
798
+ if not isinstance(transport, AuthListOAuthProvidersTransport):
799
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
763
800
  response = self._session_request(
764
801
  lambda access_token: invoke(
765
802
  transport.auth_list_oauth_providers,
@@ -768,7 +805,7 @@ class Auth:
768
805
  binding=binding,
769
806
  )
770
807
  result = _linked_oauth_providers_from_payload(response_payload(response, 200))
771
- self._owned_refresh_session(binding)
808
+ _ = self._owned_refresh_session(binding)
772
809
  return result
773
810
 
774
811
  def get_hosted_auth_url(
@@ -833,12 +870,14 @@ class Auth:
833
870
  Returns:
834
871
  The provider authorization URL containing the caller state.
835
872
 
873
+ Raises:
874
+ TypeError: The transport cannot start an OAuth sign-in flow.
875
+
836
876
  """
837
877
  provider_name = _oauth_provider_name(provider)
838
- transport = cast(
839
- "AuthOAuthAuthorizationURLTransport",
840
- self._client._transport,
841
- )
878
+ transport = self._client._transport
879
+ if not isinstance(transport, AuthOAuthAuthorizationURLTransport):
880
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
842
881
  return transport.auth_oauth_authorization_url(
843
882
  anon_key=self._client._anon_token(),
844
883
  provider=provider_name,
@@ -861,11 +900,14 @@ class Auth:
861
900
 
862
901
  Raises:
863
902
  SessionChangedError: The local session changed during the exchange.
903
+ TypeError: The transport does not support this authentication operation.
864
904
 
865
905
  """
866
906
  _validate_oauth_callback_state(state, expected_state)
867
907
  generation, _ = self._client._capture_session()
868
- transport = cast("AuthOAuthExchangeTransport", self._client._transport)
908
+ transport = self._client._transport
909
+ if not isinstance(transport, AuthOAuthExchangeTransport):
910
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
869
911
  response = invoke(
870
912
  transport.auth_oauth_exchange,
871
913
  authorization=self._client._anon_token(),
@@ -885,13 +927,16 @@ class Auth:
885
927
 
886
928
  Raises:
887
929
  AuthenticationError: There is no active session.
930
+ TypeError: The transport does not support this authentication operation.
888
931
 
889
932
  """
890
933
  provider_name = _oauth_provider_name(provider)
891
934
  binding = self._client._capture_session_binding()
892
935
  if binding[2] is None:
893
936
  raise AuthenticationError(_NO_ACTIVE_SESSION)
894
- transport = cast("AuthLinkOAuthProviderTransport", self._client._transport)
937
+ transport = self._client._transport
938
+ if not isinstance(transport, AuthLinkOAuthProviderTransport):
939
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
895
940
  response = self._session_request(
896
941
  lambda access_token: invoke(
897
942
  transport.auth_link_oauth_provider,
@@ -901,7 +946,7 @@ class Auth:
901
946
  binding=binding,
902
947
  )
903
948
  result = _oauth_link_from_payload(response_payload(response, 200))
904
- self._owned_refresh_session(binding)
949
+ _ = self._owned_refresh_session(binding)
905
950
  return result
906
951
 
907
952
  def unlink_oauth_provider(self, *, provider: OAuthProviderName) -> None:
@@ -909,16 +954,16 @@ class Auth:
909
954
 
910
955
  Raises:
911
956
  AuthenticationError: There is no active session.
957
+ TypeError: The transport cannot unlink an OAuth provider.
912
958
 
913
959
  """
914
960
  provider_name = _oauth_provider_name(provider)
915
961
  binding = self._client._capture_session_binding()
916
962
  if binding[2] is None:
917
963
  raise AuthenticationError(_NO_ACTIVE_SESSION)
918
- transport = cast(
919
- "AuthUnlinkOAuthProviderTransport",
920
- self._client._transport,
921
- )
964
+ transport = self._client._transport
965
+ if not isinstance(transport, AuthUnlinkOAuthProviderTransport):
966
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
922
967
  response = self._session_request(
923
968
  lambda access_token: invoke(
924
969
  transport.auth_unlink_oauth_provider,
@@ -927,8 +972,8 @@ class Auth:
927
972
  ),
928
973
  binding=binding,
929
974
  )
930
- response_payload(response, 204)
931
- self._owned_refresh_session(binding)
975
+ _ = response_payload(response, 204)
976
+ _ = self._owned_refresh_session(binding)
932
977
 
933
978
  def get_oauth_provider_token(
934
979
  self,
@@ -942,16 +987,16 @@ class Auth:
942
987
 
943
988
  Raises:
944
989
  AuthenticationError: There is no active session.
990
+ TypeError: The transport cannot read OAuth provider token status.
945
991
 
946
992
  """
947
993
  provider_name = _oauth_provider_name(provider)
948
994
  binding = self._client._capture_session_binding()
949
995
  if binding[2] is None:
950
996
  raise AuthenticationError(_NO_ACTIVE_SESSION)
951
- transport = cast(
952
- "AuthGetOAuthProviderTokenTransport",
953
- self._client._transport,
954
- )
997
+ transport = self._client._transport
998
+ if not isinstance(transport, AuthGetOAuthProviderTokenTransport):
999
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
955
1000
  response = self._session_request(
956
1001
  lambda access_token: invoke(
957
1002
  transport.auth_get_oauth_provider_token,
@@ -963,7 +1008,7 @@ class Auth:
963
1008
  result = _oauth_provider_token_status_from_payload(
964
1009
  response_payload(response, 200)
965
1010
  )
966
- self._owned_refresh_session(binding)
1011
+ _ = self._owned_refresh_session(binding)
967
1012
  return result
968
1013
 
969
1014
  def refresh_oauth_provider_token(
@@ -978,16 +1023,16 @@ class Auth:
978
1023
 
979
1024
  Raises:
980
1025
  AuthenticationError: There is no active session.
1026
+ TypeError: The transport cannot refresh an OAuth provider token.
981
1027
 
982
1028
  """
983
1029
  provider_name = _oauth_provider_name(provider)
984
1030
  binding = self._client._capture_session_binding()
985
1031
  if binding[2] is None:
986
1032
  raise AuthenticationError(_NO_ACTIVE_SESSION)
987
- transport = cast(
988
- "AuthRefreshOAuthProviderTokenTransport",
989
- self._client._transport,
990
- )
1033
+ transport = self._client._transport
1034
+ if not isinstance(transport, AuthRefreshOAuthProviderTokenTransport):
1035
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
991
1036
  response = self._session_request(
992
1037
  lambda access_token: invoke(
993
1038
  transport.auth_refresh_oauth_provider_token,
@@ -999,7 +1044,7 @@ class Auth:
999
1044
  result = _oauth_provider_token_status_from_payload(
1000
1045
  response_payload(response, 200)
1001
1046
  )
1002
- self._owned_refresh_session(binding)
1047
+ _ = self._owned_refresh_session(binding)
1003
1048
  return result
1004
1049
 
1005
1050
  def call_oauth_api(
@@ -1017,6 +1062,7 @@ class Auth:
1017
1062
 
1018
1063
  Raises:
1019
1064
  AuthenticationError: There is no active session.
1065
+ TypeError: The transport does not support this authentication operation.
1020
1066
 
1021
1067
  """
1022
1068
  provider_name = _oauth_provider_name(provider)
@@ -1024,7 +1070,9 @@ class Auth:
1024
1070
  binding = self._client._capture_session_binding()
1025
1071
  if binding[2] is None:
1026
1072
  raise AuthenticationError(_NO_ACTIVE_SESSION)
1027
- transport = cast("AuthCallOAuthAPITransport", self._client._transport)
1073
+ transport = self._client._transport
1074
+ if not isinstance(transport, AuthCallOAuthAPITransport):
1075
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1028
1076
  request_body = deepcopy(dict(body)) if body is not None else None
1029
1077
  response = self._session_request(
1030
1078
  lambda access_token: invoke(
@@ -1038,7 +1086,7 @@ class Auth:
1038
1086
  binding=binding,
1039
1087
  )
1040
1088
  result = _oauth_api_data_from_payload(response_payload(response, 200))
1041
- self._owned_refresh_session(binding)
1089
+ _ = self._owned_refresh_session(binding)
1042
1090
  return result
1043
1091
 
1044
1092
  def delete_session(self, *, session_id: str) -> None:
@@ -1048,6 +1096,7 @@ class Auth:
1048
1096
  AuthenticationError: There is no active session.
1049
1097
  SessionChangedError: The local session changed during deletion.
1050
1098
  TransportError: The deletion request failed before a usable response.
1099
+ TypeError: The transport does not support this authentication operation.
1051
1100
 
1052
1101
  """
1053
1102
  binding = self._client._capture_session_binding()
@@ -1059,7 +1108,9 @@ class Auth:
1059
1108
  current_session_id is not None
1060
1109
  and current_session_id.casefold() == session_id.casefold()
1061
1110
  )
1062
- transport = cast("AuthDeleteMySessionTransport", self._client._transport)
1111
+ transport = self._client._transport
1112
+ if not isinstance(transport, AuthDeleteMySessionTransport):
1113
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1063
1114
  try:
1064
1115
  response = self._session_request(
1065
1116
  lambda access_token: invoke(
@@ -1069,7 +1120,7 @@ class Auth:
1069
1120
  ),
1070
1121
  binding=binding,
1071
1122
  )
1072
- response_payload(response, 204)
1123
+ _ = response_payload(response, 204)
1073
1124
  except TransportError as error:
1074
1125
  if deletes_current and not self._client._clear_session_if_current(
1075
1126
  generation, lineage=lineage
@@ -1094,35 +1145,56 @@ class Auth:
1094
1145
  raise SessionChangedError
1095
1146
 
1096
1147
  def confirm_email(self, *, token: str) -> None:
1097
- """Confirm an email with its token without changing local state."""
1098
- transport = cast("AuthConfirmEmailTransport", self._client._transport)
1148
+ """Confirm an email with its token without changing local state.
1149
+
1150
+ Raises:
1151
+ TypeError: The transport does not support this authentication operation.
1152
+
1153
+ """
1154
+ transport = self._client._transport
1155
+ if not isinstance(transport, AuthConfirmEmailTransport):
1156
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1099
1157
  response = invoke(
1100
1158
  transport.auth_confirm_email,
1101
1159
  authorization=self._client._anon_token(),
1102
1160
  token=token,
1103
1161
  )
1104
- response_payload(response, 200)
1162
+ _ = response_payload(response, 200)
1105
1163
 
1106
1164
  def resend_confirmation(self, *, email: str) -> None:
1107
- """Request a generic confirmation resend without changing local state."""
1108
- transport = cast("AuthResendConfirmationTransport", self._client._transport)
1165
+ """Request a generic confirmation resend without changing local state.
1166
+
1167
+ Raises:
1168
+ TypeError: The transport does not support this authentication operation.
1169
+
1170
+ """
1171
+ transport = self._client._transport
1172
+ if not isinstance(transport, AuthResendConfirmationTransport):
1173
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1109
1174
  response = invoke(
1110
1175
  transport.auth_resend_confirmation,
1111
1176
  authorization=self._client._anon_token(),
1112
1177
  email=email,
1113
1178
  )
1114
- response_payload(response, 200)
1179
+ _ = response_payload(response, 200)
1115
1180
 
1116
1181
  def reset_password(self, *, token: str, new_password: str) -> None:
1117
- """Set a new password with a recovery token without changing local state."""
1118
- transport = cast("AuthResetPasswordTransport", self._client._transport)
1182
+ """Set a new password with a recovery token without changing local state.
1183
+
1184
+ Raises:
1185
+ TypeError: The transport does not support this authentication operation.
1186
+
1187
+ """
1188
+ transport = self._client._transport
1189
+ if not isinstance(transport, AuthResetPasswordTransport):
1190
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1119
1191
  response = invoke(
1120
1192
  transport.auth_reset_password,
1121
1193
  authorization=self._client._anon_token(),
1122
1194
  token=token,
1123
1195
  new_password=new_password,
1124
1196
  )
1125
- response_payload(response, 200)
1197
+ _ = response_payload(response, 200)
1126
1198
 
1127
1199
  def _update_current_user(
1128
1200
  self, payload: object, binding: tuple[int, SessionOperations, Session | None]
@@ -1141,12 +1213,15 @@ class Auth:
1141
1213
 
1142
1214
  Raises:
1143
1215
  AuthenticationError: There is no active session.
1216
+ TypeError: The transport does not support this authentication operation.
1144
1217
 
1145
1218
  """
1146
1219
  binding = self._client._capture_session_binding()
1147
1220
  if binding[2] is None:
1148
1221
  raise AuthenticationError(_NO_ACTIVE_SESSION)
1149
- transport = cast("AuthGetUserTransport", self._client._transport)
1222
+ transport = self._client._transport
1223
+ if not isinstance(transport, AuthGetUserTransport):
1224
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1150
1225
  response = self._session_request(
1151
1226
  lambda access_token: invoke(
1152
1227
  transport.auth_get_user, authorization=access_token
@@ -1168,12 +1243,15 @@ class Auth:
1168
1243
 
1169
1244
  Raises:
1170
1245
  AuthenticationError: There is no active session.
1246
+ TypeError: The transport does not support this authentication operation.
1171
1247
 
1172
1248
  """
1173
1249
  binding = self._client._capture_session_binding()
1174
1250
  if binding[2] is None:
1175
1251
  raise AuthenticationError(_NO_ACTIVE_SESSION)
1176
- transport = cast("AuthUpdateUserTransport", self._client._transport)
1252
+ transport = self._client._transport
1253
+ if not isinstance(transport, AuthUpdateUserTransport):
1254
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1177
1255
  request_metadata = None if metadata is None else deepcopy(dict(metadata))
1178
1256
  response = self._session_request(
1179
1257
  lambda access_token: invoke(
@@ -1248,7 +1326,7 @@ class Auth:
1248
1326
  rejected_response: TransportResponse,
1249
1327
  ) -> TransportResponse:
1250
1328
  try:
1251
- self._refresh_session_for_binding(binding)
1329
+ _ = self._refresh_session_for_binding(binding)
1252
1330
  except SessionChangedError:
1253
1331
  raise
1254
1332
  except VolcanoError:
@@ -1256,14 +1334,14 @@ class Auth:
1256
1334
  return rejected_response
1257
1335
  session = self._owned_refresh_session(binding)[2]
1258
1336
  response = operation(session.access_token)
1259
- self._owned_refresh_session(binding)
1337
+ _ = self._owned_refresh_session(binding)
1260
1338
  return response
1261
1339
 
1262
1340
  def _validate_read_failure(
1263
1341
  self, binding: tuple[int, SessionOperations, Session | None]
1264
1342
  ) -> None:
1265
1343
  with suppress(AuthenticationError):
1266
- self._owned_refresh_session(binding)
1344
+ _ = self._owned_refresh_session(binding)
1267
1345
 
1268
1346
  def _refresh_session_for_binding(
1269
1347
  self, binding: tuple[int, SessionOperations, Session | None]
@@ -1275,7 +1353,7 @@ class Auth:
1275
1353
  try:
1276
1354
  active_generation, _, _ = self._owned_refresh_session(binding)
1277
1355
  if active_generation == generation:
1278
- owner.refresh(
1356
+ _ = owner.refresh(
1279
1357
  lambda: self._perform_refresh(binding, current, notifications)
1280
1358
  )
1281
1359
  if owner.signing_out is not None:
@@ -1324,7 +1402,7 @@ class Auth:
1324
1402
  validate_refresh_identity(current, refreshed)
1325
1403
  owner.verify_pair(refreshed)
1326
1404
  if owner.signing_out is None:
1327
- self._client._set_session_if_current(
1405
+ _ = self._client._set_session_if_current(
1328
1406
  refreshed,
1329
1407
  generation,
1330
1408
  event="TOKEN_REFRESHED",
@@ -1356,7 +1434,9 @@ class Auth:
1356
1434
  raise
1357
1435
 
1358
1436
  def _request_refreshed_session(self, refresh_token: str) -> Session:
1359
- transport = cast("AuthRefreshTransport", self._client._transport)
1437
+ transport = self._client._transport
1438
+ if not isinstance(transport, AuthRefreshTransport):
1439
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1360
1440
  try:
1361
1441
  response = invoke(
1362
1442
  transport.auth_refresh,
@@ -1427,7 +1507,9 @@ class Auth:
1427
1507
  if refresh_error is not None and not verified:
1428
1508
  raise refresh_error
1429
1509
  if session.refresh_token is not None:
1430
- transport = cast("AuthLogoutTransport", self._client._transport)
1510
+ transport = self._client._transport
1511
+ if not isinstance(transport, AuthLogoutTransport):
1512
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1431
1513
  response = invoke(
1432
1514
  transport.auth_logout,
1433
1515
  authorization=self._client._anon_token(),
@@ -1435,7 +1517,7 @@ class Auth:
1435
1517
  )
1436
1518
  else:
1437
1519
  return
1438
- response_payload(response, 204)
1520
+ _ = response_payload(response, 204)
1439
1521
 
1440
1522
  def _revoke_access_session(
1441
1523
  self,
@@ -1445,7 +1527,9 @@ class Auth:
1445
1527
  *,
1446
1528
  joined: bool,
1447
1529
  ) -> None:
1448
- transport = cast("AuthDeleteMySessionTransport", self._client._transport)
1530
+ transport = self._client._transport
1531
+ if not isinstance(transport, AuthDeleteMySessionTransport):
1532
+ raise TypeError(_INVALID_AUTH_TRANSPORT)
1449
1533
  response = invoke(
1450
1534
  transport.auth_delete_my_session,
1451
1535
  authorization=session.access_token,
@@ -1465,7 +1549,7 @@ class Auth:
1465
1549
  authorization=refreshed.access_token,
1466
1550
  session_id=session_id,
1467
1551
  )
1468
- response_payload(response, 204)
1552
+ _ = response_payload(response, 204)
1469
1553
 
1470
1554
 
1471
1555
  def _dispatch_notifications(notifications: list[Callable[[], None]]) -> None:
@@ -205,11 +205,21 @@ class _Engine:
205
205
  return cls._loaded
206
206
 
207
207
  def seconds(self, value: int) -> EngineDuration:
208
- """Build the runtime's duration from whole seconds."""
208
+ """Build the runtime's duration from whole seconds.
209
+
210
+ Returns:
211
+ The runtime duration.
212
+
213
+ """
209
214
  return self.duration.from_seconds(value)
210
215
 
211
216
  def step_options(self, *, retry: Retry, at_most_once: bool) -> StepConfig:
212
- """Build the runtime's step options."""
217
+ """Build the runtime's step options.
218
+
219
+ Returns:
220
+ The runtime step configuration.
221
+
222
+ """
213
223
  config: dict[str, Any] = {}
214
224
  if at_most_once:
215
225
  config["step_semantics"] = self.step_semantics.AT_MOST_ONCE_PER_RETRY
@@ -258,7 +268,12 @@ class _Engine:
258
268
  return None if value is None else self.seconds(_to_seconds(value, field_name))
259
269
 
260
270
  def wait_condition_options(self, options: WaitUntilOptions) -> object:
261
- """Build the runtime's polling options."""
271
+ """Build the runtime's polling options.
272
+
273
+ Returns:
274
+ The runtime wait condition configuration.
275
+
276
+ """
262
277
  until = options.until
263
278
 
264
279
  def keep_polling(state: Any) -> bool:
@@ -288,15 +303,30 @@ class _Engine:
288
303
  return config
289
304
 
290
305
  def map_options(self, options: BatchOptions | None) -> object:
291
- """Build the runtime's map options."""
306
+ """Build the runtime's map options.
307
+
308
+ Returns:
309
+ The runtime map configuration.
310
+
311
+ """
292
312
  return self.map_config(**self._batch_options(options))
293
313
 
294
314
  def parallel_options(self, options: BatchOptions | None) -> ParallelConfig:
295
- """Build the runtime's parallel options."""
315
+ """Build the runtime's parallel options.
316
+
317
+ Returns:
318
+ The runtime parallel configuration.
319
+
320
+ """
296
321
  return self.parallel_config(**self._batch_options(options))
297
322
 
298
323
  def named_branch(self, run: Callable[[object], object], name: str | None) -> object:
299
- """Build a named runtime branch."""
324
+ """Build a named runtime branch.
325
+
326
+ Returns:
327
+ The runtime branch.
328
+
329
+ """
300
330
  return self.parallel_branch(func=run, name=name)
301
331
 
302
332
 
volcano_sdk/locks.py CHANGED
@@ -143,6 +143,11 @@ class Locks:
143
143
  LockState
144
144
  Whether the lock is held, with its expiry and fencing token if set.
145
145
 
146
+ Raises
147
+ ------
148
+ TypeError
149
+ The transport lacks lock inspection or the response is incomplete.
150
+
146
151
  """
147
152
  transport = self._client._transport
148
153
  if not isinstance(transport, LockGetTransport):
@@ -237,6 +242,11 @@ class Locks:
237
242
  An immutable replacement with the server's updated expiry and the
238
243
  same ownership and fencing tokens.
239
244
 
245
+ Raises
246
+ ------
247
+ TypeError
248
+ The transport does not support this lock operation.
249
+
240
250
  """
241
251
  _validate_ttl(ttl)
242
252
  transport = self._client._transport
@@ -273,7 +283,12 @@ class Locks:
273
283
  _ = response_payload(response, 204)
274
284
 
275
285
  def force_release(self, key: str, *, request_id: str | None = None) -> None:
276
- """Release a lock regardless of which token owns it."""
286
+ """Release a lock regardless of which token owns it.
287
+
288
+ Raises:
289
+ TypeError: The transport does not support this lock operation.
290
+
291
+ """
277
292
  transport = self._client._transport
278
293
  if not isinstance(transport, LockForceReleaseTransport):
279
294
  raise TypeError(_INVALID_LOCK_TRANSPORT)
volcano_sdk/realtime.py CHANGED
@@ -85,6 +85,7 @@ NO_ACTIVE_SESSION = "No active session"
85
85
  CONNECTION_SESSION_UNAVAILABLE = "Realtime connection has no session binding"
86
86
  CONNECTION_SESSION_CHANGED = "Realtime connection session changed"
87
87
  POSTGRES_FETCH_FAILED_MESSAGE = "Volcano realtime Postgres row fetch failed"
88
+ _POSTGRES_QUERY_UNAVAILABLE = "Transport does not support realtime Postgres row fetch"
88
89
 
89
90
 
90
91
  def _empty_presence_data() -> Mapping[str, JSONValue]:
@@ -1378,10 +1379,9 @@ class Realtime:
1378
1379
  ) -> tuple[dict[str, Any] | None, ...]:
1379
1380
  first = requests[0]
1380
1381
  row_ids = [request.row_id for request in requests]
1381
- transport = cast(
1382
- "AsyncDatabaseSelectTransport",
1383
- self._client_context._transport,
1384
- )
1382
+ transport = self._client_context._transport
1383
+ if not isinstance(transport, AsyncDatabaseSelectTransport):
1384
+ raise TypeError(_POSTGRES_QUERY_UNAVAILABLE)
1385
1385
  response = await invoke_async(
1386
1386
  transport.query_database_select_async,
1387
1387
  authorization=first.access_token,
volcano_sdk/storage.py CHANGED
@@ -63,6 +63,31 @@ _INVALID_STORAGE_TRANSPORT = (
63
63
  )
64
64
 
65
65
 
66
+ class BinaryReader(Protocol):
67
+ """Binary input required by upload operations, including read-only streams."""
68
+
69
+ def read(self, size: int = -1, /) -> bytes | None:
70
+ """Return bytes, or None when the source is temporarily unavailable."""
71
+ ...
72
+
73
+
74
+ @runtime_checkable
75
+ class SeekableBinaryReader(BinaryReader, Protocol):
76
+ """Optional stream capabilities used to avoid spooling seekable inputs."""
77
+
78
+ def seekable(self) -> bool:
79
+ """Report whether seeking is supported."""
80
+ ...
81
+
82
+ def tell(self) -> int:
83
+ """Return the current byte position."""
84
+ ...
85
+
86
+ def seek(self, offset: int, whence: int = 0, /) -> int:
87
+ """Move to a byte position and return it."""
88
+ ...
89
+
90
+
66
91
  def _optional_datetime(value: object) -> datetime | None:
67
92
  if value is None:
68
93
  return None
@@ -228,7 +253,9 @@ def _encoded_storage_path(path: str) -> str:
228
253
  return "/".join(quote(segment, safe="") for segment in segments)
229
254
 
230
255
 
231
- def _remaining_upload_bytes(source: BinaryIO) -> int | None:
256
+ def _remaining_upload_bytes(source: BinaryReader) -> int | None:
257
+ if not isinstance(source, SeekableBinaryReader):
258
+ return None
232
259
  try:
233
260
  if not source.seekable():
234
261
  return None
@@ -246,9 +273,9 @@ def _remaining_upload_bytes(source: BinaryIO) -> int | None:
246
273
  return remaining
247
274
 
248
275
 
249
- def _spool_upload_source(source: BinaryIO, target: BinaryIO) -> None:
276
+ def _spool_upload_source(source: BinaryReader, target: BinaryIO) -> None:
250
277
  while True:
251
- chunk = cast("bytes | None", source.read(_UPLOAD_SPOOL_READ_SIZE))
278
+ chunk = source.read(_UPLOAD_SPOOL_READ_SIZE)
252
279
  if chunk is None:
253
280
  raise BlockingIOError(_UPLOAD_SOURCE_UNAVAILABLE)
254
281
  if chunk == b"":
@@ -256,10 +283,10 @@ def _spool_upload_source(source: BinaryIO, target: BinaryIO) -> None:
256
283
  _ = target.write(chunk)
257
284
 
258
285
 
259
- def _read_upload_part(source: BinaryIO, part_size: int) -> bytes:
286
+ def _read_upload_part(source: BinaryReader, part_size: int) -> bytes:
260
287
  part = bytearray()
261
288
  while len(part) < part_size:
262
- chunk = cast("bytes | None", source.read(part_size - len(part)))
289
+ chunk = source.read(part_size - len(part))
263
290
  if chunk is None:
264
291
  raise BlockingIOError(_UPLOAD_SOURCE_UNAVAILABLE)
265
292
  if chunk == b"":
@@ -284,8 +311,8 @@ def _simple_upload_bytes(data: object) -> bytes:
284
311
 
285
312
  @contextmanager
286
313
  def _resumable_upload_source(
287
- data: bytes | BinaryIO,
288
- ) -> Generator[tuple[BinaryIO, int], None, None]:
314
+ data: bytes | BinaryReader,
315
+ ) -> Generator[tuple[BinaryReader, int], None, None]:
289
316
  if isinstance(data, bytes):
290
317
  with BytesIO(data) as source:
291
318
  yield source, len(data)
@@ -503,7 +530,7 @@ class StorageBucket:
503
530
  def upload(
504
531
  self,
505
532
  path: str,
506
- data: bytes | BinaryIO,
533
+ data: bytes | BinaryReader,
507
534
  *,
508
535
  content_type: str | None = None,
509
536
  ) -> dict[str, object]:
@@ -512,6 +539,9 @@ class StorageBucket:
512
539
  Returns:
513
540
  Server response fields describing the uploaded object.
514
541
 
542
+ Raises:
543
+ TypeError: The upload response is not an object.
544
+
515
545
  """
516
546
  mime_type = _upload_content_type(content_type)
517
547
  binding = self._client._capture_session_binding()
@@ -570,6 +600,9 @@ class StorageBucket:
570
600
  Returns:
571
601
  Session ID, server-selected part size and count, and expiry.
572
602
 
603
+ Raises:
604
+ TypeError: The transport does not support this storage operation.
605
+
573
606
  """
574
607
  transport = self._client._transport
575
608
  if not isinstance(transport, StorageUploadSessionTransport):
@@ -602,6 +635,9 @@ class StorageBucket:
602
635
  Returns:
603
636
  The accepted part number, ETag, and byte count.
604
637
 
638
+ Raises:
639
+ TypeError: The transport does not support this storage operation.
640
+
605
641
  """
606
642
  transport = self._client._transport
607
643
  if not isinstance(transport, StorageUploadPartTransport):
@@ -632,6 +668,9 @@ class StorageBucket:
632
668
  Returns:
633
669
  Metadata for the object assembled from the uploaded parts.
634
670
 
671
+ Raises:
672
+ TypeError: The transport does not support this storage operation.
673
+
635
674
  """
636
675
  transport = self._client._transport
637
676
  if not isinstance(transport, StorageCompleteUploadTransport):
@@ -661,6 +700,9 @@ class StorageBucket:
661
700
  Returns:
662
701
  Session state, byte and part counts, uploaded parts, and timestamps.
663
702
 
703
+ Raises:
704
+ TypeError: The transport does not support this storage operation.
705
+
664
706
  """
665
707
  transport = self._client._transport
666
708
  if not isinstance(transport, StorageUploadStatusTransport):
@@ -684,7 +726,12 @@ class StorageBucket:
684
726
  *,
685
727
  session_id: str,
686
728
  ) -> None:
687
- """Abort a resumable upload and discard its uploaded parts."""
729
+ """Abort a resumable upload and discard its uploaded parts.
730
+
731
+ Raises:
732
+ TypeError: The transport does not support this storage operation.
733
+
734
+ """
688
735
  transport = self._client._transport
689
736
  if not isinstance(transport, StorageAbortUploadTransport):
690
737
  raise TypeError(_INVALID_STORAGE_TRANSPORT)
@@ -704,7 +751,7 @@ class StorageBucket:
704
751
  def upload_resumable(
705
752
  self,
706
753
  path: str,
707
- data: bytes | BinaryIO,
754
+ data: bytes | BinaryReader,
708
755
  *,
709
756
  content_type: str = "application/octet-stream",
710
757
  part_size: int | None = None,
@@ -743,7 +790,7 @@ class StorageBucket:
743
790
  def _upload_session_parts(
744
791
  self,
745
792
  path: str,
746
- source: BinaryIO,
793
+ source: BinaryReader,
747
794
  session: UploadSession,
748
795
  total_size: int,
749
796
  on_progress: Callable[[int, int], None] | None,
@@ -777,6 +824,9 @@ class StorageBucket:
777
824
  Returns:
778
825
  An immutable object page whose next_cursor is None on the last page.
779
826
 
827
+ Raises:
828
+ TypeError: The transport does not support this storage operation.
829
+
780
830
  """
781
831
  transport = self._client._transport
782
832
  if not isinstance(transport, StorageListTransport):
@@ -829,6 +879,9 @@ class StorageBucket:
829
879
  Returns:
830
880
  Metadata for the object at its destination path.
831
881
 
882
+ Raises:
883
+ TypeError: The transport does not support this storage operation.
884
+
832
885
  """
833
886
  source, destination = _storage_paths((from_path, to_path))
834
887
  transport = self._client._transport
@@ -851,6 +904,9 @@ class StorageBucket:
851
904
  Returns:
852
905
  Metadata for the new copy at its destination path.
853
906
 
907
+ Raises:
908
+ TypeError: The transport does not support this storage operation.
909
+
854
910
  """
855
911
  source, destination = _storage_paths((from_path, to_path))
856
912
  transport = self._client._transport
@@ -873,6 +929,9 @@ class StorageBucket:
873
929
  Returns:
874
930
  Object metadata reflecting the updated visibility.
875
931
 
932
+ Raises:
933
+ TypeError: The transport does not support this storage operation.
934
+
876
935
  """
877
936
  object_path = _storage_paths(path)[0]
878
937
  visibility = _storage_visibility(is_public)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: volcano-sdk-python
3
- Version: 0.11.1
3
+ Version: 0.11.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
@@ -4,25 +4,25 @@ volcano_sdk/_function_resolution.py,sha256=6O40Lz80ZJs3WUD4w_RZVvGyo8gJsmFV3_D2q
4
4
  volcano_sdk/_lock_guard.py,sha256=Sr9CwANAoxhvI_3fdIAE_p1CS216PvP-eGjuFbV2oE0,6247
5
5
  volcano_sdk/_lock_renewer.py,sha256=cgogAmoRM_An-PdymXumuGmxm62MGqOsQU4c_PYlUjg,1000
6
6
  volcano_sdk/_lock_worker.py,sha256=IJ0TAFyKiLhS40j0LGLUcOnIrdaqCY3_ZVgETtXp0bc,3139
7
- volcano_sdk/_log_response.py,sha256=wZaugr0eD0ZLSa-M6TUEwdIDsI_wblyDXucYEwNK14c,2523
7
+ volcano_sdk/_log_response.py,sha256=k4o0vNPwNUu420EiZSg7Gx3eL6OlX3M4ilwfGtfs3tA,2523
8
8
  volcano_sdk/_realtime_fetch_worker.py,sha256=f3mUPe5qZmGuhA9jfpqEUtpLZmvlJ1FhI1XkNz238FI,10406
9
9
  volcano_sdk/_session.py,sha256=qiuAXTxo5Yz3AM2T_gqPWBD7TmKl2KhvfWwpsmu7h9g,3033
10
10
  volcano_sdk/_session_operations.py,sha256=MdEWU_SrS56jmYCzyH81jqneb_pbIaJJI8vFb2WZsJo,5807
11
- volcano_sdk/_transport.py,sha256=XcDk8NAEAHmtH3nmlMWIixcIiEFb-FP_n8VU44QcuXg,61907
12
- volcano_sdk/auth.py,sha256=OxK9s6XW9jNGA_cXos-cHEZYcmYsxrojruSyLS0mWVs,52237
11
+ volcano_sdk/_transport.py,sha256=8AbGvVACdE7JbEAMjv2uOCMJTkvpY_QIkjP3p0oPilo,62453
12
+ volcano_sdk/auth.py,sha256=dXQpzGWp2iyaoLOyUoGnVsYQn_od3EZiGd-_XegdiQo,56515
13
13
  volcano_sdk/client.py,sha256=xS4F3f24id8ZMPEY7FhLrmlj1v6cspBsBSylvWof5F0,12821
14
14
  volcano_sdk/connection_string.py,sha256=Qqo2w93WXMHGEp_ftSY0qY5S5fyB5ZIGfkldWrfIzfc,2668
15
15
  volcano_sdk/database.py,sha256=XuXGqlfEPvlOBB33jyTVNhRGe4vrgzOBne2rTRzkQis,13806
16
16
  volcano_sdk/durable.py,sha256=zdLKsapHg7o5jgG1XUGKD2r-6rpeUs7wUN58i-gTmWU,13887
17
- volcano_sdk/durable_authoring.py,sha256=92ENW366IdeP7P-ABqo-HB8V7YsG8KkE_ekVWnu9ZXU,36899
17
+ volcano_sdk/durable_authoring.py,sha256=DBB31rQqtJQqL7BtOiaEAsz75FeQ1tarUTG1ctftDN8,37322
18
18
  volcano_sdk/errors.py,sha256=ujND4F6E9OWr0-VLpuTdvnSZJPVhNUyHnvXJCDp39V0,1649
19
19
  volcano_sdk/functions.py,sha256=XcdihCueYA7dpANwTGsXF7LMoqka2ZRMpUG6c-lz2gI,13730
20
- volcano_sdk/locks.py,sha256=tC1Ku8bo58wUYTN05zzOFQhLiszuPgVA6qtTF5jUvmU,11324
20
+ volcano_sdk/locks.py,sha256=D9P50UiBg8WtXFTGpA1S7neaXJhbSy56nsujFTChYLI,11667
21
21
  volcano_sdk/logs.py,sha256=CwtBpUGqoi82xIQBnq31LJ0XrfDEsMK9Tig1_qOL4d4,4368
22
22
  volcano_sdk/models.py,sha256=ZIo2YdZ-Ba7rCmHBo3eV9LGjpEftVTeVmrrfq-zGujs,11182
23
23
  volcano_sdk/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
24
- volcano_sdk/realtime.py,sha256=qulBz-rUm8SFId_jt40z7Q-wDtTb572gi1SKMDqbAto,64213
25
- volcano_sdk/storage.py,sha256=ItsWADF2wkqriDnQJwLnRlz5vX8S75ojir03AYWYDJ8,29447
24
+ volcano_sdk/realtime.py,sha256=8SX8sPAQKJBWLVgRCHw0drFggO5nue6moyj2phghFzI,64352
25
+ volcano_sdk/storage.py,sha256=RLskrXnkVKldKPr90U8sZqgDMsdC-tjLftiDVafcXcw,31176
26
26
  volcano_sdk/_generated/__init__.py,sha256=ZlB8wMYdN6EjpUS5W_lX3jsxq9G1kOcmUr-j3Fccfn8,164
27
27
  volcano_sdk/_generated/client.py,sha256=GDzw6T2uRmPlUb1DImpBGxwy0dNbhmBknfvvIQW0GuU,12387
28
28
  volcano_sdk/_generated/errors.py,sha256=trp-p5qn1_JLRxGZhdHtICaNPaCrcDCe4TgIihBravk,546
@@ -810,7 +810,7 @@ volcano_sdk/_generated/models/usage_data_point.py,sha256=d4U08JbVTiIMM_l2BmRILL1
810
810
  volcano_sdk/_generated/models/variable.py,sha256=t8XaBfTwIH42L8RL4DFDtdqbhVfDEnRS5Axq2q6Tpvk,6405
811
811
  volcano_sdk/_generated/models/variable_deploy_source.py,sha256=G_aCiFHzQx8WhJFs0GvYZEFclfTrfkDvd3kT1e3vty8,463
812
812
  volcano_sdk/_generated/models/variable_status.py,sha256=THSsKBSiAYG4kAtBzGA4TZqxjgx8hdL0Q4qCdZfOj00,391
813
- volcano_sdk_python-0.11.1.dist-info/METADATA,sha256=Y1HYklYbJcKooBJEwg-_yXTLmd6a4FNh7LBXiBGtP9c,45774
814
- volcano_sdk_python-0.11.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
815
- volcano_sdk_python-0.11.1.dist-info/licenses/LICENSE,sha256=AIHJy-5MFqM8fHfuGFTTb9a8rvJGypcVgN4aZ-7XTWw,11387
816
- volcano_sdk_python-0.11.1.dist-info/RECORD,,
813
+ volcano_sdk_python-0.11.2.dist-info/METADATA,sha256=pPs--9XJYgPIghnP5m7VbRRVoDCnH_iAhzIi2oZSKiE,45774
814
+ volcano_sdk_python-0.11.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
815
+ volcano_sdk_python-0.11.2.dist-info/licenses/LICENSE,sha256=AIHJy-5MFqM8fHfuGFTTb9a8rvJGypcVgN4aZ-7XTWw,11387
816
+ volcano_sdk_python-0.11.2.dist-info/RECORD,,