azure-storage-blob 12.26.0b1__py3-none-any.whl → 12.27.0__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.
Files changed (72) hide show
  1. azure/storage/blob/__init__.py +6 -5
  2. azure/storage/blob/_blob_client.py +59 -38
  3. azure/storage/blob/_blob_client.pyi +780 -0
  4. azure/storage/blob/_blob_client_helpers.py +4 -3
  5. azure/storage/blob/_blob_service_client.py +57 -17
  6. azure/storage/blob/_blob_service_client.pyi +182 -0
  7. azure/storage/blob/_container_client.py +47 -22
  8. azure/storage/blob/_container_client.pyi +380 -0
  9. azure/storage/blob/_deserialize.py +1 -1
  10. azure/storage/blob/_download.py +7 -7
  11. azure/storage/blob/_encryption.py +177 -184
  12. azure/storage/blob/_generated/_azure_blob_storage.py +3 -2
  13. azure/storage/blob/_generated/_configuration.py +2 -2
  14. azure/storage/blob/_generated/_utils/__init__.py +6 -0
  15. azure/storage/blob/_generated/{_serialization.py → _utils/serialization.py} +4 -22
  16. azure/storage/blob/_generated/aio/_azure_blob_storage.py +3 -2
  17. azure/storage/blob/_generated/aio/_configuration.py +2 -2
  18. azure/storage/blob/_generated/aio/operations/_append_blob_operations.py +6 -10
  19. azure/storage/blob/_generated/aio/operations/_blob_operations.py +35 -39
  20. azure/storage/blob/_generated/aio/operations/_block_blob_operations.py +9 -13
  21. azure/storage/blob/_generated/aio/operations/_container_operations.py +20 -24
  22. azure/storage/blob/_generated/aio/operations/_page_blob_operations.py +13 -17
  23. azure/storage/blob/_generated/aio/operations/_service_operations.py +10 -14
  24. azure/storage/blob/_generated/models/_models_py3.py +30 -9
  25. azure/storage/blob/_generated/operations/_append_blob_operations.py +11 -15
  26. azure/storage/blob/_generated/operations/_blob_operations.py +60 -64
  27. azure/storage/blob/_generated/operations/_block_blob_operations.py +16 -20
  28. azure/storage/blob/_generated/operations/_container_operations.py +39 -43
  29. azure/storage/blob/_generated/operations/_page_blob_operations.py +23 -27
  30. azure/storage/blob/_generated/operations/_service_operations.py +19 -23
  31. azure/storage/blob/_lease.py +3 -2
  32. azure/storage/blob/_lease.pyi +81 -0
  33. azure/storage/blob/_list_blobs_helper.py +1 -1
  34. azure/storage/blob/_quick_query_helper.py +3 -3
  35. azure/storage/blob/_serialize.py +1 -0
  36. azure/storage/blob/_shared/__init__.py +7 -7
  37. azure/storage/blob/_shared/authentication.py +49 -32
  38. azure/storage/blob/_shared/avro/avro_io.py +44 -42
  39. azure/storage/blob/_shared/avro/avro_io_async.py +42 -41
  40. azure/storage/blob/_shared/avro/datafile.py +24 -21
  41. azure/storage/blob/_shared/avro/datafile_async.py +15 -15
  42. azure/storage/blob/_shared/avro/schema.py +196 -217
  43. azure/storage/blob/_shared/base_client.py +79 -70
  44. azure/storage/blob/_shared/base_client_async.py +53 -68
  45. azure/storage/blob/_shared/constants.py +1 -1
  46. azure/storage/blob/_shared/models.py +94 -92
  47. azure/storage/blob/_shared/parser.py +3 -3
  48. azure/storage/blob/_shared/policies.py +186 -147
  49. azure/storage/blob/_shared/policies_async.py +58 -69
  50. azure/storage/blob/_shared/request_handlers.py +50 -45
  51. azure/storage/blob/_shared/response_handlers.py +54 -45
  52. azure/storage/blob/_shared/shared_access_signature.py +65 -73
  53. azure/storage/blob/_shared/uploads.py +56 -49
  54. azure/storage/blob/_shared/uploads_async.py +70 -58
  55. azure/storage/blob/_version.py +1 -1
  56. azure/storage/blob/aio/__init__.py +8 -10
  57. azure/storage/blob/aio/_blob_client_async.py +81 -48
  58. azure/storage/blob/aio/_blob_client_async.pyi +763 -0
  59. azure/storage/blob/aio/_blob_service_client_async.py +54 -15
  60. azure/storage/blob/aio/_blob_service_client_async.pyi +187 -0
  61. azure/storage/blob/aio/_container_client_async.py +55 -26
  62. azure/storage/blob/aio/_container_client_async.pyi +384 -0
  63. azure/storage/blob/aio/_download_async.py +15 -11
  64. azure/storage/blob/aio/_lease_async.py +3 -2
  65. azure/storage/blob/aio/_lease_async.pyi +81 -0
  66. azure/storage/blob/aio/_quick_query_helper_async.py +3 -3
  67. {azure_storage_blob-12.26.0b1.dist-info → azure_storage_blob-12.27.0.dist-info}/METADATA +18 -6
  68. azure_storage_blob-12.27.0.dist-info/RECORD +94 -0
  69. {azure_storage_blob-12.26.0b1.dist-info → azure_storage_blob-12.27.0.dist-info}/WHEEL +1 -1
  70. azure_storage_blob-12.26.0b1.dist-info/RECORD +0 -85
  71. {azure_storage_blob-12.26.0b1.dist-info → azure_storage_blob-12.27.0.dist-info/licenses}/LICENSE +0 -0
  72. {azure_storage_blob-12.26.0b1.dist-info → azure_storage_blob-12.27.0.dist-info}/top_level.txt +0 -0
