diff --git a/.github/scripts/ci-checks.sh b/.github/scripts/ci-checks.sh index 77f962d8..93ccbeb6 100755 --- a/.github/scripts/ci-checks.sh +++ b/.github/scripts/ci-checks.sh @@ -1,18 +1,37 @@ - #!/bin/sh set -e -hatch run test:cov -echo SUCCESS: tests + coverage +REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" + +PACKAGES=( + "packages/aws-durable-execution-sdk-python" + "packages/aws-durable-execution-sdk-python-otel" +) + +for package_dir in "${PACKAGES[@]}"; do + full_path="$REPO_ROOT/$package_dir" + if [ -d "$full_path" ]; then + echo "==========================================" + echo "Running checks for $package_dir" + echo "==========================================" + cd "$full_path" + + hatch run test:cov + echo "SUCCESS: tests + coverage ($package_dir)" -# type checks -hatch run types:check -echo SUCCESS: typings + # type checks + hatch run types:check + echo "SUCCESS: typings ($package_dir)" -# static analysis -hatch fmt -echo SUCCESS: linting/fmt + # static analysis + hatch fmt + echo "SUCCESS: linting/fmt ($package_dir)" + else + echo "WARNING: $package_dir does not exist, skipping" + fi +done -# commit message validation +# commit message validation (run once from repo root) +cd "$REPO_ROOT" hatch run python .github/scripts/lintcommit.py diff --git a/.github/scripts/lintcommit.py b/.github/scripts/lintcommit.py index b6faaa49..f24ab886 100644 --- a/.github/scripts/lintcommit.py +++ b/.github/scripts/lintcommit.py @@ -164,7 +164,7 @@ def lint_range(git_range: str, *, skip_dirty_check: bool = False) -> LintResult: status = subprocess.run( ["git", "status", "--porcelain"], capture_output=True, - text=True, + text=True, check=False, ) if status.stdout.strip(): return LintResult( @@ -178,7 +178,7 @@ def lint_range(git_range: str, *, skip_dirty_check: bool = False) -> LintResult: result = subprocess.run( ["git", "log", "--no-merges", git_range, "-z", "--format=%H%n%B"], capture_output=True, - text=True, + text=True, check=False, ) if result.returncode != 0: return LintResult(git_error=result.stderr.strip()) diff --git a/.github/scripts/tests/test_lintcommit.py b/.github/scripts/tests/test_lintcommit.py index 98547cff..9c5bc80a 100644 --- a/.github/scripts/tests/test_lintcommit.py +++ b/.github/scripts/tests/test_lintcommit.py @@ -9,11 +9,9 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) -import pytest from lintcommit import lint_range, validate_message, validate_subject - # region validate_subject: valid subjects diff --git a/.github/scripts/tests/test_parse_sdk_branch.py b/.github/scripts/tests/test_parse_sdk_branch.py index d4586512..d5d76856 100644 --- a/.github/scripts/tests/test_parse_sdk_branch.py +++ b/.github/scripts/tests/test_parse_sdk_branch.py @@ -74,7 +74,7 @@ def test(): for input_text, expected in test_cases: result = parse_sdk_branch(input_text) # Assert is expected in test functions - assert result == expected, ( # noqa: S101 + assert result == expected, ( f"Expected '{expected}' but got '{result}' for input: {input_text[:50]}..." ) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a1580ece..1e47a2b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,10 +43,26 @@ jobs: run: | python -m pip install hatch==1.16.5 - name: static analysis - run: hatch fmt --check + run: | + for pkg in packages/*/; do + if [ -f "$pkg/pyproject.toml" ]; then + echo "=== Checking format: $pkg ===" + cd "$pkg" + hatch fmt --check + cd "$GITHUB_WORKSPACE" + fi + done - name: type checking run: hatch run types:check - name: Run tests + coverage run: hatch run test:cov - name: Build distribution - run: hatch build + run: | + for pkg in packages/*/; do + if [ -f "$pkg/pyproject.toml" ]; then + echo "=== Building: $pkg ===" + cd "$pkg" + hatch build + cd "$GITHUB_WORKSPACE" + fi + done diff --git a/.github/workflows/deploy-examples.yml b/.github/workflows/deploy-examples.yml index 415ff16c..1fdb5a51 100644 --- a/.github/workflows/deploy-examples.yml +++ b/.github/workflows/deploy-examples.yml @@ -4,8 +4,8 @@ on: pull_request: branches: [ "main", "development"] paths: - - 'src/aws_durable_execution_sdk_python/**' - - 'examples/**' + - 'packages/aws-durable-execution-sdk-python/src/**' + - 'packages/examples/**' - '.github/workflows/deploy-examples.yml' workflow_dispatch: @@ -26,7 +26,7 @@ jobs: - name: Get examples from catalog id: get-examples - working-directory: ./examples + working-directory: ./packages/examples run: | echo "examples=$(jq -c '.examples | map(select(.integration == true))' examples-catalog.json)" >> $GITHUB_OUTPUT @@ -58,10 +58,14 @@ jobs: - name: Install Hatch run: pip install hatch - name: Build examples - run: hatch run examples:build + working-directory: ./packages/examples + run: | + hatch run -- examples:pip install -e ../aws-durable-execution-sdk-python + hatch run examples:build - name: Deploy Lambda function - ${{ matrix.example.name }} id: deploy + working-directory: ./packages/examples env: AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} LAMBDA_ENDPOINT: "https://lambda.us-west-2.amazonaws.com" @@ -115,7 +119,7 @@ jobs: TEST_NAME="test_$(echo "${{ matrix.example.name }}" | tr '[:upper:]' '[:lower:]' | tr ' ' '_')" echo "Test name: ${TEST_NAME}" - # Run integration tests + # Run integration tests from repo root hatch run test:examples-integration # Wait for function to be ready diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 13441abc..0587ac57 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -41,12 +41,13 @@ jobs: run: | echo "Running SDK tests..." hatch run -- test:pip install -e ../testing-sdk - hatch run -- test:pip install -e ../language-sdk hatch fmt --check hatch run types:check hatch run test:cov - hatch run test:examples - hatch build + + - name: Verify package build + working-directory: language-sdk/packages/aws-durable-execution-sdk-python + run: hatch build e2e-tests: needs: integration-tests @@ -84,7 +85,7 @@ jobs: - name: Get integration examples id: get-examples - working-directory: language-sdk/examples + working-directory: language-sdk/packages/examples run: | echo "examples=$(jq -c '.examples | map(select(.integration == true)) | .[0:2]' examples-catalog.json)" >> $GITHUB_OUTPUT @@ -97,7 +98,7 @@ jobs: rm -rf /tmp/aws/ - name: Deploy and test examples - working-directory: language-sdk + working-directory: language-sdk/packages/examples env: AWS_ACCOUNT_ID: ${{ secrets.AWS_ACCOUNT_ID }} LAMBDA_ENDPOINT: "https://lambda.us-west-2.amazonaws.com" @@ -105,7 +106,7 @@ jobs: KMS_KEY_ARN: ${{ secrets.KMS_KEY_ARN }} run: | echo "Building examples..." - hatch run -- examples:pip install -e ../testing-sdk + hatch run -- examples:pip install -e ../../../testing-sdk hatch run examples:build # Get first integration example for testing diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index e0e0a2b6..7e7cc599 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -1,4 +1,4 @@ -# This workflow will upload a Python Package to PyPI when a release is created +# This workflow will upload Python Packages to PyPI when a release is created # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries # This workflow uses actions that are not certified by GitHub. @@ -18,59 +18,67 @@ permissions: jobs: release-build: runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + package: + - name: aws-durable-execution-sdk-python + path: packages/aws-durable-execution-sdk-python + - name: aws-durable-execution-sdk-python-otel + path: packages/aws-durable-execution-sdk-python-otel steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - + with: + ref: ${{ github.event.release.target_commitish }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: "3.11" - - name: Install Hatch - run: | - python -m pip install --upgrade hatch==1.16.5 + + - name: Install Hatch + run: python -m pip install --upgrade hatch==1.16.5 + - name: Build release distributions - run: | - # NOTE: put your own distribution build steps here. - hatch build + working-directory: ${{ matrix.package.path }} + run: hatch build - name: Upload distributions uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: release-dists - path: dist/ + name: release-dists-${{ matrix.package.name }} + path: ${{ matrix.package.path }}/dist/ pypi-publish: runs-on: ubuntu-latest needs: - release-build + strategy: + fail-fast: false + matrix: + package: + - name: aws-durable-execution-sdk-python + - name: aws-durable-execution-sdk-python-otel permissions: - # IMPORTANT: this permission is mandatory for trusted publishing id-token: write - # Dedicated environments with protections for publishing are strongly recommended. - # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules environment: name: pypi - # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status: - # url: https://pypi.org/p/aws-durable-execution-sdk-python - # - # ALTERNATIVE: if your GitHub Release name is the PyPI project version string - # ALTERNATIVE: exactly, uncomment the following line instead: - url: https://pypi.org/project/aws-durable-execution-sdk-python/${{ github.event.release.name }} + url: https://pypi.org/project/${{ matrix.package.name }}/${{ github.event.release.name }} steps: - name: Retrieve release distributions uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: release-dists + name: release-dists-${{ matrix.package.name }} path: dist/ - - name: Publish release distributions to PyPI + - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 with: packages-dir: dist/ notify-release: + if: always() && contains(needs.pypi-publish.result, 'success') needs: [pypi-publish] uses: ./.github/workflows/notify-release.yml with: diff --git a/.github/workflows/sync-package.yml b/.github/workflows/sync-package.yml deleted file mode 100644 index afe31965..00000000 --- a/.github/workflows/sync-package.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Sync package - -on: - push: - branches: [ "main" ] -env: - AWS_REGION : "us-west-2" - -# permission can be added at job level or workflow level -permissions: - id-token: write # This is required for requesting the JWT - contents: read # This is required for actions/checkout - -jobs: - on-success: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: ["3.13"] - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 - with: - python-version: ${{ matrix.python-version }} - - name: Install Hatch - run: | - python -m pip install --upgrade hatch==1.16.5 - - name: Build distribution - run: hatch build - - name: configure aws credentials - uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0 - with: - role-to-assume: "${{ secrets.ACTIONS_SYNC_ROLE_NAME }}" - role-session-name: gh-python - aws-region: ${{ env.AWS_REGION }} - - name: Copy tar gz build file to s3 - run: | - aws s3 cp ./dist/*.tar.gz \ - s3://${{ secrets.S3_BUCKET_NAME }}/aws-durable-execution-sdk-python.tar.gz - - name: commit tar gz to Gitfarm - run: | - aws lambda invoke \ - --function-name ${{ secrets.SYNC_LAMBDA_ARN }} \ - --payload '{"gitFarmRepo":"${{ secrets.GITFARM_LAN_SDK_REPO }}","gitFarmBranch":"${{ secrets.GITFARM_LAN_SDK_BRANCH }}","gitFarmFilepath":"aws-durable-execution-sdk-python.tar.gz","s3Bucket":"${{ secrets.S3_BUCKET_NAME }}","s3FilePath":"aws-durable-execution-sdk-python.tar.gz", "gitHubRepo": "aws-durable-execution-sdk-python", "gitHubCommit":"${{ github.sha }}"}' \ - --cli-binary-format raw-in-base64-out \ - output.txt - - name: Check for error in lambda invoke - run: | - if grep -q "Error" output.txt; then - cat output.txt - exit 1 - fi - - name: Copy whl build file to s3 - run: | - aws s3 cp ./dist/*.whl \ - s3://${{ secrets.S3_BUCKET_NAME }}/aws-durable-execution-sdk-python.whl - - name: commit whl to Gitfarm - run: | - aws lambda invoke \ - --function-name ${{ secrets.SYNC_LAMBDA_ARN }} \ - --payload '{"gitFarmRepo":"${{ secrets.GITFARM_LAN_SDK_REPO }}","gitFarmBranch":"${{ secrets.GITFARM_LAN_SDK_BRANCH }}","gitFarmFilepath":"aws-durable-execution-sdk-python.whl","s3Bucket":"${{ secrets.S3_BUCKET_NAME }}","s3FilePath":"aws-durable-execution-sdk-python.whl", "gitHubRepo": "aws-durable-execution-sdk-python", "gitHubCommit":"${{ github.sha }}"}' \ - --cli-binary-format raw-in-base64-out \ - output.txt - - name: Check for error in lambda invoke - run: | - if grep -q "Error" output.txt; then - cat output.txt - exit 1 - fi diff --git a/.github/workflows/update-sam-template.yml b/.github/workflows/update-sam-template.yml index 63bdde9a..3c76b9ca 100644 --- a/.github/workflows/update-sam-template.yml +++ b/.github/workflows/update-sam-template.yml @@ -3,7 +3,7 @@ name: Update SAM Template on: pull_request: paths: - - "examples/**" + - "packages/examples/**" permissions: contents: write @@ -27,7 +27,7 @@ jobs: python-version: "3.13" - name: Generate SAM template - run: python examples/scripts/generate_sam_template.py + run: python packages/examples/scripts/generate_sam_template.py - name: Commit and push changes run: | diff --git a/.gitignore b/.gitignore index bfc52e93..fa41c3e0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ __pycache__/ *$py.class *.egg-info/ +*.coverage /.coverage /.coverage.* /.cache @@ -30,7 +31,7 @@ dist/ .kiro/ -/examples/build/* -/examples/*.zip +examples/build/* +examples/*.zip .env \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a65b26a..26f15d51 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,23 +9,98 @@ information to effectively respond to your bug report or contribution. ## Dependencies Install [hatch](https://hatch.pypa.io/dev/install/). -## Developer workflow -These are all the checks you would typically do as you prepare a PR: +## Repository Structure + +This is a monorepo containing multiple packages under the `packages/` directory: + ``` -# just test -hatch test +packages/ +├── aws-durable-execution-sdk-python/ # Core SDK +│ ├── pyproject.toml +│ ├── src/ +│ ├── tests/ +│ └── examples/ +├── aws-durable-execution-sdk-python-otel/ # OpenTelemetry instrumentation +│ ├── pyproject.toml +│ ├── src/ +│ └── tests/ +└── examples/ # Example functions and tests + ├── pyproject.toml + ├── src/ + └── test/ +``` + +The root `pyproject.toml` defines all shared Hatch environments for testing, type checking, and development. Each package's `pyproject.toml` contains only build metadata, publishing configuration, and package-local tool settings (ruff, coverage, pytest markers). + +Shared files (`.github/`, `LICENSE`, `CONTRIBUTING.md`, etc.) live at the repository root. + +## Developer workflow + +All test, type checking, and development commands are run from the **repository root**: + +```bash +# Run all tests across all packages +hatch run test:all -# coverage +# Run tests with coverage hatch run test:cov -# type checks +# Type checking across all packages hatch run types:check -# static analysis +# Static analysis (per-package, since ruff config is package-local) +for pkg in packages/*/; do (cd "$pkg" && hatch fmt --check); done +``` + +### Per-package development environments + +For focused work on a single package, use the `dev-*` environments from the repo root: + +```bash +# Core SDK +hatch run dev-core:test # run core SDK tests only +hatch run dev-core:cov # run core SDK tests with coverage +hatch run dev-core:typecheck # type check core SDK only + +# OpenTelemetry package +hatch run dev-otel:test # run otel tests only +hatch run dev-otel:cov # run otel tests with coverage +hatch run dev-otel:typecheck # type check otel only + +# Examples +hatch run dev-examples:test # run examples tests only +``` + +### PyPI release testing + +To verify packages work against the published PyPI version of the core SDK (rather than the local workspace): + +```bash +hatch run test-pypi-otel:test # test otel against PyPI core SDK +hatch run test-pypi-examples:test # test examples against PyPI core SDK +``` + +### Package-level commands + +Some commands still run from within a package directory: + +```bash +cd packages/aws-durable-execution-sdk-python + +# Static analysis with auto-fix hatch fmt + +# Build distribution +hatch build + +# Examples deployment +hatch run examples:build +hatch run examples:deploy "Hello World" ``` -There is a convenience script for the above that you can run from the root of the repo as you prepare your PR: +### CI checks script + +There is a convenience script that runs all checks (tests, types, lint) from the root of the repo: ``` .github/scripts/ci-checks.sh ``` @@ -131,11 +206,15 @@ class WaitOptions: ## Set up your IDE Point your IDE at the hatch virtual environment to have it recognize dependencies -and imports. +and imports. You can use either the root environment (for cross-package work) or a +per-package dev environment (for focused work). You can find the path to the hatch Python interpreter like this: ``` -echo "$(hatch env find)/bin/python" +# From the repo root — use the dev environment for the package you're working on +hatch env find dev-core +hatch env find dev-otel +hatch env find dev-examples ``` ### VS Code @@ -148,8 +227,8 @@ errors finding the interpreter. You can create a local .venv file symlink _witho in the path: ```bash -# create a symlink at: ./.venv/bin/python -rm -rf .venv && ln -s "$(hatch env find)" .venv +# From the repo root — symlink the dev environment you want to use +rm -rf .venv && ln -s "$(hatch env find dev-core)" .venv ``` When you "Select Interpreter", enter path `./.venv/bin/python`. @@ -179,24 +258,33 @@ These `settings.json` settings are useful: ## Testing ### How to run tests -To run all tests: +Run these commands from the **repository root**: + +To run all tests across all packages: +``` +hatch run test:all +``` + +To run tests for a specific package: ``` -hatch test +hatch run dev-core:test +hatch run dev-otel:test +hatch run dev-examples:test ``` To run a single test file: ``` -hatch test tests/path_to_test_module.py +hatch run dev-core:test packages/aws-durable-execution-sdk-python/tests/path_to_test_module.py ``` To run a specific test in a module: ``` -hatch test tests/path_to_test_module.py::test_mytestmethod +hatch run dev-core:test packages/aws-durable-execution-sdk-python/tests/path_to_test_module.py::test_mytestmethod ``` -To run a single test, or a subset of tests: +To run a subset of tests by pattern: ``` -$ hatch test -k TEST_PATTERN +hatch run test:all -k TEST_PATTERN ``` This will run tests which contain names that match the given string expression (case-insensitive), @@ -220,7 +308,13 @@ tests/mypackage/mymodule_test.py ## Examples and Deployment -The project includes a unified CLI tool for managing examples, deployment, and AWS account setup: +The project includes a unified CLI tool for managing examples, deployment, and AWS account setup. +Run these commands from the core SDK package directory (`packages/aws-durable-execution-sdk-python`). + +To run examples tests from the repo root: +```bash +hatch run dev-examples:test +``` ### Bootstrap AWS Account ```bash @@ -260,17 +354,24 @@ hatch run examples:clean ``` ## Coverage + +From the repository root: ``` +# All packages combined hatch run test:cov + +# Per-package coverage +hatch run dev-core:cov +hatch run dev-otel:cov ``` ## Linting and type checks -Type checking: +Type checking (from repo root): ``` hatch run types:check ``` -Static analysis (with auto-fix of known issues): +Static analysis (from within a package directory, with auto-fix): ``` hatch fmt ``` diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000..3b5b8264 --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,106 @@ +# Releasing + +This document describes how to cut a release for packages in this monorepo and how the automated PyPI publishing workflow is triggered. + +## Packages + +This monorepo contains the following packages: + +| Package | Path | Tag Prefix | +|---------|------|------------| +| `aws-durable-execution-sdk-python` | `packages/aws-durable-execution-sdk-python` | `sdk` | +| `aws-durable-execution-sdk-python-otel` | `packages/aws-durable-execution-sdk-python-otel` | `otel` | + +## Versioning + +Each package maintains its own version in its respective `__about__.py` file: + +- SDK: `packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/__about__.py` +- OTel: `packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/__about__.py` + +Bump the version in the appropriate `__about__.py` file(s) and merge to `main` before creating a release. + +## Cutting a Release + +### 1. Bump the version + +Update the `__version__` string in the relevant `__about__.py` file(s). Commit and merge to `main`. + +### 2. Create a GitHub Release + +1. Go to the [Releases page](https://github.com/aws/aws-durable-execution-sdk-python/releases) on GitHub. +2. Click **Draft a new release**. +3. Create a new tag following the tagging convention below. +4. Set the release title (typically the same as the tag). +5. Write release notes following the format described in [Release Notes Format](#release-notes-format). +6. Click **Publish release**. + +### Tagging Convention + +The tag should be the version of the package being bumped, prepended with a descriptive prefix: + +- **SDK only:** `sdk-v` (e.g., `sdk-v1.6.0`) +- **OTel only:** `otel-v` (e.g., `otel-v0.3.0`) +- **Both packages in a single release:** comma-separate the sub-tags (e.g., `sdk-1.6.0,otel-0.3.0`) + +Examples: + +``` +sdk-1.6.0 +otel-0.3.0 +sdk-1.6.0,otel-0.3.0 +``` + +If additional packages are added to the monorepo in the future, follow the same pattern: choose a short descriptive prefix for the package and use `-`. + +## How Publishing Works + +Creating a GitHub Release triggers the [`pypi-publish.yml`](.github/workflows/pypi-publish.yml) workflow automatically. The workflow: + +1. **Builds** both packages using [Hatch](https://hatch.pypa.io/) (`hatch build`). +2. **Uploads** the built distributions as artifacts. +3. **Publishes** each package to [PyPI](https://pypi.org/) using trusted publishing (OIDC-based, no API tokens required). + +The workflow runs on the `release: [published]` event, so it fires whenever a release is published on GitHub — no manual intervention is needed beyond creating the release. + +> **Note:** The workflow builds and publishes all packages in the matrix. Ensure the version in each package's `__about__.py` is correct before publishing. If only one package has a version bump, PyPI will reject the re-upload of the unchanged package (which is expected and harmless since `fail-fast: false` is set). + +## Release Notes Format + +Release notes should maintain separate timelines for each package. Use the following structure: + +```markdown +## aws-durable-execution-sdk-python v1.6.0 + +### Features +- Added support for X +- New `context.foo()` API + +### Bug Fixes +- Fixed issue with Y under Z conditions + +### Breaking Changes +- Removed deprecated `bar()` method + +--- + +## aws-durable-execution-sdk-python-otel v0.3.0 + +### Features +- Added tracing for `map` operations + +### Bug Fixes +- Fixed span context propagation in child contexts +``` + +If only one package is being released, include only that package's section. Each package's changelog should be self-contained so users can follow the history of the package they depend on independently. + +## Checklist + +Before publishing a release: + +- [ ] Version bumped in the relevant `__about__.py` file(s) +- [ ] Changes merged to `main` +- [ ] CI checks pass on `main` +- [ ] Release notes written with separate sections per package +- [ ] Tag follows the naming convention (`sdk-X.Y.Z`, `otel-X.Y.Z`, or comma-separated) diff --git a/packages/aws-durable-execution-sdk-python-otel/README.md b/packages/aws-durable-execution-sdk-python-otel/README.md new file mode 100644 index 00000000..b69c4b51 --- /dev/null +++ b/packages/aws-durable-execution-sdk-python-otel/README.md @@ -0,0 +1,47 @@ +# aws-durable-execution-sdk-python-otel + +OpenTelemetry instrumentation for the [AWS Durable Execution SDK for Python](https://github.com/aws/aws-durable-execution-sdk-python). + +## Overview + +This package provides automatic OpenTelemetry tracing for durable execution workflows, giving you visibility into step execution, waits, retries, and overall workflow performance. + +## Installation + +```bash +pip install aws-durable-execution-sdk-python-otel +``` + +## Quick Start + +```python +from aws_durable_execution_sdk_python import DurableContext, durable_execution +from aws_durable_execution_sdk_python_otel import instrument_durable_execution + +# Instrument the SDK (call once at module load) +instrument_durable_execution() + +@durable_execution +def handler(event: dict, context: DurableContext) -> dict: + # Steps, waits, and invokes are automatically traced + result = context.step(lambda _: do_work(), name="my-step") + return {"result": result} +``` + +## Features + +- Automatic span creation for steps, waits, invokes, and child contexts +- Replay-aware tracing (distinguishes fresh executions from replays) +- Error recording with proper OTel status codes +- Configurable span attributes and naming + +## Requirements + +- Python >= 3.11 +- `aws-durable-execution-sdk-python` >= 1.5.0 +- `opentelemetry-api` >= 1.20.0 +- `opentelemetry-sdk` >= 1.20.0 + +## License + +Apache-2.0 diff --git a/packages/aws-durable-execution-sdk-python-otel/pyproject.toml b/packages/aws-durable-execution-sdk-python-otel/pyproject.toml new file mode 100644 index 00000000..57c428b5 --- /dev/null +++ b/packages/aws-durable-execution-sdk-python-otel/pyproject.toml @@ -0,0 +1,83 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "aws-durable-execution-sdk-python-otel" +dynamic = ["version"] +description = 'OpenTelemetry instrumentation for AWS Durable Execution SDK for Python' +readme = "README.md" +requires-python = ">=3.11" +license = "Apache-2.0" +keywords = ["opentelemetry", "tracing", "observability", "durable-execution"] +authors = [{ name = "AWS durable-execution-dev", email = "durable-execution-dev@amazon.com" }] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dependencies = [ + "aws-durable-execution-sdk-python>=1.5.0", + "opentelemetry-api>=1.20.0", + "opentelemetry-sdk>=1.20.0", +] + +[project.urls] +Documentation = "https://github.com/aws/aws-durable-execution-sdk-python#readme" +Issues = "https://github.com/aws/aws-durable-execution-sdk-python/issues" +Source = "https://github.com/aws/aws-durable-execution-sdk-python" + +[tool.hatch.build.targets.wheel] +packages = ["src/aws_durable_execution_sdk_python_otel"] + +[tool.hatch.version] +path = "src/aws_durable_execution_sdk_python_otel/__about__.py" + +[tool.coverage.run] +source_pkgs = ["aws_durable_execution_sdk_python_otel"] +branch = true +parallel = true +omit = ["src/aws_durable_execution_sdk_python_otel/__about__.py"] + +[tool.coverage.paths] +aws_durable_execution_sdk_python_otel = [ + "src/aws_durable_execution_sdk_python_otel", + "*/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel", +] + +[tool.coverage.report] +exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"] + +[tool.ruff] +line-length = 88 +target-version = "py311" + +[tool.ruff.lint] +preview = true +select = ["TID252"] + +[tool.ruff.lint.isort] +known-first-party = ["aws_durable_execution_sdk_python_otel"] +force-single-line = false +lines-after-imports = 2 + +[tool.ruff.lint.per-file-ignores] +"tests/**" = [ + "ARG001", + "ARG002", + "ARG005", + "S101", + "PLR2004", + "PLR6301", + "SIM117", + "TRY301", +] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "-v --strict-markers" diff --git a/packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/__about__.py b/packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/__about__.py new file mode 100644 index 00000000..1c35361c --- /dev/null +++ b/packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/__about__.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2025-present Amazon.com, Inc. or its affiliates. +# +# SPDX-License-Identifier: Apache-2.0 +__version__ = "0.1.0" diff --git a/packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/__init__.py b/packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/__init__.py new file mode 100644 index 00000000..63b1b9cc --- /dev/null +++ b/packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/__init__.py @@ -0,0 +1,8 @@ +"""OpenTelemetry instrumentation for AWS Lambda Durable Executions Python SDK.""" + +from aws_durable_execution_sdk_python_otel.__about__ import __version__ + + +__all__ = [ + "__version__", +] diff --git a/src/aws_durable_execution_sdk_python/.gitignore b/packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/py.typed similarity index 100% rename from src/aws_durable_execution_sdk_python/.gitignore rename to packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel/py.typed diff --git a/src/aws_durable_execution_sdk_python/concurrency/__init__.py b/packages/aws-durable-execution-sdk-python-otel/tests/__init__.py similarity index 100% rename from src/aws_durable_execution_sdk_python/concurrency/__init__.py rename to packages/aws-durable-execution-sdk-python-otel/tests/__init__.py diff --git a/packages/aws-durable-execution-sdk-python-otel/tests/test_init.py b/packages/aws-durable-execution-sdk-python-otel/tests/test_init.py new file mode 100644 index 00000000..4144ba82 --- /dev/null +++ b/packages/aws-durable-execution-sdk-python-otel/tests/test_init.py @@ -0,0 +1,18 @@ +"""Tests for aws_durable_execution_sdk_python_otel package.""" + +from aws_durable_execution_sdk_python_otel import __version__ + + +def test_version_is_set(): + """Verify the package version is defined.""" + assert __version__ is not None + assert isinstance(__version__, str) + assert len(__version__) > 0 + + +def test_version_format(): + """Verify the package version follows semver format.""" + parts = __version__.split(".") + assert len(parts) == 3 + for part in parts: + assert part.isdigit() diff --git a/packages/aws-durable-execution-sdk-python/.coverage b/packages/aws-durable-execution-sdk-python/.coverage new file mode 100644 index 00000000..ccb4aa74 Binary files /dev/null and b/packages/aws-durable-execution-sdk-python/.coverage differ diff --git a/packages/aws-durable-execution-sdk-python/README.md b/packages/aws-durable-execution-sdk-python/README.md new file mode 100644 index 00000000..3a772717 --- /dev/null +++ b/packages/aws-durable-execution-sdk-python/README.md @@ -0,0 +1,85 @@ +# AWS Durable Execution SDK for Python + +[![Build](https://github.com/aws/aws-durable-execution-sdk-python/actions/workflows/ci.yml/badge.svg)](https://github.com/aws/aws-durable-execution-sdk-python/actions/workflows/ci.yml) +[![PyPI - Version](https://img.shields.io/pypi/v/aws-durable-execution-sdk-python.svg)](https://pypi.org/project/aws-durable-execution-sdk-python) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/aws-durable-execution-sdk-python.svg)](https://pypi.org/project/aws-durable-execution-sdk-python) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/aws/aws-durable-execution-sdk-python/badge)](https://scorecard.dev/viewer/?uri=github.com/aws/aws-durable-execution-sdk-python) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) + +----- + +Build reliable, long-running AWS Lambda workflows with checkpointed steps, waits, callbacks, and parallel execution. + +## ✨ Key Features + +- **Automatic checkpointing** - Resume execution after Lambda pauses or restarts +- **Durable steps** - Run work with retry strategies and deterministic replay +- **Waits and callbacks** - Pause for time or external signals without blocking Lambda +- **Parallel and map operations** - Fan out work with configurable completion criteria +- **Child contexts** - Structure complex workflows into isolated subflows +- **Replay-safe logging** - Use `context.logger` for structured, de-duplicated logs +- **Local and cloud testing** - Validate workflows with the testing SDK + +## 📦 Packages + +| Package | Description | Version | +| --- | --- | --- | +| `aws-durable-execution-sdk-python` | Execution SDK for Lambda durable functions | [![PyPI - Version](https://img.shields.io/pypi/v/aws-durable-execution-sdk-python.svg)](https://pypi.org/project/aws-durable-execution-sdk-python) | +| `aws-durable-execution-sdk-python-testing` | Local/cloud test runner and pytest helpers | [![PyPI - Version](https://img.shields.io/pypi/v/aws-durable-execution-sdk-python-testing.svg)](https://pypi.org/project/aws-durable-execution-sdk-python-testing) | + +## 🚀 Quick Start + +Install the execution SDK: + +```console +pip install aws-durable-execution-sdk-python +``` + +Create a durable Lambda handler: + +```python +from aws_durable_execution_sdk_python import ( + DurableContext, + StepContext, + durable_execution, + durable_step, +) +from aws_durable_execution_sdk_python.config import Duration + +@durable_step +def validate_order(step_ctx: StepContext, order_id: str) -> dict: + step_ctx.logger.info("Validating order", extra={"order_id": order_id}) + return {"order_id": order_id, "valid": True} + +@durable_execution +def handler(event: dict, context: DurableContext) -> dict: + order_id = event["order_id"] + context.logger.info("Starting workflow", extra={"order_id": order_id}) + + validation = context.step(validate_order(order_id), name="validate_order") + if not validation["valid"]: + return {"status": "rejected", "order_id": order_id} + + # simulate approval (real world: use wait_for_callback) + context.wait(duration=Duration.from_seconds(5), name="await_confirmation") + + return {"status": "approved", "order_id": order_id} +``` + +## 📚 Documentation + +The complete documentation for the AWS Durable Execution SDK for Python lives on the AWS Documentation site: + +- **[AWS Durable Execution Documentation](https://docs.aws.amazon.com/durable-execution/)** - Concepts, getting started, core operations, advanced topics, and API reference +- **[AWS Lambda Durable Functions Guide](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html)** - How durable functions work on Lambda + +## 💬 Feedback & Support + +- [Bug report](https://github.com/aws/aws-durable-execution-sdk-python/issues/new?template=bug_report.yml) +- [Feature request](https://github.com/aws/aws-durable-execution-sdk-python/issues/new?template=feature_request.yml) +- [Documentation feedback](https://github.com/aws/aws-durable-execution-sdk-python/issues/new?template=documentation.yml) +- [Contributing guide](CONTRIBUTING.md) + +## 📄 License + +See the [LICENSE](LICENSE) file for our project's licensing. diff --git a/packages/aws-durable-execution-sdk-python/pyproject.toml b/packages/aws-durable-execution-sdk-python/pyproject.toml new file mode 100644 index 00000000..4a89b5fa --- /dev/null +++ b/packages/aws-durable-execution-sdk-python/pyproject.toml @@ -0,0 +1,88 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "aws-durable-execution-sdk-python" +dynamic = ["version"] +description = 'AWS Durable Execution SDK for Python' +readme = "README.md" +requires-python = ">=3.11" +license = "Apache-2.0" +keywords = [] +authors = [{ name = "AWS durable-execution-dev", email = "durable-execution-dev@amazon.com" }] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dependencies = ["boto3>=1.42.1"] + +[project.urls] +Documentation = "https://github.com/aws/aws-durable-execution-sdk-python#readme" +Issues = "https://github.com/aws/aws-durable-execution-sdk-python/issues" +Source = "https://github.com/aws/aws-durable-execution-sdk-python" + +[tool.hatch.build.targets.wheel] +packages = ["src/aws_durable_execution_sdk_python"] + +[tool.hatch.version] +path = "src/aws_durable_execution_sdk_python/__about__.py" + +[tool.coverage.run] +source_pkgs = ["aws_durable_execution_sdk_python"] +branch = true +parallel = true +omit = ["src/aws_durable_execution_sdk_python/__about__.py"] + +[tool.coverage.paths] +aws_durable_execution_sdk_python = [ + "src/aws_durable_execution_sdk_python", + "*/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python", +] + +[tool.coverage.report] +exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"] + +[tool.ruff] +line-length = 88 +target-version = "py311" + +[tool.ruff.lint] +preview = true +select = ["TID252"] # Enforce absolute imports (ban relative imports) + +[tool.ruff.lint.isort] +known-first-party = ["aws_durable_execution_sdk_python"] +force-single-line = false +lines-after-imports = 2 + +[tool.ruff.lint.per-file-ignores] +"tests/**" = [ + "ARG001", + "ARG002", + "ARG005", + "S101", + "PLR2004", + "PLR6301", + "SIM117", + "TRY301", +] + +[tool.pytest.ini_options] +# Declare custom markers to avoid warnings with --strict-markers +markers = [ + # Used for test selection with -m example + "example: marks tests as example tests (deselect with '-m \"not example\"')", + # Used for configuration - passes handler and lambda_function_name to durable_runner fixture + "durable_execution: marks tests that use the durable_runner fixture (not used for test selection)", +] +# Default test discovery paths +testpaths = ["tests"] +# Default options for all test runs +addopts = "-v --strict-markers" diff --git a/tests/__init__.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/.gitignore similarity index 100% rename from tests/__init__.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/.gitignore diff --git a/src/aws_durable_execution_sdk_python/__about__.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/__about__.py similarity index 100% rename from src/aws_durable_execution_sdk_python/__about__.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/__about__.py diff --git a/src/aws_durable_execution_sdk_python/__init__.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/__init__.py similarity index 100% rename from src/aws_durable_execution_sdk_python/__init__.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/__init__.py diff --git a/tests/e2e/__init__.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/concurrency/__init__.py similarity index 100% rename from tests/e2e/__init__.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/concurrency/__init__.py diff --git a/src/aws_durable_execution_sdk_python/concurrency/executor.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/concurrency/executor.py similarity index 100% rename from src/aws_durable_execution_sdk_python/concurrency/executor.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/concurrency/executor.py diff --git a/src/aws_durable_execution_sdk_python/concurrency/models.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/concurrency/models.py similarity index 100% rename from src/aws_durable_execution_sdk_python/concurrency/models.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/concurrency/models.py diff --git a/src/aws_durable_execution_sdk_python/config.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/config.py similarity index 100% rename from src/aws_durable_execution_sdk_python/config.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/config.py diff --git a/src/aws_durable_execution_sdk_python/context.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/context.py similarity index 100% rename from src/aws_durable_execution_sdk_python/context.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/context.py diff --git a/src/aws_durable_execution_sdk_python/exceptions.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/exceptions.py similarity index 100% rename from src/aws_durable_execution_sdk_python/exceptions.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/exceptions.py diff --git a/src/aws_durable_execution_sdk_python/execution.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/execution.py similarity index 100% rename from src/aws_durable_execution_sdk_python/execution.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/execution.py diff --git a/src/aws_durable_execution_sdk_python/identifier.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/identifier.py similarity index 100% rename from src/aws_durable_execution_sdk_python/identifier.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/identifier.py diff --git a/src/aws_durable_execution_sdk_python/lambda_service.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/lambda_service.py similarity index 100% rename from src/aws_durable_execution_sdk_python/lambda_service.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/lambda_service.py diff --git a/src/aws_durable_execution_sdk_python/logger.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/logger.py similarity index 100% rename from src/aws_durable_execution_sdk_python/logger.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/logger.py diff --git a/src/aws_durable_execution_sdk_python/operation/__init__.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/__init__.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/__init__.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/__init__.py diff --git a/src/aws_durable_execution_sdk_python/operation/base.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/base.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/base.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/base.py diff --git a/src/aws_durable_execution_sdk_python/operation/callback.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/callback.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/callback.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/callback.py diff --git a/src/aws_durable_execution_sdk_python/operation/child.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/child.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/child.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/child.py diff --git a/src/aws_durable_execution_sdk_python/operation/invoke.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/invoke.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/invoke.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/invoke.py diff --git a/src/aws_durable_execution_sdk_python/operation/map.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/map.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/map.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/map.py diff --git a/src/aws_durable_execution_sdk_python/operation/parallel.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/parallel.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/parallel.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/parallel.py diff --git a/src/aws_durable_execution_sdk_python/operation/step.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/step.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/step.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/step.py diff --git a/src/aws_durable_execution_sdk_python/operation/wait.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/wait.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/wait.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/wait.py diff --git a/src/aws_durable_execution_sdk_python/operation/wait_for_condition.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/wait_for_condition.py similarity index 100% rename from src/aws_durable_execution_sdk_python/operation/wait_for_condition.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/operation/wait_for_condition.py diff --git a/src/aws_durable_execution_sdk_python/py.typed b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/py.typed similarity index 100% rename from src/aws_durable_execution_sdk_python/py.typed rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/py.typed diff --git a/src/aws_durable_execution_sdk_python/retries.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/retries.py similarity index 100% rename from src/aws_durable_execution_sdk_python/retries.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/retries.py diff --git a/src/aws_durable_execution_sdk_python/serdes.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/serdes.py similarity index 100% rename from src/aws_durable_execution_sdk_python/serdes.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/serdes.py diff --git a/src/aws_durable_execution_sdk_python/state.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/state.py similarity index 100% rename from src/aws_durable_execution_sdk_python/state.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/state.py diff --git a/src/aws_durable_execution_sdk_python/suspend.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/suspend.py similarity index 100% rename from src/aws_durable_execution_sdk_python/suspend.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/suspend.py diff --git a/src/aws_durable_execution_sdk_python/threading.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/threading.py similarity index 100% rename from src/aws_durable_execution_sdk_python/threading.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/threading.py diff --git a/src/aws_durable_execution_sdk_python/types.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/types.py similarity index 100% rename from src/aws_durable_execution_sdk_python/types.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/types.py diff --git a/src/aws_durable_execution_sdk_python/waits.py b/packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/waits.py similarity index 100% rename from src/aws_durable_execution_sdk_python/waits.py rename to packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python/waits.py diff --git a/tests/operation/__init__.py b/packages/aws-durable-execution-sdk-python/tests/__init__.py similarity index 100% rename from tests/operation/__init__.py rename to packages/aws-durable-execution-sdk-python/tests/__init__.py diff --git a/tests/concurrency_test.py b/packages/aws-durable-execution-sdk-python/tests/concurrency_test.py similarity index 100% rename from tests/concurrency_test.py rename to packages/aws-durable-execution-sdk-python/tests/concurrency_test.py diff --git a/tests/config_test.py b/packages/aws-durable-execution-sdk-python/tests/config_test.py similarity index 100% rename from tests/config_test.py rename to packages/aws-durable-execution-sdk-python/tests/config_test.py diff --git a/tests/context_test.py b/packages/aws-durable-execution-sdk-python/tests/context_test.py similarity index 100% rename from tests/context_test.py rename to packages/aws-durable-execution-sdk-python/tests/context_test.py diff --git a/tests/durable_executions_python_language_sdk_test.py b/packages/aws-durable-execution-sdk-python/tests/durable_executions_python_language_sdk_test.py similarity index 100% rename from tests/durable_executions_python_language_sdk_test.py rename to packages/aws-durable-execution-sdk-python/tests/durable_executions_python_language_sdk_test.py diff --git a/packages/aws-durable-execution-sdk-python/tests/e2e/__init__.py b/packages/aws-durable-execution-sdk-python/tests/e2e/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/e2e/checkpoint_response_int_test.py b/packages/aws-durable-execution-sdk-python/tests/e2e/checkpoint_response_int_test.py similarity index 100% rename from tests/e2e/checkpoint_response_int_test.py rename to packages/aws-durable-execution-sdk-python/tests/e2e/checkpoint_response_int_test.py diff --git a/tests/e2e/execution_int_test.py b/packages/aws-durable-execution-sdk-python/tests/e2e/execution_int_test.py similarity index 100% rename from tests/e2e/execution_int_test.py rename to packages/aws-durable-execution-sdk-python/tests/e2e/execution_int_test.py diff --git a/tests/e2e/map_with_concurrent_waits_int_test.py b/packages/aws-durable-execution-sdk-python/tests/e2e/map_with_concurrent_waits_int_test.py similarity index 100% rename from tests/e2e/map_with_concurrent_waits_int_test.py rename to packages/aws-durable-execution-sdk-python/tests/e2e/map_with_concurrent_waits_int_test.py diff --git a/tests/exceptions_test.py b/packages/aws-durable-execution-sdk-python/tests/exceptions_test.py similarity index 100% rename from tests/exceptions_test.py rename to packages/aws-durable-execution-sdk-python/tests/exceptions_test.py diff --git a/tests/execution_test.py b/packages/aws-durable-execution-sdk-python/tests/execution_test.py similarity index 100% rename from tests/execution_test.py rename to packages/aws-durable-execution-sdk-python/tests/execution_test.py diff --git a/tests/lambda_service_test.py b/packages/aws-durable-execution-sdk-python/tests/lambda_service_test.py similarity index 100% rename from tests/lambda_service_test.py rename to packages/aws-durable-execution-sdk-python/tests/lambda_service_test.py diff --git a/tests/logger_test.py b/packages/aws-durable-execution-sdk-python/tests/logger_test.py similarity index 100% rename from tests/logger_test.py rename to packages/aws-durable-execution-sdk-python/tests/logger_test.py diff --git a/packages/aws-durable-execution-sdk-python/tests/operation/__init__.py b/packages/aws-durable-execution-sdk-python/tests/operation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/operation/base_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/base_test.py similarity index 100% rename from tests/operation/base_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/base_test.py diff --git a/tests/operation/callback_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/callback_test.py similarity index 100% rename from tests/operation/callback_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/callback_test.py diff --git a/tests/operation/child_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/child_test.py similarity index 100% rename from tests/operation/child_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/child_test.py diff --git a/tests/operation/invoke_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/invoke_test.py similarity index 100% rename from tests/operation/invoke_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/invoke_test.py diff --git a/tests/operation/map_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/map_test.py similarity index 84% rename from tests/operation/map_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/map_test.py index c7a653f6..fc25bc2d 100644 --- a/tests/operation/map_test.py +++ b/packages/aws-durable-execution-sdk-python/tests/operation/map_test.py @@ -980,109 +980,122 @@ def get_checkpoint_result(self, operation_id): def test_map_handler_serializes_batch_result(): """Verify map_handler serializes BatchResult at parent level.""" - with patch( - "aws_durable_execution_sdk_python.serdes.serialize" - ) as mock_serdes_serialize: - mock_serdes_serialize.return_value = '"serialized"' - importlib.reload(child) + try: + with patch( + "aws_durable_execution_sdk_python.serdes.serialize" + ) as mock_serdes_serialize: + mock_serdes_serialize.return_value = '"serialized"' + importlib.reload(child) + + parent_checkpoint = Mock() + parent_checkpoint.is_succeeded.return_value = False + parent_checkpoint.is_failed.return_value = False + parent_checkpoint.is_existent.return_value = False + parent_checkpoint.is_replay_children.return_value = False + + child_checkpoint = Mock() + child_checkpoint.is_succeeded.return_value = False + child_checkpoint.is_failed.return_value = False + child_checkpoint.is_existent.return_value = False + child_checkpoint.is_replay_children.return_value = False + + def get_checkpoint(op_id): + return ( + child_checkpoint + if op_id.startswith("child-") + else parent_checkpoint + ) - parent_checkpoint = Mock() - parent_checkpoint.is_succeeded.return_value = False - parent_checkpoint.is_failed.return_value = False - parent_checkpoint.is_existent.return_value = False - parent_checkpoint.is_replay_children.return_value = False - - child_checkpoint = Mock() - child_checkpoint.is_succeeded.return_value = False - child_checkpoint.is_failed.return_value = False - child_checkpoint.is_existent.return_value = False - child_checkpoint.is_replay_children.return_value = False - - def get_checkpoint(op_id): - return child_checkpoint if op_id.startswith("child-") else parent_checkpoint - - mock_state = Mock() - mock_state.durable_execution_arn = "arn:test" - mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) - mock_state.create_checkpoint = Mock() - - context_map = {} - - def create_id(self, i): - ctx_id = id(self) - if ctx_id not in context_map: - context_map[ctx_id] = [] - context_map[ctx_id].append(i) - return ( - "parent" - if len(context_map) == 1 and len(context_map[ctx_id]) == 1 - else f"child-{i}" - ) - - with patch.object( - DurableContext, "_create_step_id_for_logical_step", create_id - ): - context = create_test_context(state=mock_state) - result = context.map(["a", "b"], lambda ctx, item, idx, items: item) - - assert len(mock_serdes_serialize.call_args_list) == 3 - parent_call = mock_serdes_serialize.call_args_list[2] - assert parent_call[1]["value"] is result + mock_state = Mock() + mock_state.durable_execution_arn = "arn:test" + mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) + mock_state.create_checkpoint = Mock() + + context_map = {} + + def create_id(self, i): + ctx_id = id(self) + if ctx_id not in context_map: + context_map[ctx_id] = [] + context_map[ctx_id].append(i) + return ( + "parent" + if len(context_map) == 1 and len(context_map[ctx_id]) == 1 + else f"child-{i}" + ) + + with patch.object( + DurableContext, "_create_step_id_for_logical_step", create_id + ): + context = create_test_context(state=mock_state) + result = context.map(["a", "b"], lambda ctx, item, idx, items: item) + + assert len(mock_serdes_serialize.call_args_list) == 3 + parent_call = mock_serdes_serialize.call_args_list[2] + assert parent_call[1]["value"] is result + finally: + importlib.reload(child) def test_map_default_serdes_serializes_batch_result(): """Verify default serdes automatically serializes BatchResult.""" + try: + with patch( + "aws_durable_execution_sdk_python.serdes.serialize", wraps=serialize + ) as mock_serialize: + importlib.reload(child) + + parent_checkpoint = Mock() + parent_checkpoint.is_succeeded.return_value = False + parent_checkpoint.is_failed.return_value = False + parent_checkpoint.is_existent.return_value = False + parent_checkpoint.is_replay_children.return_value = False + + child_checkpoint = Mock() + child_checkpoint.is_succeeded.return_value = False + child_checkpoint.is_failed.return_value = False + child_checkpoint.is_existent.return_value = False + child_checkpoint.is_replay_children.return_value = False + + def get_checkpoint(op_id): + return ( + child_checkpoint + if op_id.startswith("child-") + else parent_checkpoint + ) - with patch( - "aws_durable_execution_sdk_python.serdes.serialize", wraps=serialize - ) as mock_serialize: - importlib.reload(child) + mock_state = Mock() + mock_state.durable_execution_arn = "arn:test" + mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) + mock_state.create_checkpoint = Mock() + + context_map = {} + + def create_id(self, i): + ctx_id = id(self) + if ctx_id not in context_map: + context_map[ctx_id] = [] + context_map[ctx_id].append(i) + return ( + "parent" + if len(context_map) == 1 and len(context_map[ctx_id]) == 1 + else f"child-{i}" + ) - parent_checkpoint = Mock() - parent_checkpoint.is_succeeded.return_value = False - parent_checkpoint.is_failed.return_value = False - parent_checkpoint.is_existent.return_value = False - parent_checkpoint.is_replay_children.return_value = False - - child_checkpoint = Mock() - child_checkpoint.is_succeeded.return_value = False - child_checkpoint.is_failed.return_value = False - child_checkpoint.is_existent.return_value = False - child_checkpoint.is_replay_children.return_value = False - - def get_checkpoint(op_id): - return child_checkpoint if op_id.startswith("child-") else parent_checkpoint - - mock_state = Mock() - mock_state.durable_execution_arn = "arn:test" - mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) - mock_state.create_checkpoint = Mock() - - context_map = {} - - def create_id(self, i): - ctx_id = id(self) - if ctx_id not in context_map: - context_map[ctx_id] = [] - context_map[ctx_id].append(i) - return ( - "parent" - if len(context_map) == 1 and len(context_map[ctx_id]) == 1 - else f"child-{i}" - ) - - with patch.object( - DurableContext, "_create_step_id_for_logical_step", create_id - ): - context = create_test_context(state=mock_state) - result = context.map(["a", "b"], lambda ctx, item, idx, items: item) - - assert isinstance(result, BatchResult) - assert len(mock_serialize.call_args_list) == 3 - parent_call = mock_serialize.call_args_list[2] - assert parent_call[1]["serdes"] is None - assert isinstance(parent_call[1]["value"], BatchResult) - assert parent_call[1]["value"] is result + with patch.object( + DurableContext, "_create_step_id_for_logical_step", create_id + ): + context = create_test_context(state=mock_state) + result = context.map(["a", "b"], lambda ctx, item, idx, items: item) + + assert isinstance(result, BatchResult) + assert len(mock_serialize.call_args_list) == 3 + parent_call = mock_serialize.call_args_list[2] + assert parent_call[1]["serdes"] is None + assert isinstance(parent_call[1]["value"], BatchResult) + assert parent_call[1]["value"] is result + finally: + importlib.reload(child) def test_map_custom_serdes_serializes_batch_result(): @@ -1090,58 +1103,67 @@ def test_map_custom_serdes_serializes_batch_result(): custom_serdes = CustomStrSerDes() - with patch("aws_durable_execution_sdk_python.serdes.serialize") as mock_serialize: - mock_serialize.return_value = '"serialized"' - importlib.reload(child) + try: + with patch( + "aws_durable_execution_sdk_python.serdes.serialize" + ) as mock_serialize: + mock_serialize.return_value = '"serialized"' + importlib.reload(child) + + parent_checkpoint = Mock() + parent_checkpoint.is_succeeded.return_value = False + parent_checkpoint.is_failed.return_value = False + parent_checkpoint.is_existent.return_value = False + parent_checkpoint.is_replay_children.return_value = False + + child_checkpoint = Mock() + child_checkpoint.is_succeeded.return_value = False + child_checkpoint.is_failed.return_value = False + child_checkpoint.is_existent.return_value = False + child_checkpoint.is_replay_children.return_value = False + + def get_checkpoint(op_id): + return ( + child_checkpoint + if op_id.startswith("child-") + else parent_checkpoint + ) - parent_checkpoint = Mock() - parent_checkpoint.is_succeeded.return_value = False - parent_checkpoint.is_failed.return_value = False - parent_checkpoint.is_existent.return_value = False - parent_checkpoint.is_replay_children.return_value = False - - child_checkpoint = Mock() - child_checkpoint.is_succeeded.return_value = False - child_checkpoint.is_failed.return_value = False - child_checkpoint.is_existent.return_value = False - child_checkpoint.is_replay_children.return_value = False - - def get_checkpoint(op_id): - return child_checkpoint if op_id.startswith("child-") else parent_checkpoint - - mock_state = Mock() - mock_state.durable_execution_arn = "arn:test" - mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) - mock_state.create_checkpoint = Mock() - - context_map = {} - - def create_id(self, i): - ctx_id = id(self) - if ctx_id not in context_map: - context_map[ctx_id] = [] - context_map[ctx_id].append(i) - return ( - "parent" - if len(context_map) == 1 and len(context_map[ctx_id]) == 1 - else f"child-{i}" - ) - - with patch.object( - DurableContext, "_create_step_id_for_logical_step", create_id - ): - context = create_test_context(state=mock_state) - result = context.map( - ["a", "b"], - lambda ctx, item, idx, items: item, - config=MapConfig(serdes=custom_serdes), - ) - - assert isinstance(result, BatchResult) - assert len(mock_serialize.call_args_list) == 3 - parent_call = mock_serialize.call_args_list[2] - assert parent_call[1]["serdes"] is custom_serdes - assert isinstance(parent_call[1]["value"], BatchResult) + mock_state = Mock() + mock_state.durable_execution_arn = "arn:test" + mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) + mock_state.create_checkpoint = Mock() + + context_map = {} + + def create_id(self, i): + ctx_id = id(self) + if ctx_id not in context_map: + context_map[ctx_id] = [] + context_map[ctx_id].append(i) + return ( + "parent" + if len(context_map) == 1 and len(context_map[ctx_id]) == 1 + else f"child-{i}" + ) + + with patch.object( + DurableContext, "_create_step_id_for_logical_step", create_id + ): + context = create_test_context(state=mock_state) + result = context.map( + ["a", "b"], + lambda ctx, item, idx, items: item, + config=MapConfig(serdes=custom_serdes), + ) + + assert isinstance(result, BatchResult) + assert len(mock_serialize.call_args_list) == 3 + parent_call = mock_serialize.call_args_list[2] + assert parent_call[1]["serdes"] is custom_serdes + assert isinstance(parent_call[1]["value"], BatchResult) + finally: + importlib.reload(child) assert parent_call[1]["value"] is result diff --git a/tests/operation/parallel_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/parallel_test.py similarity index 84% rename from tests/operation/parallel_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/parallel_test.py index cf7c7367..23dd978d 100644 --- a/tests/operation/parallel_test.py +++ b/packages/aws-durable-execution-sdk-python/tests/operation/parallel_test.py @@ -956,109 +956,122 @@ def get_checkpoint_result(self, operation_id): def test_parallel_handler_serializes_batch_result(): """Verify parallel_handler serializes BatchResult at parent level.""" + try: + with patch( + "aws_durable_execution_sdk_python.serdes.serialize" + ) as mock_serdes_serialize: + mock_serdes_serialize.return_value = '"serialized"' + importlib.reload(child) + + parent_checkpoint = Mock() + parent_checkpoint.is_succeeded.return_value = False + parent_checkpoint.is_failed.return_value = False + parent_checkpoint.is_existent.return_value = False + parent_checkpoint.is_replay_children.return_value = False + + child_checkpoint = Mock() + child_checkpoint.is_succeeded.return_value = False + child_checkpoint.is_failed.return_value = False + child_checkpoint.is_existent.return_value = False + child_checkpoint.is_replay_children.return_value = False + + def get_checkpoint(op_id): + return ( + child_checkpoint + if op_id.startswith("child-") + else parent_checkpoint + ) - with patch( - "aws_durable_execution_sdk_python.serdes.serialize" - ) as mock_serdes_serialize: - mock_serdes_serialize.return_value = '"serialized"' - importlib.reload(child) + mock_state = Mock() + mock_state.durable_execution_arn = "arn:test" + mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) + mock_state.create_checkpoint = Mock() + + context_map = {} + + def create_id(self, i): + ctx_id = id(self) + if ctx_id not in context_map: + context_map[ctx_id] = [] + context_map[ctx_id].append(i) + return ( + "parent" + if len(context_map) == 1 and len(context_map[ctx_id]) == 1 + else f"child-{i}" + ) - parent_checkpoint = Mock() - parent_checkpoint.is_succeeded.return_value = False - parent_checkpoint.is_failed.return_value = False - parent_checkpoint.is_existent.return_value = False - parent_checkpoint.is_replay_children.return_value = False - - child_checkpoint = Mock() - child_checkpoint.is_succeeded.return_value = False - child_checkpoint.is_failed.return_value = False - child_checkpoint.is_existent.return_value = False - child_checkpoint.is_replay_children.return_value = False - - def get_checkpoint(op_id): - return child_checkpoint if op_id.startswith("child-") else parent_checkpoint - - mock_state = Mock() - mock_state.durable_execution_arn = "arn:test" - mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) - mock_state.create_checkpoint = Mock() - - context_map = {} - - def create_id(self, i): - ctx_id = id(self) - if ctx_id not in context_map: - context_map[ctx_id] = [] - context_map[ctx_id].append(i) - return ( - "parent" - if len(context_map) == 1 and len(context_map[ctx_id]) == 1 - else f"child-{i}" - ) - - with patch.object( - DurableContext, "_create_step_id_for_logical_step", create_id - ): - context = create_test_context(state=mock_state) - result = context.parallel([lambda ctx: "a", lambda ctx: "b"]) - - assert len(mock_serdes_serialize.call_args_list) == 3 - parent_call = mock_serdes_serialize.call_args_list[2] - assert parent_call[1]["value"] is result + with patch.object( + DurableContext, "_create_step_id_for_logical_step", create_id + ): + context = create_test_context(state=mock_state) + result = context.parallel([lambda ctx: "a", lambda ctx: "b"]) + + assert len(mock_serdes_serialize.call_args_list) == 3 + parent_call = mock_serdes_serialize.call_args_list[2] + assert parent_call[1]["value"] is result + finally: + importlib.reload(child) def test_parallel_default_serdes_serializes_batch_result(): """Verify default serdes automatically serializes BatchResult.""" - with patch( - "aws_durable_execution_sdk_python.serdes.serialize", wraps=serialize - ) as mock_serialize: - importlib.reload(child) + try: + with patch( + "aws_durable_execution_sdk_python.serdes.serialize", wraps=serialize + ) as mock_serialize: + importlib.reload(child) + + parent_checkpoint = Mock() + parent_checkpoint.is_succeeded.return_value = False + parent_checkpoint.is_failed.return_value = False + parent_checkpoint.is_existent.return_value = False + parent_checkpoint.is_replay_children.return_value = False + + child_checkpoint = Mock() + child_checkpoint.is_succeeded.return_value = False + child_checkpoint.is_failed.return_value = False + child_checkpoint.is_existent.return_value = False + child_checkpoint.is_replay_children.return_value = False + + def get_checkpoint(op_id): + return ( + child_checkpoint + if op_id.startswith("child-") + else parent_checkpoint + ) - parent_checkpoint = Mock() - parent_checkpoint.is_succeeded.return_value = False - parent_checkpoint.is_failed.return_value = False - parent_checkpoint.is_existent.return_value = False - parent_checkpoint.is_replay_children.return_value = False - - child_checkpoint = Mock() - child_checkpoint.is_succeeded.return_value = False - child_checkpoint.is_failed.return_value = False - child_checkpoint.is_existent.return_value = False - child_checkpoint.is_replay_children.return_value = False - - def get_checkpoint(op_id): - return child_checkpoint if op_id.startswith("child-") else parent_checkpoint - - mock_state = Mock() - mock_state.durable_execution_arn = "arn:test" - mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) - mock_state.create_checkpoint = Mock() - - context_map = {} - - def create_id(self, i): - ctx_id = id(self) - if ctx_id not in context_map: - context_map[ctx_id] = [] - context_map[ctx_id].append(i) - return ( - "parent" - if len(context_map) == 1 and len(context_map[ctx_id]) == 1 - else f"child-{i}" - ) - - with patch.object( - DurableContext, "_create_step_id_for_logical_step", create_id - ): - context = create_test_context(state=mock_state) - result = context.parallel([lambda ctx: "a", lambda ctx: "b"]) - - assert isinstance(result, BatchResult) - assert len(mock_serialize.call_args_list) == 3 - parent_call = mock_serialize.call_args_list[2] - assert parent_call[1]["serdes"] is None - assert isinstance(parent_call[1]["value"], BatchResult) - assert parent_call[1]["value"] is result + mock_state = Mock() + mock_state.durable_execution_arn = "arn:test" + mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) + mock_state.create_checkpoint = Mock() + + context_map = {} + + def create_id(self, i): + ctx_id = id(self) + if ctx_id not in context_map: + context_map[ctx_id] = [] + context_map[ctx_id].append(i) + return ( + "parent" + if len(context_map) == 1 and len(context_map[ctx_id]) == 1 + else f"child-{i}" + ) + + with patch.object( + DurableContext, "_create_step_id_for_logical_step", create_id + ): + context = create_test_context(state=mock_state) + result = context.parallel([lambda ctx: "a", lambda ctx: "b"]) + + assert isinstance(result, BatchResult) + assert len(mock_serialize.call_args_list) == 3 + parent_call = mock_serialize.call_args_list[2] + assert parent_call[1]["serdes"] is None + assert isinstance(parent_call[1]["value"], BatchResult) + assert parent_call[1]["value"] is result + finally: + importlib.reload(child) def test_parallel_custom_serdes_serializes_batch_result(): @@ -1066,58 +1079,67 @@ def test_parallel_custom_serdes_serializes_batch_result(): custom_serdes = CustomStrSerDes() - with patch("aws_durable_execution_sdk_python.serdes.serialize") as mock_serialize: - mock_serialize.return_value = '"serialized"' - importlib.reload(child) + try: + with patch( + "aws_durable_execution_sdk_python.serdes.serialize" + ) as mock_serialize: + mock_serialize.return_value = '"serialized"' + importlib.reload(child) + + parent_checkpoint = Mock() + parent_checkpoint.is_succeeded.return_value = False + parent_checkpoint.is_failed.return_value = False + parent_checkpoint.is_existent.return_value = False + parent_checkpoint.is_replay_children.return_value = False + + child_checkpoint = Mock() + child_checkpoint.is_succeeded.return_value = False + child_checkpoint.is_failed.return_value = False + child_checkpoint.is_existent.return_value = False + child_checkpoint.is_replay_children.return_value = False + + def get_checkpoint(op_id): + return ( + child_checkpoint + if op_id.startswith("child-") + else parent_checkpoint + ) + + mock_state = Mock() + mock_state.durable_execution_arn = "arn:test" + mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) + mock_state.create_checkpoint = Mock() + + context_map = {} + + def create_id(self, i): + ctx_id = id(self) + if ctx_id not in context_map: + context_map[ctx_id] = [] + context_map[ctx_id].append(i) + return ( + "parent" + if len(context_map) == 1 and len(context_map[ctx_id]) == 1 + else f"child-{i}" + ) + + with patch.object( + DurableContext, "_create_step_id_for_logical_step", create_id + ): + context = create_test_context(state=mock_state) + result = context.parallel( + [lambda ctx: "a", lambda ctx: "b"], + config=ParallelConfig(serdes=custom_serdes), + ) - parent_checkpoint = Mock() - parent_checkpoint.is_succeeded.return_value = False - parent_checkpoint.is_failed.return_value = False - parent_checkpoint.is_existent.return_value = False - parent_checkpoint.is_replay_children.return_value = False - - child_checkpoint = Mock() - child_checkpoint.is_succeeded.return_value = False - child_checkpoint.is_failed.return_value = False - child_checkpoint.is_existent.return_value = False - child_checkpoint.is_replay_children.return_value = False - - def get_checkpoint(op_id): - return child_checkpoint if op_id.startswith("child-") else parent_checkpoint - - mock_state = Mock() - mock_state.durable_execution_arn = "arn:test" - mock_state.get_checkpoint_result = Mock(side_effect=get_checkpoint) - mock_state.create_checkpoint = Mock() - - context_map = {} - - def create_id(self, i): - ctx_id = id(self) - if ctx_id not in context_map: - context_map[ctx_id] = [] - context_map[ctx_id].append(i) - return ( - "parent" - if len(context_map) == 1 and len(context_map[ctx_id]) == 1 - else f"child-{i}" - ) - - with patch.object( - DurableContext, "_create_step_id_for_logical_step", create_id - ): - context = create_test_context(state=mock_state) - result = context.parallel( - [lambda ctx: "a", lambda ctx: "b"], - config=ParallelConfig(serdes=custom_serdes), - ) - - assert isinstance(result, BatchResult) - assert len(mock_serialize.call_args_list) == 3 - parent_call = mock_serialize.call_args_list[2] - assert parent_call[1]["serdes"] is custom_serdes - assert isinstance(parent_call[1]["value"], BatchResult) - assert parent_call[1]["value"] is result + assert isinstance(result, BatchResult) + assert len(mock_serialize.call_args_list) == 3 + parent_call = mock_serialize.call_args_list[2] + assert parent_call[1]["serdes"] is custom_serdes + assert isinstance(parent_call[1]["value"], BatchResult) + assert parent_call[1]["value"] is result + finally: + importlib.reload(child) # region ParallelBranch and branch naming tests diff --git a/tests/operation/step_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/step_test.py similarity index 100% rename from tests/operation/step_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/step_test.py diff --git a/tests/operation/wait_for_condition_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/wait_for_condition_test.py similarity index 100% rename from tests/operation/wait_for_condition_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/wait_for_condition_test.py diff --git a/tests/operation/wait_test.py b/packages/aws-durable-execution-sdk-python/tests/operation/wait_test.py similarity index 100% rename from tests/operation/wait_test.py rename to packages/aws-durable-execution-sdk-python/tests/operation/wait_test.py diff --git a/tests/retries_test.py b/packages/aws-durable-execution-sdk-python/tests/retries_test.py similarity index 100% rename from tests/retries_test.py rename to packages/aws-durable-execution-sdk-python/tests/retries_test.py diff --git a/tests/serdes_test.py b/packages/aws-durable-execution-sdk-python/tests/serdes_test.py similarity index 100% rename from tests/serdes_test.py rename to packages/aws-durable-execution-sdk-python/tests/serdes_test.py diff --git a/tests/state_test.py b/packages/aws-durable-execution-sdk-python/tests/state_test.py similarity index 100% rename from tests/state_test.py rename to packages/aws-durable-execution-sdk-python/tests/state_test.py diff --git a/tests/suspend_test.py b/packages/aws-durable-execution-sdk-python/tests/suspend_test.py similarity index 100% rename from tests/suspend_test.py rename to packages/aws-durable-execution-sdk-python/tests/suspend_test.py diff --git a/tests/test_helpers.py b/packages/aws-durable-execution-sdk-python/tests/test_helpers.py similarity index 100% rename from tests/test_helpers.py rename to packages/aws-durable-execution-sdk-python/tests/test_helpers.py diff --git a/tests/threading_test.py b/packages/aws-durable-execution-sdk-python/tests/threading_test.py similarity index 100% rename from tests/threading_test.py rename to packages/aws-durable-execution-sdk-python/tests/threading_test.py diff --git a/tests/types_test.py b/packages/aws-durable-execution-sdk-python/tests/types_test.py similarity index 100% rename from tests/types_test.py rename to packages/aws-durable-execution-sdk-python/tests/types_test.py diff --git a/tests/waits_test.py b/packages/aws-durable-execution-sdk-python/tests/waits_test.py similarity index 100% rename from tests/waits_test.py rename to packages/aws-durable-execution-sdk-python/tests/waits_test.py diff --git a/examples/cli.py b/packages/examples/cli.py similarity index 98% rename from examples/cli.py rename to packages/examples/cli.py index 5e135a44..4cf75cf9 100755 --- a/examples/cli.py +++ b/packages/examples/cli.py @@ -57,9 +57,12 @@ def build_examples(): logger.exception("Failed to copy testing library") return False - # Copy testing SDK source + # Copy SDK source from the main SDK package testing_src = ( - Path(__file__).parent.parent / "src" / "aws_durable_execution_sdk_python" + Path(__file__).parent.parent + / "aws-durable-execution-sdk-python" + / "src" + / "aws_durable_execution_sdk_python" ) logger.info("Copying SDK from %s", testing_src) shutil.copytree(testing_src, build_dir / "aws_durable_execution_sdk_python") diff --git a/examples/examples-catalog.json b/packages/examples/examples-catalog.json similarity index 100% rename from examples/examples-catalog.json rename to packages/examples/examples-catalog.json diff --git a/packages/examples/pyproject.toml b/packages/examples/pyproject.toml new file mode 100644 index 00000000..6e36b4f8 --- /dev/null +++ b/packages/examples/pyproject.toml @@ -0,0 +1,67 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "aws-durable-execution-sdk-python-examples" +version = "0.0.0" +description = "Examples for AWS Durable Execution SDK for Python" +requires-python = ">=3.11" +dependencies = [ + "aws-durable-execution-sdk-python", + "aws-durable-execution-sdk-python-testing", +] + +[tool.hatch.build.targets.wheel] +packages = ["src"] + +[tool.pytest.ini_options] +testpaths = ["test"] +addopts = "-v --strict-markers" +pythonpath = ["."] +markers = [ + "example: marks tests as example tests (deselect with '-m \"not example\"')", + "durable_execution: marks tests that use the durable_runner fixture (not used for test selection)", +] + +[tool.hatch.envs.examples] +dependencies = [ + "aws-durable-execution-sdk-python-testing>=1.0.0", +] + +[tool.hatch.envs.examples.scripts] +cli = "python cli.py {args}" +bootstrap = "python cli.py bootstrap" +generate-sam-template = "python scripts/generate_sam_template.py" +build = "python cli.py build" +deploy = "python cli.py deploy {args}" +invoke = "python cli.py invoke {args}" +get = "python cli.py get {args}" +history = "python cli.py history {args}" +policy = "python cli.py policy {args}" +list = "python cli.py list" +clean = "rm -rf build .aws-sam *.zip" + +[tool.ruff] +line-length = 88 +target-version = "py311" + +[tool.ruff.lint] +preview = true +select = ["TID252"] # Enforce absolute imports (ban relative imports) + +[tool.ruff.lint.isort] +known-first-party = ["aws_durable_execution_sdk_python"] +force-single-line = false +lines-after-imports = 2 + +[tool.ruff.lint.per-file-ignores] +"test/**" = [ + "ARG001", + "ARG002", + "ARG005", + "S101", + "PLR2004", + "SIM117", + "TRY301", +] diff --git a/examples/scripts/generate_sam_template.py b/packages/examples/scripts/generate_sam_template.py similarity index 100% rename from examples/scripts/generate_sam_template.py rename to packages/examples/scripts/generate_sam_template.py diff --git a/examples/src/__init__.py b/packages/examples/src/__init__.py similarity index 100% rename from examples/src/__init__.py rename to packages/examples/src/__init__.py diff --git a/examples/src/block_example/block_example.py b/packages/examples/src/block_example/block_example.py similarity index 100% rename from examples/src/block_example/block_example.py rename to packages/examples/src/block_example/block_example.py diff --git a/examples/src/callback/callback_concurrency.py b/packages/examples/src/callback/callback_concurrency.py similarity index 100% rename from examples/src/callback/callback_concurrency.py rename to packages/examples/src/callback/callback_concurrency.py diff --git a/examples/src/callback/callback_heartbeat.py b/packages/examples/src/callback/callback_heartbeat.py similarity index 100% rename from examples/src/callback/callback_heartbeat.py rename to packages/examples/src/callback/callback_heartbeat.py diff --git a/examples/src/callback/callback_mixed_ops.py b/packages/examples/src/callback/callback_mixed_ops.py similarity index 100% rename from examples/src/callback/callback_mixed_ops.py rename to packages/examples/src/callback/callback_mixed_ops.py diff --git a/examples/src/callback/callback_serdes.py b/packages/examples/src/callback/callback_serdes.py similarity index 100% rename from examples/src/callback/callback_serdes.py rename to packages/examples/src/callback/callback_serdes.py diff --git a/examples/src/callback/callback_simple.py b/packages/examples/src/callback/callback_simple.py similarity index 100% rename from examples/src/callback/callback_simple.py rename to packages/examples/src/callback/callback_simple.py diff --git a/examples/src/callback/callback_with_timeout.py b/packages/examples/src/callback/callback_with_timeout.py similarity index 100% rename from examples/src/callback/callback_with_timeout.py rename to packages/examples/src/callback/callback_with_timeout.py diff --git a/examples/src/comprehensive_operations/comprehensive_operations.py b/packages/examples/src/comprehensive_operations/comprehensive_operations.py similarity index 100% rename from examples/src/comprehensive_operations/comprehensive_operations.py rename to packages/examples/src/comprehensive_operations/comprehensive_operations.py diff --git a/examples/src/handler_error/handler_error.py b/packages/examples/src/handler_error/handler_error.py similarity index 100% rename from examples/src/handler_error/handler_error.py rename to packages/examples/src/handler_error/handler_error.py diff --git a/examples/src/hello_world.py b/packages/examples/src/hello_world.py similarity index 100% rename from examples/src/hello_world.py rename to packages/examples/src/hello_world.py diff --git a/examples/src/logger_example/logger_example.py b/packages/examples/src/logger_example/logger_example.py similarity index 100% rename from examples/src/logger_example/logger_example.py rename to packages/examples/src/logger_example/logger_example.py diff --git a/examples/src/map/map_completion.py b/packages/examples/src/map/map_completion.py similarity index 100% rename from examples/src/map/map_completion.py rename to packages/examples/src/map/map_completion.py diff --git a/examples/src/map/map_operations.py b/packages/examples/src/map/map_operations.py similarity index 100% rename from examples/src/map/map_operations.py rename to packages/examples/src/map/map_operations.py diff --git a/examples/src/map/map_operations_flat.py b/packages/examples/src/map/map_operations_flat.py similarity index 100% rename from examples/src/map/map_operations_flat.py rename to packages/examples/src/map/map_operations_flat.py diff --git a/examples/src/map/map_with_batch_serdes.py b/packages/examples/src/map/map_with_batch_serdes.py similarity index 100% rename from examples/src/map/map_with_batch_serdes.py rename to packages/examples/src/map/map_with_batch_serdes.py diff --git a/examples/src/map/map_with_custom_serdes.py b/packages/examples/src/map/map_with_custom_serdes.py similarity index 100% rename from examples/src/map/map_with_custom_serdes.py rename to packages/examples/src/map/map_with_custom_serdes.py diff --git a/examples/src/map/map_with_failure_tolerance.py b/packages/examples/src/map/map_with_failure_tolerance.py similarity index 100% rename from examples/src/map/map_with_failure_tolerance.py rename to packages/examples/src/map/map_with_failure_tolerance.py diff --git a/examples/src/map/map_with_item_namer.py b/packages/examples/src/map/map_with_item_namer.py similarity index 100% rename from examples/src/map/map_with_item_namer.py rename to packages/examples/src/map/map_with_item_namer.py diff --git a/examples/src/map/map_with_large_scale.py b/packages/examples/src/map/map_with_large_scale.py similarity index 100% rename from examples/src/map/map_with_large_scale.py rename to packages/examples/src/map/map_with_large_scale.py diff --git a/examples/src/map/map_with_max_concurrency.py b/packages/examples/src/map/map_with_max_concurrency.py similarity index 100% rename from examples/src/map/map_with_max_concurrency.py rename to packages/examples/src/map/map_with_max_concurrency.py diff --git a/examples/src/map/map_with_min_successful.py b/packages/examples/src/map/map_with_min_successful.py similarity index 100% rename from examples/src/map/map_with_min_successful.py rename to packages/examples/src/map/map_with_min_successful.py diff --git a/examples/src/no_replay_execution/no_replay_execution.py b/packages/examples/src/no_replay_execution/no_replay_execution.py similarity index 100% rename from examples/src/no_replay_execution/no_replay_execution.py rename to packages/examples/src/no_replay_execution/no_replay_execution.py diff --git a/examples/src/none_results/none_results.py b/packages/examples/src/none_results/none_results.py similarity index 100% rename from examples/src/none_results/none_results.py rename to packages/examples/src/none_results/none_results.py diff --git a/examples/src/parallel/parallel.py b/packages/examples/src/parallel/parallel.py similarity index 100% rename from examples/src/parallel/parallel.py rename to packages/examples/src/parallel/parallel.py diff --git a/examples/src/parallel/parallel_first_successful.py b/packages/examples/src/parallel/parallel_first_successful.py similarity index 100% rename from examples/src/parallel/parallel_first_successful.py rename to packages/examples/src/parallel/parallel_first_successful.py diff --git a/examples/src/parallel/parallel_flat.py b/packages/examples/src/parallel/parallel_flat.py similarity index 100% rename from examples/src/parallel/parallel_flat.py rename to packages/examples/src/parallel/parallel_flat.py diff --git a/examples/src/parallel/parallel_with_batch_serdes.py b/packages/examples/src/parallel/parallel_with_batch_serdes.py similarity index 100% rename from examples/src/parallel/parallel_with_batch_serdes.py rename to packages/examples/src/parallel/parallel_with_batch_serdes.py diff --git a/examples/src/parallel/parallel_with_custom_serdes.py b/packages/examples/src/parallel/parallel_with_custom_serdes.py similarity index 100% rename from examples/src/parallel/parallel_with_custom_serdes.py rename to packages/examples/src/parallel/parallel_with_custom_serdes.py diff --git a/examples/src/parallel/parallel_with_failure_tolerance.py b/packages/examples/src/parallel/parallel_with_failure_tolerance.py similarity index 100% rename from examples/src/parallel/parallel_with_failure_tolerance.py rename to packages/examples/src/parallel/parallel_with_failure_tolerance.py diff --git a/examples/src/parallel/parallel_with_max_concurrency.py b/packages/examples/src/parallel/parallel_with_max_concurrency.py similarity index 100% rename from examples/src/parallel/parallel_with_max_concurrency.py rename to packages/examples/src/parallel/parallel_with_max_concurrency.py diff --git a/examples/src/parallel/parallel_with_named_branches.py b/packages/examples/src/parallel/parallel_with_named_branches.py similarity index 100% rename from examples/src/parallel/parallel_with_named_branches.py rename to packages/examples/src/parallel/parallel_with_named_branches.py diff --git a/examples/src/parallel/parallel_with_wait.py b/packages/examples/src/parallel/parallel_with_wait.py similarity index 100% rename from examples/src/parallel/parallel_with_wait.py rename to packages/examples/src/parallel/parallel_with_wait.py diff --git a/examples/src/run_in_child_context/run_in_child_context.py b/packages/examples/src/run_in_child_context/run_in_child_context.py similarity index 100% rename from examples/src/run_in_child_context/run_in_child_context.py rename to packages/examples/src/run_in_child_context/run_in_child_context.py diff --git a/examples/src/run_in_child_context/run_in_child_context_large_data.py b/packages/examples/src/run_in_child_context/run_in_child_context_large_data.py similarity index 100% rename from examples/src/run_in_child_context/run_in_child_context_large_data.py rename to packages/examples/src/run_in_child_context/run_in_child_context_large_data.py diff --git a/examples/src/run_in_child_context/run_in_child_context_step_failure.py b/packages/examples/src/run_in_child_context/run_in_child_context_step_failure.py similarity index 100% rename from examples/src/run_in_child_context/run_in_child_context_step_failure.py rename to packages/examples/src/run_in_child_context/run_in_child_context_step_failure.py diff --git a/examples/src/simple_execution/simple_execution.py b/packages/examples/src/simple_execution/simple_execution.py similarity index 100% rename from examples/src/simple_execution/simple_execution.py rename to packages/examples/src/simple_execution/simple_execution.py diff --git a/examples/src/step/step.py b/packages/examples/src/step/step.py similarity index 100% rename from examples/src/step/step.py rename to packages/examples/src/step/step.py diff --git a/examples/src/step/step_no_name.py b/packages/examples/src/step/step_no_name.py similarity index 100% rename from examples/src/step/step_no_name.py rename to packages/examples/src/step/step_no_name.py diff --git a/examples/src/step/step_semantics_at_most_once.py b/packages/examples/src/step/step_semantics_at_most_once.py similarity index 100% rename from examples/src/step/step_semantics_at_most_once.py rename to packages/examples/src/step/step_semantics_at_most_once.py diff --git a/examples/src/step/step_with_exponential_backoff.py b/packages/examples/src/step/step_with_exponential_backoff.py similarity index 100% rename from examples/src/step/step_with_exponential_backoff.py rename to packages/examples/src/step/step_with_exponential_backoff.py diff --git a/examples/src/step/step_with_name.py b/packages/examples/src/step/step_with_name.py similarity index 100% rename from examples/src/step/step_with_name.py rename to packages/examples/src/step/step_with_name.py diff --git a/examples/src/step/step_with_retry.py b/packages/examples/src/step/step_with_retry.py similarity index 100% rename from examples/src/step/step_with_retry.py rename to packages/examples/src/step/step_with_retry.py diff --git a/examples/src/step/steps_with_retry.py b/packages/examples/src/step/steps_with_retry.py similarity index 100% rename from examples/src/step/steps_with_retry.py rename to packages/examples/src/step/steps_with_retry.py diff --git a/examples/src/wait/multiple_wait.py b/packages/examples/src/wait/multiple_wait.py similarity index 100% rename from examples/src/wait/multiple_wait.py rename to packages/examples/src/wait/multiple_wait.py diff --git a/examples/src/wait/wait.py b/packages/examples/src/wait/wait.py similarity index 100% rename from examples/src/wait/wait.py rename to packages/examples/src/wait/wait.py diff --git a/examples/src/wait/wait_with_name.py b/packages/examples/src/wait/wait_with_name.py similarity index 100% rename from examples/src/wait/wait_with_name.py rename to packages/examples/src/wait/wait_with_name.py diff --git a/examples/src/wait_for_callback/wait_for_callback.py b/packages/examples/src/wait_for_callback/wait_for_callback.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback.py rename to packages/examples/src/wait_for_callback/wait_for_callback.py diff --git a/examples/src/wait_for_callback/wait_for_callback_anonymous.py b/packages/examples/src/wait_for_callback/wait_for_callback_anonymous.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_anonymous.py rename to packages/examples/src/wait_for_callback/wait_for_callback_anonymous.py diff --git a/examples/src/wait_for_callback/wait_for_callback_child.py b/packages/examples/src/wait_for_callback/wait_for_callback_child.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_child.py rename to packages/examples/src/wait_for_callback/wait_for_callback_child.py diff --git a/examples/src/wait_for_callback/wait_for_callback_heartbeat.py b/packages/examples/src/wait_for_callback/wait_for_callback_heartbeat.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_heartbeat.py rename to packages/examples/src/wait_for_callback/wait_for_callback_heartbeat.py diff --git a/examples/src/wait_for_callback/wait_for_callback_mixed_ops.py b/packages/examples/src/wait_for_callback/wait_for_callback_mixed_ops.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_mixed_ops.py rename to packages/examples/src/wait_for_callback/wait_for_callback_mixed_ops.py diff --git a/examples/src/wait_for_callback/wait_for_callback_multiple_invocations.py b/packages/examples/src/wait_for_callback/wait_for_callback_multiple_invocations.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_multiple_invocations.py rename to packages/examples/src/wait_for_callback/wait_for_callback_multiple_invocations.py diff --git a/examples/src/wait_for_callback/wait_for_callback_nested.py b/packages/examples/src/wait_for_callback/wait_for_callback_nested.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_nested.py rename to packages/examples/src/wait_for_callback/wait_for_callback_nested.py diff --git a/examples/src/wait_for_callback/wait_for_callback_serdes.py b/packages/examples/src/wait_for_callback/wait_for_callback_serdes.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_serdes.py rename to packages/examples/src/wait_for_callback/wait_for_callback_serdes.py diff --git a/examples/src/wait_for_callback/wait_for_callback_submitter_failure.py b/packages/examples/src/wait_for_callback/wait_for_callback_submitter_failure.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_submitter_failure.py rename to packages/examples/src/wait_for_callback/wait_for_callback_submitter_failure.py diff --git a/examples/src/wait_for_callback/wait_for_callback_submitter_failure_catchable.py b/packages/examples/src/wait_for_callback/wait_for_callback_submitter_failure_catchable.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_submitter_failure_catchable.py rename to packages/examples/src/wait_for_callback/wait_for_callback_submitter_failure_catchable.py diff --git a/examples/src/wait_for_callback/wait_for_callback_timeout.py b/packages/examples/src/wait_for_callback/wait_for_callback_timeout.py similarity index 100% rename from examples/src/wait_for_callback/wait_for_callback_timeout.py rename to packages/examples/src/wait_for_callback/wait_for_callback_timeout.py diff --git a/examples/src/wait_for_condition/wait_for_condition.py b/packages/examples/src/wait_for_condition/wait_for_condition.py similarity index 100% rename from examples/src/wait_for_condition/wait_for_condition.py rename to packages/examples/src/wait_for_condition/wait_for_condition.py diff --git a/examples/template.yaml b/packages/examples/template.yaml similarity index 100% rename from examples/template.yaml rename to packages/examples/template.yaml diff --git a/examples/test/README.md b/packages/examples/test/README.md similarity index 100% rename from examples/test/README.md rename to packages/examples/test/README.md diff --git a/examples/test/__init__.py b/packages/examples/test/__init__.py similarity index 100% rename from examples/test/__init__.py rename to packages/examples/test/__init__.py diff --git a/examples/test/block_example/test_block_example.py b/packages/examples/test/block_example/test_block_example.py similarity index 100% rename from examples/test/block_example/test_block_example.py rename to packages/examples/test/block_example/test_block_example.py diff --git a/examples/test/callback/test_callback_concurrency.py b/packages/examples/test/callback/test_callback_concurrency.py similarity index 100% rename from examples/test/callback/test_callback_concurrency.py rename to packages/examples/test/callback/test_callback_concurrency.py diff --git a/examples/test/callback/test_callback_heartbeat.py b/packages/examples/test/callback/test_callback_heartbeat.py similarity index 100% rename from examples/test/callback/test_callback_heartbeat.py rename to packages/examples/test/callback/test_callback_heartbeat.py diff --git a/examples/test/callback/test_callback_mixed_ops.py b/packages/examples/test/callback/test_callback_mixed_ops.py similarity index 100% rename from examples/test/callback/test_callback_mixed_ops.py rename to packages/examples/test/callback/test_callback_mixed_ops.py diff --git a/examples/test/callback/test_callback_serdes.py b/packages/examples/test/callback/test_callback_serdes.py similarity index 100% rename from examples/test/callback/test_callback_serdes.py rename to packages/examples/test/callback/test_callback_serdes.py diff --git a/examples/test/callback/test_callback_simple.py b/packages/examples/test/callback/test_callback_simple.py similarity index 100% rename from examples/test/callback/test_callback_simple.py rename to packages/examples/test/callback/test_callback_simple.py diff --git a/examples/test/comprehensive_operations/test_comprehensive_operations.py b/packages/examples/test/comprehensive_operations/test_comprehensive_operations.py similarity index 100% rename from examples/test/comprehensive_operations/test_comprehensive_operations.py rename to packages/examples/test/comprehensive_operations/test_comprehensive_operations.py diff --git a/examples/test/conftest.py b/packages/examples/test/conftest.py similarity index 100% rename from examples/test/conftest.py rename to packages/examples/test/conftest.py diff --git a/examples/test/handler_error/test_handler_error.py b/packages/examples/test/handler_error/test_handler_error.py similarity index 100% rename from examples/test/handler_error/test_handler_error.py rename to packages/examples/test/handler_error/test_handler_error.py diff --git a/examples/test/logger_example/test_logger_example.py b/packages/examples/test/logger_example/test_logger_example.py similarity index 100% rename from examples/test/logger_example/test_logger_example.py rename to packages/examples/test/logger_example/test_logger_example.py diff --git a/examples/test/map/test_map_completion.py b/packages/examples/test/map/test_map_completion.py similarity index 100% rename from examples/test/map/test_map_completion.py rename to packages/examples/test/map/test_map_completion.py diff --git a/examples/test/map/test_map_operations.py b/packages/examples/test/map/test_map_operations.py similarity index 100% rename from examples/test/map/test_map_operations.py rename to packages/examples/test/map/test_map_operations.py diff --git a/examples/test/map/test_map_operations_flat.py b/packages/examples/test/map/test_map_operations_flat.py similarity index 100% rename from examples/test/map/test_map_operations_flat.py rename to packages/examples/test/map/test_map_operations_flat.py diff --git a/examples/test/map/test_map_with_batch_serdes.py b/packages/examples/test/map/test_map_with_batch_serdes.py similarity index 100% rename from examples/test/map/test_map_with_batch_serdes.py rename to packages/examples/test/map/test_map_with_batch_serdes.py diff --git a/examples/test/map/test_map_with_custom_serdes.py b/packages/examples/test/map/test_map_with_custom_serdes.py similarity index 100% rename from examples/test/map/test_map_with_custom_serdes.py rename to packages/examples/test/map/test_map_with_custom_serdes.py diff --git a/examples/test/map/test_map_with_failure_tolerance.py b/packages/examples/test/map/test_map_with_failure_tolerance.py similarity index 100% rename from examples/test/map/test_map_with_failure_tolerance.py rename to packages/examples/test/map/test_map_with_failure_tolerance.py diff --git a/examples/test/map/test_map_with_item_namer.py b/packages/examples/test/map/test_map_with_item_namer.py similarity index 100% rename from examples/test/map/test_map_with_item_namer.py rename to packages/examples/test/map/test_map_with_item_namer.py diff --git a/examples/test/map/test_map_with_large_scale.py b/packages/examples/test/map/test_map_with_large_scale.py similarity index 100% rename from examples/test/map/test_map_with_large_scale.py rename to packages/examples/test/map/test_map_with_large_scale.py diff --git a/examples/test/map/test_map_with_max_concurrency.py b/packages/examples/test/map/test_map_with_max_concurrency.py similarity index 100% rename from examples/test/map/test_map_with_max_concurrency.py rename to packages/examples/test/map/test_map_with_max_concurrency.py diff --git a/examples/test/map/test_map_with_min_successful.py b/packages/examples/test/map/test_map_with_min_successful.py similarity index 100% rename from examples/test/map/test_map_with_min_successful.py rename to packages/examples/test/map/test_map_with_min_successful.py diff --git a/examples/test/no_replay_execution/test_no_replay_execution.py b/packages/examples/test/no_replay_execution/test_no_replay_execution.py similarity index 100% rename from examples/test/no_replay_execution/test_no_replay_execution.py rename to packages/examples/test/no_replay_execution/test_no_replay_execution.py diff --git a/examples/test/none_results/test_none_results.py b/packages/examples/test/none_results/test_none_results.py similarity index 100% rename from examples/test/none_results/test_none_results.py rename to packages/examples/test/none_results/test_none_results.py diff --git a/examples/test/parallel/test_parallel.py b/packages/examples/test/parallel/test_parallel.py similarity index 100% rename from examples/test/parallel/test_parallel.py rename to packages/examples/test/parallel/test_parallel.py diff --git a/examples/test/parallel/test_parallel_flat.py b/packages/examples/test/parallel/test_parallel_flat.py similarity index 100% rename from examples/test/parallel/test_parallel_flat.py rename to packages/examples/test/parallel/test_parallel_flat.py diff --git a/examples/test/parallel/test_parallel_with_batch_serdes.py b/packages/examples/test/parallel/test_parallel_with_batch_serdes.py similarity index 100% rename from examples/test/parallel/test_parallel_with_batch_serdes.py rename to packages/examples/test/parallel/test_parallel_with_batch_serdes.py diff --git a/examples/test/parallel/test_parallel_with_custom_serdes.py b/packages/examples/test/parallel/test_parallel_with_custom_serdes.py similarity index 100% rename from examples/test/parallel/test_parallel_with_custom_serdes.py rename to packages/examples/test/parallel/test_parallel_with_custom_serdes.py diff --git a/examples/test/parallel/test_parallel_with_failure_tolerance.py b/packages/examples/test/parallel/test_parallel_with_failure_tolerance.py similarity index 100% rename from examples/test/parallel/test_parallel_with_failure_tolerance.py rename to packages/examples/test/parallel/test_parallel_with_failure_tolerance.py diff --git a/examples/test/parallel/test_parallel_with_max_concurrency.py b/packages/examples/test/parallel/test_parallel_with_max_concurrency.py similarity index 100% rename from examples/test/parallel/test_parallel_with_max_concurrency.py rename to packages/examples/test/parallel/test_parallel_with_max_concurrency.py diff --git a/examples/test/parallel/test_parallel_with_named_branches.py b/packages/examples/test/parallel/test_parallel_with_named_branches.py similarity index 100% rename from examples/test/parallel/test_parallel_with_named_branches.py rename to packages/examples/test/parallel/test_parallel_with_named_branches.py diff --git a/examples/test/parallel/test_parallel_with_wait.py b/packages/examples/test/parallel/test_parallel_with_wait.py similarity index 100% rename from examples/test/parallel/test_parallel_with_wait.py rename to packages/examples/test/parallel/test_parallel_with_wait.py diff --git a/examples/test/run_in_child_context/test_run_in_child_context.py b/packages/examples/test/run_in_child_context/test_run_in_child_context.py similarity index 100% rename from examples/test/run_in_child_context/test_run_in_child_context.py rename to packages/examples/test/run_in_child_context/test_run_in_child_context.py diff --git a/examples/test/run_in_child_context/test_run_in_child_context_large_data.py b/packages/examples/test/run_in_child_context/test_run_in_child_context_large_data.py similarity index 100% rename from examples/test/run_in_child_context/test_run_in_child_context_large_data.py rename to packages/examples/test/run_in_child_context/test_run_in_child_context_large_data.py diff --git a/examples/test/run_in_child_context/test_run_in_child_context_step_failure.py b/packages/examples/test/run_in_child_context/test_run_in_child_context_step_failure.py similarity index 100% rename from examples/test/run_in_child_context/test_run_in_child_context_step_failure.py rename to packages/examples/test/run_in_child_context/test_run_in_child_context_step_failure.py diff --git a/examples/test/simple_execution/test_simple_execution.py b/packages/examples/test/simple_execution/test_simple_execution.py similarity index 100% rename from examples/test/simple_execution/test_simple_execution.py rename to packages/examples/test/simple_execution/test_simple_execution.py diff --git a/examples/test/step/test_step.py b/packages/examples/test/step/test_step.py similarity index 100% rename from examples/test/step/test_step.py rename to packages/examples/test/step/test_step.py diff --git a/examples/test/step/test_step_permutations.py b/packages/examples/test/step/test_step_permutations.py similarity index 100% rename from examples/test/step/test_step_permutations.py rename to packages/examples/test/step/test_step_permutations.py diff --git a/examples/test/step/test_step_semantics_at_most_once.py b/packages/examples/test/step/test_step_semantics_at_most_once.py similarity index 100% rename from examples/test/step/test_step_semantics_at_most_once.py rename to packages/examples/test/step/test_step_semantics_at_most_once.py diff --git a/examples/test/step/test_step_with_retry.py b/packages/examples/test/step/test_step_with_retry.py similarity index 100% rename from examples/test/step/test_step_with_retry.py rename to packages/examples/test/step/test_step_with_retry.py diff --git a/examples/test/step/test_steps_with_retry.py b/packages/examples/test/step/test_steps_with_retry.py similarity index 100% rename from examples/test/step/test_steps_with_retry.py rename to packages/examples/test/step/test_steps_with_retry.py diff --git a/examples/test/test_hello_world.py b/packages/examples/test/test_hello_world.py similarity index 100% rename from examples/test/test_hello_world.py rename to packages/examples/test/test_hello_world.py diff --git a/examples/test/wait/test_multiple_wait.py b/packages/examples/test/wait/test_multiple_wait.py similarity index 100% rename from examples/test/wait/test_multiple_wait.py rename to packages/examples/test/wait/test_multiple_wait.py diff --git a/examples/test/wait/test_wait.py b/packages/examples/test/wait/test_wait.py similarity index 100% rename from examples/test/wait/test_wait.py rename to packages/examples/test/wait/test_wait.py diff --git a/examples/test/wait/test_wait_permutations.py b/packages/examples/test/wait/test_wait_permutations.py similarity index 100% rename from examples/test/wait/test_wait_permutations.py rename to packages/examples/test/wait/test_wait_permutations.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_anonymous.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_anonymous.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_anonymous.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_anonymous.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_child.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_child.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_child.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_child.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_failure.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_failure.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_failure.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_failure.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_heartbeat.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_heartbeat.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_heartbeat.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_heartbeat.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_mixed_ops.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_mixed_ops.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_mixed_ops.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_mixed_ops.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_multiple_invocations.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_multiple_invocations.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_multiple_invocations.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_multiple_invocations.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_nested.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_nested.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_nested.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_nested.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_serdes.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_serdes.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_serdes.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_serdes.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_submitter_failure.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_submitter_failure.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_submitter_failure.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_submitter_failure.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_submitter_failure_catchable.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_submitter_failure_catchable.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_submitter_failure_catchable.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_submitter_failure_catchable.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_success.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_success.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_success.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_success.py diff --git a/examples/test/wait_for_callback/test_wait_for_callback_timeout.py b/packages/examples/test/wait_for_callback/test_wait_for_callback_timeout.py similarity index 100% rename from examples/test/wait_for_callback/test_wait_for_callback_timeout.py rename to packages/examples/test/wait_for_callback/test_wait_for_callback_timeout.py diff --git a/examples/test/wait_for_condition/test_wait_for_condition.py b/packages/examples/test/wait_for_condition/test_wait_for_condition.py similarity index 100% rename from examples/test/wait_for_condition/test_wait_for_condition.py rename to packages/examples/test/wait_for_condition/test_wait_for_condition.py diff --git a/pyproject.toml b/pyproject.toml index 8c7836a5..ef4caf33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,106 +1,133 @@ -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - [project] -name = "aws-durable-execution-sdk-python" -dynamic = ["version"] -description = 'AWS Durable Execution SDK for Python' -readme = "README.md" +name = "aws-durable-execution-sdk-python-monorepo" +version = "0.0.0" requires-python = ">=3.11" -license = "Apache-2.0" -keywords = [] -authors = [{ name = "AWS durable-execution-dev", email = "durable-execution-dev@amazon.com" }] -classifiers = [ - "Development Status :: 4 - Beta", - "Programming Language :: Python", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", -] -dependencies = ["boto3>=1.42.1"] - -[project.urls] -Documentation = "https://github.com/aws/aws-durable-execution-sdk-python#readme" -Issues = "https://github.com/aws/aws-durable-execution-sdk-python/issues" -Source = "https://github.com/aws/aws-durable-execution-sdk-python" -[tool.hatch.build.targets.wheel] -packages = ["src/aws_durable_execution_sdk_python"] - -[tool.hatch.version] -path = "src/aws_durable_execution_sdk_python/__about__.py" +[tool.hatch.envs.default] +workspace.members = ["packages/*"] [tool.hatch.envs.test] +workspace.members = ["packages/*"] dependencies = [ "coverage[toml]", "pytest", "pytest-cov", - "aws-durable-execution-sdk-python-testing>=1.0.0", + "opentelemetry-sdk>=1.20.0", + "aws_durable_execution_sdk_python_testing" ] [tool.hatch.envs.test.scripts] -examples = "pytest --runner-mode=local -m example examples/test/ -v" -examples-integration = "pytest --runner-mode=cloud -m example examples/test/ -v {args}" -cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=src/aws_durable_execution_sdk_python --cov-fail-under=98" +all = "pytest {args}" +cov = "pytest --cov-report=term-missing --cov {args}" +examples-integration = "pytest --runner-mode=cloud -m example packages/examples/test/ -v {args}" + +[tool.pytest.ini_options] +addopts = "--import-mode=importlib" +testpaths = [ + "packages/aws-durable-execution-sdk-python/tests", + "packages/aws-durable-execution-sdk-python-otel/tests", + "packages/examples/test", +] + [tool.hatch.envs.types] +workspace.members = ["packages/*"] extra-dependencies = ["mypy>=1.0.0", "pytest", "boto3-stubs[lambda]"] [tool.hatch.envs.types.scripts] -check = "mypy --install-types --non-interactive {args:src/aws_durable_execution_sdk_python tests}" +check = "mypy --install-types --non-interactive {args}" + +[tool.hatch.envs.dev-core] +workspace.members = ["packages/aws-durable-execution-sdk-python"] +dependencies = [ + "pytest", + "pytest-cov", + "coverage[toml]", + "aws-durable-execution-sdk-python-testing", + "mypy>=1.0.0", + "boto3-stubs[lambda]", +] + +[tool.hatch.envs.dev-core.scripts] +test = "pytest packages/aws-durable-execution-sdk-python/tests {args}" +cov = "pytest --cov-report=term-missing --cov-config=packages/aws-durable-execution-sdk-python/pyproject.toml --cov=packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python --cov-fail-under=98 packages/aws-durable-execution-sdk-python/tests {args}" +typecheck = "mypy --install-types --non-interactive packages/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python packages/aws-durable-execution-sdk-python/tests" + +[tool.hatch.envs.dev-otel] +workspace.members = [ + "packages/aws-durable-execution-sdk-python", + "packages/aws-durable-execution-sdk-python-otel", +] +dependencies = [ + "pytest", + "pytest-cov", + "coverage[toml]", + "opentelemetry-sdk>=1.20.0", + "mypy>=1.0.0", +] + +[tool.hatch.envs.dev-otel.scripts] +test = "pytest packages/aws-durable-execution-sdk-python-otel/tests {args}" +cov = "pytest --cov-report=term-missing --cov-config=packages/aws-durable-execution-sdk-python-otel/pyproject.toml --cov=packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel packages/aws-durable-execution-sdk-python-otel/tests {args}" +typecheck = "mypy --install-types --non-interactive packages/aws-durable-execution-sdk-python-otel/src/aws_durable_execution_sdk_python_otel packages/aws-durable-execution-sdk-python-otel/tests" + +[tool.hatch.envs.dev-examples] +workspace.members = [ + "packages/aws-durable-execution-sdk-python", + "packages/examples", +] +dependencies = [ + "pytest", + "aws-durable-execution-sdk-python-testing", +] -[tool.hatch.envs.examples] +[tool.hatch.envs.dev-examples.scripts] +test = "pytest packages/examples/test {args}" + +[tool.hatch.envs.test-pypi-otel] dependencies = [ - "aws-durable-execution-sdk-python-testing>=1.0.0", + "aws-durable-execution-sdk-python", + "opentelemetry-sdk>=1.20.0", + "pytest", + "pytest-cov", + "coverage[toml]", +] +pre-install-commands = [ + "pip install -e packages/aws-durable-execution-sdk-python-otel", ] -[tool.hatch.envs.examples.scripts] -cli = "python examples/cli.py {args}" -bootstrap = "python examples/cli.py bootstrap" -generate-sam-template = "python examples/scripts/generate_sam_template.py" -build = "python examples/cli.py build" -deploy = "python examples/cli.py deploy {args}" -invoke = "python examples/cli.py invoke {args}" -get = "python examples/cli.py get {args}" -history = "python examples/cli.py history {args}" -policy = "python examples/cli.py policy {args}" -list = "python examples/cli.py list" -clean = "rm -rf examples/build examples/.aws-sam examples/*.zip" - -[tool.coverage.run] -source_pkgs = ["aws_durable_execution_sdk_python"] -branch = true -parallel = true -omit = ["src/aws_durable_execution_sdk_python/__about__.py"] - -[tool.coverage.paths] -aws_durable_execution_sdk_python = [ - "src/aws_durable_execution_sdk_python", - "*/aws-durable-execution-sdk-python/src/aws_durable_execution_sdk_python", +[tool.hatch.envs.test-pypi-otel.scripts] +test = "pytest packages/aws-durable-execution-sdk-python-otel/tests {args}" + +[tool.hatch.envs.test-pypi-examples] +dependencies = [ + "aws-durable-execution-sdk-python", + "aws-durable-execution-sdk-python-testing", + "pytest", +] +pre-install-commands = [ + "pip install -e packages/examples", ] -[tool.coverage.report] -exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"] +[tool.hatch.envs.test-pypi-examples.scripts] +test = "pytest packages/examples/test {args}" [tool.ruff] line-length = 88 target-version = "py311" +exclude = [".github/scripts", ".github/workflows"] [tool.ruff.lint] preview = true select = ["TID252"] # Enforce absolute imports (ban relative imports) [tool.ruff.lint.isort] -known-first-party = ["aws_durable_execution_sdk_python"] +known-first-party = ["aws_durable_execution_sdk_python", "aws_durable_execution_sdk_python_otel"] force-single-line = false lines-after-imports = 2 [tool.ruff.lint.per-file-ignores] -"tests/**" = [ +"**/tests/**" = [ "ARG001", "ARG002", "ARG005", @@ -110,7 +137,7 @@ lines-after-imports = 2 "SIM117", "TRY301", ] -"examples/test/**" = [ +"**/test/**" = [ "ARG001", "ARG002", "ARG005", @@ -119,16 +146,3 @@ lines-after-imports = 2 "SIM117", "TRY301", ] - -[tool.pytest.ini_options] -# Declare custom markers to avoid warnings with --strict-markers -markers = [ - # Used for test selection with -m example - "example: marks tests as example tests (deselect with '-m \"not example\"')", - # Used for configuration - passes handler and lambda_function_name to durable_runner fixture - "durable_execution: marks tests that use the durable_runner fixture (not used for test selection)", -] -# Default test discovery paths -testpaths = ["tests"] -# Default options for all test runs -addopts = "-v --strict-markers"