srx-lib-azure 0.1.8__tar.gz → 0.2.0__tar.gz

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.

Potentially problematic release.


This version of srx-lib-azure might be problematic. Click here for more details.

@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.4
2
+ Name: srx-lib-azure
3
+ Version: 0.2.0
4
+ Summary: Azure helpers for SRX services: Blob, Email, Table, Document Intelligence
5
+ Author-email: SRX <dev@srx.id>
6
+ Requires-Python: >=3.12
7
+ Requires-Dist: azure-ai-documentintelligence>=1.0.0
8
+ Requires-Dist: azure-communication-email>=1.0.0
9
+ Requires-Dist: azure-data-tables>=12.7.0
10
+ Requires-Dist: azure-storage-blob>=12.22.0
11
+ Requires-Dist: loguru>=0.7.2
12
+ Provides-Extra: all
13
+ Requires-Dist: azure-ai-documentintelligence>=1.0.0; extra == 'all'
14
+ Provides-Extra: document
15
+ Requires-Dist: azure-ai-documentintelligence>=1.0.0; extra == 'document'
16
+ Description-Content-Type: text/markdown
17
+
18
+ # srx-lib-azure
19
+
20
+ Lightweight wrappers over Azure SDKs used across SRX services.
21
+
22
+ What it includes:
23
+ - **Blob**: upload/download helpers, SAS URL generation
24
+ - **Email** (Azure Communication Services): simple async sender
25
+ - **Table**: simple CRUD helpers
26
+ - **Document Intelligence** (OCR): document analysis from URLs or bytes
27
+
28
+ ## Install
29
+
30
+ PyPI (public):
31
+
32
+ - `pip install srx-lib-azure`
33
+
34
+ uv (pyproject):
35
+ ```
36
+ [project]
37
+ dependencies = ["srx-lib-azure>=0.1.0"]
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ Blob:
43
+ ```
44
+ from srx_lib_azure.blob import AzureBlobService
45
+ blob = AzureBlobService()
46
+ url = await blob.upload_file(upload_file, "documents/report.pdf")
47
+ ```
48
+
49
+ Email:
50
+ ```
51
+ from srx_lib_azure.email import EmailService
52
+ svc = EmailService()
53
+ await svc.send_notification("user@example.com", "Subject", "Hello", html=False)
54
+ ```
55
+
56
+ Table:
57
+ ```
58
+ from srx_lib_azure.table import AzureTableService
59
+ store = AzureTableService()
60
+ store.ensure_table("events")
61
+ store.upsert_entity("events", {"PartitionKey":"p","RowKey":"r","EventType":"x"})
62
+ ```
63
+
64
+ Document Intelligence (OCR):
65
+ ```python
66
+ from srx_lib_azure import AzureDocumentIntelligenceService
67
+
68
+ # Initialize with endpoint and key
69
+ doc_service = AzureDocumentIntelligenceService(
70
+ endpoint="https://your-resource.cognitiveservices.azure.com/",
71
+ key="your-api-key"
72
+ )
73
+
74
+ # Analyze document from URL
75
+ result = await doc_service.analyze_document_from_url(
76
+ url="https://example.com/document.pdf",
77
+ model_id="prebuilt-read" # or "prebuilt-layout", "prebuilt-invoice", etc.
78
+ )
79
+
80
+ # Analyze document from bytes
81
+ with open("document.pdf", "rb") as f:
82
+ content = f.read()
83
+ result = await doc_service.analyze_document_from_bytes(
84
+ file_content=content,
85
+ model_id="prebuilt-read"
86
+ )
87
+
88
+ # Result structure:
89
+ # {
90
+ # "success": True/False,
91
+ # "content": "extracted text...",
92
+ # "pages": [{"page_number": 1, "width": 8.5, ...}, ...],
93
+ # "page_count": 10,
94
+ # "confidence": 0.98,
95
+ # "model_id": "prebuilt-read",
96
+ # "metadata": {...},
97
+ # "error": None # or error message if failed
98
+ # }
99
+ ```
100
+
101
+ ## Environment Variables
102
+
103
+ - **Blob & Table**: `AZURE_STORAGE_CONNECTION_STRING` (required)
104
+ - **Email (ACS)**: `ACS_CONNECTION_STRING`, `EMAIL_SENDER`
105
+ - **Document Intelligence**: `AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT`, `AZURE_DOCUMENT_INTELLIGENCE_KEY`
106
+ - **Optional**: `AZURE_STORAGE_ACCOUNT_KEY`, `AZURE_BLOB_URL`, `AZURE_SAS_TOKEN`
107
+
108
+ ## Optional Dependencies
109
+
110
+ All services are optional and won't break if their dependencies aren't installed:
111
+
112
+ ```bash
113
+ # Base installation (includes all services by default)
114
+ pip install srx-lib-azure
115
+
116
+ # Or install only what you need - document intelligence is optional
117
+ pip install srx-lib-azure[document] # Adds Document Intelligence support
118
+
119
+ # Install with all optional dependencies
120
+ pip install srx-lib-azure[all]
121
+ ```
122
+
123
+ If you import a service without its required Azure SDK, it will log a warning but won't crash.
124
+
125
+ ## Release
126
+
127
+ Tag `vX.Y.Z` to publish to GitHub Packages via Actions.
128
+
129
+ ## License
130
+
131
+ Proprietary © SRX
@@ -0,0 +1,114 @@
1
+ # srx-lib-azure
2
+
3
+ Lightweight wrappers over Azure SDKs used across SRX services.
4
+
5
+ What it includes:
6
+ - **Blob**: upload/download helpers, SAS URL generation
7
+ - **Email** (Azure Communication Services): simple async sender
8
+ - **Table**: simple CRUD helpers
9
+ - **Document Intelligence** (OCR): document analysis from URLs or bytes
10
+
11
+ ## Install
12
+
13
+ PyPI (public):
14
+
15
+ - `pip install srx-lib-azure`
16
+
17
+ uv (pyproject):
18
+ ```
19
+ [project]
20
+ dependencies = ["srx-lib-azure>=0.1.0"]
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ Blob:
26
+ ```
27
+ from srx_lib_azure.blob import AzureBlobService
28
+ blob = AzureBlobService()
29
+ url = await blob.upload_file(upload_file, "documents/report.pdf")
30
+ ```
31
+
32
+ Email:
33
+ ```
34
+ from srx_lib_azure.email import EmailService
35
+ svc = EmailService()
36
+ await svc.send_notification("user@example.com", "Subject", "Hello", html=False)
37
+ ```
38
+
39
+ Table:
40
+ ```
41
+ from srx_lib_azure.table import AzureTableService
42
+ store = AzureTableService()
43
+ store.ensure_table("events")
44
+ store.upsert_entity("events", {"PartitionKey":"p","RowKey":"r","EventType":"x"})
45
+ ```
46
+
47
+ Document Intelligence (OCR):
48
+ ```python
49
+ from srx_lib_azure import AzureDocumentIntelligenceService
50
+
51
+ # Initialize with endpoint and key
52
+ doc_service = AzureDocumentIntelligenceService(
53
+ endpoint="https://your-resource.cognitiveservices.azure.com/",
54
+ key="your-api-key"
55
+ )
56
+
57
+ # Analyze document from URL
58
+ result = await doc_service.analyze_document_from_url(
59
+ url="https://example.com/document.pdf",
60
+ model_id="prebuilt-read" # or "prebuilt-layout", "prebuilt-invoice", etc.
61
+ )
62
+
63
+ # Analyze document from bytes
64
+ with open("document.pdf", "rb") as f:
65
+ content = f.read()
66
+ result = await doc_service.analyze_document_from_bytes(
67
+ file_content=content,
68
+ model_id="prebuilt-read"
69
+ )
70
+
71
+ # Result structure:
72
+ # {
73
+ # "success": True/False,
74
+ # "content": "extracted text...",
75
+ # "pages": [{"page_number": 1, "width": 8.5, ...}, ...],
76
+ # "page_count": 10,
77
+ # "confidence": 0.98,
78
+ # "model_id": "prebuilt-read",
79
+ # "metadata": {...},
80
+ # "error": None # or error message if failed
81
+ # }
82
+ ```
83
+
84
+ ## Environment Variables
85
+
86
+ - **Blob & Table**: `AZURE_STORAGE_CONNECTION_STRING` (required)
87
+ - **Email (ACS)**: `ACS_CONNECTION_STRING`, `EMAIL_SENDER`
88
+ - **Document Intelligence**: `AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT`, `AZURE_DOCUMENT_INTELLIGENCE_KEY`
89
+ - **Optional**: `AZURE_STORAGE_ACCOUNT_KEY`, `AZURE_BLOB_URL`, `AZURE_SAS_TOKEN`
90
+
91
+ ## Optional Dependencies
92
+
93
+ All services are optional and won't break if their dependencies aren't installed:
94
+
95
+ ```bash
96
+ # Base installation (includes all services by default)
97
+ pip install srx-lib-azure
98
+
99
+ # Or install only what you need - document intelligence is optional
100
+ pip install srx-lib-azure[document] # Adds Document Intelligence support
101
+
102
+ # Install with all optional dependencies
103
+ pip install srx-lib-azure[all]
104
+ ```
105
+
106
+ If you import a service without its required Azure SDK, it will log a warning but won't crash.
107
+
108
+ ## Release
109
+
110
+ Tag `vX.Y.Z` to publish to GitHub Packages via Actions.
111
+
112
+ ## License
113
+
114
+ Proprietary © SRX
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "srx-lib-azure"
7
- version = "0.1.8"
8
- description = "Azure helpers for SRX services: Blob, Email, Table"
7
+ version = "0.2.0"
8
+ description = "Azure helpers for SRX services: Blob, Email, Table, Document Intelligence"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
11
11
  authors = [{ name = "SRX", email = "dev@srx.id" }]
