aws-durable-execution-sdk-python 1.1.2__tar.gz → 1.4.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.
Files changed (108) hide show
  1. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/workflows/ci.yml +2 -2
  2. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/workflows/integration-tests.yml +3 -5
  3. aws_durable_execution_sdk_python-1.4.0/.github/workflows/notify_slack.yml +39 -0
  4. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/workflows/pypi-publish.yml +3 -3
  5. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/workflows/scorecard.yml +2 -2
  6. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/workflows/sync-package.yml +2 -2
  7. aws_durable_execution_sdk_python-1.1.2/docs/agents.md → aws_durable_execution_sdk_python-1.4.0/AGENTS.md +4 -3
  8. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/PKG-INFO +1 -1
  9. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/logger.md +74 -0
  10. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/map.md +33 -82
  11. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/getting-started.md +2 -1
  12. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/pyproject.toml +7 -0
  13. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/__about__.py +1 -1
  14. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/__init__.py +7 -1
  15. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/concurrency/executor.py +6 -0
  16. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/concurrency/models.py +88 -17
  17. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/context.py +26 -5
  18. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/logger.py +1 -1
  19. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/step.py +3 -2
  20. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/wait_for_condition.py +3 -2
  21. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/serdes.py +1 -5
  22. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/state.py +76 -34
  23. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/concurrency_test.py +192 -49
  24. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/context_test.py +161 -53
  25. aws_durable_execution_sdk_python-1.4.0/tests/durable_executions_python_language_sdk_test.py +15 -0
  26. aws_durable_execution_sdk_python-1.4.0/tests/e2e/map_with_concurrent_waits_int_test.py +200 -0
  27. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/logger_test.py +2 -2
  28. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/map_test.py +60 -6
  29. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/parallel_test.py +25 -6
  30. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/wait_for_condition_test.py +121 -1
  31. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/state_test.py +274 -10
  32. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/test_helpers.py +5 -2
  33. aws_durable_execution_sdk_python-1.1.2/tests/durable_executions_python_language_sdk_test.py +0 -6
  34. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  35. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  36. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/ISSUE_TEMPLATE/documentation.yml +0 -0
  37. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  38. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/dependabot.yml +0 -0
  39. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/workflows/lintcommit.js +0 -0
  40. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.github/workflows/test-parser.yml +0 -0
  41. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/.gitignore +0 -0
  42. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/CODE_OF_CONDUCT.md +0 -0
  43. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/CONTRIBUTING.md +0 -0
  44. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/LICENSE +0 -0
  45. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/NOTICE +0 -0
  46. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/README.md +0 -0
  47. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/advanced/error-handling.md +0 -0
  48. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/advanced/serialization.md +0 -0
  49. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/advanced/testing-modes.md +0 -0
  50. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/api-reference/.gitkeep +0 -0
  51. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/architecture.md +0 -0
  52. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/best-practices.md +0 -0
  53. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/callbacks.md +0 -0
  54. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/child-contexts.md +0 -0
  55. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/invoke.md +0 -0
  56. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/parallel.md +0 -0
  57. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/steps.md +0 -0
  58. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/core/wait.md +0 -0
  59. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/index.md +0 -0
  60. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/testing-patterns/.gitkeep +0 -0
  61. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/testing-patterns/basic-tests.md +0 -0
  62. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/testing-patterns/complex-workflows.md +0 -0
  63. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/docs/testing-patterns/stores.md +0 -0
  64. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/ops/__tests__/test_parse_sdk_branch.py +0 -0
  65. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/ops/ci-checks.sh +0 -0
  66. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/ops/parse_sdk_branch.py +0 -0
  67. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/.gitignore +0 -0
  68. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/concurrency/__init__.py +0 -0
  69. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/config.py +0 -0
  70. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/exceptions.py +0 -0
  71. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/execution.py +0 -0
  72. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/identifier.py +0 -0
  73. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/lambda_service.py +0 -0
  74. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/__init__.py +0 -0
  75. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/base.py +0 -0
  76. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/callback.py +0 -0
  77. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/child.py +0 -0
  78. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/invoke.py +0 -0
  79. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/map.py +0 -0
  80. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/parallel.py +0 -0
  81. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/operation/wait.py +0 -0
  82. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/py.typed +0 -0
  83. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/retries.py +0 -0
  84. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/suspend.py +0 -0
  85. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/threading.py +0 -0
  86. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/types.py +0 -0
  87. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/src/aws_durable_execution_sdk_python/waits.py +0 -0
  88. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/__init__.py +0 -0
  89. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/config_test.py +0 -0
  90. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/e2e/__init__.py +0 -0
  91. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/e2e/checkpoint_response_int_test.py +0 -0
  92. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/e2e/execution_int_test.py +0 -0
  93. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/exceptions_test.py +0 -0
  94. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/execution_test.py +0 -0
  95. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/lambda_service_test.py +0 -0
  96. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/__init__.py +0 -0
  97. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/base_test.py +0 -0
  98. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/callback_test.py +0 -0
  99. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/child_test.py +0 -0
  100. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/invoke_test.py +0 -0
  101. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/step_test.py +0 -0
  102. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/operation/wait_test.py +0 -0
  103. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/retries_test.py +0 -0
  104. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/serdes_test.py +0 -0
  105. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/suspend_test.py +0 -0
  106. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/threading_test.py +0 -0
  107. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/types_test.py +0 -0
  108. {aws_durable_execution_sdk_python-1.1.2 → aws_durable_execution_sdk_python-1.4.0}/tests/waits_test.py +0 -0
