Skip to content

[Storage] [Named Keywords] [Blob] _blob_client.py and aio #40206

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

Open
wants to merge 43 commits into
base: feature/storage-blob-named-keywords
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
9c44ab3
[WIP] _blob_client.py
weirongw23-msft Mar 24, 2025
58e2213
type/pylint ignore errors formatting for _blob_service_client.py
weirongw23-msft Mar 24, 2025
e3d51a8
BlobClient needs integral default values for max/min configs
weirongw23-msft Mar 25, 2025
978a151
[WIP] upload_blob
weirongw23-msft Mar 25, 2025
f7345a9
upload_blob
weirongw23-msft Mar 26, 2025
a7a5fa0
Removed extra file
weirongw23-msft Mar 26, 2025
bc46497
download_blob
weirongw23-msft Mar 26, 2025
1333854
Some formatting...
weirongw23-msft Mar 26, 2025
5e140d7
pop etag if None
weirongw23-msft Mar 26, 2025
0e0d185
match condition typo
weirongw23-msft Mar 26, 2025
abedcea
updated default values for upload/download apis
weirongw23-msft Mar 26, 2025
6061a3a
include_source_blob_properties in upload_blob_from_url should be defa…
weirongw23-msft Mar 27, 2025
e4df2ec
missing encryption_algorithm
weirongw23-msft Mar 27, 2025
688c71c
suppressed too-many-locals pylint error
weirongw23-msft Mar 27, 2025
5ef4abb
Fixed overloaded signature for download_blob API
weirongw23-msft Mar 27, 2025
83fef4b
delete_blob
weirongw23-msft Mar 27, 2025
f93bc36
query_blob
weirongw23-msft Mar 27, 2025
683fc8f
Fixed annotation errors for delete_blob
weirongw23-msft Mar 27, 2025
23fbeca
undelete_blob, get_blob_properties, exists
weirongw23-msft Mar 27, 2025
d44278c
Fixed cpk in get_blob_properties
weirongw23-msft Mar 28, 2025
613d33e
BlobQueryError import fix
weirongw23-msft Mar 28, 2025
1206998
set_blob_metadata
weirongw23-msft Apr 7, 2025
2fe75dc
set/delete_immutability_policy
weirongw23-msft Apr 7, 2025
cbab54e
set_legal_hold
weirongw23-msft Apr 7, 2025
77b13ab
create_page_blob
weirongw23-msft Apr 7, 2025
9c3975e
removed disable docstring should match keyword only
weirongw23-msft Apr 7, 2025
cbde1e4
create_append_blob
weirongw23-msft Apr 7, 2025
bef6ff3
create_snapshot
weirongw23-msft Apr 7, 2025
5a27b87
Fixed cls bug for ADLS calls to get_blob_properties
weirongw23-msft Apr 7, 2025
5b78142
start_copy_from_url
weirongw23-msft Apr 7, 2025
ba31f52
acquire_lease
weirongw23-msft Apr 7, 2025
7f0d109
set_standard_blob_tier
weirongw23-msft Apr 7, 2025
b16ee4a
stage_block
weirongw23-msft Apr 7, 2025
e127faf
converted kwargs.pop('kwarg', default_value) into kwargs.pop('kwarg')…
weirongw23-msft Apr 7, 2025
52f0e3e
Added implicit kwargs to from_* APIs for parity to the constructor
weirongw23-msft Apr 7, 2025
fe5e747
options update only non-None kwargs
weirongw23-msft Apr 9, 2025
e115a8b
Rest of the APIs
weirongw23-msft Apr 9, 2025
f7ad368
Fixed pylint and mypy errors
weirongw23-msft Apr 9, 2025
8de799a
Fixed missing await
weirongw23-msft Apr 9, 2025
d8aebd0
Fixed test failures
weirongw23-msft Apr 9, 2025
b6bf768
PR feedback
weirongw23-msft Apr 17, 2025
043c4ec
Reverted couple of redundant changes
weirongw23-msft Apr 17, 2025
ba17d5c
specific type ignore
weirongw23-msft Apr 17, 2025
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
1,348 changes: 1,131 additions & 217 deletions sdk/storage/azure-storage-blob/azure/storage/blob/_blob_client.py

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,17 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
def __init__(
self, account_url: str,
credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
*,
api_version: Optional[str] = None,
# TODO
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could remove this TODO if you want 😄 or leave it since it's going into a feature branch

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah I'll leave it so I know where to start <3

**kwargs: Any
) -> None:
parsed_url, sas_token = _parse_url(account_url=account_url)
_, sas_token = parse_query(parsed_url.query)
self._query_str, credential = self._format_query_string(sas_token, credential)
super(BlobServiceClient, self).__init__(parsed_url, service='blob', credential=credential, **kwargs)
self._client = AzureBlobStorage(self.url, base_url=self.url, pipeline=self._pipeline)
self._client._config.version = get_api_version(kwargs) # type: ignore [assignment]
self._client._config.version = get_api_version(api_version) # type: ignore [assignment]
self._configure_encryption(kwargs)

