Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions sdk/storage/azure-storage-file-share/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
## 12.26.0b1 (Unreleased)

### Features Added
- Added support for the keyword `file_property_semantics` in `ShareClient`'s `create_directory` and `DirectoryClient`'s
`create_directory` APIs, which specifies permissions to be configured upon directory creation.
- Added support for the keyword `data` to `FileClient`'s `create_file` API, which specifies the
optional initial data to be uploaded (up to 4MB).

## 12.25.0b1 (2026-01-27)

Expand Down
2 changes: 1 addition & 1 deletion sdk/storage/azure-storage-file-share/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "python",
"TagPrefix": "python/storage/azure-storage-file-share",
"Tag": "python/storage/azure-storage-file-share_c5fe7fb7b7"
"Tag": "python/storage/azure-storage-file-share_b02a740ab3"
}
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,16 @@ def create_directory(self, **kwargs: Any) -> Dict[str, Any]:
NFS only. The owning group of the directory.
:keyword str file_mode:
NFS only. The file mode of the directory.
:keyword file_property_semantics:
SMB only. Specifies permissions to be configured. Default value is None.
If not specified or None is passed, New will be the default. Possible values are:

New - forcefully add the ARCHIVE attribute flag and alter the permissions specified in
x-ms-file-permission to inherit missing permissions from the parent.

Restore - apply changes without further modification.

:paramtype file_property_semantics: Optional[Literal["New", "Restore"]]
:keyword int timeout:
Sets the server-side timeout for the operation in seconds. For more details see
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class ShareDirectoryClient(StorageAccountHostsMixin):
owner: Optional[str] = None,
group: Optional[str] = None,
file_mode: Optional[str] = None,
file_property_semantics: Optional[Literal["New", "Restore"]] = None,
timeout: Optional[int] = None,
**kwargs: Any
) -> Dict[str, Any]: ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,18 @@ def create_file(
NFS only. The owning group of the file.
:keyword str file_mode:
NFS only. The file mode of the file.
:keyword file_property_semantics:
SMB only. Specifies permissions to be configured. Default value is None.
If not specified or None is passed, New will be the default. Possible values are:

New - forcefully add the ARCHIVE attribute flag and alter the permissions specified in
x-ms-file-permission to inherit missing permissions from the parent.

Restore - apply changes without further modification.

:paramtype file_property_semantics: Optional[Literal["New", "Restore"]]
:keyword data: Optional initial data to upload, up to 4MB.
:paramtype data: bytes
:keyword int timeout:
Sets the server-side timeout for the operation in seconds. For more details see
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ class ShareFileClient(StorageAccountHostsMixin):
owner: Optional[str] = None,
group: Optional[str] = None,
file_mode: Optional[str] = None,
file_property_semantics: Optional[Literal["New", "Restore"]] = None,
data: Optional[bytes] = None,
timeout: Optional[int] = None,
**kwargs: Any
) -> Dict[str, Any]: ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,16 @@ def create_directory(self, directory_name: str, **kwargs: Any) -> ShareDirectory
NFS only. The owning group of the directory.
:keyword str file_mode:
NFS only. The file mode of the directory.
:keyword file_property_semantics:
SMB only. Specifies permissions to be configured. Default value is None.
If not specified or None is passed, New will be the default. Possible values are:

New - forcefully add the ARCHIVE attribute flag and alter the permissions specified in
x-ms-file-permission to inherit missing permissions from the parent.

Restore - apply changes without further modification.

:paramtype file_property_semantics: Optional[Literal["New", "Restore"]]
:keyword int timeout:
Sets the server-side timeout for the operation in seconds. For more details see
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ class ShareClient(StorageAccountHostsMixin):
owner: Optional[str] = None,
group: Optional[str] = None,
file_mode: Optional[str] = None,
file_property_semantics: Optional[Literal["New", "Restore"]] = None,
timeout: Optional[int] = None,
**kwargs: Any
) -> ShareDirectoryClient: ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,16 @@ async def create_directory(self, **kwargs: Any) -> Dict[str, Any]:
NFS only. The owning group of the directory.
:keyword str file_mode:
NFS only. The file mode of the directory.
:keyword file_property_semantics:
SMB only. Specifies permissions to be configured. Default value is None.
If not specified or None is passed, New will be the default. Possible values are:

New - forcefully add the ARCHIVE attribute flag and alter the permissions specified in
x-ms-file-permission to inherit missing permissions from the parent.

Restore - apply changes without further modification.

:paramtype file_property_semantics: Optional[Literal["New", "Restore"]]
:keyword int timeout:
Sets the server-side timeout for the operation in seconds. For more details see
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class ShareDirectoryClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMix
owner: Optional[str] = None,
group: Optional[str] = None,
file_mode: Optional[str] = None,
file_property_semantics: Optional[Literal["New", "Restore"]] = None,
timeout: Optional[int] = None,
**kwargs: Any
) -> Dict[str, Any]: ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,18 @@ async def create_file(
NFS only. The owning group of the file.
:keyword str file_mode:
NFS only. The file mode of the file.
:keyword file_property_semantics:
SMB only. Specifies permissions to be configured. Default value is None.
If not specified or None is passed, New will be the default. Possible values are:

New - forcefully add the ARCHIVE attribute flag and alter the permissions specified in
x-ms-file-permission to inherit missing permissions from the parent.

Restore - apply changes without further modification.

:paramtype file_property_semantics: Optional[Literal["New", "Restore"]]
:keyword data: Optional initial data to upload, up to 4MB.
:paramtype data: bytes
:keyword int timeout:
Sets the server-side timeout for the operation in seconds. For more details see
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ class ShareFileClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin):
owner: Optional[str] = None,
group: Optional[str] = None,
file_mode: Optional[str] = None,
file_property_semantics: Optional[Literal["New", "Restore"]] = None,
data: Optional[bytes] = None,
timeout: Optional[int] = None,
**kwargs: Any
) -> Dict[str, Any]: ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,16 @@ async def create_directory(self, directory_name: str, **kwargs: Any) -> ShareDir
NFS only. The owning group of the directory.
:keyword str file_mode:
NFS only. The file mode of the directory.
:keyword file_property_semantics:
SMB only. Specifies permissions to be configured. Default value is None.
If not specified or None is passed, New will be the default. Possible values are:

New - forcefully add the ARCHIVE attribute flag and alter the permissions specified in
x-ms-file-permission to inherit missing permissions from the parent.

Restore - apply changes without further modification.

:paramtype file_property_semantics: Optional[Literal["New", "Restore"]]
:keyword int timeout:
Sets the server-side timeout for the operation in seconds. For more details see
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ class ShareClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin): # t
owner: Optional[str] = None,
group: Optional[str] = None,
file_mode: Optional[str] = None,
file_property_semantics: Optional[Literal["New", "Restore"]] = None,
timeout: Optional[int] = None,
**kwargs: Any
) -> ShareDirectoryClient: ...
Expand Down
24 changes: 24 additions & 0 deletions sdk/storage/azure-storage-file-share/tests/test_directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import os
import unittest
from datetime import datetime, timedelta, timezone

Expand Down Expand Up @@ -1477,6 +1478,29 @@ def test_file_permission_format_directory(self, **kwargs):

new_directory_client.delete_directory()

@FileSharePreparer()
@recorded_by_proxy
def test_create_directory_semantics(self, **kwargs):
storage_account_name = kwargs.pop("storage_account_name")
storage_account_key = kwargs.pop("storage_account_key")

self._setup(storage_account_name, storage_account_key)
share_client = self.fsc.get_share_client(self.share_name)

directory = share_client.create_directory('dir1', file_property_semantics=None)
props = directory.get_directory_properties()
assert props is not None

directory = share_client.create_directory('dir2', file_property_semantics='New')
props = directory.get_directory_properties()
assert props is not None

directory = share_client.create_directory(
'dir3', file_property_semantics='Restore', file_permission=TEST_FILE_PERMISSIONS
)
props = directory.get_directory_properties()
assert props is not None

# ------------------------------------------------------------------------------
if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import unittest
import asyncio
import os
import unittest
from datetime import datetime, timedelta, timezone

import pytest
Expand Down Expand Up @@ -1580,4 +1581,27 @@ async def test_file_permission_format_directory(self, **kwargs):

await new_directory_client.delete_directory()

@FileSharePreparer()
@recorded_by_proxy_async
async def test_create_directory_semantics(self, **kwargs):
storage_account_name = kwargs.pop("storage_account_name")
storage_account_key = kwargs.pop("storage_account_key")