@@ -18,7 +18,7 @@ jobs:
18
18
  steps:
19
19
  - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
20
20
  - name: Use Node.js
21
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
21
+ uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
22
22
  with:
23
23
  node-version: 22.x
24
24
  - name: Check PR title
@@ -42,7 +42,7 @@ jobs:
42
42
  python-version: ${{ matrix.python-version }}
43
43
  - name: Install Hatch
44
44
  run: |
45
- python -m pip install hatch==1.15.0
45
+ python -m pip install hatch==1.16.5
46
46
  - name: static analysis
47
47
  run: hatch fmt --check
48
48
  - name: type checking
@@ -33,7 +33,6 @@ jobs:
33
33
  with:
34
34
  repository: aws/aws-durable-execution-sdk-python-testing
35
35
  ref: ${{ steps.parse.outputs.testing_ref }}
36
- token: ${{ secrets.CROSS_REPO_PAT }}
37
36
  path: testing-sdk
38
37
 
39
38
  - name: Set up Python ${{ matrix.python-version }}
@@ -42,7 +41,7 @@ jobs:
42
41
  python-version: ${{ matrix.python-version }}
43
42
 
44
43
  - name: Install Hatch
45
- run: python -m pip install hatch==1.15.0
44
+ run: python -m pip install hatch==1.16.5
46
45
 
47
46
  - name: Setup and run Testing SDK
48
47
  working-directory: testing-sdk
@@ -82,7 +81,6 @@ jobs:
82
81
  with:
83
82
  repository: aws/aws-durable-execution-sdk-python-testing
84
83
  ref: ${{ steps.parse.outputs.testing_ref }}
85
- token: ${{ secrets.CROSS_REPO_PAT }}
86
84
  path: testing-sdk
87
85
 
88
86
  - name: Set up Python 3.13
@@ -91,7 +89,7 @@ jobs:
91
89
  python-version: '3.13'
92
90
 
93
91
  - name: Configure AWS credentials
94
- uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
92
+ uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
95
93
  with:
96
94
  role-to-assume: "${{ secrets.ACTIONS_INTEGRATION_ROLE_NAME }}"
97
95
  role-session-name: languageSDKIntegrationTest
@@ -102,7 +100,7 @@ jobs:
102
100
  env:
103
101
  AWS_DURABLE_SDK_URL: file://${{ github.workspace }}/language-sdk
104
102
  run: |
105
- pip install hatch==1.15.0
103
+ pip install hatch==1.16.5
106
104
  python -m pip install -e .
107
105
 
108
106
  - name: Get integration examples
@@ -0,0 +1,39 @@
1
+ name: Slack Notifications
2
+
3
+ on:
4
+ issues:
5
+ types: [opened, reopened]
6
+ pull_request_target:
7
+ types: [opened, reopened]
8
+
9
+ permissions: {}
10
+
11
+ jobs:
12
+ notify:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Send issue notification to Slack
16
+ if: github.event_name == 'issues'
17
+ uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
18
+ with:
19
+ webhook: ${{ secrets.SLACK_WEBHOOK_URL_ISSUE }}
20
+ webhook-type: incoming-webhook
21
+ payload: |
22
+ {
23
+ "action": "${{ github.event.action }}",
24
+ "issue_url": "${{ github.event.issue.html_url }}",
25
+ "package_name": "${{ github.repository }}"
26
+ }
27
+
28
+ - name: Send pull request notification to Slack
29
+ if: github.event_name == 'pull_request_target'
30
+ uses: slackapi/slack-github-action@af78098f536edbc4de71162a307590698245be95 # v3.0.1
31
+ with:
32
+ webhook: ${{ secrets.SLACK_WEBHOOK_URL_PR }}
33
+ webhook-type: incoming-webhook
34
+ payload: |
35
+ {
36
+ "action": "${{ github.event.action }}",
37
+ "pr_url": "${{ github.event.pull_request.html_url }}",
38
+ "package_name": "${{ github.repository }}"
39
+ }
@@ -27,14 +27,14 @@ jobs:
27
27
  python-version: "3.11"
