Skip to content

Commit ed8718f

Browse files
committed
Remove BlobPayloadStoreOptions and fix constructor, update agents instructions
1 parent 9cbae72 commit ed8718f

File tree

11 files changed

+86
-134
lines changed

11 files changed

+86
-134
lines changed

.github/copilot-instructions.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@ building durable orchestrations. The repo contains two packages:
1515
- Follow PEP 8 conventions.
1616
- Use `autopep8` for Python formatting.
1717

18+
## Python Type Checking
19+
20+
Before linting, check for and fix any Pylance errors in the files you
21+
changed. Use the editor's diagnostics (or the `get_errors` tool) to
22+
identify type errors and resolve them first — type safety takes
23+
priority over style.
24+
1825
## Python Linting
1926

2027
This repository uses [flake8](https://flake8.pycqa.org/) for Python
2128
linting. Run it after making changes to verify there are no issues:
2229

2330
```bash
24-
flake8 path/to/changed/file.py
31+
python -m flake8 path/to/changed/file.py
2532
```
2633

2734
## Markdown Style
@@ -57,33 +64,33 @@ repository root.
5764
To lint a single file:
5865

5966
```bash
60-
pymarkdown -c .pymarkdown.json scan path/to/file.md
67+
python -m pymarkdown -c .pymarkdown.json scan path/to/file.md
6168
```
6269

6370
To lint all Markdown files in the repository:
6471

6572
```bash
66-
pymarkdown -c .pymarkdown.json scan **/*.md
73+
python -m pymarkdown -c .pymarkdown.json scan **/*.md
6774
```
6875

6976
Install the linter via the dev dependencies:
7077

7178
```bash
72-
pip install -r dev-requirements.txt
79+
python -m pip install -r dev-requirements.txt
7380
```
7481

7582
## Building and Testing
7683

7784
Install the packages locally in editable mode:
7885

7986
```bash
80-
pip install -e . -e ./durabletask-azuremanaged
87+
python -m pip install -e . -e ./durabletask-azuremanaged
8188
```
8289

8390
Run tests with pytest:
8491

8592
```bash
86-
pytest
93+
python -m pytest
8794
```
8895

8996
## Project Structure

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ ADDED
1515
Pass a `BlobPayloadStore` to the worker and client via the
1616
`payload_store` parameter.
1717
- Added `durabletask.extensions.azure_blob_payloads` extension
18-
package with `BlobPayloadStore` and `BlobPayloadStoreOptions`
18+
package with `BlobPayloadStore`
1919
- Added `PayloadStore` abstract base class in
2020
`durabletask.payload` for custom storage backends
2121
- Added `durabletask.testing` module with `InMemoryOrchestrationBackend` for testing orchestrations without a sidecar process

docs/features.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,15 @@ The built-in `BlobPayloadStore` uses Azure Blob Storage. Create a
186186
store instance and pass it to both the worker and client:
187187

188188
```python
189-
from durabletask.extensions.azure_blob_payloads import BlobPayloadStore, BlobPayloadStoreOptions
189+
from durabletask.extensions.azure_blob_payloads import BlobPayloadStore
190190

191-
options = BlobPayloadStoreOptions(
191+
store = BlobPayloadStore(
192192
connection_string="DefaultEndpointsProtocol=https;...",
193193
container_name="durabletask-payloads", # default
194194
threshold_bytes=900_000, # default (900 KB)
195195
max_stored_payload_bytes=10_485_760, # default (10 MB)
196196
enable_compression=True, # default
197197
)
198-
store = BlobPayloadStore(options)
199198
```
200199

201200
Then pass the store to the worker and client:
@@ -226,11 +225,10 @@ You can also authenticate using `account_url` and a
226225
```python
227226
from azure.identity import DefaultAzureCredential
228227

229-
options = BlobPayloadStoreOptions(
228+
store = BlobPayloadStore(
230229
account_url="https://<account>.blob.core.windows.net",
231230
credential=DefaultAzureCredential(),
232231
)
233-
store = BlobPayloadStore(options)
234232
```
235233

236234
#### Configuration options

docs/supported-patterns.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,14 @@ install the optional dependency and configure a payload store on the
133133
worker and client:
134134

135135
```python
136-
from durabletask.extensions.azure_blob_payloads import BlobPayloadStore, BlobPayloadStoreOptions
136+
from durabletask.extensions.azure_blob_payloads import BlobPayloadStore
137137
from durabletask.azuremanaged.client import DurableTaskSchedulerClient
138138
from durabletask.azuremanaged.worker import DurableTaskSchedulerWorker
139139

140140
# Configure the blob payload store
141-
store = BlobPayloadStore(BlobPayloadStoreOptions(
141+
store = BlobPayloadStore(
142142
connection_string="DefaultEndpointsProtocol=https;...",
143-
))
143+
)
144144

145145
# Pass the store to both worker and client
146146
with DurableTaskSchedulerWorker(

durabletask/extensions/azure_blob_payloads/__init__.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@
1313
1414
Usage::
1515
16-
from durabletask.extensions.azure_blob_payloads import (
17-
BlobPayloadStore,
18-
BlobPayloadStoreOptions,
19-
)
16+
from durabletask.extensions.azure_blob_payloads import BlobPayloadStore
2017
2118
store = BlobPayloadStore(
2219
connection_string="DefaultEndpointsProtocol=https;...",
@@ -33,6 +30,5 @@
3330
) from exc
3431

3532
from durabletask.extensions.azure_blob_payloads.blob_payload_store import BlobPayloadStore
36-
from durabletask.extensions.azure_blob_payloads.options import BlobPayloadStoreOptions
3733

38-
__all__ = ["BlobPayloadStore", "BlobPayloadStoreOptions"]
34+
__all__ = ["BlobPayloadStore"]

durabletask/extensions/azure_blob_payloads/blob_payload_store.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
import gzip
99
import logging
1010
import uuid
11-
from typing import Optional
11+
from typing import Any, Optional
1212

1313
from azure.storage.blob import BlobServiceClient
1414
from azure.storage.blob.aio import BlobServiceClient as AsyncBlobServiceClient
1515

16-
from durabletask.extensions.azure_blob_payloads.options import BlobPayloadStoreOptions
1716
from durabletask.payload.store import LargePayloadStorageOptions, PayloadStore
1817

1918
logger = logging.getLogger("durabletask-blobpayloads")
@@ -36,59 +35,66 @@ class BlobPayloadStore(PayloadStore):
3635
account_url: Azure Storage account URL. Must be combined with
3736
*credential*.
3837
credential: A ``TokenCredential`` for token-based auth.
39-
options: Additional configuration. If not provided, defaults
40-
are used.
38+
container_name: Blob container for externalized payloads.
39+
threshold_bytes: Payloads larger than this are externalized.
40+
max_stored_payload_bytes: Maximum externalized payload size.
41+
enable_compression: GZip-compress payloads before uploading.
42+
api_version: Azure Storage API version override (useful for
43+
Azurite compatibility).
4144
"""
4245

4346
def __init__(
4447
self,
4548
*,
4649
connection_string: Optional[str] = None,
4750
account_url: Optional[str] = None,
48-
credential: Optional[object] = None,
49-
options: Optional[BlobPayloadStoreOptions] = None,
51+
credential: Any = None,
52+
container_name: str = "durabletask-payloads",
53+
threshold_bytes: int = 900_000,
54+
max_stored_payload_bytes: int = 10 * 1024 * 1024,
55+
enable_compression: bool = True,
56+
api_version: Optional[str] = None,
5057
):
51-
if options is None:
52-
options = BlobPayloadStoreOptions(
53-
connection_string=connection_string,
54-
account_url=account_url,
55-
credential=credential,
56-
)
57-
58-
if not options.connection_string and not options.account_url:
58+
if not connection_string and not account_url:
5959
raise ValueError(
6060
"Either 'connection_string' or 'account_url' (with 'credential') must be provided."
6161
)
6262

63-
self._options = options
64-
self._container_name = options.container_name
63+
self._options = LargePayloadStorageOptions(
64+
threshold_bytes=threshold_bytes,
65+
max_stored_payload_bytes=max_stored_payload_bytes,
66+
enable_compression=enable_compression,
67+
)
68+
self._container_name = container_name
6569

6670
# Optional kwargs shared by both sync and async clients.
6771
extra_kwargs: dict = {}
68-
if options.api_version:
69-
extra_kwargs["api_version"] = options.api_version
72+
if api_version:
73+
extra_kwargs["api_version"] = api_version
7074

7175
# Build sync client
72-
if options.connection_string:
76+
if connection_string:
7377
self._blob_service_client = BlobServiceClient.from_connection_string(
74-
options.connection_string, **extra_kwargs,
78+
connection_string, **extra_kwargs,
7579
)
7680
else:
81+
assert account_url is not None # guaranteed by validation above
7782
self._blob_service_client = BlobServiceClient(
78-
account_url=options.account_url,
79-
credential=options.credential,
83+
account_url=account_url,
84+
credential=credential,
8085
**extra_kwargs,
8186
)
8287

8388
# Build async client
84-
if options.connection_string:
89+
if connection_string:
8590
self._async_blob_service_client = AsyncBlobServiceClient.from_connection_string(
86-
options.connection_string, **extra_kwargs,
91+
connection_string, **extra_kwargs,
8792
)
8893
else:
94+
assert account_url is not None # guaranteed by validation above
8995
self._async_blob_service_client = AsyncBlobServiceClient(
90-
account_url=options.account_url,
91-
credential=options.credential,
96+
account_url=account_url,
97+
credential=credential,
9298
**extra_kwargs,
9399
)
94100

durabletask/extensions/azure_blob_payloads/options.py

Lines changed: 0 additions & 38 deletions
This file was deleted.

examples/large_payload/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ $env:STORAGE_CONNECTION_STRING = "DefaultEndpointsProtocol=https;..."
102102

103103
## Configuration Options
104104

105-
The `BlobPayloadStoreOptions` class supports the following settings:
105+
The `BlobPayloadStore` constructor supports the following settings:
106106

107107
| Option | Default | Description |
108108
|---|---|---|

examples/large_payload/app.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
1515
Usage (emulator + Azurite — no Azure resources needed):
1616
# Start the DTS emulator (port 8080) and Azurite (port 10000)
17-
export STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"
1817
python app.py
1918
2019
Usage (Azure):
@@ -31,7 +30,7 @@
3130
from durabletask import client, task
3231
from durabletask.azuremanaged.client import DurableTaskSchedulerClient
3332
from durabletask.azuremanaged.worker import DurableTaskSchedulerWorker
34-
from durabletask.extensions.azure_blob_payloads import BlobPayloadStore, BlobPayloadStoreOptions
33+
from durabletask.extensions.azure_blob_payloads import BlobPayloadStore
3534

3635

3736
# --------------- Activities ---------------
@@ -71,22 +70,18 @@ def main():
7170
# Azure Storage connection string (defaults to Azurite)
7271
storage_conn_str = os.getenv(
7372
"STORAGE_CONNECTION_STRING",
74-
"DefaultEndpointsProtocol=http;"
75-
"AccountName=devstoreaccount1;"
76-
"AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsu"
77-
"Fq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;"
78-
"BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;",
73+
"UseDevelopmentStorage=true",
7974
)
8075

8176
print(f"Using taskhub: {taskhub_name}")
8277
print(f"Using endpoint: {endpoint}")
8378

8479
# Configure the blob payload store
85-
store = BlobPayloadStore(BlobPayloadStoreOptions(
80+
store = BlobPayloadStore(
8681
connection_string=storage_conn_str,
8782
# Use a low threshold so that we can see externalization in action
8883
threshold_bytes=1_024,
89-
))
84+
)
9085

9186
secure_channel = endpoint.startswith("https://")
9287
credential = DefaultAzureCredential() if secure_channel else None

tests/durabletask/test_large_payload.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -409,38 +409,32 @@ def test_is_known_token(self):
409409

410410

411411
# ------------------------------------------------------------------
412-
# Tests: BlobPayloadStoreOptions
412+
# Tests: BlobPayloadStore construction and defaults
413413
# ------------------------------------------------------------------
414414

415415

416-
class TestBlobPayloadStoreOptions:
416+
class TestBlobPayloadStoreDefaults:
417417
def test_default_options(self):
418-
"""Default options should match .NET SDK defaults."""
418+
"""Constructing with connection_string should use .NET SDK defaults."""
419419
pytest.importorskip("azure.storage.blob")
420-
from durabletask.extensions.azure_blob_payloads.options import BlobPayloadStoreOptions
420+
from durabletask.extensions.azure_blob_payloads.blob_payload_store import BlobPayloadStore
421421

422-
opts = BlobPayloadStoreOptions()
422+
store = BlobPayloadStore(connection_string="UseDevelopmentStorage=true")
423+
opts = store.options
423424
assert opts.threshold_bytes == 900_000
424425
assert opts.max_stored_payload_bytes == 10 * 1024 * 1024
425426
assert opts.enable_compression is True
426-
assert opts.container_name == "durabletask-payloads"
427-
assert opts.connection_string is None
428-
assert opts.account_url is None
429-
assert opts.credential is None
430427

431428
def test_custom_options(self):
432-
"""Custom options should be respected."""
429+
"""Custom constructor params should be reflected in options."""
433430
pytest.importorskip("azure.storage.blob")
434-
from durabletask.extensions.azure_blob_payloads.options import BlobPayloadStoreOptions
431+
from durabletask.extensions.azure_blob_payloads.blob_payload_store import BlobPayloadStore
435432

436-
opts = BlobPayloadStoreOptions(
437-
threshold_bytes=500_000,
438-
container_name="my-container",
433+
store = BlobPayloadStore(
439434
connection_string="UseDevelopmentStorage=true",
435+
threshold_bytes=500_000,
440436
)
441-
assert opts.threshold_bytes == 500_000
442-
assert opts.container_name == "my-container"
443-
assert opts.connection_string == "UseDevelopmentStorage=true"
437+
assert store.options.threshold_bytes == 500_000
444438

445439

446440
# ------------------------------------------------------------------

0 commit comments

Comments
 (0)