await self._setup(storage_account_name, storage_account_key)
share_client = self.fsc.get_share_client(self.share_name)

directory = await share_client.create_directory('dir1', file_property_semantics=None)
props = await directory.get_directory_properties()
assert props is not None

directory = await share_client.create_directory('dir2', file_property_semantics='New')
props = await directory.get_directory_properties()
assert props is not None

directory = await share_client.create_directory(
'dir3', file_property_semantics='Restore', file_permission=TEST_FILE_PERMISSIONS
)
props = await directory.get_directory_properties()
assert props is not None

# ------------------------------------------------------------------------------
60 changes: 60 additions & 0 deletions sdk/storage/azure-storage-file-share/tests/test_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -4015,4 +4015,64 @@ def test_download_file_no_decompress_chunks(self, **kwargs):
result = file_client.download_file(decompress=False).readall()
assert result == compressed_data

@FileSharePreparer()
@recorded_by_proxy
def test_create_file_semantics(self, **kwargs):
storage_account_name = kwargs.pop("storage_account_name")
storage_account_key = kwargs.pop("storage_account_key")

self._setup(storage_account_name, storage_account_key)
storage_account_key = storage_account_key.secret
file_name = self._get_file_reference()

file1 = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file1",
credential=storage_account_key
)
file1.create_file(1024, file_property_semantics=None)
props = file1.get_file_properties()
assert props is not None

file2 = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file2",
credential=storage_account_key
)
file2.create_file(1024, file_property_semantics="New")
props = file2.get_file_properties()
assert props is not None

file3 = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file2",
credential=storage_account_key
)
file3.create_file(1024, file_property_semantics="Restore", file_permission=TEST_FILE_PERMISSIONS)
props = file3.get_file_properties()
assert props is not None

@FileSharePreparer()
@recorded_by_proxy
def test_create_file_with_data(self, **kwargs):
storage_account_name = kwargs.pop("storage_account_name")
storage_account_key = kwargs.pop("storage_account_key")

self._setup(storage_account_name, storage_account_key)
file_name = self._get_file_reference()
file_client = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file",
credential=storage_account_key.secret
)
size = 1024
data = b"abc" * size
file_client.create_file(len(data), data=data)
downloaded_data = file_client.download_file().readall()
assert downloaded_data == data

# ------------------------------------------------------------------------------
64 changes: 63 additions & 1 deletion sdk/storage/azure-storage-file-share/tests/test_file_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------

import asyncio
import base64
import os
Expand Down Expand Up @@ -4141,3 +4140,66 @@ async def test_download_file_no_decompress_chunks(self, **kwargs):

result = await (await file_client.download_file(decompress=False)).readall()
assert result == compressed_data

@FileSharePreparer()
@recorded_by_proxy_async
async def test_create_file_semantics(self, **kwargs):
storage_account_name = kwargs.pop("storage_account_name")
storage_account_key = kwargs.pop("storage_account_key")

self._setup(storage_account_name, storage_account_key)
await self._setup_share(storage_account_name, storage_account_key)
storage_account_key = storage_account_key.secret
file_name = self._get_file_reference()

file1 = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file1",
credential=storage_account_key
)
await file1.create_file(1024, file_property_semantics=None)
props = await file1.get_file_properties()
assert props is not None

file2 = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file2",
credential=storage_account_key
)
await file2.create_file(1024, file_property_semantics="New")
props = await file2.get_file_properties()
assert props is not None

file3 = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file2",
credential=storage_account_key
)
await file3.create_file(1024, file_property_semantics="Restore", file_permission=TEST_FILE_PERMISSIONS)
props = await file3.get_file_properties()
assert props is not None

@FileSharePreparer()
@recorded_by_proxy_async
async def test_create_file_with_data(self, **kwargs):
storage_account_name = kwargs.pop("storage_account_name")
storage_account_key = kwargs.pop("storage_account_key")

self._setup(storage_account_name, storage_account_key)
await self._setup_share(storage_account_name, storage_account_key)

file_name = self._get_file_reference()
file_client = ShareFileClient(
self.account_url(storage_account_name, "file"),
share_name=self.share_name,
file_path=file_name + "file",
credential=storage_account_key.secret
)
size = 1024
data = b"abc" * size
await file_client.create_file(len(data), data=data)
downloaded_data = await (await file_client.download_file()).readall()
assert downloaded_data == data