28
28
  - name: Install Hatch
29
29
  run: |
30
- python -m pip install --upgrade hatch==1.15.0
30
+ python -m pip install --upgrade hatch==1.16.5
31
31
  - name: Build release distributions
32
32
  run: |
33
33
  # NOTE: put your own distribution build steps here.
34
34
  hatch build
35
35
 
36
36
  - name: Upload distributions
37
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
37
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
38
38
  with:
39
39
  name: release-dists
40
40
  path: dist/
@@ -60,7 +60,7 @@ jobs:
60
60
 
61
61
  steps:
62
62
  - name: Retrieve release distributions
63
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
63
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
64
64
  with:
65
65
  name: release-dists
66
66
  path: dist/
@@ -66,7 +66,7 @@ jobs:
66
66
  # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
67
67
  # format to the repository Actions tab.
68
68
  - name: "Upload artifact"
69
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
69
+ uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
70
70
  with:
71
71
  name: SARIF file
72
72
  path: results.sarif
@@ -75,6 +75,6 @@ jobs:
75
75
  # Upload the results to GitHub's code scanning dashboard (optional).
76
76
  # Commenting out will disable upload of results to your repo's Code Scanning dashboard
77
77
  - name: "Upload to code-scanning"
78
- uses: github/codeql-action/upload-sarif@19b2f06db2b6f5108140aeb04014ef02b648f789 # v4.31.11
78
+ uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
79
79
  with:
80
80
  sarif_file: results.sarif
@@ -27,11 +27,11 @@ jobs:
27
27
  python-version: ${{ matrix.python-version }}
28
28
  - name: Install Hatch
29
29
  run: |
30
- python -m pip install --upgrade hatch==1.15.0
30
+ python -m pip install --upgrade hatch==1.16.5
31
31
  - name: Build distribution
32
32
  run: hatch build
33
33
  - name: configure aws credentials
34
- uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5.1.1
34
+ uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0
35
35
  with:
36
36
  role-to-assume: "${{ secrets.ACTIONS_SYNC_ROLE_NAME }}"
37
37
  role-session-name: gh-python
@@ -495,9 +495,10 @@ const allResults = results.getResults();
495
495
  **Python:**
496
496
 