@@ -14,6 +14,17 @@ dependencies = [
14
14
  "azure-storage-blob>=12.22.0",
15
15
  "azure-communication-email>=1.0.0",
16
16
  "azure-data-tables>=12.7.0",
17
+ "azure-ai-documentintelligence>=1.0.0",
18
+ ]
19
+
20
+ [project.optional-dependencies]
21
+ # Optional extra for Document Intelligence (OCR)
22
+ document = [
23
+ "azure-ai-documentintelligence>=1.0.0",
24
+ ]
25
+ # Install all optional dependencies
26
+ all = [
27
+ "azure-ai-documentintelligence>=1.0.0",
17
28
  ]
18
29
 
19
30
  [tool.hatch.build.targets.wheel]
@@ -0,0 +1,11 @@
1
+ from .blob import AzureBlobService
2
+ from .document import AzureDocumentIntelligenceService
3
+ from .email import EmailService
4
+ from .table import AzureTableService
5
+
6
+ __all__ = [
7
+ "AzureBlobService",
8
+ "AzureDocumentIntelligenceService",
9
+ "AzureTableService",
10
+ "EmailService",
11
+ ]
@@ -0,0 +1,262 @@
1
+ import os
2
+ import io
3
+ import asyncio
4
+ from typing import Dict, Any, Optional
5
+
6
+ from loguru import logger
7
+
8
+ try:
9
+ from azure.ai.documentintelligence import DocumentIntelligenceClient
10
+ from azure.ai.documentintelligence.models import AnalyzeDocumentRequest, AnalyzeResult
11
+ from azure.core.credentials import AzureKeyCredential
12
+ from azure.core.exceptions import (
13
+ ClientAuthenticationError,
14
+ HttpResponseError,
15
+ ServiceRequestError,
16
+ )
17
+ except Exception: # pragma: no cover - optional dependency at import time
18
+ DocumentIntelligenceClient = None # type: ignore
19
+ AnalyzeDocumentRequest = None # type: ignore
20
+ AnalyzeResult = None # type: ignore
21
+ AzureKeyCredential = None # type: ignore
22
+ ClientAuthenticationError = None # type: ignore
23
+ HttpResponseError = None # type: ignore
24
+ ServiceRequestError = None # type: ignore
25
+
26
+
27
+ class AzureDocumentIntelligenceService:
28
+ """Wrapper for Azure Document Intelligence (OCR/Document Analysis).
29
+
30
+ Does not raise on missing configuration to keep the library optional.
31
+ If not configured, analysis calls return error responses with descriptive messages.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ *,
37
+ endpoint: Optional[str] = None,
38
+ key: Optional[str] = None,
39
+ warn_if_unconfigured: bool = False,
40
+ ):
41
+ """Initialize Document Intelligence service.
42
+
43
+ Args:
44
+ endpoint: Azure Document Intelligence endpoint URL
45
+ key: Azure Document Intelligence API key
46
+ warn_if_unconfigured: Whether to log a warning if not configured
47
+ """
48
+ self.endpoint = endpoint or os.getenv("AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT")
49
+ self.key = key or os.getenv("AZURE_DOCUMENT_INTELLIGENCE_KEY")
50
+
51
+ if not self.endpoint or not self.key or DocumentIntelligenceClient is None:
52
+ self.client = None
53
+ if warn_if_unconfigured:
54
+ logger.warning(
55
+ "AzureDocumentIntelligenceService not configured "
56
+ "(missing endpoint/key or azure-ai-documentintelligence SDK). "
57
+ "Calls will return error responses."
58
+ )
59
+ else:
60
+ try:
61
+ self.client = DocumentIntelligenceClient(
62
+ endpoint=self.endpoint, credential=AzureKeyCredential(self.key)
63
+ )
64
+ except Exception as e:
65
+ self.client = None
66
+ logger.warning("DocumentIntelligenceClient initialization failed: %s", e)
67
+
68
+ async def analyze_document_from_url(
69
+ self, url: str, model_id: str = "prebuilt-read"
70
+ ) -> Dict[str, Any]:
71
+ """Analyze a document from a URL using Azure Document Intelligence.
72
+
73
+ Args:
74
+ url: URL of the document to analyze (must be accessible to Azure)
75
+ model_id: Model to use (default: "prebuilt-read" for OCR)
76
+ Other options: "prebuilt-layout", "prebuilt-invoice", etc.
77
+
78
+ Returns:
79
+ Dict with analysis results:
80
+ - success (bool): Whether analysis succeeded
81
+ - content (str | None): Extracted text content
82
+ - pages (list[dict] | None): Page information
83
+ - page_count (int | None): Total number of pages
84
+ - confidence (float | None): Average OCR confidence (0-1)
85
+ - model_id (str | None): Model used
86
+ - metadata (dict | None): Additional metadata
87
+ - error (str | None): Error message if failed
88
+ """
89
+ if not self.client:
90
+ logger.warning("Document analysis from URL skipped: service not configured")
91
+ return {
92
+ "success": False,
93
+ "error": "Document Intelligence service not configured",
94
+ }
95
+
96
+ try:
97
+ logger.info(f"Starting document analysis from URL: {url} (model: {model_id})")
98
+
99
+ # Run the blocking operation in a thread pool
100
+ poller = await asyncio.to_thread(
101
+ self.client.begin_analyze_document,
102
+ model_id,
103
+ AnalyzeDocumentRequest(url_source=url),
104
+ )
105
+
106
+ # Wait for the result
107
+ result: AnalyzeResult = await asyncio.to_thread(poller.result)
108
+
109
+ logger.info(
110
+ f"Document analysis completed (model: {model_id}, pages: {len(result.pages or [])})"
111
+ )
112
+
113
+ return self._format_result(result, model_id)
114
+
115
+ except ClientAuthenticationError as e:
116
+ logger.error(f"Authentication failed for document analysis: {e}")
117
+ return {"success": False, "error": f"Authentication failed: {e}"}
118
+ except HttpResponseError as e:
119
+ logger.error(f"Azure service error analyzing document: {e.status_code} - {e.message}")
120
+ return {
121
+ "success": False,
122
+ "error": f"Azure service error ({e.status_code}): {e.message}",
123
+ }
124
+ except ServiceRequestError as e:
125
+ logger.error(f"Network error analyzing document: {e}")
126
+ return {"success": False, "error": f"Network error: {e}"}
127
+ except Exception as e:
128
+ logger.error(f"Unexpected error analyzing document from URL: {e}")
129
+ return {"success": False, "error": f"Unexpected error: {e}"}
130
+
131
+ async def analyze_document_from_bytes(
132
+ self, file_content: bytes, model_id: str = "prebuilt-read"
133
+ ) -> Dict[str, Any]:
134
+ """Analyze a document from bytes using Azure Document Intelligence.
135
+
136
+ Args:
137
+ file_content: Document content as bytes (PDF, image, etc.)
138
+ model_id: Model to use (default: "prebuilt-read" for OCR)
139
+
140
+ Returns:
141
+ Dict with analysis results (same format as analyze_document_from_url)
142
+ """
143
+ if not self.client:
144
+ logger.warning("Document analysis from bytes skipped: service not configured")
145
+ return {
146
+ "success": False,
147
+ "error": "Document Intelligence service not configured",
148
+ }
149
+
150
+ try:
151
+ logger.info(
152
+ f"Starting document analysis from bytes (size: {len(file_content)} bytes, model: {model_id})"
153
+ )
154
+
155
+ # Create a file-like object from bytes
156
+ file_stream = io.BytesIO(file_content)
157
+
158
+ # Run the blocking operation in a thread pool
159
+ poller = await asyncio.to_thread(
160
+ self.client.begin_analyze_document,
161
+ model_id,
162
+ body=file_stream,
163
+ )
164
+
165
+ # Wait for the result
166
+ result: AnalyzeResult = await asyncio.to_thread(poller.result)
167
+
168
+ logger.info(
169
+ f"Document analysis completed (model: {model_id}, pages: {len(result.pages or [])})"
170
+ )
171
+
172
+ return self._format_result(result, model_id)
173
+
174
+ except ClientAuthenticationError as e:
175
+ logger.error(f"Authentication failed for document analysis: {e}")
176
+ return {"success": False, "error": f"Authentication failed: {e}"}
177
+ except HttpResponseError as e:
178
+ logger.error(f"Azure service error analyzing document: {e.status_code} - {e.message}")
179
+ return {
180
+ "success": False,
181
+ "error": f"Azure service error ({e.status_code}): {e.message}",
182
+ }
183
+ except ServiceRequestError as e:
184
+ logger.error(f"Network error analyzing document: {e}")
185
+ return {"success": False, "error": f"Network error: {e}"}
186
+ except Exception as e:
187
+ logger.error(f"Unexpected error analyzing document from bytes: {e}")
188
+ return {"success": False, "error": f"Unexpected error: {e}"}
189
+
190
+ def _format_result(self, result: AnalyzeResult, model_id: str) -> Dict[str, Any]:
191
+ """Format the AnalyzeResult into a dict response.
192
+
193
+ Args:
194
+ result: Azure Document Intelligence AnalyzeResult
195
+ model_id: Model ID used for analysis
196
+
197
+ Returns:
198
+ Formatted dict with extracted content and metadata
199
+ """
200
+ # Extract all text content
201
+ content_parts: list[str] = []
202
+ pages_info: list[Dict[str, Any]] = []
203
+ total_confidence = 0.0
204
+ confidence_count = 0
205
+
206
+ if result.pages:
207
+ for page in result.pages:
208
+ # Collect page info
209
+ page_info = {
210
+ "page_number": page.page_number,
211
+ "width": page.width,
212
+ "height": page.height,
213
+ "unit": page.unit,
214
+ "lines_count": len(page.lines or []),
215
+ "words_count": len(page.words or []),
216
+ }
217
+ pages_info.append(page_info)
218
+
219
+ # Extract text from lines
220
+ if page.lines:
221
+ for line in page.lines:
222
+ content_parts.append(line.content)
223
+ # Track confidence if available
224
+ if hasattr(line, "confidence") and line.confidence is not None:
225
+ total_confidence += line.confidence
226
+ confidence_count += 1
227
+
228
+ # Combine all content with newlines
229
+ full_content = "\n".join(content_parts)
230
+
231
+ # Calculate average confidence
232
+ avg_confidence = total_confidence / confidence_count if confidence_count > 0 else None
233
+
234
+ # Build metadata
235
+ metadata: Dict[str, Any] = {
236
+ "content_format": (
237
+ result.content_format if hasattr(result, "content_format") else None
238
+ ),
239
+ "api_version": result.api_version if hasattr(result, "api_version") else None,
240
+ }
241
+
242
+ # Add languages if detected
243
+ if hasattr(result, "languages") and result.languages:
244
+ metadata["languages"] = [
245
+ {"locale": lang.locale, "confidence": lang.confidence} for lang in result.languages
246
+ ]
247
+
248
+ # Add styles if detected (e.g., handwriting)
249
+ if hasattr(result, "styles") and result.styles:
250
+ metadata["has_handwriting"] = any(
251
+ style.is_handwritten for style in result.styles if hasattr(style, "is_handwritten")
252
+ )
253
+
254
+ return {
255
+ "success": True,
256
+ "content": full_content if full_content else None,
257
+ "pages": pages_info if pages_info else None,
258
+ "page_count": len(pages_info) if pages_info else None,
259
+ "confidence": avg_confidence,
260
+ "model_id": model_id,
261
+ "metadata": metadata,
262
+ }
@@ -1,70 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: srx-lib-azure
3
- Version: 0.1.8
4
- Summary: Azure helpers for SRX services: Blob, Email, Table
5
- Author-email: SRX <dev@srx.id>
6
- Requires-Python: >=3.12
7
- Requires-Dist: azure-communication-email>=1.0.0
8
- Requires-Dist: azure-data-tables>=12.7.0
9
- Requires-Dist: azure-storage-blob>=12.22.0
10
- Requires-Dist: loguru>=0.7.2
11
- Description-Content-Type: text/markdown
12
-
13
- # srx-lib-azure
14
-
15
- Lightweight wrappers over Azure SDKs used across SRX services.
16
-
17
- What it includes:
18
- - Blob: upload/download helpers, SAS URL generation
19
- - Email (Azure Communication Services): simple async sender
20
- - Table: simple CRUD helpers
21
-
22
- ## Install
23
-
24
- PyPI (public):
25
-
26
- - `pip install srx-lib-azure`
27
-
28
- uv (pyproject):
29
- ```
30
- [project]
31
- dependencies = ["srx-lib-azure>=0.1.0"]
32
- ```
33
-
34
- ## Usage
35
-
36
- Blob:
37
- ```
38
- from srx_lib_azure.blob import AzureBlobService
39
- blob = AzureBlobService()
40
- url = await blob.upload_file(upload_file, "documents/report.pdf")
41
- ```
42
-
43
- Email:
44
- ```
45
- from srx_lib_azure.email import EmailService
46
- svc = EmailService()
47
- await svc.send_notification("user@example.com", "Subject", "Hello", html=False)
48
- ```
49
-
50
- Table:
51
- ```
52
- from srx_lib_azure.table import AzureTableService
53
- store = AzureTableService()
54
- store.ensure_table("events")
55
- store.upsert_entity("events", {"PartitionKey":"p","RowKey":"r","EventType":"x"})
56
- ```
57
-
58
- ## Environment Variables
59
-
60
- - Blob & Table: `AZURE_STORAGE_CONNECTION_STRING` (required)
61
- - Email (ACS): `ACS_CONNECTION_STRING`, `EMAIL_SENDER`
62
- - Optional: `AZURE_STORAGE_ACCOUNT_KEY`, `AZURE_BLOB_URL`, `AZURE_SAS_TOKEN`
63
-
64
- ## Release
65
-
66
- Tag `vX.Y.Z` to publish to GitHub Packages via Actions.
67
-
68
- ## License
69
-
70
- Proprietary © SRX
@@ -1,58 +0,0 @@
1
- # srx-lib-azure
2
-
3
- Lightweight wrappers over Azure SDKs used across SRX services.
4
-
5
- What it includes:
6
- - Blob: upload/download helpers, SAS URL generation
7
- - Email (Azure Communication Services): simple async sender
8
- - Table: simple CRUD helpers
9
-
10
- ## Install
11
-
12
- PyPI (public):
13
-
14
- - `pip install srx-lib-azure`
15
-
16
- uv (pyproject):
17
- ```
18
- [project]
19
- dependencies = ["srx-lib-azure>=0.1.0"]
20
- ```
21
-
22
- ## Usage
23
-
24
- Blob:
25
- ```
26
- from srx_lib_azure.blob import AzureBlobService
27
- blob = AzureBlobService()
28
- url = await blob.upload_file(upload_file, "documents/report.pdf")
29
- ```
30
-
31
- Email:
32
- ```
33
- from srx_lib_azure.email import EmailService
34
- svc = EmailService()
35
- await svc.send_notification("user@example.com", "Subject", "Hello", html=False)
36
- ```
37
-
38
- Table:
39
- ```
40
- from srx_lib_azure.table import AzureTableService
41
- store = AzureTableService()
42
- store.ensure_table("events")
43
- store.upsert_entity("events", {"PartitionKey":"p","RowKey":"r","EventType":"x"})
44
- ```
45
-
46
- ## Environment Variables
47
-
48
- - Blob & Table: `AZURE_STORAGE_CONNECTION_STRING` (required)
49
- - Email (ACS): `ACS_CONNECTION_STRING`, `EMAIL_SENDER`
50
- - Optional: `AZURE_STORAGE_ACCOUNT_KEY`, `AZURE_BLOB_URL`, `AZURE_SAS_TOKEN`
51
-
52
- ## Release
53
-
54
- Tag `vX.Y.Z` to publish to GitHub Packages via Actions.
55
-
56
- ## License
57
-
58
- Proprietary © SRX
@@ -1,5 +0,0 @@
1
- from .blob import AzureBlobService
2
- from .email import EmailService
3
- from .table import AzureTableService
4
-
5
- __all__ = ["AzureBlobService", "EmailService", "AzureTableService"]
File without changes