@@ -11,44 +11,45 @@ from .parser import _to_utc_datetime
11
11
  from .constants import X_MS_VERSION
12
12
  from . import sign_string, url_quote
13
13
 
14
+
14
15
  # cspell:ignoreRegExp rsc.
15
16
  # cspell:ignoreRegExp s..?id
16
17
  class QueryStringConstants(object):
17
- SIGNED_SIGNATURE = 'sig'
18
- SIGNED_PERMISSION = 'sp'
19
- SIGNED_START = 'st'
20
- SIGNED_EXPIRY = 'se'
21
- SIGNED_RESOURCE = 'sr'
22
- SIGNED_IDENTIFIER = 'si'
23
- SIGNED_IP = 'sip'
24
- SIGNED_PROTOCOL = 'spr'
25
- SIGNED_VERSION = 'sv'
26
- SIGNED_CACHE_CONTROL = 'rscc'
27
- SIGNED_CONTENT_DISPOSITION = 'rscd'
28
- SIGNED_CONTENT_ENCODING = 'rsce'
29
- SIGNED_CONTENT_LANGUAGE = 'rscl'
30
- SIGNED_CONTENT_TYPE = 'rsct'
31
- START_PK = 'spk'
32
- START_RK = 'srk'
33
- END_PK = 'epk'
34
- END_RK = 'erk'
35
- SIGNED_RESOURCE_TYPES = 'srt'
36
- SIGNED_SERVICES = 'ss'
37
- SIGNED_OID = 'skoid'
38
- SIGNED_TID = 'sktid'
39
- SIGNED_KEY_START = 'skt'
40
- SIGNED_KEY_EXPIRY = 'ske'
41
- SIGNED_KEY_SERVICE = 'sks'
42
- SIGNED_KEY_VERSION = 'skv'
43
- SIGNED_ENCRYPTION_SCOPE = 'ses'
44
- SIGNED_KEY_DELEGATED_USER_TID = 'skdutid'
45
- SIGNED_DELEGATED_USER_OID = 'sduoid'
18
+ SIGNED_SIGNATURE = "sig"
19
+ SIGNED_PERMISSION = "sp"
20
+ SIGNED_START = "st"
21
+ SIGNED_EXPIRY = "se"
22
+ SIGNED_RESOURCE = "sr"
23
+ SIGNED_IDENTIFIER = "si"
24
+ SIGNED_IP = "sip"
25
+ SIGNED_PROTOCOL = "spr"
26
+ SIGNED_VERSION = "sv"
27
+ SIGNED_CACHE_CONTROL = "rscc"
28
+ SIGNED_CONTENT_DISPOSITION = "rscd"
29
+ SIGNED_CONTENT_ENCODING = "rsce"
30
+ SIGNED_CONTENT_LANGUAGE = "rscl"
31
+ SIGNED_CONTENT_TYPE = "rsct"
32
+ START_PK = "spk"
33
+ START_RK = "srk"
34
+ END_PK = "epk"
35
+ END_RK = "erk"
36
+ SIGNED_RESOURCE_TYPES = "srt"
37
+ SIGNED_SERVICES = "ss"
38
+ SIGNED_OID = "skoid"
39
+ SIGNED_TID = "sktid"
40
+ SIGNED_KEY_START = "skt"
41
+ SIGNED_KEY_EXPIRY = "ske"
42
+ SIGNED_KEY_SERVICE = "sks"
43
+ SIGNED_KEY_VERSION = "skv"
44
+ SIGNED_ENCRYPTION_SCOPE = "ses"
45
+ SIGNED_KEY_DELEGATED_USER_TID = "skdutid"
46
+ SIGNED_DELEGATED_USER_OID = "sduoid"
46
47
 