497
497
  ```python
498
+ from collections.abc import Sequence
498
499
  from aws_durable_execution_sdk_python.concurrency import MapConfig, CompletionConfig
499
500
 
500
- def process_item(ctx: DurableContext, item: dict, index: int) -> dict:
501
+ def process_item(ctx: DurableContext, item: dict, index: int, items: Sequence[dict]) -> dict:
501
502
  return ctx.step(lambda _: process(item), name=f"process-{index}")
502
503
 
503
504
  results = context.map(
@@ -833,7 +834,7 @@ Resources:
833
834
  Type: AWS::Lambda::Function
834
835
  Properties:
835
836
  FunctionName: myDurableFunction
836
- Runtime: nodejs22.x # or python3.12
837
+ Runtime: nodejs22.x # or python3.14
837
838
  Handler: index.handler
838
839
  Role: !GetAtt DurableFunctionRole.Arn
839
840
  Code:
@@ -894,7 +895,7 @@ Resources:
894
895
  Type: AWS::Serverless::Function
895
896
  Properties:
896
897
  FunctionName: myDurableFunction
897
- Runtime: nodejs22.x # or python3.12
898
+ Runtime: nodejs22.x # or python3.14
898
899
  Handler: index.handler
899
900
  CodeUri: ./src
900
901
  DurableConfig:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aws-durable-execution-sdk-python
3
- Version: 1.1.2
3
+ Version: 1.4.0
4
4
  Summary: AWS Durable Execution SDK for Python
5
5
  Project-URL: Documentation, https://github.com/aws/aws-durable-execution-sdk-python#readme
6
6
  Project-URL: Issues, https://github.com/aws/aws-durable-execution-sdk-python/issues
@@ -14,6 +14,7 @@ The Durable Execution SDK automatically enriches your logs with execution contex
14
14
  - [Integration with Powertools for AWS Lambda (Python)](#integration-with-powertools-for-aws-lambda-python)
15
15
  - [Replay behavior and log deduplication](#replay-behavior-and-log-deduplication)
16
16
  - [Best practices](#best-practices)
17
+ - [Enabling debug logging](#enabling-debug-logging)
17
18
  - [FAQ](#faq)
18
19
  - [Testing logger integration](#testing-logger-integration)
19
20
  - [See also](#see-also)
@@ -485,6 +486,79 @@ context.logger.info("User authenticated", extra={"password": password})
485
486
 
486
487
  [↑ Back to top](#table-of-contents)
487
488
 
489
+ ## Enabling debug logging
490
+
491
+ The SDK logs internally using Python's standard `logging` module. To see these logs, set `ApplicationLogLevel: DEBUG` in [Advanced logging controls](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs-advanced.html).
492
+
493
+ Advanced logging controls filters logs before they reach CloudWatch. If you set DEBUG level in code but leave Advanced logging controls at INFO, your debug logs will be dropped. You must configure the level in Advanced logging controls - it auto-patches all loggers, so you don't need to configure log levels in code.
494
+
495
+ ```mermaid
496
+ flowchart LR
497
+ A[Logger emits DEBUG] --> B{Advanced Logging Controls}
498
+ B -->|ApplicationLogLevel = DEBUG| C[CloudWatch ✓]
499
+ B -->|ApplicationLogLevel = INFO| D[Dropped ✗]
500
+ ```
501
+
502
+ **Important:** DEBUG level applies to all libraries including botocore. Since the SDK uses boto3 internally, this will flood your logs with HTTP request/response details. Silence botocore in your code:
503
+
504
+ ```python
505
+ import logging
506
+
507
+ # Silence botocore/urllib3 noise
508
+ logging.getLogger("botocore").setLevel(logging.WARNING)
509
+ logging.getLogger("urllib3").setLevel(logging.WARNING)
510
+ ```
511
+
512
+ Configure ALC via SAM/CloudFormation:
513
+
514
+ ```yaml
515
+ # SAM template
516
+ Resources:
517
+ MyFunction:
518
+ Type: AWS::Serverless::Function
519
+ Properties:
520
+ LoggingConfig:
521
+ LogFormat: JSON
522
+ ApplicationLogLevel: DEBUG
523
+ ```
524
+
525
+ Or in the Lambda console under Configuration → Monitoring and operations tools → Logging configuration.
526
+
527
+ ### Selective logging
528
+
529
+ Python loggers are hierarchical. Silencing `aws_durable_execution_sdk_python` silences all SDK modules. To keep some modules at DEBUG while silencing others:
530
+
531
+ ```python
532
+ import logging
533
+
534
+ # Silence all SDK logs
535
+ logging.getLogger("aws_durable_execution_sdk_python").setLevel(logging.WARNING)
536
+
537
+ # Or silence specific modules only
538
+ logging.getLogger("aws_durable_execution_sdk_python.state").setLevel(logging.WARNING)
539
+ logging.getLogger("aws_durable_execution_sdk_python.concurrency").setLevel(logging.WARNING)
540
+ ```
541
+
542
+ SDK logger namespaces:
543
+
544
+ | Namespace | Description |
545
+ |-----------|-------------|
546
+ | `aws_durable_execution_sdk_python` | Root - silences all SDK logs |
547
+ | `aws_durable_execution_sdk_python.state` | Checkpoint and replay state management |
548
+ | `aws_durable_execution_sdk_python.execution` | Durable execution lifecycle |
549
+ | `aws_durable_execution_sdk_python.context` | DurableContext operations |
550
+ | `aws_durable_execution_sdk_python.lambda_service` | Lambda API calls |
551
+ | `aws_durable_execution_sdk_python.serdes` | Serialization/deserialization |
552
+ | `aws_durable_execution_sdk_python.concurrency` | Parallel and map execution |
553
+ | `aws_durable_execution_sdk_python.operation.step` | Step operations |
554
+ | `aws_durable_execution_sdk_python.operation.wait` | Wait operations |
555
+ | `aws_durable_execution_sdk_python.operation.invoke` | Invoke operations |
556
+ | `aws_durable_execution_sdk_python.operation.child` | Child context operations |
557
+ | `aws_durable_execution_sdk_python.operation.parallel` | Parallel operations |
558
+ | `aws_durable_execution_sdk_python.operation.map` | Map operations |
559
+
560
+ [↑ Back to top](#table-of-contents)
561
+
488
562
  ## FAQ
489
563
 
490
564
  **Q: Does logging work during replays?**
@@ -28,8 +28,6 @@
28
28
 
29
29
  **Concurrency control** - Limiting how many items process simultaneously using `max_concurrency` in `MapConfig`.
30
30
 
31
- **Item batching** - Grouping multiple items together for processing as a single unit to optimize efficiency.
32
-
33
31
  **Completion criteria** - Rules that determine when a map operation succeeds or fails based on individual item results.
34
32
 
35
33
  [↑ Back to top](#table-of-contents)
@@ -42,7 +40,7 @@ Use map operations to:
42
40
  - Transform collections with automatic checkpointing
43
41
  - Process lists of items in parallel
44
42
  - Handle large datasets with resilience
45
- - Control concurrency and batching behavior
43
+ - Control concurrency behavior
46
44
  - Define custom success/failure criteria
47
45
 
48
46
  Map operations use `context.map()` to process collections efficiently. Each item becomes an independent operation that executes in parallel with other items.
@@ -55,7 +53,6 @@ Map operations use `context.map()` to process collections efficiently. Each item
55
53
  - **Independent checkpointing** - Each item's result is saved separately
56
54
  - **Partial completion** - Completed items don't reprocess on replay
57
55
  - **Concurrency control** - Limit simultaneous processing with `max_concurrency`
58
- - **Batching support** - Group items for efficient processing
59
56
  - **Flexible completion** - Define custom success/failure criteria
60
57
  - **Result ordering** - Results maintain the same order as inputs
61
58
 
@@ -77,19 +74,20 @@ def square(context: DurableContext, item: int, index: int, items: list[int]) ->
77
74
  return item * item
78
75
 
79
76
  @durable_execution
80
- def handler(event: dict, context: DurableContext) -> BatchResult[int]:
77
+ def handler(event: dict, context: DurableContext) -> dict:
81
78
  """Process a list of items using map operations."""
82
79
  items = [1, 2, 3, 4, 5]
83
-
80
+
84
81
  result = context.map(items, square)
85
- return result
82
+ # Convert to dict for JSON serialization (BatchResult is not JSON serializable)
83
+ return result.to_dict()
86
84
  ```
