Skip to content

Commit 127cf6a

Browse files
authored
Merge pull request #327 from zezha-msft/wastore_master_07_13
Wastore master to Azure master
2 parents 8021250 + 8dc8c8d commit 127cf6a

File tree

646 files changed

+33258
-22061
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

646 files changed

+33258
-22061
lines changed

ChangeLog.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22

33
> See [BreakingChanges](BreakingChanges.md) for a detailed list of API breaks.
44
5+
## Version 0.35.0:
6+
7+
### All:
8+
- Support for 2017-04-17 REST version. Please see our REST API documentation and blogs for information about the related added features. If you are using the Storage Emulator, please update to Emulator version 5.2.
9+
- Fixed a bug where deserialization of service stats throws a TypeError when the service is unavailable.
10+
11+
### Blob:
12+
- For Premium Accounts only, added support for getting and setting the tier on a page blob. The tier can also be set when creating or copying from an existing page blob.
13+
- create_from_* and and append_blob_from_* methods will return response_properties which contains the etag and last modified time.
14+
15+
### Table:
16+
- Fixed syntax error in _convert_json_response_to_entities.
17+
- Fixed a bug where the urls are not correctly formed when making commit_batch to the emulator.
18+
19+
### File:
20+
- The `server_encrypted` file property will now be populated when calling 'get_directory_properties', 'get_file', and 'get_file_properties'. This value is set to True if the file data (for files) and application metadata are completely encrypted.
21+
522
## Version 0.34.3:
623
- All: Made the socket timeout configurable. Increased the default socket timeout to 20 seconds.
724
- All: Fixed a bug where SAS tokens were being duplicated on retries
@@ -179,4 +196,4 @@
179196
- Client-side validation added for ranges used in APIs.
180197
- Metadata returned for shares, directories, and files will be returned without the 'x-ms-meta' prefix on the keys. Namely, metadata will be returned as it is received.
181198
- get_share_properties, get_directory_properties, and get_file_properties return parsed Share, Directory, and File objects, respectively, instead of string header dictionaries.
182-
- copy_file returns a parsed CopyProperties object instead of a string header dictionary.
199+
- copy_file returns a parsed CopyProperties object instead of a string header dictionary.

azure/storage/_connection.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def __init__(self, service, account_name=None, account_key=None, sas_token=None,
5555
self.account_key = account_key
5656
self.sas_token = sas_token
5757
self.protocol = protocol or DEFAULT_PROTOCOL
58+
self.is_emulated = is_emulated
5859

5960
if is_emulated:
6061
self.account_name = DEV_ACCOUNT_NAME

azure/storage/_constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
import platform
1616

1717
__author__ = 'Microsoft Corp. <[email protected]>'
18-
__version__ = '0.34.3'
18+
__version__ = '0.35.0'
1919

2020
# x-ms-version for storage service.
21-
X_MS_VERSION = '2016-05-31'
21+
X_MS_VERSION = '2017-04-17'
2222

2323
# UserAgent string sample: 'Azure-Storage/0.32.0 (Python CPython 3.4.2; Windows 8)'
2424
USER_AGENT_STRING = 'Azure-Storage/{} (Python {} {}; {} {})'.format(__version__, platform.python_implementation(), platform.python_version(), platform.system(), platform.release())

azure/storage/_deserialization.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ def _int_to_str(value):
3737
def _bool(value):
3838
return value.lower() == 'true'
3939

40+
def _to_upper_str(value):
41+
return _to_str(value).upper() if value is not None else None
42+
4043
def _get_download_size(start_range, end_range, resource_size):
4144
if start_range is not None:
4245
end_range = end_range if end_range else (resource_size if resource_size else None)
@@ -55,6 +58,8 @@ def _get_download_size(start_range, end_range, resource_size):
5558
'content-range': (None, 'content_range', _to_str),
5659
'x-ms-blob-sequence-number': (None, 'page_blob_sequence_number', _int_to_str),
5760
'x-ms-blob-committed-block-count': (None, 'append_blob_committed_block_count', _int_to_str),
61+
'x-ms-access-tier': (None, 'blob_tier', _to_upper_str),
62+
'x-ms-access-tier-inferred': (None, 'blob_tier_inferred', _bool),
5863
'x-ms-share-quota': (None, 'quota', _int_to_str),
5964
'x-ms-server-encrypted': (None, 'server_encrypted', _bool),
6065
'content-type': ('content_settings', 'content_type', _to_str),
@@ -184,7 +189,8 @@ def _convert_xml_to_service_stats(response):
184189

185190
geo_replication = GeoReplication()
186191
geo_replication.status = geo_replication_element.find('Status').text
187-
geo_replication.last_sync_time = parser.parse(geo_replication_element.find('LastSyncTime').text)
192+
last_sync_time = geo_replication_element.find('LastSyncTime').text
193+
geo_replication.last_sync_time = parser.parse(last_sync_time) if last_sync_time else None
188194

189195
service_stats = ServiceStats()
190196
service_stats.geo_replication = geo_replication

azure/storage/blob/_deserialization.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ def _convert_xml_to_containers(response):
233233
'CopyProgress': ('copy', 'progress', _to_str),
234234
'CopyCompletionTime': ('copy', 'completion_time', _to_str),
235235
'CopyStatusDescription': ('copy', 'status_description', _to_str),
236+
'AccessTier': (None, 'blob_tier', _to_str)
236237
}
237238