47
48
  # for ADLS
48
- SIGNED_AUTHORIZED_OID = 'saoid'
49
- SIGNED_UNAUTHORIZED_OID = 'suoid'
50
- SIGNED_CORRELATION_ID = 'scid'
51
- SIGNED_DIRECTORY_DEPTH = 'sdd'
49
+ SIGNED_AUTHORIZED_OID = "saoid"
50
+ SIGNED_UNAUTHORIZED_OID = "suoid"
51
+ SIGNED_CORRELATION_ID = "scid"
52
+ SIGNED_DIRECTORY_DEPTH = "sdd"
52
53
 
53
54
  @staticmethod
54
55
  def to_list():
@@ -91,38 +92,30 @@ class QueryStringConstants(object):
91
92
 
92
93
 
93
94
  class SharedAccessSignature(object):
94
- '''
95
+ """
95
96
  Provides a factory for creating account access
96
97
  signature tokens with an account name and account key. Users can either
97
98
  use the factory or can construct the appropriate service and use the
98
99
  generate_*_shared_access_signature method directly.
99
- '''
100
+ """
100
101
 
101
102
  def __init__(self, account_name, account_key, x_ms_version=X_MS_VERSION):
102
- '''
103
+ """
103
104
  :param str account_name:
104
105
  The storage account name used to generate the shared access signatures.
105
106
  :param str account_key:
106
107
  The access key to generate the shares access signatures.
107
108
  :param str x_ms_version:
108
109
  The service version used to generate the shared access signatures.
109
- '''
110
+ """
110
111
  self.account_name = account_name
111
112
  self.account_key = account_key
112
113
  self.x_ms_version = x_ms_version
113
114
 
114
115
  def generate_account(
115
- self, services,
116
- resource_types,
117
- permission,
118
- expiry,
119
- start=None,
120
- ip=None,
121
- protocol=None,
122
- sts_hook=None,
123
- **kwargs
116
+ self, services, resource_types, permission, expiry, start=None, ip=None, protocol=None, sts_hook=None, **kwargs
124
117
  ) -> str:
125
- '''
118
+ """
126
119
  Generates a shared access signature for the account.
127
120
  Use the returned signature with the sas_token parameter of the service
128
121
  or to create a new account object.
@@ -169,9 +162,9 @@ class SharedAccessSignature(object):
169
162
  For debugging purposes only. If provided, the hook is called with the string to sign
170
163
  that was used to generate the SAS.
171
164
  :type sts_hook: Optional[Callable[[str], None]]
172
- :returns: The generated SAS token for the account.
165
+ :return: The generated SAS token for the account.
173
166
  :rtype: str
174
- '''
167
+ """
175
168
  sas = _SharedAccessHelper()
176
169
  sas.add_base(permission, expiry, start, ip, protocol, self.x_ms_version)
177
170
  sas.add_account(services, resource_types)
@@ -194,7 +187,7 @@ class _SharedAccessHelper(object):
194
187
  self.query_dict[name] = str(val) if val is not None else None
195
188
 
196
189
  def add_encryption_scope(self, **kwargs):
197
- self._add_query(QueryStringConstants.SIGNED_ENCRYPTION_SCOPE, kwargs.pop('encryption_scope', None))
190
+ self._add_query(QueryStringConstants.SIGNED_ENCRYPTION_SCOPE, kwargs.pop("encryption_scope", None))
198
191
 