def _format_url(self, hostname):
Expand Down Expand Up @@ -240,7 +243,7 @@ def get_account_information(self, **kwargs: Any) -> Dict[str, str]:
:caption: Getting account information for the blob service.
"""
try:
return self._client.service.get_account_info(cls=return_response_headers, **kwargs) # type: ignore
return self._client.service.get_account_info(cls=return_response_headers, **kwargs) # type: ignore
except HttpResponseError as error:
process_storage_error(error)

Expand Down Expand Up @@ -284,7 +287,7 @@ def get_service_stats(self, **kwargs: Any) -> Dict[str, Any]:
"""
timeout = kwargs.pop('timeout', None)
try:
stats = self._client.service.get_statistics( # type: ignore
stats = self._client.service.get_statistics( # type: ignore
timeout=timeout, use_location=LocationMode.SECONDARY, **kwargs)
return service_stats_deserialize(stats)
except HttpResponseError as error:
Expand Down Expand Up @@ -391,7 +394,7 @@ def set_service_properties(
logging=analytics_logging,
hour_metrics=hour_metrics,
minute_metrics=minute_metrics,
cors=CorsRule._to_generated(cors), # pylint: disable=protected-access
cors=CorsRule._to_generated(cors), # pylint: disable=protected-access
default_service_version=target_version,
delete_retention_policy=delete_retention_policy,
static_website=static_website
Expand Down Expand Up @@ -648,7 +651,7 @@ def _rename_container(self, name: str, new_name: str, **kwargs: Any) -> Containe
except AttributeError:
kwargs['source_lease_id'] = lease
try:
renamed_container._client.container.rename(name, **kwargs) # pylint: disable = protected-access
renamed_container._client.container.rename(name, **kwargs) # pylint: disable=protected-access
return renamed_container
except HttpResponseError as error:
process_storage_error(error)
Expand Down Expand Up @@ -685,7 +688,7 @@ def undelete_container(
warnings.warn("`new_name` is no longer supported.", DeprecationWarning)
container = self.get_container_client(new_name or deleted_container_name)
try:
container._client.container.restore(deleted_container_name=deleted_container_name, # pylint: disable = protected-access
container._client.container.restore(deleted_container_name=deleted_container_name, # pylint: disable=protected-access
deleted_container_version=deleted_container_version,
timeout=kwargs.pop('timeout', None), **kwargs)
return container
Expand Down Expand Up @@ -718,8 +721,8 @@ def get_container_client(self, container: Union[ContainerProperties, str]) -> Co
else:
container_name = container
_pipeline = Pipeline(
transport=TransportWrapper(self._pipeline._transport), # pylint: disable = protected-access
policies=self._pipeline._impl_policies # pylint: disable = protected-access
transport=TransportWrapper(self._pipeline._transport), # pylint: disable=protected-access
policies=self._pipeline._impl_policies # pylint: disable=protected-access
)
return ContainerClient(
self.url, container_name=container_name,
Expand Down Expand Up @@ -776,8 +779,8 @@ def get_blob_client(
else:
container_name = container
_pipeline = Pipeline(
transport=TransportWrapper(self._pipeline._transport), # pylint: disable = protected-access
policies=self._pipeline._impl_policies # pylint: disable = protected-access
transport=TransportWrapper(self._pipeline._transport), # pylint: disable=protected-access
policies=self._pipeline._impl_policies # pylint: disable=protected-access
)
return BlobClient(
self.url, container_name=container_name, blob_name=blob_name, snapshot=snapshot,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ def __init__(
self, account_url: str,
container_name: str,
credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
*,
api_version: Optional[str] = None,
# TODO
**kwargs: Any
) -> None:
parsed_url, sas_token = _parse_url(account_url=account_url, container_name=container_name)
Expand All @@ -146,7 +149,7 @@ def __init__(
self._raw_credential = credential if credential else sas_token
self._query_str, credential = self._format_query_string(sas_token, credential)
super(ContainerClient, self).__init__(parsed_url, service='blob', credential=credential, **kwargs)
self._api_version = get_api_version(kwargs)
self._api_version = get_api_version(api_version)
self._client = self._build_generated_client()
self._configure_encryption(kwargs)

Expand Down
22 changes: 14 additions & 8 deletions sdk/storage/azure-storage-blob/azure/storage/blob/_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

if TYPE_CHECKING:
from ._lease import BlobLeaseClient
from aio._lease_async import BlobLeaseClient as AsyncBlobLeaseClient


_SUPPORTED_API_VERSIONS = [
Expand Down Expand Up @@ -90,12 +91,16 @@ def _get_match_headers(
return if_match, if_none_match


def get_access_conditions(lease: Optional[Union["BlobLeaseClient", str]]) -> Optional[LeaseAccessConditions]:
try:
lease_id = lease.id # type: ignore
except AttributeError:
lease_id = lease # type: ignore
return LeaseAccessConditions(lease_id=lease_id) if lease_id else None
def get_access_conditions(
lease: Optional[Union["BlobLeaseClient", "AsyncBlobLeaseClient", str]]
) -> Optional[LeaseAccessConditions]:
if lease is None:
return None
if hasattr(lease, "id"):
lease_id = lease.id # type: ignore
else:
lease_id = lease # type: ignore
return LeaseAccessConditions(lease_id=lease_id)


def get_modify_conditions(kwargs: Dict[str, Any]) -> ModifiedAccessConditions:
Expand Down Expand Up @@ -143,18 +148,19 @@ def get_container_cpk_scope_info(kwargs: Dict[str, Any]) -> Optional[ContainerCp
return None


def get_api_version(kwargs: Dict[str, Any]) -> str:
api_version = kwargs.get('api_version', None)
def get_api_version(api_version: Optional[str] = None) -> str:
if api_version and api_version not in _SUPPORTED_API_VERSIONS:
versions = '\n'.join(_SUPPORTED_API_VERSIONS)
raise ValueError(f"Unsupported API version '{api_version}'. Please select from:\n{versions}")
return api_version or _SUPPORTED_API_VERSIONS[-1]


def get_version_id(self_vid: Optional[str], kwargs: Dict[str, Any]) -> Optional[str]:
if 'version_id' in kwargs:
return cast(str, kwargs.pop('version_id'))
return self_vid


def serialize_blob_tags_header(tags: Optional[Dict[str, str]] = None) -> Optional[str]:
if tags is None:
return None
Expand Down
Loading
Loading