Skip to content
Merged
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ All notable changes to this project will be documented in this file.
- Type-hint-driven validation via `df_loads(s, expected_type=...)`: when the V2 programming model provides a return-type annotation for an activity or sub-orchestrator, the annotation is threaded through call sites so the SDK's `df_loads` can validate the deserialized payload against that type (when available). On older `azure-functions` releases the argument is accepted but ignored.
- Return-type discovery for V2 decorated activities/sub-orchestrators (`azure.durable_functions.models.utils.type_discovery`): resolves the concrete return annotation from the user's registered function, used to supply `expected_type` to `df_loads`.

### Changed

- `purge_instance_history_by` now raises a clear `ValueError` when the required `created_time_from` argument is omitted, instead of sending a request that the Durable extension rejects.

## 1.0.0b6

- [Create timer](https://github.com/Azure/azure-functions-durable-python/issues/35) functionality available
Expand Down
11 changes: 10 additions & 1 deletion azure/durable_functions/models/DurableOrchestrationClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,8 @@ async def purge_instance_history_by(
Parameters
----------
created_time_from : Optional[datetime]
Comment thread
andystaples marked this conversation as resolved.
Delete orchestration history which were created after this Date.
Delete orchestration history which were created after this Date. This argument
is required.
created_time_to: Optional[datetime]
Delete orchestration history which were created before this Date.
runtime_status: Optional[List[OrchestrationRuntimeStatus]]
Expand All @@ -434,7 +435,15 @@ async def purge_instance_history_by(
-------
PurgeHistoryResult
The results of the request to purge history

Raises
------
ValueError
When `created_time_from` is not provided.
"""
if created_time_from is None:
raise ValueError("created_time_from is required when purging instance history")

options = RpcManagementOptions(created_time_from=created_time_from,
created_time_to=created_time_to,
runtime_status=runtime_status)
Expand Down
40 changes: 31 additions & 9 deletions tests/models/test_DurableOrchestrationClient.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
from datetime import datetime
from typing import Any

import pytest
Expand Down Expand Up @@ -366,40 +367,61 @@ async def test_delete_500_purge_instance_history(binding_string):

@pytest.mark.asyncio
async def test_delete_200_purge_instance_history_by(binding_string):
mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/?runtimeStatus=Running",
response=[200, dict(instancesDeleted=1)])
mock_request = MockRequest(
expected_url=f"{RPC_BASE_URL}instances/"
"?createdTimeFrom=2000-01-01T00:00:00.000000Z"
"&runtimeStatus=Completed",
response=[200, dict(instancesDeleted=1)])
client = DurableOrchestrationClient(binding_string)
client._delete_async_request = mock_request.delete

result = await client.purge_instance_history_by(
runtime_status=[OrchestrationRuntimeStatus.Running])
created_time_from=datetime(2000, 1, 1),
runtime_status=[OrchestrationRuntimeStatus.Completed])
assert result is not None
assert result.instances_deleted == 1


@pytest.mark.asyncio
async def test_delete_404_purge_instance_history_by(binding_string):
mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/?runtimeStatus=Running",
response=[404, MESSAGE_404])
mock_request = MockRequest(
expected_url=f"{RPC_BASE_URL}instances/"
"?createdTimeFrom=2000-01-01T00:00:00.000000Z"
"&runtimeStatus=Completed",
response=[404, MESSAGE_404])
client = DurableOrchestrationClient(binding_string)
client._delete_async_request = mock_request.delete

result = await client.purge_instance_history_by(
runtime_status=[OrchestrationRuntimeStatus.Running])
created_time_from=datetime(2000, 1, 1),
runtime_status=[OrchestrationRuntimeStatus.Completed])
assert result is not None
assert result.instances_deleted == 0


@pytest.mark.asyncio
async def test_delete_500_purge_instance_history_by(binding_string):
mock_request = MockRequest(expected_url=f"{RPC_BASE_URL}instances/?runtimeStatus=Running",
response=[500, MESSAGE_500])
mock_request = MockRequest(
expected_url=f"{RPC_BASE_URL}instances/"
"?createdTimeFrom=2000-01-01T00:00:00.000000Z"
"&runtimeStatus=Completed",
response=[500, MESSAGE_500])
client = DurableOrchestrationClient(binding_string)
client._delete_async_request = mock_request.delete

with pytest.raises(Exception):
await client.purge_instance_history_by(
runtime_status=[OrchestrationRuntimeStatus.Running])
created_time_from=datetime(2000, 1, 1),
runtime_status=[OrchestrationRuntimeStatus.Completed])


@pytest.mark.asyncio
async def test_purge_instance_history_by_requires_created_time_from(binding_string):
client = DurableOrchestrationClient(binding_string)

with pytest.raises(ValueError, match="created_time_from is required"):
await client.purge_instance_history_by(
runtime_status=[OrchestrationRuntimeStatus.Completed])


@pytest.mark.asyncio
Expand Down
Loading