199
192
  def add_base(self, permission, expiry, start, ip, protocol, x_ms_version):
200
193
  if isinstance(start, date):
@@ -220,11 +213,9 @@ class _SharedAccessHelper(object):
220
213
  self._add_query(QueryStringConstants.SIGNED_SERVICES, services)
221
214
  self._add_query(QueryStringConstants.SIGNED_RESOURCE_TYPES, resource_types)
222
215
 
223
- def add_override_response_headers(self, cache_control,
224
- content_disposition,
225
- content_encoding,
226
- content_language,
227
- content_type):
216
+ def add_override_response_headers(
217
+ self, cache_control, content_disposition, content_encoding, content_language, content_type
218
+ ):
228
219
  self._add_query(QueryStringConstants.SIGNED_CACHE_CONTROL, cache_control)
229
220
  self._add_query(QueryStringConstants.SIGNED_CONTENT_DISPOSITION, content_disposition)
230
221
  self._add_query(QueryStringConstants.SIGNED_CONTENT_ENCODING, content_encoding)
@@ -233,24 +224,25 @@ class _SharedAccessHelper(object):
233
224
 
234
225
  def add_account_signature(self, account_name, account_key):
235
226
  def get_value_to_append(query):
236
- return_value = self.query_dict.get(query) or ''
237
- return return_value + '\n'
238
-
239
- string_to_sign = \
240
- (account_name + '\n' +
241
- get_value_to_append(QueryStringConstants.SIGNED_PERMISSION) +
242
- get_value_to_append(QueryStringConstants.SIGNED_SERVICES) +
243
- get_value_to_append(QueryStringConstants.SIGNED_RESOURCE_TYPES) +
244
- get_value_to_append(QueryStringConstants.SIGNED_START) +
245
- get_value_to_append(QueryStringConstants.SIGNED_EXPIRY) +
246
- get_value_to_append(QueryStringConstants.SIGNED_IP) +
247
- get_value_to_append(QueryStringConstants.SIGNED_PROTOCOL) +
248
- get_value_to_append(QueryStringConstants.SIGNED_VERSION) +
249
- get_value_to_append(QueryStringConstants.SIGNED_ENCRYPTION_SCOPE))
250
-
251
- self._add_query(QueryStringConstants.SIGNED_SIGNATURE,
252
- sign_string(account_key, string_to_sign))
227
+ return_value = self.query_dict.get(query) or ""
228
+ return return_value + "\n"
229
+
230
+ string_to_sign = (
231
+ account_name
232
+ + "\n"
233
+ + get_value_to_append(QueryStringConstants.SIGNED_PERMISSION)
234
+ + get_value_to_append(QueryStringConstants.SIGNED_SERVICES)
235
+ + get_value_to_append(QueryStringConstants.SIGNED_RESOURCE_TYPES)
236
+ + get_value_to_append(QueryStringConstants.SIGNED_START)
237
+ + get_value_to_append(QueryStringConstants.SIGNED_EXPIRY)
238
+ + get_value_to_append(QueryStringConstants.SIGNED_IP)
239
+ + get_value_to_append(QueryStringConstants.SIGNED_PROTOCOL)
240
+ + get_value_to_append(QueryStringConstants.SIGNED_VERSION)
241
+ + get_value_to_append(QueryStringConstants.SIGNED_ENCRYPTION_SCOPE)
242
+ )
243
+
244
+ self._add_query(QueryStringConstants.SIGNED_SIGNATURE, sign_string(account_key, string_to_sign))
253
245
  self.string_to_sign = string_to_sign
254
246
 
255
247
  def get_token(self) -> str:
256
- return '&'.join([f'{n}={url_quote(v)}' for n, v in self.query_dict.items() if v is not None])
248
+ return "&".join([f"{n}={url_quote(v)}" for n, v in self.query_dict.items() if v is not None])
@@ -12,7 +12,7 @@ from threading import Lock
12
12
 
13
13
  from azure.core.tracing.common import with_current_context
14
14
 
15
- from .import encode_base64, url_quote
15
+ from . import encode_base64, url_quote
16
16
  from .request_handlers import get_length
17
17
  from .response_handlers import return_response_headers
18
18
 
@@ -41,20 +41,21 @@ def _parallel_uploads(executor, uploader, pending, running):
41
41
 
