Skip to content

[Storage] [Typing] [Blob] Misc files (_serialize.py, _deserialize.py, _download.py) #33613

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
bd51fee
Draft 1
vincenttran-msft Dec 7, 2023
428a923
Fix imporT
vincenttran-msft Dec 7, 2023
a0643ad
Fix try-except logic
vincenttran-msft Dec 7, 2023
99696b1
Fix import order
vincenttran-msft Dec 7, 2023
cdba8f5
Fix import
vincenttran-msft Dec 7, 2023
64f5b6c
PR feedback
vincenttran-msft Dec 8, 2023
e914972
lint
vincenttran-msft Dec 8, 2023
e4e82c9
No more errors _container_client_helpers
vincenttran-msft Dec 13, 2023
1709984
Omitted one last _build_generated_client substitution
vincenttran-msft Dec 13, 2023
7559229
Lint
vincenttran-msft Dec 14, 2023
1dd5560
Bring generated helper back
vincenttran-msft Dec 18, 2023
e1514a6
_serialize v1
vincenttran-msft Dec 18, 2023
3e49c5e
Fix collection error
vincenttran-msft Dec 19, 2023
7d59bfe
Fix dialect import
vincenttran-msft Dec 19, 2023
a6c0350
Fixing _deserialize, required _models changes
vincenttran-msft Dec 19, 2023
0b74704
Merge branch 'feature/storage-blob-typing2' into vincenttran/blob_typ…
vincenttran-msft Dec 19, 2023
ceb4f41
Fix PageList import in deserialize, pt1 download
vincenttran-msft Dec 19, 2023
8fb36ef
Finished download to the best of my ability
vincenttran-msft Dec 20, 2023
a832be5
Fix some failing tests
vincenttran-msft Dec 20, 2023
f68e765
Fix content type in _download
vincenttran-msft Dec 20, 2023
165d319
Fix erroneous typehint in _encryption and fix failing download
vincenttran-msft Dec 20, 2023
08c07d1
Fixed test_put_blob tests
vincenttran-msft Dec 20, 2023
ba2cbeb
Fixed all download tests hopefully
vincenttran-msft Dec 20, 2023
eba3fd0
Finish _download.py
vincenttran-msft Dec 20, 2023
ce6855a
Fix ivar
vincenttran-msft Dec 20, 2023
26239ed
PR feedback 1
vincenttran-msft Jan 9, 2024
cb274e9
Get _download in a good state, rollback _models
vincenttran-msft Jan 11, 2024
ec516fa
Fix PyLint
vincenttran-msft Jan 11, 2024
0205dc7
Download Fb
vincenttran-msft Jan 12, 2024
fa975fb
Fix typehint for parse_tags here for blob_client PR
vincenttran-msft Jan 12, 2024
66474b9
Revert parse_tags
vincenttran-msft Jan 12, 2024
a7b48e5
More correct type-hint for parse_tags
vincenttran-msft Jan 12, 2024
1fed0df
unused import..
vincenttran-msft Jan 12, 2024
662b90b
unused import
vincenttran-msft Jan 13, 2024
c07cc0e
Feedback round
vincenttran-msft Jan 22, 2024
93b2b7d
indents pylint
vincenttran-msft Jan 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 62 additions & 36 deletions sdk/storage/azure-storage-blob/azure/storage/blob/_deserialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
# license information.
# --------------------------------------------------------------------------

from typing import (
Dict, List, Optional, Tuple, Union,
TYPE_CHECKING
)
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING
from urllib.parse import unquote
from xml.etree.ElementTree import Element

Expand All @@ -25,24 +23,31 @@
ObjectReplicationPolicy,
ObjectReplicationRule,
RetentionPolicy,
StaticWebsite,
StaticWebsite
)
from ._shared.models import get_enum_value
from ._shared.response_handlers import deserialize_metadata

if TYPE_CHECKING:
from ._generated.models import BlobTag, PageList

from azure.core.pipeline import PipelineResponse
from ._generated.models import (
BlobItemInternal,
BlobTags,
PageList,
StorageServiceProperties,
StorageServiceStats,
)
from ._shared.models import LocationMode

def deserialize_pipeline_response_into_cls(cls_method, response, obj, headers):
def deserialize_pipeline_response_into_cls(cls_method, response: "PipelineResponse", obj: Any, headers: Dict[str, Any]):
try:
deserialized_response = response.http_response
except AttributeError:
deserialized_response = response
return cls_method(deserialized_response, obj, headers)


