azpaddypy 0.5.9__py3-none-any.whl → 0.5.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,8 +5,11 @@ including Key Vault, Storage, and other Azure services.
5
5
  """
6
6
 
7
7
  from .keyvault import AzureKeyVault, create_azure_keyvault
8
+ from .storage import AzureStorage, create_azure_storage
8
9
 
9
10
  __all__ = [
10
11
  "AzureKeyVault",
11
12
  "create_azure_keyvault",
13
+ "AzureStorage",
14
+ "create_azure_storage",
12
15
  ]
@@ -0,0 +1,830 @@
1
+ from typing import Optional, Dict, Any, Union, List, BinaryIO
2
+ from azure.storage.blob import BlobServiceClient, BlobClient, ContainerClient
3
+ from azure.storage.fileshare import ShareServiceClient, ShareClient, ShareFileClient
4
+ from azure.storage.queue import QueueServiceClient, QueueClient
5
+ from azure.core.exceptions import ResourceNotFoundError, ClientAuthenticationError, ResourceExistsError
6
+ from azure.core.credentials import TokenCredential
7
+ from ..mgmt.logging import AzureLogger
8
+ from ..mgmt.identity import AzureIdentity
9
+ import io
10
+ from datetime import datetime
11
+
12
+
13
+ class AzureStorage:
14
+ """Azure Storage Account management with comprehensive blob, file, and queue operations.
15
+
16
+ Provides standardized Azure Storage operations using Azure SDK clients
17
+ with integrated logging, error handling, and OpenTelemetry tracing support.
18
+ Supports operations for blob storage, file shares, and queues with proper
19
+ authentication and authorization handling. Container and queue creation
20
+ is handled by infrastructure as code.
21
+
22
+ Attributes:
23
+ account_url: Azure Storage Account URL
24
+ service_name: Service identifier for logging and tracing
25
+ service_version: Service version for context
26
+ logger: AzureLogger instance for structured logging
27
+ credential: Azure credential for authentication
28
+ blob_service_client: Azure Blob Service Client instance
29
+ file_service_client: Azure File Share Service Client instance
30
+ queue_service_client: Azure Queue Service Client instance
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ account_url: str,
36
+ credential: Optional[TokenCredential] = None,
37
+ azure_identity: Optional[AzureIdentity] = None,
38
+ service_name: str = "azure_storage",
39
+ service_version: str = "1.0.0",
40
+ logger: Optional[AzureLogger] = None,
41
+ connection_string: Optional[str] = None,
42
+ enable_blob_storage: bool = True,
43
+ enable_file_storage: bool = True,
44
+ enable_queue_storage: bool = True,
45
+ ):
46
+ """Initialize Azure Storage with comprehensive configuration.
47
+
48
+ Args:
49
+ account_url: Azure Storage Account URL (e.g., https://account.blob.core.windows.net/)
50
+ credential: Azure credential for authentication
51
+ azure_identity: AzureIdentity instance for credential management
52
+ service_name: Service name for tracing context
53
+ service_version: Service version for metadata
54
+ logger: Optional AzureLogger instance
55
+ connection_string: Application Insights connection string
56
+ enable_blob_storage: Enable blob storage operations client
57
+ enable_file_storage: Enable file storage operations client
58
+ enable_queue_storage: Enable queue storage operations client
59
+
60
+ Raises:
61
+ ValueError: If neither credential nor azure_identity is provided
62
+ Exception: If client initialization fails
63
+ """
64
+ self.account_url = account_url
65
+ self.service_name = service_name
66
+ self.service_version = service_version
67
+ self.enable_blob_storage = enable_blob_storage
68
+ self.enable_file_storage = enable_file_storage
69
+ self.enable_queue_storage = enable_queue_storage
70
+
71
+ # Initialize logger - use provided instance or create new one
72
+ if logger is not None:
73
+ self.logger = logger
74
+ else:
75
+ self.logger = AzureLogger(
76
+ service_name=service_name,
77
+ service_version=service_version,
78
+ connection_string=connection_string,
79
+ enable_console_logging=True,
80
+ )
81
+
82
+ # Setup credential
83
+ if azure_identity is not None:
84
+ self.credential = azure_identity.get_credential()
85
+ self.azure_identity = azure_identity
86
+ elif credential is not None:
87
+ self.credential = credential
88
+ self.azure_identity = None
89
+ else:
90
+ raise ValueError("Either 'credential' or 'azure_identity' must be provided")
91
+
92
+ # Initialize clients
93
+ self.blob_service_client = None
94
+ self.file_service_client = None
95
+ self.queue_service_client = None
96
+
97
+ self._setup_clients()
98
+
99
+ self.logger.info(
100
+ f"Azure Storage initialized for service '{service_name}' v{service_version}",
101
+ extra={
102
+ "account_url": account_url,
103
+ "blob_enabled": enable_blob_storage,
104
+ "file_enabled": enable_file_storage,
105
+ "queue_enabled": enable_queue_storage,
106
+ }
107
+ )
108
+
109
+ def _setup_clients(self):
110
+ """Initialize Storage clients based on enabled features.
111
+
112
+ Raises:
113
+ Exception: If client initialization fails
114
+ """
115
+ try:
116
+ if self.enable_blob_storage:
117
+ self.blob_service_client = BlobServiceClient(
118
+ account_url=self.account_url,
119
+ credential=self.credential
120
+ )
121
+ self.logger.debug("BlobServiceClient initialized successfully")
122
+
123
+ if self.enable_file_storage:
124
+ # Convert blob URL to file URL
125
+ file_url = self.account_url.replace('.blob.', '.file.')
126
+ self.file_service_client = ShareServiceClient(
127
+ account_url=file_url,
128
+ credential=self.credential,
129
+ token_intent='backup'
130
+ )
131
+ self.logger.debug("ShareServiceClient initialized successfully")
132
+
133
+ if self.enable_queue_storage:
134
+ # Convert blob URL to queue URL
135
+ queue_url = self.account_url.replace('.blob.', '.queue.')
136
+ self.queue_service_client = QueueServiceClient(
137
+ account_url=queue_url,
138
+ credential=self.credential
139
+ )
140
+ self.logger.debug("QueueServiceClient initialized successfully")
141
+
142
+ except Exception as e:
143
+ self.logger.error(
144
+ f"Failed to initialize Storage clients: {e}",
145
+ exc_info=True
146
+ )
147
+ raise
148
+
149
+ # Blob Storage Operations
150
+ def upload_blob(
151
+ self,
152
+ container_name: str,
153
+ blob_name: str,
154
+ data: Union[bytes, str, BinaryIO],
155
+ overwrite: bool = False,
156
+ metadata: Optional[Dict[str, str]] = None,
157
+ content_type: Optional[str] = None,
158
+ **kwargs
159
+ ) -> bool:
160
+ """Upload a blob to Azure Blob Storage.
161
+
162
+ Args:
163
+ container_name: Name of the container
164
+ blob_name: Name of the blob
165
+ data: Data to upload (bytes, string, or file-like object)
166
+ overwrite: Whether to overwrite existing blob
167
+ metadata: Optional metadata for the blob
168
+ content_type: Optional content type for the blob
169
+ **kwargs: Additional parameters for blob upload
170
+
171
+ Returns:
172
+ True if blob was uploaded successfully
173
+
174
+ Raises:
175
+ RuntimeError: If blob service client is not initialized
176
+ Exception: If blob upload fails
177
+ """
178
+ with self.logger.create_span(
179
+ "AzureStorage.upload_blob",
180
+ attributes={
181
+ "service.name": self.service_name,
182
+ "operation.type": "blob_upload",
183
+ "storage.container_name": container_name,
184
+ "storage.blob_name": blob_name,
185
+ "storage.account_url": self.account_url
186
+ }
187
+ ):
188
+ if self.blob_service_client is None:
189
+ error_msg = "Blob service client not initialized. Enable blob storage during initialization."
190
+ self.logger.error(error_msg)
191
+ raise RuntimeError(error_msg)
192
+
193
+ try:
194
+ self.logger.debug(
195
+ "Uploading blob to Azure Storage",
196
+ extra={
197
+ "container_name": container_name,
198
+ "blob_name": blob_name,
199
+ "overwrite": overwrite,
200
+ "has_metadata": metadata is not None,
201
+ "content_type": content_type
202
+ }
203
+ )
204
+
205
+ blob_client = self.blob_service_client.get_blob_client(
206
+ container=container_name,
207
+ blob=blob_name
208
+ )
209
+
210
+ blob_client.upload_blob(
211
+ data,
212
+ overwrite=overwrite,
213
+ metadata=metadata,
214
+ content_type=content_type,
215
+ **kwargs
216
+ )
217
+
218
+ self.logger.info(
219
+ "Blob uploaded successfully",
220
+ extra={
221
+ "container_name": container_name,
222
+ "blob_name": blob_name,
223
+ "overwrite": overwrite
224
+ }
225
+ )
226
+
227
+ return True
228
+
229
+ except Exception as e:
230
+ self.logger.error(
231
+ f"Failed to upload blob '{blob_name}': {e}",
232
+ extra={
233
+ "container_name": container_name,
234
+ "blob_name": blob_name
235
+ },
236
+ exc_info=True
237
+ )
238
+ raise
239
+
240
+ def download_blob(
241
+ self,
242
+ container_name: str,
243
+ blob_name: str,
244
+ **kwargs
245
+ ) -> Optional[bytes]:
246
+ """Download a blob from Azure Blob Storage.
247
+
248
+ Args:
249
+ container_name: Name of the container
250
+ blob_name: Name of the blob
251
+ **kwargs: Additional parameters for blob download
252
+
253
+ Returns:
254
+ Blob data as bytes if found, None if not found
255
+
256
+ Raises:
257
+ RuntimeError: If blob service client is not initialized
258
+ Exception: If blob download fails for reasons other than not found
259
+ """
260
+ with self.logger.create_span(
261
+ "AzureStorage.download_blob",
262
+ attributes={
263
+ "service.name": self.service_name,
264
+ "operation.type": "blob_download",
265
+ "storage.container_name": container_name,
266
+ "storage.blob_name": blob_name,
267
+ "storage.account_url": self.account_url
268
+ }
269
+ ):
270
+ if self.blob_service_client is None:
271
+ error_msg = "Blob service client not initialized. Enable blob storage during initialization."
272
+ self.logger.error(error_msg)
273
+ raise RuntimeError(error_msg)
274
+
275
+ try:
276
+ self.logger.debug(
277
+ "Downloading blob from Azure Storage",
278
+ extra={
279
+ "container_name": container_name,
280
+ "blob_name": blob_name
281
+ }
282
+ )
283
+
284
+ blob_client = self.blob_service_client.get_blob_client(
285
+ container=container_name,
286
+ blob=blob_name
287
+ )
288
+
289
+ blob_data = blob_client.download_blob(**kwargs)
290
+ content = blob_data.readall()
291
+
292
+ self.logger.info(
293
+ "Blob downloaded successfully",
294
+ extra={
295
+ "container_name": container_name,
296
+ "blob_name": blob_name,
297
+ "content_length": len(content) if content else 0
298
+ }
299
+ )
300
+
301
+ return content
302
+
303
+ except ResourceNotFoundError:
304
+ self.logger.warning(
305
+ f"Blob '{blob_name}' not found in container '{container_name}'",
306
+ extra={"container_name": container_name, "blob_name": blob_name}
307
+ )
308
+ return None
309
+ except Exception as e:
310
+ self.logger.error(
311
+ f"Failed to download blob '{blob_name}': {e}",
312
+ extra={
313
+ "container_name": container_name,
314
+ "blob_name": blob_name
315
+ },
316
+ exc_info=True
317
+ )
318
+ raise
319
+
320
+ def delete_blob(
321
+ self,
322
+ container_name: str,
323
+ blob_name: str,
324
+ **kwargs
325
+ ) -> bool:
326
+ """Delete a blob from Azure Blob Storage.
327
+
328
+ Args:
329
+ container_name: Name of the container
330
+ blob_name: Name of the blob to delete
331
+ **kwargs: Additional parameters for blob deletion
332
+
333
+ Returns:
334
+ True if blob was deleted successfully
335
+
336
+ Raises:
337
+ RuntimeError: If blob service client is not initialized
338
+ Exception: If blob deletion fails
339
+ """
340
+ with self.logger.create_span(
341
+ "AzureStorage.delete_blob",
342
+ attributes={
343
+ "service.name": self.service_name,
344
+ "operation.type": "blob_deletion",
345
+ "storage.container_name": container_name,
346
+ "storage.blob_name": blob_name,
347
+ "storage.account_url": self.account_url
348
+ }
349
+ ):
350
+ if self.blob_service_client is None:
351
+ error_msg = "Blob service client not initialized. Enable blob storage during initialization."
352
+ self.logger.error(error_msg)
353
+ raise RuntimeError(error_msg)
354
+
355
+ try:
356
+ self.logger.debug(
357
+ "Deleting blob from Azure Storage",
358
+ extra={
359
+ "container_name": container_name,
360
+ "blob_name": blob_name
361
+ }
362
+ )
363
+
364
+ blob_client = self.blob_service_client.get_blob_client(
365
+ container=container_name,
366
+ blob=blob_name
367
+ )
368
+
369
+ blob_client.delete_blob(**kwargs)
370
+
371
+ self.logger.info(
372
+ "Blob deleted successfully",
373
+ extra={
374
+ "container_name": container_name,
375
+ "blob_name": blob_name
376
+ }
377
+ )
378
+
379
+ return True
380
+
381
+ except ResourceNotFoundError:
382
+ self.logger.warning(
383
+ f"Blob '{blob_name}' not found in container '{container_name}' for deletion",
384
+ extra={"container_name": container_name, "blob_name": blob_name}
385
+ )
386
+ return False
387
+ except Exception as e:
388
+ self.logger.error(
389
+ f"Failed to delete blob '{blob_name}': {e}",
390
+ extra={
391
+ "container_name": container_name,
392
+ "blob_name": blob_name
393
+ },
394
+ exc_info=True
395
+ )
396
+ raise
397
+
398
+ def list_blobs(
399
+ self,
400
+ container_name: str,
401
+ name_starts_with: Optional[str] = None,
402
+ **kwargs
403
+ ) -> List[str]:
404
+ """List blobs in a container.
405
+
406
+ Args:
407
+ container_name: Name of the container
408
+ name_starts_with: Optional prefix to filter blob names
409
+ **kwargs: Additional parameters for listing blobs
410
+
411
+ Returns:
412
+ List of blob names
413
+
414
+ Raises:
415
+ RuntimeError: If blob service client is not initialized
416
+ Exception: If listing blobs fails
417
+ """
418
+ with self.logger.create_span(
419
+ "AzureStorage.list_blobs",
420
+ attributes={
421
+ "service.name": self.service_name,
422
+ "operation.type": "blob_listing",
423
+ "storage.container_name": container_name,
424
+ "storage.account_url": self.account_url
425
+ }
426
+ ):
427
+ if self.blob_service_client is None:
428
+ error_msg = "Blob service client not initialized. Enable blob storage during initialization."
429
+ self.logger.error(error_msg)
430
+ raise RuntimeError(error_msg)
431
+
432
+ try:
433
+ self.logger.debug(
434
+ "Listing blobs from Azure Storage",
435
+ extra={
436
+ "container_name": container_name,
437
+ "name_starts_with": name_starts_with
438
+ }
439
+ )
440
+
441
+ container_client = self.blob_service_client.get_container_client(container_name)
442
+
443
+ blob_names = []
444
+ for blob in container_client.list_blobs(
445
+ name_starts_with=name_starts_with,
446
+ **kwargs
447
+ ):
448
+ blob_names.append(blob.name)
449
+
450
+ self.logger.info(
451
+ "Blobs listed successfully",
452
+ extra={
453
+ "container_name": container_name,
454
+ "blob_count": len(blob_names)
455
+ }
456
+ )
457
+
458
+ return blob_names
459
+
460
+ except Exception as e:
461
+ self.logger.error(
462
+ f"Failed to list blobs in container '{container_name}': {e}",
463
+ extra={"container_name": container_name},
464
+ exc_info=True
465
+ )
466
+ raise
467
+
468
+
469
+
470
+ # Queue Operations
471
+ def send_message(
472
+ self,
473
+ queue_name: str,
474
+ content: str,
475
+ visibility_timeout: Optional[int] = None,
476
+ time_to_live: Optional[int] = None,
477
+ **kwargs
478
+ ) -> bool:
479
+ """Send a message to an Azure Storage Queue.
480
+
481
+ Args:
482
+ queue_name: Name of the queue
483
+ content: Message content
484
+ visibility_timeout: Optional visibility timeout in seconds
485
+ time_to_live: Optional time to live in seconds
486
+ **kwargs: Additional parameters for message sending
487
+
488
+ Returns:
489
+ True if message was sent successfully
490
+
491
+ Raises:
492
+ RuntimeError: If queue service client is not initialized
493
+ Exception: If message sending fails
494
+ """
495
+ with self.logger.create_span(
496
+ "AzureStorage.send_message",
497
+ attributes={
498
+ "service.name": self.service_name,
499
+ "operation.type": "queue_send_message",
500
+ "storage.queue_name": queue_name,
501
+ "storage.account_url": self.account_url
502
+ }
503
+ ):
504
+ if self.queue_service_client is None:
505
+ error_msg = "Queue service client not initialized. Enable queue storage during initialization."
506
+ self.logger.error(error_msg)
507
+ raise RuntimeError(error_msg)
508
+
509
+ try:
510
+ self.logger.debug(
511
+ "Sending message to Azure Storage Queue",
512
+ extra={
513
+ "queue_name": queue_name,
514
+ "message_length": len(content),
515
+ "visibility_timeout": visibility_timeout,
516
+ "time_to_live": time_to_live
517
+ }
518
+ )
519
+
520
+ queue_client = self.queue_service_client.get_queue_client(queue_name)
521
+
522
+ queue_client.send_message(
523
+ content=content,
524
+ visibility_timeout=visibility_timeout,
525
+ time_to_live=time_to_live,
526
+ **kwargs
527
+ )
528
+
529
+ self.logger.info(
530
+ "Message sent successfully",
531
+ extra={"queue_name": queue_name}
532
+ )
533
+
534
+ return True
535
+
536
+ except Exception as e:
537
+ self.logger.error(
538
+ f"Failed to send message to queue '{queue_name}': {e}",
539
+ extra={"queue_name": queue_name},
540
+ exc_info=True
541
+ )
542
+ raise
543
+
544
+ def receive_messages(
545
+ self,
546
+ queue_name: str,
547
+ messages_per_page: int = 1,
548
+ visibility_timeout: Optional[int] = None,
549
+ **kwargs
550
+ ) -> List[Dict[str, Any]]:
551
+ """Receive messages from an Azure Storage Queue.
552
+
553
+ Args:
554
+ queue_name: Name of the queue
555
+ messages_per_page: Number of messages to receive per page
556
+ visibility_timeout: Optional visibility timeout in seconds
557
+ **kwargs: Additional parameters for message receiving
558
+
559
+ Returns:
560
+ List of message dictionaries containing message data
561
+
562
+ Raises:
563
+ RuntimeError: If queue service client is not initialized
564
+ Exception: If message receiving fails
565
+ """
566
+ with self.logger.create_span(
567
+ "AzureStorage.receive_messages",
568
+ attributes={
569
+ "service.name": self.service_name,
570
+ "operation.type": "queue_receive_messages",
571
+ "storage.queue_name": queue_name,
572
+ "storage.account_url": self.account_url
573
+ }
574
+ ):
575
+ if self.queue_service_client is None:
576
+ error_msg = "Queue service client not initialized. Enable queue storage during initialization."
577
+ self.logger.error(error_msg)
578
+ raise RuntimeError(error_msg)
579
+
580
+ try:
581
+ self.logger.debug(
582
+ "Receiving messages from Azure Storage Queue",
583
+ extra={
584
+ "queue_name": queue_name,
585
+ "messages_per_page": messages_per_page,
586
+ "visibility_timeout": visibility_timeout
587
+ }
588
+ )
589
+
590
+ queue_client = self.queue_service_client.get_queue_client(queue_name)
591
+
592
+ messages = []
593
+ for message_page in queue_client.receive_messages(
594
+ messages_per_page=messages_per_page,
595
+ visibility_timeout=visibility_timeout,
596
+ **kwargs
597
+ ):
598
+ for message in message_page:
599
+ messages.append({
600
+ "id": message.id,
601
+ "content": message.content,
602
+ "dequeue_count": message.dequeue_count,
603
+ "insertion_time": message.insertion_time,
604
+ "expiration_time": message.expiration_time,
605
+ "pop_receipt": message.pop_receipt
606
+ })
607
+
608
+ self.logger.info(
609
+ "Messages received successfully",
610
+ extra={
611
+ "queue_name": queue_name,
612
+ "message_count": len(messages)
613
+ }
614
+ )
615
+
616
+ return messages
617
+
618
+ except Exception as e:
619
+ self.logger.error(
620
+ f"Failed to receive messages from queue '{queue_name}': {e}",
621
+ extra={"queue_name": queue_name},
622
+ exc_info=True
623
+ )
624
+ raise
625
+
626
+ def delete_message(
627
+ self,
628
+ queue_name: str,
629
+ message_id: str,
630
+ pop_receipt: str,
631
+ **kwargs
632
+ ) -> bool:
633
+ """Delete a message from an Azure Storage Queue.
634
+
635
+ Args:
636
+ queue_name: Name of the queue
637
+ message_id: ID of the message to delete
638
+ pop_receipt: Pop receipt of the message
639
+ **kwargs: Additional parameters for message deletion
640
+
641
+ Returns:
642
+ True if message was deleted successfully
643
+
644
+ Raises:
645
+ RuntimeError: If queue service client is not initialized
646
+ Exception: If message deletion fails
647
+ """
648
+ with self.logger.create_span(
649
+ "AzureStorage.delete_message",
650
+ attributes={
651
+ "service.name": self.service_name,
652
+ "operation.type": "queue_delete_message",
653
+ "storage.queue_name": queue_name,
654
+ "storage.message_id": message_id,
655
+ "storage.account_url": self.account_url
656
+ }
657
+ ):
658
+ if self.queue_service_client is None:
659
+ error_msg = "Queue service client not initialized. Enable queue storage during initialization."
660
+ self.logger.error(error_msg)
661
+ raise RuntimeError(error_msg)
662
+
663
+ try:
664
+ self.logger.debug(
665
+ "Deleting message from Azure Storage Queue",
666
+ extra={
667
+ "queue_name": queue_name,
668
+ "message_id": message_id
669
+ }
670
+ )
671
+
672
+ queue_client = self.queue_service_client.get_queue_client(queue_name)
673
+
674
+ queue_client.delete_message(
675
+ message=message_id,
676
+ pop_receipt=pop_receipt,
677
+ **kwargs
678
+ )
679
+
680
+ self.logger.info(
681
+ "Message deleted successfully",
682
+ extra={
683
+ "queue_name": queue_name,
684
+ "message_id": message_id
685
+ }
686
+ )
687
+
688
+ return True
689
+
690
+ except Exception as e:
691
+ self.logger.error(
692
+ f"Failed to delete message '{message_id}' from queue '{queue_name}': {e}",
693
+ extra={
694
+ "queue_name": queue_name,
695
+ "message_id": message_id
696
+ },
697
+ exc_info=True
698
+ )
699
+ raise
700
+
701
+
702
+
703
+ def test_connection(self) -> bool:
704
+ """Test connection to Azure Storage by attempting to list containers.
705
+
706
+ Returns:
707
+ True if connection is successful, False otherwise
708
+ """
709
+ with self.logger.create_span(
710
+ "AzureStorage.test_connection",
711
+ attributes={
712
+ "service.name": self.service_name,
713
+ "operation.type": "connection_test",
714
+ "storage.account_url": self.account_url
715
+ }
716
+ ):
717
+ try:
718
+ self.logger.debug(
719
+ "Testing Azure Storage connection",
720
+ extra={"account_url": self.account_url}
721
+ )
722
+
723
+ if self.blob_service_client is not None:
724
+ # Try to list containers (limited to 1) to test connection
725
+ list(self.blob_service_client.list_containers(results_per_page=1))
726
+ elif self.queue_service_client is not None:
727
+ # Try to list queues if blob storage is disabled
728
+ list(self.queue_service_client.list_queues(results_per_page=1))
729
+ elif self.file_service_client is not None:
730
+ # Try to list shares if queues are disabled
731
+ list(self.file_service_client.list_shares(results_per_page=1))
732
+ else:
733
+ self.logger.error("No clients available for connection testing")
734
+ return False
735
+
736
+ self.logger.info("Azure Storage connection test successful")
737
+ return True
738
+
739
+ except Exception as e:
740
+ self.logger.warning(
741
+ f"Azure Storage connection test failed: {e}",
742
+ extra={"account_url": self.account_url}
743
+ )
744
+ return False
745
+
746
+ def set_correlation_id(self, correlation_id: str):
747
+ """Set correlation ID for request/transaction tracking.
748
+
749
+ Args:
750
+ correlation_id: Unique identifier for transaction correlation
751
+ """
752
+ self.logger.set_correlation_id(correlation_id)
753
+
754
+ def get_correlation_id(self) -> Optional[str]:
755
+ """Get current correlation ID.
756
+
757
+ Returns:
758
+ Current correlation ID if set, otherwise None
759
+ """
760
+ return self.logger.get_correlation_id()
761
+
762
+
763
+ def create_azure_storage(
764
+ account_url: str,
765
+ credential: Optional[TokenCredential] = None,
766
+ azure_identity: Optional[AzureIdentity] = None,
767
+ service_name: str = "azure_storage",
768
+ service_version: str = "1.0.0",
769
+ logger: Optional[AzureLogger] = None,
770
+ connection_string: Optional[str] = None,
771
+ enable_blob_storage: bool = True,
772
+ enable_file_storage: bool = True,
773
+ enable_queue_storage: bool = True,
774
+ ) -> AzureStorage:
775
+ """Factory function to create AzureStorage instance.
776
+
777
+ Provides a convenient way to create an AzureStorage instance with
778
+ common configuration patterns. If no credential or azure_identity
779
+ is provided, creates a default AzureIdentity instance.
780
+
781
+ Args:
782
+ account_url: Azure Storage Account URL
783
+ credential: Azure credential for authentication
784
+ azure_identity: AzureIdentity instance for credential management
785
+ service_name: Service name for tracing context
786
+ service_version: Service version for metadata
787
+ logger: Optional AzureLogger instance
788
+ connection_string: Application Insights connection string
789
+ enable_blob_storage: Enable blob storage operations client
790
+ enable_file_storage: Enable file storage operations client
791
+ enable_queue_storage: Enable queue storage operations client
792
+
793
+ Returns:
794
+ Configured AzureStorage instance
795
+
796
+ Example:
797
+ # Basic usage with default credential
798
+ storage = create_azure_storage("https://account.blob.core.windows.net/")
799
+
800
+ # With custom service name and specific features
801
+ storage = create_azure_storage(
802
+ "https://account.blob.core.windows.net/",
803
+ service_name="my_app",
804
+ enable_file_storage=False,
805
+ enable_queue_storage=False
806
+ )
807
+
808
+ # Note: Containers and queues should be created via infrastructure as code
809
+ """
810
+ if credential is None and azure_identity is None:
811
+ # Create default AzureIdentity instance
812
+ from ..mgmt.identity import create_azure_identity
813
+ azure_identity = create_azure_identity(
814
+ service_name=f"{service_name}_identity",
815
+ service_version=service_version,
816
+ connection_string=connection_string,
817
+ )
818
+
819
+ return AzureStorage(
820
+ account_url=account_url,
821
+ credential=credential,
822
+ azure_identity=azure_identity,
823
+ service_name=service_name,
824
+ service_version=service_version,
825
+ logger=logger,
826
+ connection_string=connection_string,
827
+ enable_blob_storage=enable_blob_storage,
828
+ enable_file_storage=enable_file_storage,
829
+ enable_queue_storage=enable_queue_storage,
830
+ )
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.4
2
+ Name: azpaddypy
3
+ Version: 0.5.10
4
+ Summary: Comprehensive Python logger for Azure, integrating OpenTelemetry for advanced, structured, and distributed tracing.
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Operating System :: OS Independent
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: azure-monitor-opentelemetry<2.0.0,>=1.6.4
11
+ Requires-Dist: azure-functions<2.0.0,>=1.21.3
12
+ Requires-Dist: azure-identity<2.0.0,>=1.20.0
13
+ Requires-Dist: azure-keyvault-secrets<5.0.0,>=4.9.0
14
+ Requires-Dist: azure-keyvault-keys<5.0.0,>=4.9.0
15
+ Requires-Dist: azure-keyvault-certificates<5.0.0,>=4.9.0
16
+ Requires-Dist: azure-storage-blob<13.0.0,>=12.20.0
17
+ Requires-Dist: azure-storage-file-share<13.0.0,>=12.17.0
18
+ Requires-Dist: azure-storage-queue<13.0.0,>=12.12.0
19
+ Dynamic: license-file
@@ -0,0 +1,13 @@
1
+ azpaddypy/__init__.py,sha256=hrWNAh4OHZOvm3Pbhq5eUjO-pSRYn0h0W0J87tc-lNI,45
2
+ azpaddypy/mgmt/__init__.py,sha256=waW9EAnTFDh2530ieQX1Z0r0Z-ZKHRwabVDfapjfN58,441
3
+ azpaddypy/mgmt/identity.py,sha256=mA_krQslMsK_sDob-z-QA0B9khK_JUO2way7xwPopR8,12001
4
+ azpaddypy/mgmt/local_env_manager.py,sha256=WHXJXHQFGwkgr96YkEtqpgFUxmCjBa5pArbNxZUSKQk,7762
5
+ azpaddypy/mgmt/logging.py,sha256=iuoYxwliBFmHKEZh30FYlGBFwlhic_yFmOi18gFjTEE,36962
6
+ azpaddypy/resources/__init__.py,sha256=KKqntqNJZW39aic_V6CeZmJ5VCZO-GDIn7HCWfOsJyk,422
7
+ azpaddypy/resources/keyvault.py,sha256=4J08vLqoLFd1_UUDBji2oG2fatZaPkgnRyT_Z6wHAOc,20312
8
+ azpaddypy/resources/storage.py,sha256=MnajBW8xtiOQ0YLwgcNLUml-ZiG2_od0ICT9m9Yin6c,31601
9
+ azpaddypy-0.5.10.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
10
+ azpaddypy-0.5.10.dist-info/METADATA,sha256=gToRWpgcDOVSKym89joZD2bUB442z18Q_zwRRfSk58g,867
11
+ azpaddypy-0.5.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ azpaddypy-0.5.10.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
13
+ azpaddypy-0.5.10.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: azpaddypy
3
- Version: 0.5.9
4
- Summary: Comprehensive Python logger for Azure, integrating OpenTelemetry for advanced, structured, and distributed tracing.
5
- Classifier: Programming Language :: Python :: 3
6
- Classifier: Operating System :: OS Independent
7
- Requires-Python: >=3.11
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Requires-Dist: azure-monitor-opentelemetry==1.6.10
11
- Requires-Dist: azure-functions==1.23.0
12
- Requires-Dist: azure-identity==1.23.0
13
- Requires-Dist: azure-keyvault-secrets==4.10.0
14
- Requires-Dist: azure-keyvault-keys==4.10.0
15
- Requires-Dist: azure-keyvault-certificates==4.10.0
16
- Dynamic: license-file
@@ -1,12 +0,0 @@
1
- azpaddypy/__init__.py,sha256=hrWNAh4OHZOvm3Pbhq5eUjO-pSRYn0h0W0J87tc-lNI,45
2
- azpaddypy/mgmt/__init__.py,sha256=waW9EAnTFDh2530ieQX1Z0r0Z-ZKHRwabVDfapjfN58,441
3
- azpaddypy/mgmt/identity.py,sha256=mA_krQslMsK_sDob-z-QA0B9khK_JUO2way7xwPopR8,12001
4
- azpaddypy/mgmt/local_env_manager.py,sha256=WHXJXHQFGwkgr96YkEtqpgFUxmCjBa5pArbNxZUSKQk,7762
5
- azpaddypy/mgmt/logging.py,sha256=iuoYxwliBFmHKEZh30FYlGBFwlhic_yFmOi18gFjTEE,36962
6
- azpaddypy/resources/__init__.py,sha256=Bvt3VK4RqwoxYpoh6EbLXIR18RuFPKaLP6zLL-icyFk,314
7
- azpaddypy/resources/keyvault.py,sha256=4J08vLqoLFd1_UUDBji2oG2fatZaPkgnRyT_Z6wHAOc,20312
8
- azpaddypy-0.5.9.dist-info/licenses/LICENSE,sha256=hQ6t0g2QaewGCQICHqTckBFbMVakGmoyTAzDpmEYV4c,1089
9
- azpaddypy-0.5.9.dist-info/METADATA,sha256=5PkaGLqbgBlFbaVjAt6hokzh1n6FtyGjnXhF5bsfx-I,665
10
- azpaddypy-0.5.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- azpaddypy-0.5.9.dist-info/top_level.txt,sha256=hsDuboDhT61320ML8X479ezSTwT3rrlDWz1_Z45B2cs,10
12
- azpaddypy-0.5.9.dist-info/RECORD,,