42
42
 
43
43
  def upload_data_chunks(
44
- service=None,
45
- uploader_class=None,
46
- total_size=None,
47
- chunk_size=None,
48
- max_concurrency=None,
49
- stream=None,
50
- validate_content=None,
51
- progress_hook=None,
52
- **kwargs):
44
+ service=None,
45
+ uploader_class=None,
46
+ total_size=None,
47
+ chunk_size=None,
48
+ max_concurrency=None,
49
+ stream=None,
50
+ validate_content=None,
51
+ progress_hook=None,
52
+ **kwargs,
53
+ ):
53
54
 
54
55
  parallel = max_concurrency > 1
55
- if parallel and 'modified_access_conditions' in kwargs:
56
+ if parallel and "modified_access_conditions" in kwargs:
56
57
  # Access conditions do not work with parallelism
57
- kwargs['modified_access_conditions'] = None
58
+ kwargs["modified_access_conditions"] = None
58
59
 
59
60
  uploader = uploader_class(
60
61
  service=service,
@@ -64,7 +65,8 @@ def upload_data_chunks(
64
65
  parallel=parallel,
65
66
  validate_content=validate_content,
66
67
  progress_hook=progress_hook,
67
- **kwargs)
68
+ **kwargs,
69
+ )
68
70
  if parallel:
69
71
  with futures.ThreadPoolExecutor(max_concurrency) as executor:
70
72
  upload_tasks = uploader.get_chunk_streams()
@@ -81,18 +83,19 @@ def upload_data_chunks(
81
83
 
82
84
 
83
85
  def upload_substream_blocks(
84
- service=None,
85
- uploader_class=None,
86
- total_size=None,
87
- chunk_size=None,
88
- max_concurrency=None,
89
- stream=None,
90
- progress_hook=None,
91
- **kwargs):
86
+ service=None,
87
+ uploader_class=None,
88
+ total_size=None,
89
+ chunk_size=None,
90
+ max_concurrency=None,
91
+ stream=None,
92
+ progress_hook=None,
93
+ **kwargs,
94
+ ):
92
95
  parallel = max_concurrency > 1
93
- if parallel and 'modified_access_conditions' in kwargs:
96
+ if parallel and "modified_access_conditions" in kwargs:
94
97
  # Access conditions do not work with parallelism
95
- kwargs['modified_access_conditions'] = None
98
+ kwargs["modified_access_conditions"] = None
96
99
  uploader = uploader_class(
97
100
  service=service,
98
101
  total_size=total_size,
@@ -100,7 +103,8 @@ def upload_substream_blocks(
100
103
  stream=stream,
101
104
  parallel=parallel,
102
105
  progress_hook=progress_hook,
103
- **kwargs)
106
+ **kwargs,
107
+ )
104
108
 
105
109
  if parallel:
106
110
  with futures.ThreadPoolExecutor(max_concurrency) as executor:
@@ -120,15 +124,17 @@ def upload_substream_blocks(
120
124
  class _ChunkUploader(object): # pylint: disable=too-many-instance-attributes
121
125
 
122
126
  def __init__(
123
- self, service,
124
- total_size,
125
- chunk_size,
126
- stream,
127
- parallel,
128
- encryptor=None,
129
- padder=None,
130
- progress_hook=None,
131
- **kwargs):
127
+ self,
128
+ service,
129
+ total_size,
130
+ chunk_size,
131
+ stream,
132
+ parallel,
133
+ encryptor=None,
134
+ padder=None,
135
+ progress_hook=None,
136
+ **kwargs,
137
+ ):
132
138
  self.service = service
133
139
  self.total_size = total_size
134
140
  self.chunk_size = chunk_size
@@ -253,7 +259,7 @@ class BlockBlobChunkUploader(_ChunkUploader):
253
259
 
254
260
  def _upload_chunk(self, chunk_offset, chunk_data):
255
261
  # TODO: This is incorrect, but works with recording.
256
- index = f'{chunk_offset:032d}'
262
+ index = f"{chunk_offset:032d}"
257
263
  block_id = encode_base64(url_quote(encode_base64(index)))
