google-api-core 2.40.0__tar.gz → 2.41.0__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.
- {google_api_core-2.40.0/google_api_core.egg-info → google_api_core-2.41.0}/PKG-INFO +1 -1
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/resumable_transfer/upload.py +15 -2
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/resumable_transfer/upload_async.py +182 -80
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/version.py +1 -1
- {google_api_core-2.40.0 → google_api_core-2.41.0/google_api_core.egg-info}/PKG-INFO +1 -1
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/test_resumable_transfer_async.py +302 -3
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/operations_v1/test_operations_rest_client.py +12 -16
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_resumable_transfer.py +109 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/LICENSE +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/MANIFEST.in +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/README.rst +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/_feature_gating_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/_observability.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/_python_package_support.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/_python_version_support.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/_rest_streaming_base.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/bidi.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/bidi_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/bidi_base.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/client_info.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/client_logging.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/client_options.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/datetime_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/exceptions.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/extended_operation.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/future/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/future/_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/future/async_future.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/future/base.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/future/polling.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/client_info.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/config.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/config_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/method.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/method_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/requests.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/gapic_v1/routing_header.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/general_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/grpc_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/grpc_helpers_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/iam.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operation.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operation_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/abstract_operations_base_client.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/abstract_operations_client.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/operations_async_client.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/operations_client.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/operations_client_config.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/operations_rest_client_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/pagers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/pagers_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/pagers_base.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/transports/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/transports/base.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/transports/rest.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/operations_v1/transports/rest_asyncio.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/page_iterator.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/page_iterator_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/path_template.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/protobuf_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/py.typed +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/rest_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/rest_streaming.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/rest_streaming_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/resumable_transfer/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/resumable_transfer/common.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/resumable_transfer/upload_state.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/retry/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/retry/retry_base.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/retry/retry_streaming.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/retry/retry_streaming_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/retry/retry_unary.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/retry/retry_unary_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/retry_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/timeout.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/universe.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/version_header.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google_api_core.egg-info/SOURCES.txt +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google_api_core.egg-info/dependency_links.txt +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google_api_core.egg-info/requires.txt +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/google_api_core.egg-info/top_level.txt +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/pyproject.toml +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/setup.cfg +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/setup.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/future/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/future/test_async_future.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/gapic/test_config_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/gapic/test_method_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/operations_v1/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/operations_v1/test_operations_async_client.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/retry/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/retry/test_retry_streaming_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/retry/test_retry_unary_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/test_bidi_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/test_grpc_helpers_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/test_operation_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/test_page_iterator_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/asyncio/test_rest_streaming_async.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/conftest.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/future/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/future/test__helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/future/test_polling.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/gapic/test_client_info.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/gapic/test_config.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/gapic/test_method.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/gapic/test_requests.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/gapic/test_routing_header.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/operations_v1/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/operations_v1/test_operations_client.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/retry/__init__.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/retry/test_retry_base.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/retry/test_retry_imports.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/retry/test_retry_streaming.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/retry/test_retry_unary.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_bidi.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_client_info.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_client_logging.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_client_options.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_datetime_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_exceptions.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_extended_operation.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_feature_gating_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_grpc_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_iam.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_observability.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_operation.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_packaging.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_page_iterator.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_path_template.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_protobuf_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_python_package_support.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_python_version_support.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_rest_helpers.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_rest_streaming.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_resumable_transfer_scenarios.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_timeout.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_universe.py +0 -0
- {google_api_core-2.40.0 → google_api_core-2.41.0}/tests/unit/test_version_header.py +0 -0
{google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/resumable_transfer/upload.py
RENAMED
|
@@ -105,6 +105,7 @@ class ResumableUploadSession:
|
|
|
105
105
|
response_type: Optional[Any] = None,
|
|
106
106
|
start_retry: Optional[google.api_core.retry.Retry] = None,
|
|
107
107
|
start_timeout: float = DEFAULT_START_TIMEOUT,
|
|
108
|
+
request_body: Optional[Union[str, bytes]] = None,
|
|
108
109
|
) -> None:
|
|
109
110
|
"""Initializes a ResumableUploadSession.
|
|
110
111
|
|
|
@@ -132,6 +133,9 @@ class ResumableUploadSession:
|
|
|
132
133
|
``UnseekableStreamError``) are never retried.
|
|
133
134
|
start_timeout: Timeout in seconds for the start request. Defaults to
|
|
134
135
|
``60.0`` seconds.
|
|
136
|
+
request_body: Optional default metadata payload sent with the start request.
|
|
137
|
+
Used by ``upload()`` and ``iter_upload()`` whenever they are called
|
|
138
|
+
without an explicit ``request_body``. When ``None``, an empty payload is sent.
|
|
135
139
|
"""
|
|
136
140
|
self._config = config or ResumableUploadConfig()
|
|
137
141
|
self._transport = transport
|
|
@@ -139,6 +143,9 @@ class ResumableUploadSession:
|
|
|
139
143
|
self._response_type = response_type
|
|
140
144
|
self._start_retry = start_retry
|
|
141
145
|
self._start_timeout = start_timeout
|
|
146
|
+
self._request_body: Union[str, bytes] = (
|
|
147
|
+
request_body if request_body is not None else ""
|
|
148
|
+
)
|
|
142
149
|
self._response: Optional[Any] = None
|
|
143
150
|
self._state = upload_state._ProtocolState(
|
|
144
151
|
upload_url=upload_url,
|
|
@@ -810,7 +817,7 @@ class ResumableUploadSession:
|
|
|
810
817
|
def upload(
|
|
811
818
|
self,
|
|
812
819
|
stream: Union[BinaryIO, bytes, Iterable[bytes]],
|
|
813
|
-
request_body: Union[str, bytes] =
|
|
820
|
+
request_body: Optional[Union[str, bytes]] = None,
|
|
814
821
|
size: Optional[int] = None,
|
|
815
822
|
transport: Optional[requests.Session] = None,
|
|
816
823
|
content_type: Optional[str] = None,
|
|
@@ -822,6 +829,8 @@ class ResumableUploadSession:
|
|
|
822
829
|
Args:
|
|
823
830
|
stream: Data payload to upload (file-like stream, bytes, or iterable of bytes).
|
|
824
831
|
request_body: Initial metadata payload sent with the start request.
|
|
832
|
+
When ``None``, the ``request_body`` supplied to the session constructor
|
|
833
|
+
(if any) is used.
|
|
825
834
|
size: Total stream size in bytes, if known.
|
|
826
835
|
transport: Optional requests session.
|
|
827
836
|
content_type: Optional MIME type of the stream payload.
|
|
@@ -859,7 +868,7 @@ class ResumableUploadSession:
|
|
|
859
868
|
def iter_upload(
|
|
860
869
|
self,
|
|
861
870
|
stream: Union[BinaryIO, bytes, Iterable[bytes]],
|
|
862
|
-
request_body: Union[str, bytes] =
|
|
871
|
+
request_body: Optional[Union[str, bytes]] = None,
|
|
863
872
|
size: Optional[int] = None,
|
|
864
873
|
transport: Optional[requests.Session] = None,
|
|
865
874
|
content_type: Optional[str] = None,
|
|
@@ -871,6 +880,8 @@ class ResumableUploadSession:
|
|
|
871
880
|
Args:
|
|
872
881
|
stream: Data payload to upload (file-like stream, bytes, or iterable of bytes).
|
|
873
882
|
request_body: Initial metadata payload sent with the start request.
|
|
883
|
+
When ``None``, the ``request_body`` supplied to the session constructor
|
|
884
|
+
(if any) is used.
|
|
874
885
|
size: Total stream size in bytes, if known.
|
|
875
886
|
transport: Optional requests session.
|
|
876
887
|
content_type: Optional MIME type of the stream payload.
|
|
@@ -896,6 +907,8 @@ class ResumableUploadSession:
|
|
|
896
907
|
sess = self._get_transport(transport)
|
|
897
908
|
if content_type is not None:
|
|
898
909
|
self._content_type = content_type
|
|
910
|
+
if request_body is None:
|
|
911
|
+
request_body = self._request_body
|
|
899
912
|
self._reset_transfer_state()
|
|
900
913
|
progress_queue: List[UploadProgress] = []
|
|
901
914
|
try:
|
{google_api_core-2.40.0 → google_api_core-2.41.0}/google/api_core/resumable_transfer/upload_async.py
RENAMED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
|
-
"""Asynchronous Resumable Upload session and helpers
|
|
15
|
+
"""Asynchronous Resumable Upload session and helpers."""
|
|
16
16
|
|
|
17
17
|
import asyncio
|
|
18
18
|
import datetime
|
|
@@ -28,6 +28,7 @@ from typing import (
|
|
|
28
28
|
Awaitable,
|
|
29
29
|
BinaryIO,
|
|
30
30
|
Callable,
|
|
31
|
+
Dict,
|
|
31
32
|
Generator,
|
|
32
33
|
Generic,
|
|
33
34
|
Iterable,
|
|
@@ -37,6 +38,7 @@ from typing import (
|
|
|
37
38
|
Tuple,
|
|
38
39
|
TypeVar,
|
|
39
40
|
Union,
|
|
41
|
+
cast,
|
|
40
42
|
)
|
|
41
43
|
|
|
42
44
|
try:
|
|
@@ -46,6 +48,14 @@ try:
|
|
|
46
48
|
except ImportError: # pragma: NO COVER
|
|
47
49
|
_HAS_AIOHTTP = False
|
|
48
50
|
|
|
51
|
+
try:
|
|
52
|
+
from google.auth import exceptions as auth_exceptions
|
|
53
|
+
from google.auth.aio.transport.sessions import AsyncAuthorizedSession
|
|
54
|
+
|
|
55
|
+
_HAS_GOOGLE_AUTH_AIO = True
|
|
56
|
+
except ImportError: # pragma: NO COVER
|
|
57
|
+
_HAS_GOOGLE_AUTH_AIO = False
|
|
58
|
+
|
|
49
59
|
import google.api_core.retry
|
|
50
60
|
from google.api_core import exceptions
|
|
51
61
|
from google.api_core.resumable_transfer import common, upload_state
|
|
@@ -60,6 +70,20 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
60
70
|
_monotonic_clock = time.monotonic
|
|
61
71
|
|
|
62
72
|
|
|
73
|
+
AsyncTransport = Union["aiohttp.ClientSession", "AsyncAuthorizedSession"]
|
|
74
|
+
"""Asynchronous HTTP transports accepted by :class:`AsyncResumableUploadSession`.
|
|
75
|
+
|
|
76
|
+
``google.auth.aio.transport.sessions.AsyncAuthorizedSession`` is the transport
|
|
77
|
+
used by generated asynchronous REST clients.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
# google-auth >= 2.49.0 accepts ``total_attempts`` to cap AsyncAuthorizedSession's
|
|
81
|
+
# own status-code retries; older releases forward unknown kwargs to aiohttp.
|
|
82
|
+
_HAS_TOTAL_ATTEMPTS = _HAS_GOOGLE_AUTH_AIO and (
|
|
83
|
+
"total_attempts" in inspect.signature(AsyncAuthorizedSession.request).parameters
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
63
87
|
def _get_buffer_size(stream: object) -> Optional[int]:
|
|
64
88
|
"""Returns buffer size in bytes if stream exposes getbuffer(), else None."""
|
|
65
89
|
getbuffer_fn = getattr(stream, "getbuffer", None)
|
|
@@ -166,11 +190,12 @@ class AsyncResumableUploadSession:
|
|
|
166
190
|
self,
|
|
167
191
|
upload_url: Optional[str] = None,
|
|
168
192
|
config: Optional[ResumableUploadConfig] = None,
|
|
169
|
-
transport: Optional[
|
|
193
|
+
transport: Optional[AsyncTransport] = None,
|
|
170
194
|
content_type: Optional[str] = None,
|
|
171
195
|
response_type: Optional[Any] = None,
|
|
172
196
|
start_retry: Optional[google.api_core.retry.AsyncRetry] = None,
|
|
173
197
|
start_timeout: float = DEFAULT_START_TIMEOUT,
|
|
198
|
+
request_body: Optional[Union[str, bytes]] = None,
|
|
174
199
|
) -> None:
|
|
175
200
|
"""Initializes an AsyncResumableUploadSession.
|
|
176
201
|
|
|
@@ -179,7 +204,7 @@ class AsyncResumableUploadSession:
|
|
|
179
204
|
new upload, or the pre-existing upload session URL when resuming.
|
|
180
205
|
config: Optional upload configuration parameters. Defaults to
|
|
181
206
|
``ResumableUploadConfig()`` when ``None``.
|
|
182
|
-
transport: Optional
|
|
207
|
+
transport: Optional :data:`AsyncTransport`. When ``None``, a
|
|
183
208
|
transport must be provided to ``upload()`` or ``resume()``.
|
|
184
209
|
content_type: Optional MIME type of the stream payload. When
|
|
185
210
|
``None``, no content-type header is sent unless overridden.
|
|
@@ -198,6 +223,9 @@ class AsyncResumableUploadSession:
|
|
|
198
223
|
retried.
|
|
199
224
|
start_timeout: Timeout in seconds for the start request. Defaults to
|
|
200
225
|
``60.0`` seconds.
|
|
226
|
+
request_body: Optional default metadata payload sent with the start request.
|
|
227
|
+
Used by ``upload()`` whenever it is called without an explicit
|
|
228
|
+
``request_body``. When ``None``, an empty payload is sent.
|
|
201
229
|
"""
|
|
202
230
|
self._config = config or ResumableUploadConfig()
|
|
203
231
|
self._transport = transport
|
|
@@ -205,6 +233,9 @@ class AsyncResumableUploadSession:
|
|
|
205
233
|
self._response_type = response_type
|
|
206
234
|
self._start_retry = start_retry
|
|
207
235
|
self._start_timeout = start_timeout
|
|
236
|
+
self._request_body: Union[str, bytes] = (
|
|
237
|
+
request_body if request_body is not None else ""
|
|
238
|
+
)
|
|
208
239
|
self._response: Optional[Any] = None
|
|
209
240
|
self._state = upload_state._ProtocolState(
|
|
210
241
|
upload_url=upload_url,
|
|
@@ -276,6 +307,93 @@ class AsyncResumableUploadSession:
|
|
|
276
307
|
"Please install google-api-core[async_rest]."
|
|
277
308
|
)
|
|
278
309
|
|
|
310
|
+
def _get_transport(self, transport: Optional[AsyncTransport]) -> AsyncTransport:
|
|
311
|
+
"""Returns the transport to use, raising ValueError when none is set."""
|
|
312
|
+
sess = transport or self._transport
|
|
313
|
+
if sess is None:
|
|
314
|
+
raise ValueError(
|
|
315
|
+
"An aiohttp.ClientSession or AsyncAuthorizedSession transport "
|
|
316
|
+
"must be provided."
|
|
317
|
+
)
|
|
318
|
+
return sess
|
|
319
|
+
|
|
320
|
+
async def _send_request(
|
|
321
|
+
self,
|
|
322
|
+
transport: AsyncTransport,
|
|
323
|
+
method: str,
|
|
324
|
+
url: str,
|
|
325
|
+
payload: bytes,
|
|
326
|
+
headers: Mapping[str, str],
|
|
327
|
+
timeout: float,
|
|
328
|
+
) -> Tuple[int, Mapping[str, str], bytes]:
|
|
329
|
+
"""Sends one request over ``transport`` and reads the whole response.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
transport: The transport to dispatch the request over.
|
|
333
|
+
method: HTTP method verb.
|
|
334
|
+
url: Request URL.
|
|
335
|
+
payload: Request body bytes.
|
|
336
|
+
headers: Request headers.
|
|
337
|
+
timeout: Total timeout in seconds for this attempt.
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
Tuple of (status code, response headers, response body bytes).
|
|
341
|
+
|
|
342
|
+
Raises:
|
|
343
|
+
exceptions.GoogleAPICallError: If the status is not 200 or 201.
|
|
344
|
+
asyncio.TimeoutError: If the attempt times out, whichever transport
|
|
345
|
+
is used.
|
|
346
|
+
"""
|
|
347
|
+
if _HAS_GOOGLE_AUTH_AIO and isinstance(transport, AsyncAuthorizedSession):
|
|
348
|
+
# google-auth applies its own overall deadline (``max_allowed_time``,
|
|
349
|
+
# 180s by default) on top of the per-request ``timeout``; use the
|
|
350
|
+
# caller's timeout for both. Where supported, a single attempt also
|
|
351
|
+
# disables google-auth's own status-code retries so that this module
|
|
352
|
+
# is the only retry layer.
|
|
353
|
+
retry_kwargs: Dict[str, Any] = (
|
|
354
|
+
{"total_attempts": 1} if _HAS_TOTAL_ATTEMPTS else {}
|
|
355
|
+
)
|
|
356
|
+
try:
|
|
357
|
+
response = await transport.request(
|
|
358
|
+
method,
|
|
359
|
+
url,
|
|
360
|
+
data=payload,
|
|
361
|
+
headers=headers,
|
|
362
|
+
timeout=timeout,
|
|
363
|
+
max_allowed_time=timeout,
|
|
364
|
+
**retry_kwargs,
|
|
365
|
+
)
|
|
366
|
+
try:
|
|
367
|
+
status_code = response.status_code
|
|
368
|
+
resp_headers: Mapping[str, str] = dict(response.headers)
|
|
369
|
+
body = await response.read()
|
|
370
|
+
finally:
|
|
371
|
+
await response.close()
|
|
372
|
+
except auth_exceptions.TimeoutError as exc:
|
|
373
|
+
# google-auth raises its own TimeoutError (not an asyncio one, and
|
|
374
|
+
# not reliably chained to one); re-raise it as asyncio.TimeoutError
|
|
375
|
+
# so stall control sees the same type as with aiohttp.ClientSession.
|
|
376
|
+
raise asyncio.TimeoutError(str(exc)) from exc
|
|
377
|
+
else:
|
|
378
|
+
# mypy cannot narrow the negative of the guarded check above.
|
|
379
|
+
session = cast("aiohttp.ClientSession", transport)
|
|
380
|
+
async with session.request(
|
|
381
|
+
method,
|
|
382
|
+
url,
|
|
383
|
+
data=payload,
|
|
384
|
+
headers=headers,
|
|
385
|
+
timeout=aiohttp.ClientTimeout(total=timeout),
|
|
386
|
+
) as resp:
|
|
387
|
+
status_code = resp.status
|
|
388
|
+
resp_headers = dict(resp.headers)
|
|
389
|
+
body = await resp.read()
|
|
390
|
+
|
|
391
|
+
if status_code not in (200, 201):
|
|
392
|
+
raise exceptions.from_http_status(
|
|
393
|
+
status_code, body.decode("utf-8", errors="replace")
|
|
394
|
+
)
|
|
395
|
+
return status_code, resp_headers, body
|
|
396
|
+
|
|
279
397
|
def _enrich_exception(self, exc: BaseException) -> None:
|
|
280
398
|
"""Attaches session diagnostic metadata to an active exception.
|
|
281
399
|
|
|
@@ -366,7 +484,9 @@ class AsyncResumableUploadSession:
|
|
|
366
484
|
``UnseekableStreamError``) always return ``False``.
|
|
367
485
|
2. Protocol-recoverable errors during chunk transfer
|
|
368
486
|
(``RECOVERABLE_STATUS_CODES`` and ``MissingStatusHeaderError``)
|
|
369
|
-
and transport errors (``aiohttp.ClientError
|
|
487
|
+
and transport errors (``aiohttp.ClientError``,
|
|
488
|
+
``google.auth.exceptions.TransportError``,
|
|
489
|
+
``google.auth.exceptions.ResponseError``, and
|
|
370
490
|
``asyncio.TimeoutError``) always return ``True`` so the session
|
|
371
491
|
can query server state and recover.
|
|
372
492
|
|
|
@@ -389,6 +509,10 @@ class AsyncResumableUploadSession:
|
|
|
389
509
|
_HAS_AIOHTTP and isinstance(exc, aiohttp.ClientError)
|
|
390
510
|
):
|
|
391
511
|
return True
|
|
512
|
+
if _HAS_GOOGLE_AUTH_AIO and isinstance(
|
|
513
|
+
exc, (auth_exceptions.TransportError, auth_exceptions.ResponseError)
|
|
514
|
+
):
|
|
515
|
+
return True
|
|
392
516
|
if (
|
|
393
517
|
custom_predicate is not None
|
|
394
518
|
and custom_predicate is not google.api_core.retry.if_transient_error
|
|
@@ -453,7 +577,7 @@ class AsyncResumableUploadSession:
|
|
|
453
577
|
|
|
454
578
|
async def _initiate(
|
|
455
579
|
self,
|
|
456
|
-
transport:
|
|
580
|
+
transport: AsyncTransport,
|
|
457
581
|
request_body: Union[str, bytes] = "",
|
|
458
582
|
size: Optional[int] = None,
|
|
459
583
|
progress_queue: Optional[List[UploadProgress]] = None,
|
|
@@ -462,7 +586,7 @@ class AsyncResumableUploadSession:
|
|
|
462
586
|
"""Initiates the upload session asynchronously.
|
|
463
587
|
|
|
464
588
|
Args:
|
|
465
|
-
transport: The
|
|
589
|
+
transport: The asynchronous transport to dispatch requests over.
|
|
466
590
|
request_body: Initial metadata payload sent with start request.
|
|
467
591
|
size: Total stream size in bytes, if known.
|
|
468
592
|
progress_queue: Optional queue to receive progress event.
|
|
@@ -483,21 +607,15 @@ class AsyncResumableUploadSession:
|
|
|
483
607
|
)
|
|
484
608
|
|
|
485
609
|
async def do_initiate() -> str:
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
resp.status, body.decode("utf-8", errors="replace")
|
|
496
|
-
)
|
|
497
|
-
session_url = self._state.process_start_response(
|
|
498
|
-
resp.status, resp_headers
|
|
499
|
-
)
|
|
500
|
-
return session_url
|
|
610
|
+
status_code, resp_headers, _ = await self._send_request(
|
|
611
|
+
transport,
|
|
612
|
+
method,
|
|
613
|
+
url,
|
|
614
|
+
payload,
|
|
615
|
+
headers,
|
|
616
|
+
timeout=self._get_start_timeout(),
|
|
617
|
+
)
|
|
618
|
+
return self._state.process_start_response(status_code, resp_headers)
|
|
501
619
|
|
|
502
620
|
retry_policy = self._get_async_retry()
|
|
503
621
|
retryable_initiate = retry_policy(do_initiate)
|
|
@@ -507,7 +625,7 @@ class AsyncResumableUploadSession:
|
|
|
507
625
|
|
|
508
626
|
async def _transmit_chunk(
|
|
509
627
|
self,
|
|
510
|
-
transport:
|
|
628
|
+
transport: AsyncTransport,
|
|
511
629
|
reader_fn: Callable[[int], Awaitable[bytes]],
|
|
512
630
|
size: Optional[int],
|
|
513
631
|
progress_queue: Optional[List[UploadProgress]] = None,
|
|
@@ -516,7 +634,7 @@ class AsyncResumableUploadSession:
|
|
|
516
634
|
"""Transmits the next data chunk asynchronously with stall control.
|
|
517
635
|
|
|
518
636
|
Args:
|
|
519
|
-
transport: The
|
|
637
|
+
transport: The asynchronous transport to dispatch requests over.
|
|
520
638
|
reader_fn: Async callable returning chunk bytes.
|
|
521
639
|
size: Total stream size in bytes, if known.
|
|
522
640
|
progress_queue: Optional queue to receive progress updates.
|
|
@@ -563,23 +681,16 @@ class AsyncResumableUploadSession:
|
|
|
563
681
|
per_attempt_timeout = self._compute_chunk_timeout(
|
|
564
682
|
data_len, timeout_override=timeout
|
|
565
683
|
)
|
|
566
|
-
client_timeout = aiohttp.ClientTimeout(total=per_attempt_timeout)
|
|
567
684
|
t_start = _monotonic_clock()
|
|
568
685
|
try:
|
|
569
|
-
|
|
686
|
+
status_code, resp_headers, resp_body = await self._send_request(
|
|
687
|
+
transport,
|
|
570
688
|
method,
|
|
571
689
|
url,
|
|
572
|
-
|
|
573
|
-
headers
|
|
574
|
-
timeout=
|
|
575
|
-
)
|
|
576
|
-
resp_headers = dict(resp.headers)
|
|
577
|
-
resp_body = await resp.read()
|
|
578
|
-
if resp.status not in (200, 201):
|
|
579
|
-
raise exceptions.from_http_status(
|
|
580
|
-
resp.status, resp_body.decode("utf-8", errors="replace")
|
|
581
|
-
)
|
|
582
|
-
status_code = resp.status
|
|
690
|
+
payload,
|
|
691
|
+
headers,
|
|
692
|
+
timeout=per_attempt_timeout,
|
|
693
|
+
)
|
|
583
694
|
t_elapsed = _monotonic_clock() - t_start
|
|
584
695
|
except Exception as exc:
|
|
585
696
|
self._enrich_exception(exc)
|
|
@@ -684,14 +795,14 @@ class AsyncResumableUploadSession:
|
|
|
684
795
|
|
|
685
796
|
async def _recover(
|
|
686
797
|
self,
|
|
687
|
-
transport:
|
|
798
|
+
transport: AsyncTransport,
|
|
688
799
|
stream_obj: Optional[object] = None,
|
|
689
800
|
progress_queue: Optional[List[UploadProgress]] = None,
|
|
690
801
|
) -> Tuple[int, Mapping[str, str], bytes]:
|
|
691
802
|
"""Queries server for committed byte offset and adjusts buffer.
|
|
692
803
|
|
|
693
804
|
Args:
|
|
694
|
-
transport: The
|
|
805
|
+
transport: The asynchronous transport to dispatch requests over.
|
|
695
806
|
stream_obj: Underlying stream object to rewind if seekable.
|
|
696
807
|
progress_queue: Optional queue to receive progress updates.
|
|
697
808
|
|
|
@@ -703,18 +814,14 @@ class AsyncResumableUploadSession:
|
|
|
703
814
|
exceptions.GoogleAPICallError: If query request fails on the server.
|
|
704
815
|
"""
|
|
705
816
|
method, url, headers, payload = self._state.build_query_request()
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
raise exceptions.from_http_status(
|
|
715
|
-
resp.status, body.decode("utf-8", errors="replace")
|
|
716
|
-
)
|
|
717
|
-
status_code = resp.status
|
|
817
|
+
status_code, resp_headers, body = await self._send_request(
|
|
818
|
+
transport,
|
|
819
|
+
method,
|
|
820
|
+
url,
|
|
821
|
+
payload,
|
|
822
|
+
headers,
|
|
823
|
+
timeout=self._get_start_timeout(),
|
|
824
|
+
)
|
|
718
825
|
|
|
719
826
|
received = self._state.process_query_response(status_code, resp_headers)
|
|
720
827
|
self._notify_progress(common.ProgressState.OFFSET_RECEIVED, progress_queue)
|
|
@@ -760,37 +867,32 @@ class AsyncResumableUploadSession:
|
|
|
760
867
|
chunk_size=self.chunk_size,
|
|
761
868
|
)
|
|
762
869
|
|
|
763
|
-
async def cancel(self, transport: Optional[
|
|
870
|
+
async def cancel(self, transport: Optional[AsyncTransport] = None) -> None:
|
|
764
871
|
"""Cancels the resumable upload session asynchronously.
|
|
765
872
|
|
|
766
873
|
Args:
|
|
767
|
-
transport: Optional aiohttp
|
|
874
|
+
transport: Optional aiohttp.ClientSession or AsyncAuthorizedSession.
|
|
768
875
|
|
|
769
876
|
Raises:
|
|
770
877
|
ValueError: If transport is missing.
|
|
771
878
|
exceptions.GoogleAPICallError: If cancellation request fails on the server.
|
|
772
879
|
"""
|
|
773
880
|
self._ensure_aiohttp()
|
|
774
|
-
sess =
|
|
775
|
-
if sess is None:
|
|
776
|
-
raise ValueError("An aiohttp.ClientSession transport must be provided.")
|
|
881
|
+
sess = self._get_transport(transport)
|
|
777
882
|
method, url, headers, payload = self._state.build_cancel_request()
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
resp.status, body.decode("utf-8", errors="replace")
|
|
788
|
-
)
|
|
789
|
-
self._state.process_cancel_response(resp.status, resp_headers)
|
|
883
|
+
status_code, resp_headers, _ = await self._send_request(
|
|
884
|
+
sess,
|
|
885
|
+
method,
|
|
886
|
+
url,
|
|
887
|
+
payload,
|
|
888
|
+
headers,
|
|
889
|
+
timeout=self._get_start_timeout(),
|
|
890
|
+
)
|
|
891
|
+
self._state.process_cancel_response(status_code, resp_headers)
|
|
790
892
|
|
|
791
893
|
async def _transmit_all_chunks(
|
|
792
894
|
self,
|
|
793
|
-
transport:
|
|
895
|
+
transport: AsyncTransport,
|
|
794
896
|
reader_fn: Callable[[int], Awaitable[bytes]],
|
|
795
897
|
computed_size: Optional[int],
|
|
796
898
|
progress_queue: Optional[List[UploadProgress]] = None,
|
|
@@ -801,7 +903,7 @@ class AsyncResumableUploadSession:
|
|
|
801
903
|
"""Transmits chunks until completion using a single outer AsyncStreamingRetry coordinator.
|
|
802
904
|
|
|
803
905
|
Args:
|
|
804
|
-
transport: The
|
|
906
|
+
transport: The asynchronous transport to dispatch requests over.
|
|
805
907
|
reader_fn: Async callable returning chunk bytes.
|
|
806
908
|
computed_size: Total stream size in bytes, if known.
|
|
807
909
|
progress_queue: Optional list receiving UploadProgress snapshots.
|
|
@@ -885,9 +987,9 @@ class AsyncResumableUploadSession:
|
|
|
885
987
|
def upload(
|
|
886
988
|
self,
|
|
887
989
|
stream: Union[AsyncIterable[bytes], BinaryIO, bytes, Iterable[bytes]],
|
|
888
|
-
request_body: Union[str, bytes] =
|
|
990
|
+
request_body: Optional[Union[str, bytes]] = None,
|
|
889
991
|
size: Optional[int] = None,
|
|
890
|
-
transport: Optional[
|
|
992
|
+
transport: Optional[AsyncTransport] = None,
|
|
891
993
|
content_type: Optional[str] = None,
|
|
892
994
|
retry: Optional[google.api_core.retry.AsyncStreamingRetry] = None,
|
|
893
995
|
timeout: Optional[float] = None,
|
|
@@ -897,8 +999,10 @@ class AsyncResumableUploadSession:
|
|
|
897
999
|
Args:
|
|
898
1000
|
stream: Data payload to upload (async iterable, binary stream, bytes, or iterable).
|
|
899
1001
|
request_body: Initial metadata payload sent with the start request.
|
|
1002
|
+
When ``None``, the ``request_body`` supplied to the session constructor
|
|
1003
|
+
(if any) is used.
|
|
900
1004
|
size: Total stream size in bytes, if known.
|
|
901
|
-
transport: Optional aiohttp
|
|
1005
|
+
transport: Optional aiohttp.ClientSession or AsyncAuthorizedSession.
|
|
902
1006
|
content_type: Optional MIME type of the stream payload.
|
|
903
1007
|
retry: Optional retry configuration (``AsyncStreamingRetry``) for
|
|
904
1008
|
chunk upload requests. Use this to customize exponential backoff timing between chunk retries or to
|
|
@@ -919,12 +1023,12 @@ class AsyncResumableUploadSession:
|
|
|
919
1023
|
ValueError: If transport is missing.
|
|
920
1024
|
"""
|
|
921
1025
|
self._ensure_aiohttp()
|
|
922
|
-
sess =
|
|
923
|
-
if sess is None:
|
|
924
|
-
raise ValueError("An aiohttp.ClientSession transport must be provided.")
|
|
1026
|
+
sess = self._get_transport(transport)
|
|
925
1027
|
|
|
926
1028
|
if content_type is not None:
|
|
927
1029
|
self._content_type = content_type
|
|
1030
|
+
if request_body is None:
|
|
1031
|
+
request_body = self._request_body
|
|
928
1032
|
|
|
929
1033
|
self._reset_transfer_state()
|
|
930
1034
|
progress_queue: List[UploadProgress] = []
|
|
@@ -963,7 +1067,7 @@ class AsyncResumableUploadSession:
|
|
|
963
1067
|
stream: Union[AsyncIterable[bytes], BinaryIO, bytes, Iterable[bytes]],
|
|
964
1068
|
size: Optional[int] = None,
|
|
965
1069
|
chunk_size: Optional[int] = None,
|
|
966
|
-
transport: Optional[
|
|
1070
|
+
transport: Optional[AsyncTransport] = None,
|
|
967
1071
|
retry: Optional[google.api_core.retry.AsyncStreamingRetry] = None,
|
|
968
1072
|
timeout: Optional[float] = None,
|
|
969
1073
|
) -> AsyncUploadOperation:
|
|
@@ -975,7 +1079,7 @@ class AsyncResumableUploadSession:
|
|
|
975
1079
|
Data payload to resume uploading.
|
|
976
1080
|
size (Optional[int]): Total stream size in bytes, if known.
|
|
977
1081
|
chunk_size (Optional[int]): Optional chunk size override in bytes.
|
|
978
|
-
transport (Optional[
|
|
1082
|
+
transport (Optional[AsyncTransport]): Optional transport override.
|
|
979
1083
|
retry (Optional[google.api_core.retry.AsyncStreamingRetry]): Optional
|
|
980
1084
|
retry configuration (``AsyncStreamingRetry``) for chunk upload
|
|
981
1085
|
requests. Use this to customize exponential backoff timing
|
|
@@ -998,9 +1102,7 @@ class AsyncResumableUploadSession:
|
|
|
998
1102
|
ValueError: If transport, upload_url, or stream is missing.
|
|
999
1103
|
"""
|
|
1000
1104
|
self._ensure_aiohttp()
|
|
1001
|
-
sess =
|
|
1002
|
-
if sess is None:
|
|
1003
|
-
raise ValueError("An aiohttp.ClientSession transport must be provided.")
|
|
1105
|
+
sess = self._get_transport(transport)
|
|
1004
1106
|
actual_url = upload_url or self.upload_url
|
|
1005
1107
|
if not actual_url:
|
|
1006
1108
|
raise ValueError("An upload URL must be provided to resume.")
|