87
85
 
88
86
  When this function runs:
89
87
  1. Each item is processed in parallel
90
88
  2. The `square` function is called for each item
91
89
  3. Each result is checkpointed independently
92
- 4. The function returns a `BatchResult` with results `[1, 4, 9, 16, 25]`
90
+ 4. The function returns a dict with results `[1, 4, 9, 16, 25]`
93
91
 
94
92
  If the function is interrupted after processing items 0-2, it resumes at item 3 without reprocessing the first three items.
95
93
 
@@ -102,7 +100,7 @@ If the function is interrupted after processing items 0-2, it resumes at item 3
102
100
  ```python
103
101
  def map(
104
102
  inputs: Sequence[U],
105
- func: Callable[[DurableContext, U | BatchedInput[Any, U], int, Sequence[U]], T],
103
+ func: Callable[[DurableContext, U, int, Sequence[U]], T],
106
104
  name: str | None = None,
107
105
  config: MapConfig | None = None,
108
106
  ) -> BatchResult[T]
@@ -113,7 +111,7 @@ def map(
113
111
  - `inputs` - A sequence of items to process (list, tuple, or any sequence type).
114
112
  - `func` - A callable that processes each item. See [Map function signature](#map-function-signature) for details.
115
113
  - `name` (optional) - A name for the map operation, useful for debugging and testing.
116
- - `config` (optional) - A `MapConfig` object to configure concurrency, batching, and completion criteria.
114
+ - `config` (optional) - A `MapConfig` object to configure concurrency and completion criteria.
117
115
 
118
116
  **Returns:** A `BatchResult[T]` containing the results from processing all items.
119
117
 
@@ -128,7 +126,7 @@ The map function receives four parameters:
128
126
  ```python
129
127
  def process_item(
130
128
  context: DurableContext,
131
- item: U | BatchedInput[Any, U],
129
+ item: U,
132
130
  index: int,
133
131
  items: Sequence[U]
134
132
  ) -> T:
@@ -140,7 +138,7 @@ def process_item(
140
138
  **Parameters:**
141
139
 
142
140
  - `context` - A `DurableContext` for the item's processing. Use this to call steps, waits, or other operations.
143
- - `item` - The current item being processed. Can be a `BatchedInput` if batching is configured.
141
+ - `item` - The current item being processed.
144
142
  - `index` - The zero-based index of the item in the original collection.
145
143
  - `items` - The full collection of items being processed.
146
144
 
@@ -165,10 +163,10 @@ def validate_email(
165
163
  }
166
164
 
167
165
  @durable_execution
168
- def handler(event: dict, context: DurableContext) -> BatchResult[dict]:
166
+ def handler(event: dict, context: DurableContext) -> dict:
169
167
  emails = ["jane_doe@example.com", "john_doe@example.org", "invalid"]
170
168
  result = context.map(emails, validate_email)
171
- return result
169
+ return result.to_dict()
172
170
  ```
173
171
 
174
172
  [↑ Back to top](#table-of-contents)
@@ -186,7 +184,6 @@ from aws_durable_execution_sdk_python import (
186
184
  from aws_durable_execution_sdk_python.config import (
187
185
  MapConfig,
188
186
  CompletionConfig,
189
- ItemBatcher,
190
187
  )
191
188
 
192
189
  def process_item(context: DurableContext, item: int, index: int, items: list[int]) -> dict:
@@ -194,26 +191,23 @@ def process_item(context: DurableContext, item: int, index: int, items: list[int
194
191
  return {"item": item, "squared": item * item}
195
192
 
196
193
  @durable_execution
197
- def handler(event: dict, context: DurableContext) -> BatchResult[dict]:
194
+ def handler(event: dict, context: DurableContext) -> dict:
198
195
  items = list(range(100))
199
-
196
+
200
197
  # Configure map operation
201
198
  config = MapConfig(
202
199
  max_concurrency=10, # Process 10 items at a time
203
- item_batcher=ItemBatcher(max_items_per_batch=5), # Batch 5 items together
204
200
  completion_config=CompletionConfig.all_successful(), # Require all to succeed
205
201
  )
206
-
202
+
207
203
  result = context.map(items, process_item, name="process_numbers", config=config)
208
- return result
204
+ return result.to_dict()
209
205
  ```
210
206
 
211
207
  ### MapConfig parameters
212
208
 
213
209
  **max_concurrency** - Maximum number of items to process concurrently. If `None`, all items process in parallel. Use this to control resource usage.
214
210
 
215
- **item_batcher** - Configuration for batching items together. Use `ItemBatcher(max_items_per_batch=N)` to group items.
216
-
217
211
  **completion_config** - Defines when the map operation succeeds or fails:
218
212
  - `CompletionConfig()` - Default, allows any number of failures
219
213
  - `CompletionConfig.all_successful()` - Requires all items to succeed
@@ -244,45 +238,14 @@ def fetch_data(context: DurableContext, url: str, index: int, urls: list[str]) -
244
238
  return {"url": url, "data": "..."}
245
239
 
246
240
  @durable_execution
247
- def handler(event: dict, context: DurableContext) -> BatchResult[dict]:
241
+ def handler(event: dict, context: DurableContext) -> dict:
248
242
  urls = [f"https://example.com/api/{i}" for i in range(100)]
249
-
243
+
250
244
  # Process only 5 URLs at a time
251
245
  config = MapConfig(max_concurrency=5)
252
-
253
- result = context.map(urls, fetch_data, config=config)
254
- return result
255
- ```
256
-
257
- ### Batching items
258
-
259
- Group multiple items for efficient processing:
260
246
 
261
- ```python
262
- from aws_durable_execution_sdk_python.config import MapConfig, ItemBatcher, BatchedInput
263
-
264
- def process_batch(
265
- context: DurableContext,
266
- batch: BatchedInput[None, int],
267
- index: int,
268
- items: list[int]
269
- ) -> list[dict]:
270
- """Process a batch of items together."""
271
- # Process all items in the batch together
272
- return [{"item": item, "squared": item * item} for item in batch.items]
273
-
274
- @durable_execution
275
- def handler(event: dict, context: DurableContext) -> BatchResult[list[dict]]:
276
- items = list(range(100))
277
-
278
- # Process items in batches of 10
279
- config = MapConfig(
280
- item_batcher=ItemBatcher(max_items_per_batch=10)
281
- )
282
-
283
- result = context.map(items, process_batch, config=config)
284
- return result
285
- ```
247
+ result = context.map(urls, fetch_data, config=config)
248
+ return result.to_dict()```
286
249
 
287
250
  ### Custom completion criteria
288
251
 
@@ -299,9 +262,9 @@ def process_item(context: DurableContext, item: int, index: int, items: list[int
299
262
  return {"item": item, "processed": True}
300
263
 
301
264
  @durable_execution
302
- def handler(event: dict, context: DurableContext) -> BatchResult[dict]:
265
+ def handler(event: dict, context: DurableContext) -> dict:
303
266
  items = list(range(20))
304
-
267
+
305
268
  # Succeed if at least 15 items succeed, fail after 5 failures
306
269
  config = MapConfig(
307
270
  completion_config=CompletionConfig(
@@ -309,9 +272,9 @@ def handler(event: dict, context: DurableContext) -> BatchResult[dict]:
309
272
  tolerated_failure_count=5,
310
273
  )
311
274
  )
312
-
275
+
313
276
  result = context.map(items, process_item, config=config)
314
- return result
277
+ return result.to_dict()
315
278
  ```
316
279
 
317
280
  ### Using context operations in map functions
@@ -344,11 +307,13 @@ def process_user(
344
307
  return {"user_id": user_id, "notification_sent": notification["sent"]}
345
308
 
346
309
  @durable_execution
347
- def handler(event: dict, context: DurableContext) -> BatchResult[dict]:
310
+ def handler(event: dict, context: DurableContext) -> dict:
311
+ """Process multiple users using context operations within map functions."""
348
312
  user_ids = ["user_1", "user_2", "user_3"]
349
-
313
+
350
314
  result = context.map(user_ids, process_user)
351
- return result
315
+ # Convert to dict for JSON serialization (BatchResult is not JSON serializable)
316
+ return result.to_dict()
352
317
  ```
353
318
 
354
319
  ### Filtering and transforming results
@@ -391,8 +356,6 @@ def handler(event: dict, context: DurableContext) -> list[str]:
391
356
 
392
357
  **Control concurrency for external calls** - When calling external APIs, use `max_concurrency` to avoid rate limits.
393
358
 
394
- **Batch for efficiency** - For small, fast operations, use `item_batcher` to reduce overhead.
395
-
396
359
  **Define completion criteria** - Use `CompletionConfig` to specify when the operation should succeed or fail.
397
360
 
398
361
  **Keep map functions focused** - Each map function should process one item. Don't mix collection iteration with item processing.
@@ -401,7 +364,7 @@ def handler(event: dict, context: DurableContext) -> list[str]:
401
364
 
402
365
  **Handle errors gracefully** - Wrap error-prone code in try-except blocks or use completion criteria to tolerate failures.
403
366
 
404
- **Consider collection size** - For very large collections (10,000+ items), consider batching or processing in chunks.
367
+ **Consider collection size** - For very large collections (10,000+ items), consider processing in chunks.
405
368
 
406
369
  **Monitor memory usage** - Large collections create many checkpoints. Monitor Lambda memory usage.
407
370
 
@@ -415,23 +378,15 @@ def handler(event: dict, context: DurableContext) -> list[str]:
415
378
 
416
379
  **Use max_concurrency wisely** - Too much concurrency can overwhelm external services or exhaust Lambda resources. Start conservative and increase as needed.
417
380
 
418
- **Batch small operations** - If each item processes quickly (< 100ms), batching reduces overhead:
419
-
420
- ```python
421
- config = MapConfig(
422
- item_batcher=ItemBatcher(max_items_per_batch=10)
423
- )
424
- ```
425
-
426
381
  **Optimize map functions** - Keep map functions lightweight. Move heavy computation into steps within the map function.
427
382
 
428
383
  **Use appropriate completion criteria** - Fail fast with `tolerated_failure_count` to avoid processing remaining items when many fail.
429
384
 
430
385
  **Monitor checkpoint size** - Large result objects increase checkpoint size and Lambda memory usage. Return only necessary data.
431
386
 
432
- **Consider memory limits** - Processing thousands of items creates many checkpoints. Monitor Lambda memory and adjust batch size or concurrency.
387
+ **Consider memory limits** - Processing thousands of items creates many checkpoints. Monitor Lambda memory and adjust concurrency.
433
388
 
434
- **Profile your workload** - Test with representative data to find optimal concurrency and batch settings.
389
+ **Profile your workload** - Test with representative data to find optimal concurrency settings.
435
390
 
436
391
  [↑ Back to top](#table-of-contents)
437
392
 
@@ -443,7 +398,7 @@ A: Map operations process a collection of similar items using the same function.
443
398
 
444
399
  **Q: How many items can I process?**
445
400
 
446
- A: There's no hard limit, but consider Lambda's memory and timeout constraints. For very large collections (10,000+ items), use batching or process in chunks.
401
+ A: There's no hard limit, but consider Lambda's memory and timeout constraints. For very large collections (10,000+ items), consider processing in chunks.
447
402
 
448
403
  **Q: Do items process in order?**
449
404
 
@@ -471,10 +426,6 @@ for item_result in batch_result.results:
471
426
 
472
427
  A: Yes, you can call `context.map()` inside a map function to process nested collections.
473
428
 
474
- **Q: How does batching work?**
475
-
476
- A: When you configure `item_batcher`, multiple items are grouped together and passed as a `BatchedInput` to your map function. Process all items in `batch.items`.
477
-
478
429
  **Q: What's the difference between serdes and item_serdes?**
479
430
 
480
431
  A: `item_serdes` serializes individual item results as they complete. `serdes` serializes the entire `BatchResult` at the end. Use both for custom serialization at different levels.
@@ -168,13 +168,14 @@ pip install aws-durable-execution-sdk-python-testing
168
168
 
169
169
  ```python
170
170
  import pytest
171
+ from aws_durable_execution_sdk_python.execution import InvocationStatus
171
172
  from my_function import handler
172
173
 
173
174
  @pytest.mark.durable_execution(handler=handler, lambda_function_name="my_function")
174
175
  def test_my_function(durable_runner):
175
176
  with durable_runner:
176
177
  result = durable_runner.run(input={"data": "test"}, timeout=10)
177
- assert result.status == "SUCCEEDED"
178
+ assert result.status == InvocationStatus.SUCCEEDED
178
179
  ```
179
180
 
180
181
  Run tests without AWS credentials:
@@ -62,9 +62,16 @@ exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"]
62
62
 
63
63
  [tool.ruff]
64
64
  line-length = 88
65
+ target-version = "py311"
65
66
 
66
67
  [tool.ruff.lint]
67
68
  preview = true
69
+ select = ["TID252"] # Enforce absolute imports (ban relative imports)
70
+
71
+ [tool.ruff.lint.isort]
72
+ known-first-party = ["aws_durable_execution_sdk_python"]
73
+ force-single-line = false
74
+ lines-after-imports = 2
68
75
 
69
76
  [tool.ruff.lint.per-file-ignores]
70
77
  "tests/**" = [
@@ -1,4 +1,4 @@
1
1
  # SPDX-FileCopyrightText: 2025-present Amazon.com, Inc. or its affiliates.
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
- __version__ = "1.1.2"
4
+ __version__ = "1.4.0"
@@ -1,7 +1,12 @@
1
1
  """AWS Lambda Durable Executions Python SDK."""
2
2
 
3
+ # Package metadata
4
+ from aws_durable_execution_sdk_python.__about__ import __version__
5
+
3
6
  # Main context - used in every durable function
4
7
  # Helper decorators - commonly used for step functions
8
+ # Concurrency
9
+ from aws_durable_execution_sdk_python.concurrency.models import BatchResult
5
10
  from aws_durable_execution_sdk_python.context import (
6
11
  DurableContext,
7
12
  durable_step,
@@ -20,7 +25,7 @@ from aws_durable_execution_sdk_python.exceptions import (
20
25
  from aws_durable_execution_sdk_python.execution import durable_execution
21
26
 
22
27
  # Essential context types - passed to user functions
23
- from aws_durable_execution_sdk_python.types import BatchResult, StepContext
28
+ from aws_durable_execution_sdk_python.types import StepContext
24
29
 
25
30
  __all__ = [
26
31
  "BatchResult",
@@ -29,6 +34,7 @@ __all__ = [
29
34
  "InvocationError",
30
35
  "StepContext",
31
36
  "ValidationError",
37
+ "__version__",
32
38
  "durable_execution",
33
39
  "durable_step",
34
40
  "durable_wait_for_callback",
@@ -30,6 +30,7 @@ from aws_durable_execution_sdk_python.identifier import OperationIdentifier
30
30
  from aws_durable_execution_sdk_python.lambda_service import ErrorObject
31
31
  from aws_durable_execution_sdk_python.operation.child import child_handler
32
32
 
33
+
33
34
  if TYPE_CHECKING:
34
35
  from collections.abc import Callable
35
36
 
@@ -196,6 +197,11 @@ class ConcurrentExecutor(ABC, Generic[CallableType, ResultType]):
196
197
  "▶️ Executing concurrent operation, items: %d", len(self.executables)
197
198
  )
198
199
 
200
+ # Early return for empty executables
201
+ if not self.executables:
202
+ logger.debug("No items to execute, returning empty result")
203
+ return self._create_result()
204
+
199
205
  max_workers = self.max_concurrency or len(self.executables)
200
206
 
201
207
  self.executables_with_state = [