258
264
  self.service.stage_block(
259
265
  block_id,
@@ -261,20 +267,20 @@ class BlockBlobChunkUploader(_ChunkUploader):
261
267
  chunk_data,
262
268
  data_stream_total=self.total_size,
263
269
  upload_stream_current=self.progress_total,
264
- **self.request_options
270
+ **self.request_options,
265
271
  )
266
272
  return index, block_id
267
273
 
268
274
  def _upload_substream_block(self, index, block_stream):
269
275
  try:
270
- block_id = f'BlockId{(index//self.chunk_size):05}'
276
+ block_id = f"BlockId{(index//self.chunk_size):05}"
271
277
  self.service.stage_block(
272
278
  block_id,
273
279
  len(block_stream),
274
280
  block_stream,
275
281
  data_stream_total=self.total_size,
276
282
  upload_stream_current=self.progress_total,
277
- **self.request_options
283
+ **self.request_options,
278
284
  )
279
285
  finally:
280
286
  block_stream.close()
@@ -302,11 +308,11 @@ class PageBlobChunkUploader(_ChunkUploader):
302
308
  cls=return_response_headers,
303
309
  data_stream_total=self.total_size,
304
310
  upload_stream_current=self.progress_total,
305
- **self.request_options
311
+ **self.request_options,
306
312
  )
307
313
 
308
- if not self.parallel and self.request_options.get('modified_access_conditions'):
309
- self.request_options['modified_access_conditions'].if_match = self.response_headers['etag']
314
+ if not self.parallel and self.request_options.get("modified_access_conditions"):
315
+ self.request_options["modified_access_conditions"].if_match = self.response_headers["etag"]
310
316
 
311
317
  def _upload_substream_block(self, index, block_stream):
312
318
  pass
@@ -326,19 +332,20 @@ class AppendBlobChunkUploader(_ChunkUploader):
326
332
  cls=return_response_headers,
327
333
  data_stream_total=self.total_size,
328
334
  upload_stream_current=self.progress_total,
329
- **self.request_options
335
+ **self.request_options,
330
336
  )
331
337
  self.current_length = int(self.response_headers["blob_append_offset"])
332
338
  else:
333
- self.request_options['append_position_access_conditions'].append_position = \
339
+ self.request_options["append_position_access_conditions"].append_position = (
334
340
  self.current_length + chunk_offset
341
+ )
335
342
  self.response_headers = self.service.append_block(
336
343
  body=chunk_data,
337
344
  content_length=len(chunk_data),
338
345
  cls=return_response_headers,
339
346
  data_stream_total=self.total_size,
340
347
  upload_stream_current=self.progress_total,
341
- **self.request_options
348
+ **self.request_options,
342
349
  )
343
350
 
344
351
  def _upload_substream_block(self, index, block_stream):
@@ -356,11 +363,11 @@ class DataLakeFileChunkUploader(_ChunkUploader):
356
363
  cls=return_response_headers,
357
364
  data_stream_total=self.total_size,
358
365
  upload_stream_current=self.progress_total,
359
- **self.request_options
366
+ **self.request_options,
360
367
  )
361
368
 
362
- if not self.parallel and self.request_options.get('modified_access_conditions'):
363
- self.request_options['modified_access_conditions'].if_match = self.response_headers['etag']
369
+ if not self.parallel and self.request_options.get("modified_access_conditions"):
370
+ self.request_options["modified_access_conditions"].if_match = self.response_headers["etag"]
364
371
 
365
372
  def _upload_substream_block(self, index, block_stream):
366
373
  try:
@@ -371,7 +378,7 @@ class DataLakeFileChunkUploader(_ChunkUploader):
371
378
  cls=return_response_headers,
372
379
  data_stream_total=self.total_size,
373
380
  upload_stream_current=self.progress_total,
374
- **self.request_options
381
+ **self.request_options,
375
382
  )
376
383
  finally:
377
384
  block_stream.close()
@@ -388,9 +395,9 @@ class FileChunkUploader(_ChunkUploader):
388
395
  length,
389
396
  data_stream_total=self.total_size,
390
397
  upload_stream_current=self.progress_total,
391
- **self.request_options
398
+ **self.request_options,
392
399
  )
393
- return f'bytes={chunk_offset}-{chunk_end}', response
400
+ return f"bytes={chunk_offset}-{chunk_end}", response
394
401
 
395
402
  # TODO: Implement this method.
396
403
  def _upload_substream_block(self, index, block_stream):