238239
def _convert_xml_to_blob_list(response):
@@ -267,6 +268,7 @@ def _convert_xml_to_blob_list(response):
267268
<CopyProgress>bytes copied/bytes total</CopyProgress>
268269
<CopyCompletionTime>datetime</CopyCompletionTime>
269270
<CopyStatusDescription>error string</CopyStatusDescription>
271+
<AccessTier>P4 | P6 | P10 | P20 | P30 | P40 | P50 | P60</AccessTier>
270272
</Properties>
271273
<Metadata>
272274
<Name>value</Name>

azure/storage/blob/_upload_chunking.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import sys
1616
from threading import Lock
1717
from time import sleep
18+
1819
from cryptography.hazmat.primitives.padding import PKCS7
1920
from .._common_conversion import _encode_base64
2021
from .._serialization import (
@@ -37,7 +38,7 @@ def _upload_blob_chunks(blob_service, container_name, blob_name,
3738
blob_size, block_size, stream, max_connections,
3839
progress_callback, validate_content, lease_id, uploader_class,
3940
maxsize_condition=None, if_match=None, timeout=None,
40-
content_encryption_key=None, initialization_vector=None):
41+
content_encryption_key=None, initialization_vector=None, resource_properties=None):
4142

4243
encryptor, padder = _get_blob_encryptor_and_padder(content_encryption_key, initialization_vector,
4344
uploader_class is not _PageBlobChunkUploader)
@@ -104,6 +105,10 @@ def _upload_blob_chunks(blob_service, container_name, blob_name,
104105
else:
105106
range_ids = [uploader.process_chunk(result) for result in uploader.get_chunk_streams()]
106107

108+
if resource_properties:
109+
resource_properties.last_modified = uploader.last_modified
110+
resource_properties.etag = uploader.etag
111+
107112
return range_ids
108113

109114
def _upload_blob_substream_blocks(blob_service, container_name, blob_name,
@@ -249,6 +254,10 @@ def _upload_substream_block_with_progress(self, block_id, block_stream):
249254
self._update_progress(len(block_stream))
250255
return range_id
251256

257+
def set_response_properties(self, resp):
258+
self.etag = resp.etag
259+
self.last_modified = resp.last_modified
260+
252261
class _BlockBlobChunkUploader(_BlobChunkUploader):
253262
def _upload_chunk(self, chunk_offset, chunk_data):
254263
block_id = url_quote(_encode_base64('{0:032d}'.format(chunk_offset)))
@@ -297,6 +306,8 @@ def _upload_chunk(self, chunk_start, chunk_data):
297306
if not self.parallel:
298307
self.if_match = resp.etag
299308

309+
self.set_response_properties(resp)
310+
300311
class _AppendBlobChunkUploader(_BlobChunkUploader):
301312
def _upload_chunk(self, chunk_offset, chunk_data):
302313
if not hasattr(self, 'current_length'):
@@ -323,6 +334,8 @@ def _upload_chunk(self, chunk_offset, chunk_data):
323334
timeout=self.timeout,
324335
)
325336

337+
self.set_response_properties(resp)
338+
326339
class _SubStream(IOBase):
327340
def __init__(self, wrapped_stream, stream_begin_index, length, lockObj):
328341
# Python 2.7: file-like objects created with open() typically support seek(), but are not

azure/storage/blob/appendblobservice.py

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333
_AppendBlobChunkUploader,
3434
_upload_blob_chunks,
3535
)
36-
from .models import _BlobTypes
36+
from .models import (
37+
_BlobTypes,
38+
ResourceProperties
39+
)
3740
from .._constants import (
3841
SERVICE_HOST_BASE,
3942
DEFAULT_PROTOCOL,
@@ -325,6 +328,8 @@ def append_blob_from_path(
325328
The timeout parameter is expressed in seconds. This method may make
326329
multiple calls to the Azure service and the timeout will apply to
327330
each call individually.
331+
:return: ETag and last modified properties for the Append Blob
332+
:rtype: :class:`~azure.storage.blob.models.ResourceProperties`
328333
'''
329334
_validate_not_none('container_name', container_name)
330335
_validate_not_none('blob_name', blob_name)
@@ -333,16 +338,16 @@ def append_blob_from_path(
333338

334339
count = path.getsize(file_path)
335340
with open(file_path, 'rb') as stream:
336-
self.append_blob_from_stream(
337-
container_name,
338-
blob_name,
339-
stream,
340-
count=count,
341-
validate_content=validate_content,
342-
maxsize_condition=maxsize_condition,
343-
progress_callback=progress_callback,
344-
lease_id=lease_id,
345-
timeout=timeout)
341+
return self.append_blob_from_stream(
342+
container_name,
343+
blob_name,
344+
stream,
345+
count=count,
346+
validate_content=validate_content,
347+
maxsize_condition=maxsize_condition,
348+
progress_callback=progress_callback,
349+
lease_id=lease_id,
350+
timeout=timeout)
346351

347352
def append_blob_from_bytes(
348353
self, container_name, blob_name, blob, index=0, count=None,
@@ -387,6 +392,8 @@ def append_blob_from_bytes(
387392
The timeout parameter is expressed in seconds. This method may make
388393
multiple calls to the Azure service and the timeout will apply to
389394
each call individually.
395+
:return: ETag and last modified properties for the Append Blob
396+
:rtype: :class:`~azure.storage.blob.models.ResourceProperties`
390397
'''
391398
_validate_not_none('container_name', container_name)
392399
_validate_not_none('blob_name', blob_name)
@@ -404,16 +411,16 @@ def append_blob_from_bytes(
404411
stream = BytesIO(blob)
405412
stream.seek(index)
406413

407-
self.append_blob_from_stream(
408-
container_name,
409-
blob_name,
410-
stream,
411-
count=count,
412-
validate_content=validate_content,
413-
maxsize_condition=maxsize_condition,
414-
lease_id=lease_id,
415-
progress_callback=progress_callback,
416-
timeout=timeout)
414+
return self.append_blob_from_stream(
415+
container_name,
416+
blob_name,
417+
stream,
418+
count=count,
419+
validate_content=validate_content,
420+
maxsize_condition=maxsize_condition,
421+
lease_id=lease_id,
422+
progress_callback=progress_callback,
423+
timeout=timeout)
417424

418425
def append_blob_from_text(
419426
self, container_name, blob_name, text, encoding='utf-8',
@@ -455,6 +462,8 @@ def append_blob_from_text(
455462
The timeout parameter is expressed in seconds. This method may make
456463
multiple calls to the Azure service and the timeout will apply to
457464
each call individually.
465+
:return: ETag and last modified properties for the Append Blob
466+
:rtype: :class:`~azure.storage.blob.models.ResourceProperties`
458467
'''
459468
_validate_not_none('container_name', container_name)
460469
_validate_not_none('blob_name', blob_name)
@@ -465,17 +474,17 @@ def append_blob_from_text(
465474
_validate_not_none('encoding', encoding)
466475
text = text.encode(encoding)
467476

468-
self.append_blob_from_bytes(
469-
container_name,
470-
blob_name,
471-
text,
472-
index=0,
473-
count=len(text),
474-
validate_content=validate_content,
475-
maxsize_condition=maxsize_condition,
476-
lease_id=lease_id,
477-
progress_callback=progress_callback,
478-
timeout=timeout)
477+
return self.append_blob_from_bytes(
478+
container_name,
479+
blob_name,
480+
text,
481+
index=0,
482+
count=len(text),
483+
validate_content=validate_content,
484+
maxsize_condition=maxsize_condition,
485+
lease_id=lease_id,
486+
progress_callback=progress_callback,
487+
timeout=timeout)
479488

480489
def append_blob_from_stream(
481490
self, container_name, blob_name, stream, count=None,
@@ -518,12 +527,18 @@ def append_blob_from_stream(
518527
The timeout parameter is expressed in seconds. This method may make
519528
multiple calls to the Azure service and the timeout will apply to
520529
each call individually.
530+
:return: ETag and last modified properties for the Append Blob
531+
:rtype: :class:`~azure.storage.blob.models.ResourceProperties`
521532
'''
522533
_validate_not_none('container_name', container_name)
523534
_validate_not_none('blob_name', blob_name)
524535
_validate_not_none('stream', stream)
525536
_validate_encryption_unsupported(self.require_encryption, self.key_encryption_key)
526537

538+
# _upload_blob_chunks returns the block ids for block blobs so resource_properties
539+
# is passed as a parameter to get the last_modified and etag for page and append blobs.
540+
# this info is not needed for block_blobs since _put_block_list is called after which gets this info
541+
resource_properties = ResourceProperties()
527542
_upload_blob_chunks(
528543
blob_service=self,
529544
container_name=container_name,
@@ -537,5 +552,8 @@ def append_blob_from_stream(
537552
lease_id=lease_id,
538553
uploader_class=_AppendBlobChunkUploader,
539554
maxsize_condition=maxsize_condition,
540-
timeout=timeout
541-
)
555+
timeout=timeout,
556+
resource_properties=resource_properties
557+
)
558+
559+
return resource_properties

azure/storage/blob/baseblobservice.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2981,6 +2981,7 @@ def copy_blob(self, container_name, blob_name, copy_source,
29812981
'''
29822982
return self._copy_blob(container_name, blob_name, copy_source,
29832983
metadata,
2984+
None,
29842985
source_if_modified_since, source_if_unmodified_since,
29852986
source_if_match, source_if_none_match,
29862987
destination_if_modified_since,
@@ -2993,6 +2994,7 @@ def copy_blob(self, container_name, blob_name, copy_source,
29932994

29942995
def _copy_blob(self, container_name, blob_name, copy_source,
29952996
metadata=None,
2997+
premium_page_blob_tier=None,
29962998
source_if_modified_since=None,
29972999
source_if_unmodified_since=None,
29983000
source_if_match=None, source_if_none_match=None,
@@ -3053,7 +3055,8 @@ def _copy_blob(self, container_name, blob_name, copy_source,
30533055
'If-Match': _to_str(destination_if_match),
30543056
'If-None-Match': _to_str(destination_if_none_match),
30553057
'x-ms-lease-id': _to_str(destination_lease_id),
3056-
'x-ms-source-lease-id': _to_str(source_lease_id)
3058+
'x-ms-source-lease-id': _to_str(source_lease_id),
3059+
'x-ms-access-tier': _to_str(premium_page_blob_tier)
30573060
}
30583061
_add_metadata_headers(metadata, request)
30593062

0 commit comments

Comments
 (0)