Azure File Share storage client library for Python
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The ShareLeaseClient provides lease management operations for files and shares, enabling exclusive access control through lease acquisition, renewal, release, and breaking operations.
from azure.storage.fileshare import ShareLeaseClient, ShareClient, ShareFileClient
from typing import Union, Any, Optionalclass ShareLeaseClient:
def __init__(
self,
client: Union[ShareClient, ShareFileClient],
lease_id: Optional[str] = None
) -> None:
"""
Create a ShareLeaseClient for managing leases.
Parameters:
client: ShareClient or ShareFileClient to manage leases for
lease_id: Optional existing lease ID (UUID format)
"""def acquire(
self,
**kwargs: Any
) -> None:
"""
Requests a new lease for the file or share.
Parameters:
lease_duration: Duration of the lease in seconds (-1 for infinite, default: -1)
timeout: Request timeout in seconds
Note:
- For files: lease_duration can be 15-60 seconds or -1 for infinite
- For shares: lease_duration is always infinite (-1)
- After acquisition, the lease_id property will contain the lease ID
"""
def renew(
self,
**kwargs: Any
) -> None:
"""
Renews the lease for the file or share.
Parameters:
timeout: Request timeout in seconds
Note:
- Lease must be in 'leased' state to be renewed
- Extends the lease for the same duration as originally acquired
"""
def release(
self,
**kwargs: Any
) -> None:
"""
Releases the lease for the file or share.
Parameters:
timeout: Request timeout in seconds
Note:
- Makes the file/share available for other operations immediately
- Lease cannot be renewed after release
"""
def change(
self,
proposed_lease_id: str,
**kwargs: Any
) -> None:
"""
Changes the lease ID of an active lease.
Parameters:
proposed_lease_id: New lease ID (UUID format)
timeout: Request timeout in seconds
Note:
- Lease must be in 'leased' state to change ID
- Updates the lease_id property to the new ID
"""
def break_lease(
self,
**kwargs: Any
) -> int:
"""
Breaks the lease, if the file or share has an active lease.
Parameters:
lease_break_period: Time to wait before lease is broken (0-60 seconds)
timeout: Request timeout in seconds
Returns:
int: Time remaining until lease is broken (seconds)
Note:
- If lease_break_period is not specified, lease breaks immediately
- Returns 0 if lease is broken immediately
"""@property
def id(self) -> str:
"""
The lease ID for the lease.
Returns:
str: UUID string representing the lease ID
"""
@property
def etag(self) -> Optional[str]:
"""
The ETag of the lease.
Returns:
Optional[str]: ETag from the last lease operation
"""
@property
def last_modified(self) -> Optional[datetime]:
"""
The last modified timestamp of the lease.
Returns:
Optional[datetime]: Last modified time from the last lease operation
"""def __enter__(self) -> ShareLeaseClient:
"""
Enter context manager and acquire lease.
Returns:
ShareLeaseClient: Self for use in with statement
"""
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
"""
Exit context manager and release lease.
Parameters:
exc_type: Exception type if exception occurred
exc_val: Exception value if exception occurred
exc_tb: Exception traceback if exception occurred
"""from azure.storage.fileshare import ShareFileClient, ShareLeaseClient
from azure.core.credentials import AzureNamedKeyCredential
import uuid
# Initialize file client
credential = AzureNamedKeyCredential("myaccount", "mykey")
file_client = ShareFileClient(
account_url="https://myaccount.file.core.windows.net",
share_name="documents",
file_path="important_file.txt",
credential=credential
)
# Acquire lease with specific ID
lease_id = str(uuid.uuid4())
lease_client = ShareLeaseClient(file_client, lease_id=lease_id)
lease_client.acquire(lease_duration=60) # 60-second lease
print(f"Lease acquired: {lease_client.id}")
# Perform operations with lease
try:
# File operations now require lease_id
file_client.set_file_metadata(
{"locked": "true", "locked_by": "process_123"},
lease_id=lease_client.id
)
# Upload new content with lease protection
file_client.upload_file(
data=b"Updated content under lease",
overwrite=True,
lease_id=lease_client.id
)
finally:
# Always release the lease
lease_client.release()
print("Lease released")# Automatic lease management using context manager
with ShareLeaseClient(file_client) as lease:
print(f"Lease automatically acquired: {lease.id}")
# Perform protected operations
file_client.upload_file(
data=b"Content updated with automatic lease management",
overwrite=True,
lease_id=lease.id
)
properties = file_client.get_file_properties()
print(f"File size: {properties.size} bytes")
# Lease is automatically released when exiting context
print("Lease automatically released")from azure.storage.fileshare import ShareClient
# Initialize share client
share_client = ShareClient(
account_url="https://myaccount.file.core.windows.net",
share_name="protected-share",
credential=credential
)
# Acquire infinite lease on share
share_lease = ShareLeaseClient(share_client)
share_lease.acquire() # Share leases are always infinite
print(f"Share lease acquired: {share_lease.id}")
try:
# Share operations require lease_id
share_client.set_share_metadata(
{"maintenance_mode": "true", "locked_by": "admin"},
lease_id=share_lease.id
)
# Create directory with share lease
directory_client = share_client.create_directory(
"maintenance",
lease_id=share_lease.id
)
finally:
share_lease.release()
print("Share lease released")import time
# Acquire short-term lease
lease_client = ShareLeaseClient(file_client)
lease_client.acquire(lease_duration=30) # 30-second lease
print(f"Initial lease acquired: {lease_client.id}")
# Simulate long-running operation with lease renewal
for i in range(5):
# Perform some work
print(f"Processing step {i+1}...")
time.sleep(10)
# Renew lease before it expires
try:
lease_client.renew()
print("Lease renewed successfully")
except Exception as e:
print(f"Failed to renew lease: {e}")
break
lease_client.release()import uuid
# Start with specific lease ID
original_lease_id = str(uuid.uuid4())
lease_client = ShareLeaseClient(file_client, lease_id=original_lease_id)
lease_client.acquire(lease_duration=-1) # Infinite lease
print(f"Original lease ID: {lease_client.id}")
# Change lease ID (useful for transferring lease ownership)
new_lease_id = str(uuid.uuid4())
lease_client.change(proposed_lease_id=new_lease_id)
print(f"Changed lease ID to: {lease_client.id}")
# Verify the change worked
assert lease_client.id == new_lease_id
print("Lease ID change confirmed")
# Operations now use new lease ID
file_client.set_file_metadata(
{"lease_changed": "true"},
lease_id=lease_client.id
)
lease_client.release()# Scenario: Another process needs to break an existing lease
lease_client = ShareLeaseClient(file_client)
lease_client.acquire(lease_duration=-1) # Infinite lease
print(f"Lease acquired: {lease_client.id}")
# Simulate another process that needs to break the lease
breaker_lease = ShareLeaseClient(file_client)
# Break the lease with 30-second break period
remaining_time = breaker_lease.break_lease(lease_break_period=30)
print(f"Lease break initiated, {remaining_time} seconds remaining")
# Original lease operations will now fail
try:
file_client.upload_file(
data=b"This will fail",
lease_id=lease_client.id
)
except Exception as e:
print(f"Operation failed as expected: {e}")
# Wait for lease to be broken or break immediately
if remaining_time > 0:
print("Waiting for lease to break naturally...")
time.sleep(remaining_time + 1)
else:
print("Lease broken immediately")
# Now operations work without lease
file_client.upload_file(data=b"This works after lease break", overwrite=True)
print("Operation successful after lease break")from azure.core.exceptions import HttpResponseError
def safe_lease_operations(file_client):
"""Demonstrate safe lease handling with error recovery."""
lease_client = ShareLeaseClient(file_client)
try:
# Attempt to acquire lease
lease_client.acquire(lease_duration=60)
print(f"Lease acquired successfully: {lease_client.id}")
# Perform operations
return perform_lease_operations(file_client, lease_client)
except HttpResponseError as e:
if e.error_code == "LeaseAlreadyPresent":
print("File is already leased by another client")
# Try to break existing lease
existing_lease = ShareLeaseClient(file_client)
existing_lease.break_lease(lease_break_period=0) # Break immediately
print("Broke existing lease, retrying...")
# Retry acquisition
lease_client.acquire(lease_duration=60)
return perform_lease_operations(file_client, lease_client)
else:
print(f"Lease operation failed: {e.message}")
raise
except Exception as e:
print(f"Unexpected error: {e}")
raise
finally:
# Ensure lease is released
try:
lease_client.release()
print("Lease released in cleanup")
except:
pass # Ignore release errors in cleanup
def perform_lease_operations(file_client, lease_client):
"""Perform file operations under lease protection."""
try:
# Update file metadata
file_client.set_file_metadata(
{"processing": "true", "start_time": time.time()},
lease_id=lease_client.id
)
# Simulate processing
print("Performing protected operations...")
time.sleep(2)
# Update content
file_client.upload_file(
data=b"Processed content",
overwrite=True,
lease_id=lease_client.id
)
# Final metadata update
file_client.set_file_metadata(
{"processing": "complete", "end_time": time.time()},
lease_id=lease_client.id
)
return True
except HttpResponseError as e:
if e.error_code in ["LeaseIdMissing", "LeaseIdMismatch", "LeaseNotPresent"]:
print("Lease was lost during operation")
return False
raise
# Use the safe lease operations
success = safe_lease_operations(file_client)
print(f"Operation completed successfully: {success}")import threading
import time
def worker_with_lease(worker_id, file_client, work_duration=5):
"""Worker function that tries to acquire lease and perform work."""
print(f"Worker {worker_id}: Starting")
lease_client = ShareLeaseClient(file_client)
try:
# Try to acquire lease
lease_client.acquire(lease_duration=work_duration + 5) # Extra buffer
print(f"Worker {worker_id}: Lease acquired {lease_client.id}")
# Perform exclusive work
for i in range(work_duration):
print(f"Worker {worker_id}: Working... step {i+1}")
# Update file to show work progress
file_client.set_file_metadata(
{
"worker": str(worker_id),
"step": str(i+1),
"timestamp": str(time.time())
},
lease_id=lease_client.id
)
time.sleep(1)
print(f"Worker {worker_id}: Work completed")
except HttpResponseError as e:
if e.error_code == "LeaseAlreadyPresent":
print(f"Worker {worker_id}: File is locked by another worker")
else:
print(f"Worker {worker_id}: Error - {e.message}")
except Exception as e:
print(f"Worker {worker_id}: Unexpected error - {e}")
finally:
try:
lease_client.release()
print(f"Worker {worker_id}: Lease released")
except:
pass
# Start multiple workers (only one will get the lease)
threads = []
for i in range(3):
thread = threading.Thread(target=worker_with_lease, args=(i, file_client))
threads.append(thread)
thread.start()
# Wait for all workers to complete
for thread in threads:
thread.join()
print("All workers finished")def monitor_lease_status(file_client, lease_client):
"""Monitor and report lease status."""
properties = file_client.get_file_properties()
lease_props = properties.lease
print(f"Lease Status Report:")
print(f" Status: {lease_props.status}") # locked/unlocked
print(f" State: {lease_props.state}") # available/leased/expired/breaking/broken
print(f" Duration: {lease_props.duration}") # infinite/fixed
if lease_props.state == "leased":
print(f" Current lease ID: {lease_client.id}")
print(f" Lease ETag: {lease_client.etag}")
print(f" Last modified: {lease_client.last_modified}")
return lease_props.state
# Demonstrate lease monitoring
lease_client = ShareLeaseClient(file_client)
# Before lease
print("Before acquiring lease:")
monitor_lease_status(file_client, lease_client)
# Acquire lease
lease_client.acquire(lease_duration=60)
print("\nAfter acquiring lease:")
state = monitor_lease_status(file_client, lease_client)
# Renew lease
if state == "leased":
lease_client.renew()
print("\nAfter renewing lease:")
monitor_lease_status(file_client, lease_client)
# Release lease
lease_client.release()
print("\nAfter releasing lease:")
monitor_lease_status(file_client, lease_client)The ShareLeaseClient provides robust lease management capabilities for controlling exclusive access to files and shares, ensuring data consistency and preventing concurrent modification conflicts in multi-client scenarios.
Install with Tessl CLI
npx tessl i tessl/pypi-azure-storage-file-share