def deserialize_blob_properties(response, obj, headers):
def deserialize_blob_properties(response: "PipelineResponse", obj: Any, headers: Dict[str, Any]) -> BlobProperties:
blob_properties = BlobProperties(
metadata=deserialize_metadata(response, obj, headers),
object_replication_source_properties=deserialize_ors_policies(response.http_response.headers),
Expand All @@ -56,7 +61,7 @@ def deserialize_blob_properties(response, obj, headers):
return blob_properties


def deserialize_ors_policies(policy_dictionary):
def deserialize_ors_policies(policy_dictionary: Optional[Dict[str, str]]) -> Optional[List[ObjectReplicationPolicy]]:

if policy_dictionary is None:
return None
Expand All @@ -83,13 +88,21 @@ def deserialize_ors_policies(policy_dictionary):
return result_list


def deserialize_blob_stream(response, obj, headers):
def deserialize_blob_stream(
response: "PipelineResponse",
obj: Any,
headers: Dict[str, Any]
) -> Tuple["LocationMode", Any]:
blob_properties = deserialize_blob_properties(response, obj, headers)
obj.properties = blob_properties
return response.http_response.location_mode, obj


def deserialize_container_properties(response, obj, headers):
def deserialize_container_properties(
response: "PipelineResponse",
obj: Any,
headers: Dict[str, Any]
) -> ContainerProperties:
metadata = deserialize_metadata(response, obj, headers)
container_properties = ContainerProperties(
metadata=metadata,
Expand All @@ -98,45 +111,50 @@ def deserialize_container_properties(response, obj, headers):
return container_properties


def get_page_ranges_result(ranges):
# type: (PageList) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]
page_range = [] # type: ignore
clear_range = [] # type: List
def get_page_ranges_result(ranges: "PageList") -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]:
page_range = []
clear_range: List = []
if ranges.page_range:
page_range = [{'start': b.start, 'end': b.end} for b in ranges.page_range] # type: ignore
page_range = [{'start': b.start, 'end': b.end} for b in ranges.page_range]
if ranges.clear_range:
clear_range = [{'start': b.start, 'end': b.end} for b in ranges.clear_range]
return page_range, clear_range # type: ignore
return page_range, clear_range


# Deserialize a ServiceStats objects into a dict.
def service_stats_deserialize(generated):
def service_stats_deserialize(generated: "StorageServiceStats") -> Dict[str, Any]:
status = None
last_sync_time = None
if generated.geo_replication is not None:
status = generated.geo_replication.status
last_sync_time = generated.geo_replication.last_sync_time
return {
'geo_replication': {
'status': generated.geo_replication.status,
'last_sync_time': generated.geo_replication.last_sync_time,
'status': status,
'last_sync_time': last_sync_time
}
}

# Deserialize a ServiceProperties objects into a dict.
def service_properties_deserialize(generated):
def service_properties_deserialize(generated: "StorageServiceProperties") -> Dict[str, Any]:
cors_list = None
if generated.cors is not None:
cors_list = [CorsRule._from_generated(cors) for cors in generated.cors]
return {
'analytics_logging': BlobAnalyticsLogging._from_generated(generated.logging), # pylint: disable=protected-access
'hour_metrics': Metrics._from_generated(generated.hour_metrics), # pylint: disable=protected-access
'minute_metrics': Metrics._from_generated(generated.minute_metrics), # pylint: disable=protected-access
'cors': [CorsRule._from_generated(cors) for cors in generated.cors], # pylint: disable=protected-access
'cors': cors_list,
'target_version': generated.default_service_version, # pylint: disable=protected-access
'delete_retention_policy': RetentionPolicy._from_generated(generated.delete_retention_policy), # pylint: disable=protected-access
'static_website': StaticWebsite._from_generated(generated.static_website), # pylint: disable=protected-access
}


def get_blob_properties_from_generated_code(generated):
def get_blob_properties_from_generated_code(generated: "BlobItemInternal") -> BlobProperties:
blob = BlobProperties()
if generated.name.encoded:
if generated.name.encoded and generated.name.content is not None:
blob.name = unquote(generated.name.content)
else:
blob.name = generated.name.content
blob.name = generated.name.content #type: ignore
blob_type = get_enum_value(generated.properties.blob_type)
blob.blob_type = BlobType(blob_type) if blob_type else None
blob.etag = generated.properties.etag
Expand Down Expand Up @@ -172,11 +190,11 @@ def get_blob_properties_from_generated_code(generated):
blob.has_versions_only = generated.has_versions_only
return blob

def parse_tags(generated_tags: Optional[List["BlobTag"]]) -> Union[Dict[str, str], None]:
def parse_tags(generated_tags: Optional["BlobTags"]) -> Union[Dict[str, str], None]:
"""Deserialize a list of BlobTag objects into a dict.

:param Optional[List[BlobTag]] generated_tags:
A list containing the BlobTag objects from generated code.
:param Optional[[BlobTags]] generated_tags:
The BlobTags objects from generated code.
:returns: A dictionary of the BlobTag objects.
:rtype: Dict[str, str] or None
"""
Expand All @@ -186,24 +204,32 @@ def parse_tags(generated_tags: Optional[List["BlobTag"]]) -> Union[Dict[str, str
return None


def load_single_xml_node(element: Element, name: str) -> Union[Element, None]:
return element.find(name)
def load_single_xml_node(element: Element, name: str) -> Element:
found_element = element.find(name)
if found_element is not None:
return found_element
else:
raise ValueError("No element found.")


def load_many_xml_nodes(element: Element, name: str, wrapper: Element = None) -> List[Union[Element, None]]:
def load_many_xml_nodes(
element: Element,
name: str,
wrapper: Optional[str] = None
) -> Any:
if wrapper:
element = load_single_xml_node(element, wrapper)
return list(element.findall(name))


def load_xml_string(element: Element, name: str) -> str:
def load_xml_string(element: Element, name: str) -> Optional[str]:
node = element.find(name)
if node is None or not node.text:
return None
return node.text


def load_xml_int(element: Element, name: str) -> int:
def load_xml_int(element: Element, name: str) -> Optional[int]:
node = element.find(name)
if node is None or not node.text:
return None
Expand Down
Loading