From 19f390045b1747ef0d7be36907e404b8818b4133 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Fri, 21 Nov 2025 16:01:55 -0800 Subject: [PATCH 01/18] chore(release): changelog for 4.3.0 --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 34032ff..a6a545e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -2,6 +2,14 @@ Changelog ********* +4.3.0 -- 2025-11-24 +=================== + +Deprecation +----------- +* Removed ``pkg_resources`` in favor of ``importlib.metadata`` +`#428 ` __. + 4.2.0 -- 2024-09-09 =================== From ca897a0ef78e6920430444931fae9650741b7987 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Fri, 21 Nov 2025 16:05:57 -0800 Subject: [PATCH 02/18] chore(release): changelog for 4.3.0 --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a6a545e..0ee81d8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,7 +8,7 @@ Changelog Deprecation ----------- * Removed ``pkg_resources`` in favor of ``importlib.metadata`` -`#428 ` __. + `#428 ` __. 4.2.0 -- 2024-09-09 =================== From 42f31be895e165e0c2c77816fbb51876df207ddd Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Fri, 21 Nov 2025 16:08:48 -0800 Subject: [PATCH 03/18] chore(release): changelog for 4.3.0 --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0ee81d8..1aec903 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,7 +8,8 @@ Changelog Deprecation ----------- * Removed ``pkg_resources`` in favor of ``importlib.metadata`` - `#428 ` __. + `#428 `_ + 4.2.0 -- 2024-09-09 =================== From ffea17687f6af5b99d510427dc8ea98fed32db8a Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Fri, 21 Nov 2025 16:22:41 -0800 Subject: [PATCH 04/18] chore(release): prepare 4.3.0 --- api_compatibility_tests/tox.ini | 3 ++- src/aws_encryption_sdk_cli/internal/identifiers.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api_compatibility_tests/tox.ini b/api_compatibility_tests/tox.ini index 5c9c4e6..ce13249 100644 --- a/api_compatibility_tests/tox.ini +++ b/api_compatibility_tests/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py{3,38}-awses_cli_{1.7.0,1.8.0,1.9.0,2.0.0,2.1.0,2.2.0,3.0.0,3.1.0,3.1.2,4.0.0,4.1.0,4.2.0} + py{3,38}-awses_cli_{1.7.0,1.8.0,1.9.0,2.0.0,2.1.0,2.2.0,3.0.0,3.1.0,3.1.2,4.0.0,4.1.0,4.2.0,4.3.0} [testenv:base-command] commands = pytest --basetemp={envtmpdir} -l test/ {posargs} @@ -37,6 +37,7 @@ deps = awses_cli_4.0.0: -rcompatibility-requirements/4.0.0 awses_cli_4.1.0: -rcompatibility-requirements/4.1.0 awses_cli_4.2.0: -rcompatibility-requirements/4.2.0 + awses_cli_4.2.0: -rcompatibility-requirements/4.3.0 awses_cli_local: -e {env:AWSES_CLI_LOCAL_PATH} commands = {[testenv:base-command]commands} diff --git a/src/aws_encryption_sdk_cli/internal/identifiers.py b/src/aws_encryption_sdk_cli/internal/identifiers.py index 83729a3..ddea41a 100644 --- a/src/aws_encryption_sdk_cli/internal/identifiers.py +++ b/src/aws_encryption_sdk_cli/internal/identifiers.py @@ -31,7 +31,7 @@ "DEFAULT_MASTER_KEY_PROVIDER", "OperationResult", ) -__version__ = "4.2.0" # type: str +__version__ = "4.3.0" # type: str #: Suffix added to output files if specific output filename is not specified. OUTPUT_SUFFIX = { From 143515522238cdc99ddec9bdb4d654d2fb994668 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Mon, 24 Nov 2025 16:50:42 -0800 Subject: [PATCH 05/18] fix(CI): Drop pypi-parker dependency --- CHANGELOG.rst | 4 ++ .../compatibility-requirements/4.3.0 | 1 + api_compatibility_tests/tox.ini | 2 +- codebuild/release/prod-release.yml | 1 - codebuild/release/test-release.yml | 1 - dev_requirements/release-requirements.txt | 1 - park.cfg | 38 ------------------- tox.ini | 8 ---- 8 files changed, 6 insertions(+), 50 deletions(-) create mode 100644 api_compatibility_tests/compatibility-requirements/4.3.0 delete mode 100644 park.cfg diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1aec903..61fc67e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,10 @@ Deprecation * Removed ``pkg_resources`` in favor of ``importlib.metadata`` `#428 `_ +Operational +----------- +* Drop release dependency on ``pypi-parker`` + 4.2.0 -- 2024-09-09 =================== diff --git a/api_compatibility_tests/compatibility-requirements/4.3.0 b/api_compatibility_tests/compatibility-requirements/4.3.0 new file mode 100644 index 0000000..e942f1c --- /dev/null +++ b/api_compatibility_tests/compatibility-requirements/4.3.0 @@ -0,0 +1 @@ +aws-encryption-sdk-cli==4.3.0 \ No newline at end of file diff --git a/api_compatibility_tests/tox.ini b/api_compatibility_tests/tox.ini index ce13249..d801ba5 100644 --- a/api_compatibility_tests/tox.ini +++ b/api_compatibility_tests/tox.ini @@ -37,7 +37,7 @@ deps = awses_cli_4.0.0: -rcompatibility-requirements/4.0.0 awses_cli_4.1.0: -rcompatibility-requirements/4.1.0 awses_cli_4.2.0: -rcompatibility-requirements/4.2.0 - awses_cli_4.2.0: -rcompatibility-requirements/4.3.0 + awses_cli_4.3.0: -rcompatibility-requirements/4.3.0 awses_cli_local: -e {env:AWSES_CLI_LOCAL_PATH} commands = {[testenv:base-command]commands} diff --git a/codebuild/release/prod-release.yml b/codebuild/release/prod-release.yml index b3c70bd..63ec010 100644 --- a/codebuild/release/prod-release.yml +++ b/codebuild/release/prod-release.yml @@ -25,7 +25,6 @@ phases: fi build: commands: - - tox -e park - tox -e release batch: diff --git a/codebuild/release/test-release.yml b/codebuild/release/test-release.yml index 1a5905c..3c1dbcf 100644 --- a/codebuild/release/test-release.yml +++ b/codebuild/release/test-release.yml @@ -25,7 +25,6 @@ phases: fi build: commands: - - tox -e park - tox -e test-release diff --git a/dev_requirements/release-requirements.txt b/dev_requirements/release-requirements.txt index a091636..ba996ed 100644 --- a/dev_requirements/release-requirements.txt +++ b/dev_requirements/release-requirements.txt @@ -1,4 +1,3 @@ -pypi-parker setuptools wheel twine \ No newline at end of file diff --git a/park.cfg b/park.cfg deleted file mode 100644 index ce26f91..0000000 --- a/park.cfg +++ /dev/null @@ -1,38 +0,0 @@ -[DEFAULT] -version: 0.0.1 -author: Amazon Web Services -author_email: aws-cryptools@amazon.com -url: http://aws-encryption-sdk-cli.readthedocs.io/en/latest/ -description: Did you mean to install aws-encryption-sdk-cli? -long_description: - This package has been parked by {author} to protect you against packages - adopting names that might be common mistakes when looking for ours. You probably - wanted to install aws-encryption-sdk-cli. For more information, see {url}. -description_keys: - author - url - -[names] -aws-crypto: -awscrypto: -aws-cyrpto: -awscyrpto: -aws-crpyto: -awscrpyto: -aws-crytpo: -awscrytpo: -awsencryptionsdkcli: -aws-encyrption-sdk-cli: -awsencyrptionsdkcli: -aws-encrpytion-sdk-cli: -awsencrpytionsdkcli: -aws-encrytpion-sdk-cli: -awsencrytpionsdkcli: -aws-encryption-cli: -awsencryptioncli: -aws-encyrption-cli: -awsencyrptioncli: -aws-encrpytion-cli: -awsencrpytioncli: -aws-encrytpion-cli: -awsencrytpioncli: \ No newline at end of file diff --git a/tox.ini b/tox.ini index 852aa3f..4204b64 100644 --- a/tox.ini +++ b/tox.ini @@ -23,7 +23,6 @@ envlist = # Operational helper environments: # docs :: Builds Sphinx documentation. # serve-docs :: Starts local webserver to serve built documentation. -# park :: Builds name-parking packages using pypi-parker. # build :: Builds source and wheel dist files. # test-release :: Builds dist files and uploads to testpypi pypirc profile. # release :: Builds dist files and uploads to pypi pypirc profile. @@ -290,13 +289,6 @@ deps = commands = python -m http.server {posargs} -# Release tooling -[testenv:park] -basepython = python3 -skip_install = true -deps = -rdev_requirements/release-requirements.txt -commands = python setup.py park - [testenv:build] basepython = python3 skip_install = true From 8e43b972cf3badf197b168875e7e8007104afd68 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Tue, 25 Nov 2025 11:39:48 -0800 Subject: [PATCH 06/18] fix(CI): use macos-latest --- .github/workflows/ci_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index 9d508e3..f586a57 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -18,7 +18,7 @@ jobs: # x86 builds are only meaningful for Windows - os: windows-latest architecture: x86 - - os: macos-13 + - os: macos-latest architecture: x64 python: - 3.8 From d2b30816ea6007b46ee6ab8902fd51b55ddb83af Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Tue, 25 Nov 2025 11:43:31 -0800 Subject: [PATCH 07/18] fix(CI): use macos-14 --- .github/workflows/ci_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index f586a57..3839c8e 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -18,7 +18,7 @@ jobs: # x86 builds are only meaningful for Windows - os: windows-latest architecture: x86 - - os: macos-latest + - os: macos-14 architecture: x64 python: - 3.8 From 3e11c3bdef36adff5689ef51520ab3f8394e2722 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Tue, 25 Nov 2025 12:00:27 -0800 Subject: [PATCH 08/18] chore: Deprecate Python < 3.10 --- .github/workflows/ci_static-analysis.yaml | 2 +- .github/workflows/ci_tests.yaml | 4 +--- .github/workflows/python-examples.yml | 6 +----- .github/workflows/python-integration.yml | 6 +----- .readthedocs.yaml | 2 +- CHANGELOG.rst | 3 +++ README.rst | 2 +- api_compatibility_tests/setup.py | 10 ++-------- examples/setup.py | 3 --- setup.py | 2 -- 10 files changed, 11 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci_static-analysis.yaml b/.github/workflows/ci_static-analysis.yaml index 8230a8f..d5df8b3 100644 --- a/.github/workflows/ci_static-analysis.yaml +++ b/.github/workflows/ci_static-analysis.yaml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: 3.10 - run: | python -m pip install --upgrade pip pip install --upgrade -r dev_requirements/ci-requirements.txt diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index 3839c8e..a273834 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -18,11 +18,9 @@ jobs: # x86 builds are only meaningful for Windows - os: windows-latest architecture: x86 - - os: macos-14 + - os: macos-latest architecture: x64 python: - - 3.8 - - 3.9 - "3.10" - "3.11" - "3.12" diff --git a/.github/workflows/python-examples.yml b/.github/workflows/python-examples.yml index 8986644..0f79b6c 100644 --- a/.github/workflows/python-examples.yml +++ b/.github/workflows/python-examples.yml @@ -9,12 +9,8 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] include: - - python-version: '3.8' - tox-env: 'py38-examples' - - python-version: '3.9' - tox-env: 'py39-examples' - python-version: '3.10' tox-env: 'py310-examples' - python-version: '3.11' diff --git a/.github/workflows/python-integration.yml b/.github/workflows/python-integration.yml index 2a400f5..5f9147d 100644 --- a/.github/workflows/python-integration.yml +++ b/.github/workflows/python-integration.yml @@ -9,12 +9,8 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.8', '3.9', '3.10', '3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] include: - - python-version: '3.8' - tox-env: 'py38-integ' - - python-version: '3.9' - tox-env: 'py39-integ' - python-version: '3.10' tox-env: 'py310-integ' - python-version: '3.11' diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 82c9c98..9fa906b 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -9,7 +9,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.8" + python: "3.10" # Build documentation in the doc/ directory with Sphinx sphinx: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 61fc67e..a08d545 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,6 +7,9 @@ Changelog Deprecation ----------- +----------- +* The AWS Encryption SDK CLI no longer supports Python 3.8 and 3.9 +as of major version 4.3.x; only Python 3.10+ is supported. * Removed ``pkg_resources`` in favor of ``importlib.metadata`` `#428 `_ diff --git a/README.rst b/README.rst index f978a19..57c68e2 100644 --- a/README.rst +++ b/README.rst @@ -44,7 +44,7 @@ Getting Started Required Prerequisites ====================== -* Python 3.8+ +* Python 3.10+ * aws-encryption-sdk >= 3.1.0 Installation diff --git a/api_compatibility_tests/setup.py b/api_compatibility_tests/setup.py index f32d4a1..3b2cd33 100644 --- a/api_compatibility_tests/setup.py +++ b/api_compatibility_tests/setup.py @@ -46,16 +46,10 @@ def get_requirements(): "Natural Language :: English", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Security", "Topic :: Security :: Cryptography", diff --git a/examples/setup.py b/examples/setup.py index 4da279d..8692980 100644 --- a/examples/setup.py +++ b/examples/setup.py @@ -48,9 +48,6 @@ def get_requirements(): "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Security", diff --git a/setup.py b/setup.py index 258c1c8..29c21a4 100644 --- a/setup.py +++ b/setup.py @@ -49,8 +49,6 @@ def get_requirements(): "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", From 847dc32dc52a5b8489026c8d9702823824d1ab8b Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Tue, 25 Nov 2025 12:26:24 -0800 Subject: [PATCH 09/18] fix: CI --- .github/workflows/ci_static-analysis.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_static-analysis.yaml b/.github/workflows/ci_static-analysis.yaml index d5df8b3..6b42c0f 100644 --- a/.github/workflows/ci_static-analysis.yaml +++ b/.github/workflows/ci_static-analysis.yaml @@ -28,7 +28,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: - python-version: 3.10 + python-version: '3.10' - run: | python -m pip install --upgrade pip pip install --upgrade -r dev_requirements/ci-requirements.txt From 73eb515d5d0c01fe78d9da1d168b060458cd04ee Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Tue, 25 Nov 2025 12:28:25 -0800 Subject: [PATCH 10/18] fix: CI --- .github/workflows/ci_tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index a273834..387831d 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -18,7 +18,7 @@ jobs: # x86 builds are only meaningful for Windows - os: windows-latest architecture: x86 - - os: macos-latest + - os: macos-14 architecture: x64 python: - "3.10" From 671f9db72f936b084daf5dea1720a6164a6fec20 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 10:03:35 -0800 Subject: [PATCH 11/18] fix: CI --- .github/workflows/ci_tests.yaml | 2 +- CHANGELOG.rst | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index 387831d..008523d 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -31,7 +31,7 @@ jobs: # - integ steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python }} architecture: ${{ matrix.platform.architecture }} diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a08d545..8bb5552 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -7,9 +7,7 @@ Changelog Deprecation ----------- ------------ -* The AWS Encryption SDK CLI no longer supports Python 3.8 and 3.9 -as of major version 4.3.x; only Python 3.10+ is supported. +* The AWS Encryption SDK CLI no longer supports Python < 3.10 as of major version 4.3.x; only Python 3.10+ is supported. * Removed ``pkg_resources`` in favor of ``importlib.metadata`` `#428 `_ From 6579adc64215b97af70100e3db089e6d32fa690d Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 10:05:36 -0800 Subject: [PATCH 12/18] fix: CI --- .github/workflows/ci_tests.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index 008523d..1a316f8 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -19,7 +19,6 @@ jobs: - os: windows-latest architecture: x86 - os: macos-14 - architecture: x64 python: - "3.10" - "3.11" From 8c5564bdd6409fecab5e2d2df988a9714a0b0b0d Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 10:55:30 -0800 Subject: [PATCH 13/18] fix: CI --- .github/workflows/ci_tests.yaml | 2 +- dev_requirements/linter-requirements.txt | 4 ++-- src/aws_encryption_sdk_cli/internal/master_key_parsing.py | 2 +- tox.ini | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci_tests.yaml b/.github/workflows/ci_tests.yaml index 1a316f8..1fe313d 100644 --- a/.github/workflows/ci_tests.yaml +++ b/.github/workflows/ci_tests.yaml @@ -30,7 +30,7 @@ jobs: # - integ steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} architecture: ${{ matrix.platform.architecture }} diff --git a/dev_requirements/linter-requirements.txt b/dev_requirements/linter-requirements.txt index 3c0b55d..abc5682 100644 --- a/dev_requirements/linter-requirements.txt +++ b/dev_requirements/linter-requirements.txt @@ -1,4 +1,4 @@ -bandit==1.7.5 +bandit==1.9.2 black==22.8.0 doc8==1.0.0 flake8==4.0.1 @@ -7,7 +7,7 @@ flake8-print==4.0.0 isort==5.10.1 mock==4.0.3 pyflakes==2.4.0 -pylint==2.12.2 +pylint==3.0.3 pytest==7.4.0 pytest-cov==4.1.0 pytest-mock==3.11.1 diff --git a/src/aws_encryption_sdk_cli/internal/master_key_parsing.py b/src/aws_encryption_sdk_cli/internal/master_key_parsing.py index c273e68..c5bc471 100644 --- a/src/aws_encryption_sdk_cli/internal/master_key_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/master_key_parsing.py @@ -47,7 +47,7 @@ def _discover_entry_points(): _LOGGER.debug("Discovering master key provider plugins") for dist in distributions(): - dist_name = dist.metadata.get("Name") or dist.metadata.get("name") or "unknown" + dist_name = dist.metadata['Name'] or dist.metadata['name'] or "unknown" for entry_point in dist.entry_points: if entry_point.group != MASTER_KEY_PROVIDERS_ENTRY_POINT: diff --git a/tox.ini b/tox.ini index 4204b64..3f052dd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py{38,39,310,311,312}-{local,integ,examples}, + py{310,311,312}-{local,integ,examples}, mypy-py{3}, bandit, doc8, readme, docs, flake8{,-tests,-examples}, pylint{,-tests,-examples}, From 43ec2aae3c647985e172489445a44a0dac3c0aeb Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 11:55:49 -0800 Subject: [PATCH 14/18] fix: lint fix using Q --- dev_requirements/linter-requirements.txt | 2 +- src/aws_encryption_sdk_cli/__init__.py | 2 +- .../internal/arg_parsing.py | 5 +- .../internal/io_handling.py | 32 ++++++----- .../internal/logging_utils.py | 13 +++-- .../internal/master_key_parsing.py | 14 ++--- src/pylintrc | 1 - test/integration/integration_test_utils.py | 7 +-- test/pylintrc | 6 +- test/unit/internal/test_io_handling.py | 56 +++++++++---------- test/unit/internal/test_metadata.py | 12 ++-- 11 files changed, 74 insertions(+), 76 deletions(-) diff --git a/dev_requirements/linter-requirements.txt b/dev_requirements/linter-requirements.txt index abc5682..deee2ae 100644 --- a/dev_requirements/linter-requirements.txt +++ b/dev_requirements/linter-requirements.txt @@ -7,7 +7,7 @@ flake8-print==4.0.0 isort==5.10.1 mock==4.0.3 pyflakes==2.4.0 -pylint==3.0.3 +pylint==4.0.3 pytest==7.4.0 pytest-cov==4.1.0 pytest-mock==3.11.1 diff --git a/src/aws_encryption_sdk_cli/__init__.py b/src/aws_encryption_sdk_cli/__init__.py index 115cff6..38a6349 100644 --- a/src/aws_encryption_sdk_cli/__init__.py +++ b/src/aws_encryption_sdk_cli/__init__.py @@ -184,7 +184,7 @@ def process_cli_request(stream_args, parsed_args): # noqa: C901 decode_input=parsed_args.decode, encode_output=parsed_args.encode, required_encryption_context=parsed_args.encryption_context, - required_encryption_context_keys=parsed_args.required_encryption_context_keys, + required_enc_context_keys=parsed_args.required_encryption_context_keys, commitment_policy=commitment_policy, buffer_output=parsed_args.buffer, max_encrypted_data_keys=parsed_args.max_encrypted_data_keys, diff --git a/src/aws_encryption_sdk_cli/internal/arg_parsing.py b/src/aws_encryption_sdk_cli/internal/arg_parsing.py index f87dde9..0f983cf 100644 --- a/src/aws_encryption_sdk_cli/internal/arg_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/arg_parsing.py @@ -40,7 +40,8 @@ RAW_CONFIG, ) except ImportError: # pragma: no cover - cast = lambda typ, val: val # noqa pylint: disable=invalid-name + def cast(typ, val): # noqa pylint: disable=invalid-name,missing-function-docstring,unused-argument + return val # We only actually need the other imports when running the mypy checks __all__ = ("parse_args",) @@ -664,6 +665,6 @@ def parse_args(raw_args=None): if parsed_args.caching is not None: parsed_args.caching = _process_caching_config(parsed_args.caching) except ParameterParseError as error: - parser.error(*error.args) + parser.error(str(error)) return parsed_args diff --git a/src/aws_encryption_sdk_cli/internal/io_handling.py b/src/aws_encryption_sdk_cli/internal/io_handling.py index e3bdc88..2c690f1 100644 --- a/src/aws_encryption_sdk_cli/internal/io_handling.py +++ b/src/aws_encryption_sdk_cli/internal/io_handling.py @@ -34,7 +34,8 @@ from aws_encryption_sdk_cli.internal.mypy_types import SOURCE, STREAM_KWARGS # noqa pylint: disable=unused-import except ImportError: # pragma: no cover - cast = lambda typ, val: val # noqa pylint: disable=invalid-name + def cast(typ, val): # noqa pylint: disable=invalid-name,missing-function-docstring,unused-argument + return val IO = None # type: ignore # We only actually need the other imports when running the mypy checks @@ -191,9 +192,10 @@ def __init__( # noqa pylint: disable=too-many-arguments interactive, # type: bool no_overwrite, # type: bool decode_input, # type: bool + *, encode_output, # type: bool required_encryption_context, # type: Dict[str, str] - required_encryption_context_keys, # type: List[str] + required_enc_context_keys, # type: List[str] commitment_policy, # type: CommitmentPolicy buffer_output, max_encrypted_data_keys, # type: Union[None, int] @@ -209,7 +211,7 @@ def __init__( # noqa pylint: disable=too-many-arguments self.decode_input = decode_input self.encode_output = encode_output self.required_encryption_context = required_encryption_context - self.required_encryption_context_keys = required_encryption_context_keys # pylint: disable=invalid-name + self.required_encryption_context_keys = required_enc_context_keys self.buffer_output = buffer_output self.client = aws_encryption_sdk.EncryptionSDKClient( commitment_policy=commitment_policy, @@ -233,12 +235,12 @@ def _single_io_write(self, stream_args, source, destination_writer): destination_writer, self.encode_output ) as _destination: # noqa pylint: disable=line-too-long with self.client.stream(source=_source, **stream_args) as handler, self.metadata_writer as metadata: - metadata_kwargs = dict( - mode=stream_args["mode"], - input=source.name, - output=destination_writer.name, - header=json_ready_header(handler.header), - ) + metadata_kwargs = { + "mode": stream_args["mode"], + "input": source.name, + "output": destination_writer.name, + "header": json_ready_header(handler.header), + } try: header_auth = handler.header_auth except AttributeError: @@ -256,12 +258,12 @@ def _single_io_write(self, stream_args, source, destination_writer): "Skipping decrypt because discovered encryption context did not match required elements." ) metadata_kwargs.update( - dict( - skipped=True, - reason="Missing encryption context key or value", - missing_encryption_context_keys=list(missing_keys), - missing_encryption_context_pairs=list(missing_pairs), - ) + { + "skipped": True, + "reason": "Missing encryption context key or value", + "missing_encryption_context_keys": list(missing_keys), + "missing_encryption_context_pairs": list(missing_pairs), + } ) metadata.write_metadata(**metadata_kwargs) return OperationResult.FAILED_VALIDATION diff --git a/src/aws_encryption_sdk_cli/internal/logging_utils.py b/src/aws_encryption_sdk_cli/internal/logging_utils.py index 0310d25..bde0753 100644 --- a/src/aws_encryption_sdk_cli/internal/logging_utils.py +++ b/src/aws_encryption_sdk_cli/internal/logging_utils.py @@ -19,7 +19,8 @@ try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Dict, Sequence, Text, Union, cast # noqa pylint: disable=unused-import except ImportError: # pragma: no cover - cast = lambda typ, val: val # noqa pylint: disable=invalid-name + def cast(typ, val): # noqa pylint: disable=invalid-name,missing-function-docstring,unused-argument + return val # We only actually need the other imports when running the mypy checks __all__ = ("setup_logger", "LOGGER_NAME") @@ -33,7 +34,7 @@ class _KMSKeyRedactingFormatter(logging.Formatter): """Log formatter that redacts ``Plaintext`` values from KMS request and response bodies.""" - def __to_str(self, value): # pylint: disable=no-self-use + def __to_str(self, value): # type: (Union[Text, str, bytes]) -> Text """Converts bytes or str to str. @@ -45,7 +46,7 @@ def __to_str(self, value): # pylint: disable=no-self-use return codecs.decode(value, "utf-8") return value - def __is_kms_encrypt_request(self, record): # pylint: disable=no-self-use + def __is_kms_encrypt_request(self, record): # type: (logging.LogRecord) -> bool """Determine if a record contains a kms:Encrypt request. @@ -76,9 +77,9 @@ def __redact_encrypt_request(self, record): parsed_body["Plaintext"] = _REDACTED cast(tuple, record.args)[-1]["body"] = json.dumps(parsed_body, sort_keys=True) except Exception: # pylint: disable=broad-except - return + pass - def __is_kms_response_with_plaintext(self, record): # pylint: disable=no-self-use + def __is_kms_response_with_plaintext(self, record): # type: (logging.LogRecord) -> bool """Determine if a record contains a KMS response with plaintext. @@ -111,7 +112,7 @@ def __redact_key_from_response(self, record): new_args = (json.dumps(parsed_body, sort_keys=True),) + cast(tuple, record.args)[1:] record.args = new_args except Exception: # pylint: disable=broad-except - return + pass def __redact_record(self, record): # type: (logging.LogRecord) -> logging.LogRecord diff --git a/src/aws_encryption_sdk_cli/internal/master_key_parsing.py b/src/aws_encryption_sdk_cli/internal/master_key_parsing.py index c5bc471..3d71882 100644 --- a/src/aws_encryption_sdk_cli/internal/master_key_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/master_key_parsing.py @@ -59,13 +59,13 @@ def _discover_entry_points(): _LOGGER.info('Collecting plugin "%s" registered by "%s"', entry_point.name, dist_name) _LOGGER.debug( "Plugin details: %s", - dict( - name=entry_point.name, - module_name=module_name, - attrs=[attr] if attr else [], - extras=getattr(entry_point, "extras", ()), - dist=dist_name, - ), + { + "name": entry_point.name, + "module_name": module_name, + "attrs": [attr] if attr else [], + "extras": getattr(entry_point, "extras", ()), + "dist": dist_name, + }, ) if PLUGIN_NAMESPACE_DIVIDER in entry_point.name: diff --git a/src/pylintrc b/src/pylintrc index 2116655..6fca4d8 100644 --- a/src/pylintrc +++ b/src/pylintrc @@ -2,7 +2,6 @@ # Disabling messages that we either don't care about # for tests or are necessary to break for tests. disable = - bad-continuation, # we let black handle this ungrouped-imports, # we let black handle this duplicate-code, # we have several functions in io_handling with similar profiles # All below are disabled because we need to support Python 2 diff --git a/test/integration/integration_test_utils.py b/test/integration/integration_test_utils.py index 2697aec..e967329 100644 --- a/test/integration/integration_test_utils.py +++ b/test/integration/integration_test_utils.py @@ -14,7 +14,7 @@ import logging import os import platform -from distutils.spawn import find_executable # distutils confuses pylint: disable=import-error,no-name-in-module +import shutil import pytest import six @@ -30,10 +30,9 @@ def is_windows(): def aws_encryption_cli_is_findable(): - path = find_executable("aws-encryption-cli") + path = shutil.which("aws-encryption-cli") if path is None: - UserWarning("aws-encryption-cli executable could not be found") - return False + raise UserWarning("aws-encryption-cli executable could not be found") return True diff --git a/test/pylintrc b/test/pylintrc index 71b8420..3a7cb20 100644 --- a/test/pylintrc +++ b/test/pylintrc @@ -5,7 +5,6 @@ # C0103 : invalid-name (we prefer long, descriptive, names for tests) # C0111 : missing-docstring (we don't write docstrings for tests) # C0209: consider-using-f-string (raised when using string instead of a fstring) -# C0330 : bad-continuation (we let black handle this) # C0412 : ungrouped-imports (we let isort handle this) # E1101 : no-member (raised on patched objects with mock checks) # R0205 : useless-object-inheritance (we need to support Python 2, so no, not useless) @@ -15,10 +14,7 @@ # W0212 : protected-access (raised when calling _ methods) # W0621 : redefined-outer-name (raised when using pytest-mock) # W0613 : unused-argument (raised when patches are needed but not called) -# D101 : Missing docstring in public class (For tests, classes are created for logical grouping) -# D102 : Missing docstring in public method (For tests, methods are created for logical grouping) -# R0201 : No self use (For Tests, classes are created for logical grouping) -disable = C0103, C0111, C0209, C0330, C0412, E1101, R0205, R0801, R0903, R0914, W0212, W0621, W0613, D102, D101, R0201 +disable = C0103, C0111, C0209, C0412, E1101, R0205, R0801, R0903, R0914, W0212, W0621, W0613 [VARIABLES] additional-builtins = raw_input diff --git a/test/unit/internal/test_io_handling.py b/test/unit/internal/test_io_handling.py index e8e587e..8ce60bc 100644 --- a/test/unit/internal/test_io_handling.py +++ b/test/unit/internal/test_io_handling.py @@ -96,18 +96,18 @@ def patch_json_ready_header_auth(mocker): return io_handling.json_ready_header_auth -GOOD_IOHANDLER_KWARGS = dict( - metadata_writer=metadata.MetadataWriter(True)(), - interactive=False, - no_overwrite=False, - decode_input=False, - encode_output=False, - required_encryption_context={}, - required_encryption_context_keys=[], - commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT, - buffer_output=False, - max_encrypted_data_keys=None, -) +GOOD_IOHANDLER_KWARGS = { + "metadata_writer": metadata.MetadataWriter(True)(), + "interactive": False, + "no_overwrite": False, + "decode_input": False, + "encode_output": False, + "required_encryption_context": {}, + "required_enc_context_keys": [], + "commitment_policy": CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT, + "buffer_output": False, + "max_encrypted_data_keys": None, +} @pytest.fixture @@ -196,15 +196,15 @@ def test_iohandler_attrs_good(): @pytest.mark.parametrize( "kwargs", ( - dict(metadata_writer="not a MetadataWriter"), - dict(interactive="not a bool"), - dict(no_overwrite="not a bool"), - dict(decode_input="not a bool"), - dict(encode_output="not a bool"), - dict(encryption_context="not a dict"), - dict(required_encryption_context_keys="not a list"), - dict(commitment_policy="not a CommitmentPolicy"), - dict(buffer_output="not a bool"), + {"metadata_writer": "not a MetadataWriter"}, + {"interactive": "not a bool"}, + {"no_overwrite": "not a bool"}, + {"decode_input": "not a bool"}, + {"encode_output": "not a bool"}, + {"encryption_context": "not a dict"}, + {"required_enc_context_keys": "not a list"}, + {"commitment_policy": "not a CommitmentPolicy"}, + {"buffer_output": "not a bool"}, ), ) def test_iohandler_attrs_fail(kwargs): @@ -412,7 +412,7 @@ def test_f_should_write_file_does_not_exist(tmpdir, interactive, no_overwrite): assert not os.path.exists(str(target)) # Should always be true regardless of input if file does not exist kwargs = GOOD_IOHANDLER_KWARGS.copy() - kwargs.update(dict(interactive=interactive, no_overwrite=no_overwrite)) + kwargs.update({"interactive": interactive, "no_overwrite": no_overwrite}) handler = io_handling.IOHandler(**kwargs) assert handler._should_write_file(str(target)) @@ -430,12 +430,12 @@ def test_f_should_write_file_does_not_exist(tmpdir, interactive, no_overwrite): (False, False, None, True), # interactive is not set, and no_overwrite is not set ), ) -def test_should_write_file_does_exist(tmpdir, patch_input, interactive, no_overwrite, user_input, expected): +def test_should_write_file_does_exist(tmpdir, patch_input, interactive, no_overwrite, user_input, expected): # pylint: disable=too-many-positional-arguments target_file = tmpdir.join("target") target_file.write(b"") patch_input.return_value = user_input kwargs = GOOD_IOHANDLER_KWARGS.copy() - kwargs.update(dict(interactive=interactive, no_overwrite=no_overwrite)) + kwargs.update({"interactive": interactive, "no_overwrite": no_overwrite}) handler = io_handling.IOHandler(**kwargs) should_write = handler._should_write_file(str(target_file)) @@ -463,19 +463,19 @@ def test_should_write_file_does_exist(tmpdir, patch_input, interactive, no_overw ("decrypt-unsigned", True, True, 1.0), ), ) -def test_process_single_file( +def test_process_single_file( # pylint: disable=too-many-positional-arguments tmpdir, patch_process_single_operation, mode, decode_input, encode_output, expected_multiplier ): patch_process_single_operation.return_value = identifiers.OperationResult.SUCCESS source = tmpdir.join("source") source.write("some data") kwargs = GOOD_IOHANDLER_KWARGS.copy() - kwargs.update(dict(decode_input=decode_input, encode_output=encode_output)) + kwargs.update({"decode_input": decode_input, "encode_output": encode_output}) handler = io_handling.IOHandler(**kwargs) destination = tmpdir.join("destination") - initial_kwargs = dict(mode=mode, a=sentinel.a, b=sentinel.b) + initial_kwargs = {"mode": mode, "a": sentinel.a, "b": sentinel.b} expected_length = int(os.path.getsize(str(source)) * expected_multiplier) - updated_kwargs = dict(mode=mode, a=sentinel.a, b=sentinel.b, source_length=expected_length) + updated_kwargs = {"mode": mode, "a": sentinel.a, "b": sentinel.b, "source_length": expected_length} with patch("aws_encryption_sdk_cli.internal.io_handling.open", create=True) as mock_open: handler.process_single_file(stream_args=initial_kwargs, source=str(source), destination=str(destination)) mock_open.assert_called_once_with(str(source), "rb") diff --git a/test/unit/internal/test_metadata.py b/test/unit/internal/test_metadata.py index 547017e..adf95b4 100644 --- a/test/unit/internal/test_metadata.py +++ b/test/unit/internal/test_metadata.py @@ -25,22 +25,22 @@ from aws_encryption_sdk_cli.internal import metadata pytestmark = [pytest.mark.unit, pytest.mark.local] -GOOD_INIT_KWARGS = dict(suppress_output=False) +GOOD_INIT_KWARGS = {"suppress_output": False} @pytest.mark.parametrize( "init_kwargs, call_kwargs", ( - (dict(suppress_output=True), {}), - (dict(suppress_output=False), dict(output_file="-")), - (dict(suppress_output=False), dict(output_file="asdf")), + ({"suppress_output": True}, {}), + ({"suppress_output": False}, {"output_file": "-"}), + ({"suppress_output": False}, {"output_file": "asdf"}), ), ) def test_attrs_good(init_kwargs, call_kwargs): metadata.MetadataWriter(**init_kwargs)(**call_kwargs) -@pytest.mark.parametrize("init_kwargs_patch, error_type", ((dict(suppress_output=None), TypeError),)) +@pytest.mark.parametrize("init_kwargs_patch, error_type", (({"suppress_output": None}, TypeError),)) def test_attrs_fail(init_kwargs_patch, error_type): """Verifying that validators are applied because we overwrite attrs init.""" init_kwargs = GOOD_INIT_KWARGS.copy() @@ -52,7 +52,7 @@ def test_attrs_fail(init_kwargs_patch, error_type): @pytest.mark.parametrize( "init_kwargs, call_kwargs, error_type, error_message", - ((dict(suppress_output=False), {}, TypeError, r"output_file cannot be None when suppress_output is False"),), + (({"suppress_output": False}, {}, TypeError, r"output_file cannot be None when suppress_output is False"),), ) def test_custom_fail(init_kwargs, call_kwargs, error_type, error_message): with pytest.raises(error_type) as excinfo: From 12fd93310d07f1922df2992ba35b64df768168ec Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 12:03:26 -0800 Subject: [PATCH 15/18] Revert "fix: lint fix using Q" This reverts commit 43ec2aae3c647985e172489445a44a0dac3c0aeb. --- dev_requirements/linter-requirements.txt | 2 +- src/aws_encryption_sdk_cli/__init__.py | 2 +- .../internal/arg_parsing.py | 5 +- .../internal/io_handling.py | 32 +++++------ .../internal/logging_utils.py | 13 ++--- .../internal/master_key_parsing.py | 14 ++--- src/pylintrc | 1 + test/integration/integration_test_utils.py | 7 ++- test/pylintrc | 6 +- test/unit/internal/test_io_handling.py | 56 +++++++++---------- test/unit/internal/test_metadata.py | 12 ++-- 11 files changed, 76 insertions(+), 74 deletions(-) diff --git a/dev_requirements/linter-requirements.txt b/dev_requirements/linter-requirements.txt index deee2ae..abc5682 100644 --- a/dev_requirements/linter-requirements.txt +++ b/dev_requirements/linter-requirements.txt @@ -7,7 +7,7 @@ flake8-print==4.0.0 isort==5.10.1 mock==4.0.3 pyflakes==2.4.0 -pylint==4.0.3 +pylint==3.0.3 pytest==7.4.0 pytest-cov==4.1.0 pytest-mock==3.11.1 diff --git a/src/aws_encryption_sdk_cli/__init__.py b/src/aws_encryption_sdk_cli/__init__.py index 38a6349..115cff6 100644 --- a/src/aws_encryption_sdk_cli/__init__.py +++ b/src/aws_encryption_sdk_cli/__init__.py @@ -184,7 +184,7 @@ def process_cli_request(stream_args, parsed_args): # noqa: C901 decode_input=parsed_args.decode, encode_output=parsed_args.encode, required_encryption_context=parsed_args.encryption_context, - required_enc_context_keys=parsed_args.required_encryption_context_keys, + required_encryption_context_keys=parsed_args.required_encryption_context_keys, commitment_policy=commitment_policy, buffer_output=parsed_args.buffer, max_encrypted_data_keys=parsed_args.max_encrypted_data_keys, diff --git a/src/aws_encryption_sdk_cli/internal/arg_parsing.py b/src/aws_encryption_sdk_cli/internal/arg_parsing.py index 0f983cf..f87dde9 100644 --- a/src/aws_encryption_sdk_cli/internal/arg_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/arg_parsing.py @@ -40,8 +40,7 @@ RAW_CONFIG, ) except ImportError: # pragma: no cover - def cast(typ, val): # noqa pylint: disable=invalid-name,missing-function-docstring,unused-argument - return val + cast = lambda typ, val: val # noqa pylint: disable=invalid-name # We only actually need the other imports when running the mypy checks __all__ = ("parse_args",) @@ -665,6 +664,6 @@ def parse_args(raw_args=None): if parsed_args.caching is not None: parsed_args.caching = _process_caching_config(parsed_args.caching) except ParameterParseError as error: - parser.error(str(error)) + parser.error(*error.args) return parsed_args diff --git a/src/aws_encryption_sdk_cli/internal/io_handling.py b/src/aws_encryption_sdk_cli/internal/io_handling.py index 2c690f1..e3bdc88 100644 --- a/src/aws_encryption_sdk_cli/internal/io_handling.py +++ b/src/aws_encryption_sdk_cli/internal/io_handling.py @@ -34,8 +34,7 @@ from aws_encryption_sdk_cli.internal.mypy_types import SOURCE, STREAM_KWARGS # noqa pylint: disable=unused-import except ImportError: # pragma: no cover - def cast(typ, val): # noqa pylint: disable=invalid-name,missing-function-docstring,unused-argument - return val + cast = lambda typ, val: val # noqa pylint: disable=invalid-name IO = None # type: ignore # We only actually need the other imports when running the mypy checks @@ -192,10 +191,9 @@ def __init__( # noqa pylint: disable=too-many-arguments interactive, # type: bool no_overwrite, # type: bool decode_input, # type: bool - *, encode_output, # type: bool required_encryption_context, # type: Dict[str, str] - required_enc_context_keys, # type: List[str] + required_encryption_context_keys, # type: List[str] commitment_policy, # type: CommitmentPolicy buffer_output, max_encrypted_data_keys, # type: Union[None, int] @@ -211,7 +209,7 @@ def __init__( # noqa pylint: disable=too-many-arguments self.decode_input = decode_input self.encode_output = encode_output self.required_encryption_context = required_encryption_context - self.required_encryption_context_keys = required_enc_context_keys + self.required_encryption_context_keys = required_encryption_context_keys # pylint: disable=invalid-name self.buffer_output = buffer_output self.client = aws_encryption_sdk.EncryptionSDKClient( commitment_policy=commitment_policy, @@ -235,12 +233,12 @@ def _single_io_write(self, stream_args, source, destination_writer): destination_writer, self.encode_output ) as _destination: # noqa pylint: disable=line-too-long with self.client.stream(source=_source, **stream_args) as handler, self.metadata_writer as metadata: - metadata_kwargs = { - "mode": stream_args["mode"], - "input": source.name, - "output": destination_writer.name, - "header": json_ready_header(handler.header), - } + metadata_kwargs = dict( + mode=stream_args["mode"], + input=source.name, + output=destination_writer.name, + header=json_ready_header(handler.header), + ) try: header_auth = handler.header_auth except AttributeError: @@ -258,12 +256,12 @@ def _single_io_write(self, stream_args, source, destination_writer): "Skipping decrypt because discovered encryption context did not match required elements." ) metadata_kwargs.update( - { - "skipped": True, - "reason": "Missing encryption context key or value", - "missing_encryption_context_keys": list(missing_keys), - "missing_encryption_context_pairs": list(missing_pairs), - } + dict( + skipped=True, + reason="Missing encryption context key or value", + missing_encryption_context_keys=list(missing_keys), + missing_encryption_context_pairs=list(missing_pairs), + ) ) metadata.write_metadata(**metadata_kwargs) return OperationResult.FAILED_VALIDATION diff --git a/src/aws_encryption_sdk_cli/internal/logging_utils.py b/src/aws_encryption_sdk_cli/internal/logging_utils.py index bde0753..0310d25 100644 --- a/src/aws_encryption_sdk_cli/internal/logging_utils.py +++ b/src/aws_encryption_sdk_cli/internal/logging_utils.py @@ -19,8 +19,7 @@ try: # Python 3.5.0 and 3.5.1 have incompatible typing modules from typing import Dict, Sequence, Text, Union, cast # noqa pylint: disable=unused-import except ImportError: # pragma: no cover - def cast(typ, val): # noqa pylint: disable=invalid-name,missing-function-docstring,unused-argument - return val + cast = lambda typ, val: val # noqa pylint: disable=invalid-name # We only actually need the other imports when running the mypy checks __all__ = ("setup_logger", "LOGGER_NAME") @@ -34,7 +33,7 @@ def cast(typ, val): # noqa pylint: disable=invalid-name,missing-function-docstr class _KMSKeyRedactingFormatter(logging.Formatter): """Log formatter that redacts ``Plaintext`` values from KMS request and response bodies.""" - def __to_str(self, value): + def __to_str(self, value): # pylint: disable=no-self-use # type: (Union[Text, str, bytes]) -> Text """Converts bytes or str to str. @@ -46,7 +45,7 @@ def __to_str(self, value): return codecs.decode(value, "utf-8") return value - def __is_kms_encrypt_request(self, record): + def __is_kms_encrypt_request(self, record): # pylint: disable=no-self-use # type: (logging.LogRecord) -> bool """Determine if a record contains a kms:Encrypt request. @@ -77,9 +76,9 @@ def __redact_encrypt_request(self, record): parsed_body["Plaintext"] = _REDACTED cast(tuple, record.args)[-1]["body"] = json.dumps(parsed_body, sort_keys=True) except Exception: # pylint: disable=broad-except - pass + return - def __is_kms_response_with_plaintext(self, record): + def __is_kms_response_with_plaintext(self, record): # pylint: disable=no-self-use # type: (logging.LogRecord) -> bool """Determine if a record contains a KMS response with plaintext. @@ -112,7 +111,7 @@ def __redact_key_from_response(self, record): new_args = (json.dumps(parsed_body, sort_keys=True),) + cast(tuple, record.args)[1:] record.args = new_args except Exception: # pylint: disable=broad-except - pass + return def __redact_record(self, record): # type: (logging.LogRecord) -> logging.LogRecord diff --git a/src/aws_encryption_sdk_cli/internal/master_key_parsing.py b/src/aws_encryption_sdk_cli/internal/master_key_parsing.py index 3d71882..c5bc471 100644 --- a/src/aws_encryption_sdk_cli/internal/master_key_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/master_key_parsing.py @@ -59,13 +59,13 @@ def _discover_entry_points(): _LOGGER.info('Collecting plugin "%s" registered by "%s"', entry_point.name, dist_name) _LOGGER.debug( "Plugin details: %s", - { - "name": entry_point.name, - "module_name": module_name, - "attrs": [attr] if attr else [], - "extras": getattr(entry_point, "extras", ()), - "dist": dist_name, - }, + dict( + name=entry_point.name, + module_name=module_name, + attrs=[attr] if attr else [], + extras=getattr(entry_point, "extras", ()), + dist=dist_name, + ), ) if PLUGIN_NAMESPACE_DIVIDER in entry_point.name: diff --git a/src/pylintrc b/src/pylintrc index 6fca4d8..2116655 100644 --- a/src/pylintrc +++ b/src/pylintrc @@ -2,6 +2,7 @@ # Disabling messages that we either don't care about # for tests or are necessary to break for tests. disable = + bad-continuation, # we let black handle this ungrouped-imports, # we let black handle this duplicate-code, # we have several functions in io_handling with similar profiles # All below are disabled because we need to support Python 2 diff --git a/test/integration/integration_test_utils.py b/test/integration/integration_test_utils.py index e967329..2697aec 100644 --- a/test/integration/integration_test_utils.py +++ b/test/integration/integration_test_utils.py @@ -14,7 +14,7 @@ import logging import os import platform -import shutil +from distutils.spawn import find_executable # distutils confuses pylint: disable=import-error,no-name-in-module import pytest import six @@ -30,9 +30,10 @@ def is_windows(): def aws_encryption_cli_is_findable(): - path = shutil.which("aws-encryption-cli") + path = find_executable("aws-encryption-cli") if path is None: - raise UserWarning("aws-encryption-cli executable could not be found") + UserWarning("aws-encryption-cli executable could not be found") + return False return True diff --git a/test/pylintrc b/test/pylintrc index 3a7cb20..71b8420 100644 --- a/test/pylintrc +++ b/test/pylintrc @@ -5,6 +5,7 @@ # C0103 : invalid-name (we prefer long, descriptive, names for tests) # C0111 : missing-docstring (we don't write docstrings for tests) # C0209: consider-using-f-string (raised when using string instead of a fstring) +# C0330 : bad-continuation (we let black handle this) # C0412 : ungrouped-imports (we let isort handle this) # E1101 : no-member (raised on patched objects with mock checks) # R0205 : useless-object-inheritance (we need to support Python 2, so no, not useless) @@ -14,7 +15,10 @@ # W0212 : protected-access (raised when calling _ methods) # W0621 : redefined-outer-name (raised when using pytest-mock) # W0613 : unused-argument (raised when patches are needed but not called) -disable = C0103, C0111, C0209, C0412, E1101, R0205, R0801, R0903, R0914, W0212, W0621, W0613 +# D101 : Missing docstring in public class (For tests, classes are created for logical grouping) +# D102 : Missing docstring in public method (For tests, methods are created for logical grouping) +# R0201 : No self use (For Tests, classes are created for logical grouping) +disable = C0103, C0111, C0209, C0330, C0412, E1101, R0205, R0801, R0903, R0914, W0212, W0621, W0613, D102, D101, R0201 [VARIABLES] additional-builtins = raw_input diff --git a/test/unit/internal/test_io_handling.py b/test/unit/internal/test_io_handling.py index 8ce60bc..e8e587e 100644 --- a/test/unit/internal/test_io_handling.py +++ b/test/unit/internal/test_io_handling.py @@ -96,18 +96,18 @@ def patch_json_ready_header_auth(mocker): return io_handling.json_ready_header_auth -GOOD_IOHANDLER_KWARGS = { - "metadata_writer": metadata.MetadataWriter(True)(), - "interactive": False, - "no_overwrite": False, - "decode_input": False, - "encode_output": False, - "required_encryption_context": {}, - "required_enc_context_keys": [], - "commitment_policy": CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT, - "buffer_output": False, - "max_encrypted_data_keys": None, -} +GOOD_IOHANDLER_KWARGS = dict( + metadata_writer=metadata.MetadataWriter(True)(), + interactive=False, + no_overwrite=False, + decode_input=False, + encode_output=False, + required_encryption_context={}, + required_encryption_context_keys=[], + commitment_policy=CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT, + buffer_output=False, + max_encrypted_data_keys=None, +) @pytest.fixture @@ -196,15 +196,15 @@ def test_iohandler_attrs_good(): @pytest.mark.parametrize( "kwargs", ( - {"metadata_writer": "not a MetadataWriter"}, - {"interactive": "not a bool"}, - {"no_overwrite": "not a bool"}, - {"decode_input": "not a bool"}, - {"encode_output": "not a bool"}, - {"encryption_context": "not a dict"}, - {"required_enc_context_keys": "not a list"}, - {"commitment_policy": "not a CommitmentPolicy"}, - {"buffer_output": "not a bool"}, + dict(metadata_writer="not a MetadataWriter"), + dict(interactive="not a bool"), + dict(no_overwrite="not a bool"), + dict(decode_input="not a bool"), + dict(encode_output="not a bool"), + dict(encryption_context="not a dict"), + dict(required_encryption_context_keys="not a list"), + dict(commitment_policy="not a CommitmentPolicy"), + dict(buffer_output="not a bool"), ), ) def test_iohandler_attrs_fail(kwargs): @@ -412,7 +412,7 @@ def test_f_should_write_file_does_not_exist(tmpdir, interactive, no_overwrite): assert not os.path.exists(str(target)) # Should always be true regardless of input if file does not exist kwargs = GOOD_IOHANDLER_KWARGS.copy() - kwargs.update({"interactive": interactive, "no_overwrite": no_overwrite}) + kwargs.update(dict(interactive=interactive, no_overwrite=no_overwrite)) handler = io_handling.IOHandler(**kwargs) assert handler._should_write_file(str(target)) @@ -430,12 +430,12 @@ def test_f_should_write_file_does_not_exist(tmpdir, interactive, no_overwrite): (False, False, None, True), # interactive is not set, and no_overwrite is not set ), ) -def test_should_write_file_does_exist(tmpdir, patch_input, interactive, no_overwrite, user_input, expected): # pylint: disable=too-many-positional-arguments +def test_should_write_file_does_exist(tmpdir, patch_input, interactive, no_overwrite, user_input, expected): target_file = tmpdir.join("target") target_file.write(b"") patch_input.return_value = user_input kwargs = GOOD_IOHANDLER_KWARGS.copy() - kwargs.update({"interactive": interactive, "no_overwrite": no_overwrite}) + kwargs.update(dict(interactive=interactive, no_overwrite=no_overwrite)) handler = io_handling.IOHandler(**kwargs) should_write = handler._should_write_file(str(target_file)) @@ -463,19 +463,19 @@ def test_should_write_file_does_exist(tmpdir, patch_input, interactive, no_overw ("decrypt-unsigned", True, True, 1.0), ), ) -def test_process_single_file( # pylint: disable=too-many-positional-arguments +def test_process_single_file( tmpdir, patch_process_single_operation, mode, decode_input, encode_output, expected_multiplier ): patch_process_single_operation.return_value = identifiers.OperationResult.SUCCESS source = tmpdir.join("source") source.write("some data") kwargs = GOOD_IOHANDLER_KWARGS.copy() - kwargs.update({"decode_input": decode_input, "encode_output": encode_output}) + kwargs.update(dict(decode_input=decode_input, encode_output=encode_output)) handler = io_handling.IOHandler(**kwargs) destination = tmpdir.join("destination") - initial_kwargs = {"mode": mode, "a": sentinel.a, "b": sentinel.b} + initial_kwargs = dict(mode=mode, a=sentinel.a, b=sentinel.b) expected_length = int(os.path.getsize(str(source)) * expected_multiplier) - updated_kwargs = {"mode": mode, "a": sentinel.a, "b": sentinel.b, "source_length": expected_length} + updated_kwargs = dict(mode=mode, a=sentinel.a, b=sentinel.b, source_length=expected_length) with patch("aws_encryption_sdk_cli.internal.io_handling.open", create=True) as mock_open: handler.process_single_file(stream_args=initial_kwargs, source=str(source), destination=str(destination)) mock_open.assert_called_once_with(str(source), "rb") diff --git a/test/unit/internal/test_metadata.py b/test/unit/internal/test_metadata.py index adf95b4..547017e 100644 --- a/test/unit/internal/test_metadata.py +++ b/test/unit/internal/test_metadata.py @@ -25,22 +25,22 @@ from aws_encryption_sdk_cli.internal import metadata pytestmark = [pytest.mark.unit, pytest.mark.local] -GOOD_INIT_KWARGS = {"suppress_output": False} +GOOD_INIT_KWARGS = dict(suppress_output=False) @pytest.mark.parametrize( "init_kwargs, call_kwargs", ( - ({"suppress_output": True}, {}), - ({"suppress_output": False}, {"output_file": "-"}), - ({"suppress_output": False}, {"output_file": "asdf"}), + (dict(suppress_output=True), {}), + (dict(suppress_output=False), dict(output_file="-")), + (dict(suppress_output=False), dict(output_file="asdf")), ), ) def test_attrs_good(init_kwargs, call_kwargs): metadata.MetadataWriter(**init_kwargs)(**call_kwargs) -@pytest.mark.parametrize("init_kwargs_patch, error_type", (({"suppress_output": None}, TypeError),)) +@pytest.mark.parametrize("init_kwargs_patch, error_type", ((dict(suppress_output=None), TypeError),)) def test_attrs_fail(init_kwargs_patch, error_type): """Verifying that validators are applied because we overwrite attrs init.""" init_kwargs = GOOD_INIT_KWARGS.copy() @@ -52,7 +52,7 @@ def test_attrs_fail(init_kwargs_patch, error_type): @pytest.mark.parametrize( "init_kwargs, call_kwargs, error_type, error_message", - (({"suppress_output": False}, {}, TypeError, r"output_file cannot be None when suppress_output is False"),), + ((dict(suppress_output=False), {}, TypeError, r"output_file cannot be None when suppress_output is False"),), ) def test_custom_fail(init_kwargs, call_kwargs, error_type, error_message): with pytest.raises(error_type) as excinfo: From ab10978d73c21800845e05cdd0a4fbdd9751cd0c Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 12:11:13 -0800 Subject: [PATCH 16/18] fix: pylint errors only --- src/aws_encryption_sdk_cli/internal/arg_parsing.py | 2 +- src/pylintrc | 1 + test/pylintrc | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/aws_encryption_sdk_cli/internal/arg_parsing.py b/src/aws_encryption_sdk_cli/internal/arg_parsing.py index f87dde9..15a8de8 100644 --- a/src/aws_encryption_sdk_cli/internal/arg_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/arg_parsing.py @@ -664,6 +664,6 @@ def parse_args(raw_args=None): if parsed_args.caching is not None: parsed_args.caching = _process_caching_config(parsed_args.caching) except ParameterParseError as error: - parser.error(*error.args) + parser.error(*error.args) # pylint: disable=no-value-for-parameter return parsed_args diff --git a/src/pylintrc b/src/pylintrc index 2116655..cf052ec 100644 --- a/src/pylintrc +++ b/src/pylintrc @@ -1,4 +1,5 @@ [MESSAGES CONTROL] +errors-only = yes # Disabling messages that we either don't care about # for tests or are necessary to break for tests. disable = diff --git a/test/pylintrc b/test/pylintrc index 71b8420..87fcba1 100644 --- a/test/pylintrc +++ b/test/pylintrc @@ -1,4 +1,5 @@ [MESSAGES CONTROL] +errors-only = yes # Disabling messages that we either don't care about # for tests or are necessary to break for tests. # From f018867a445c9f2d05e22fdda19be4497a4bd55a Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 12:23:01 -0800 Subject: [PATCH 17/18] fix: flake8 --- dev_requirements/linter-requirements.txt | 8 ++++---- src/aws_encryption_sdk_cli/internal/arg_parsing.py | 2 +- src/aws_encryption_sdk_cli/internal/io_handling.py | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dev_requirements/linter-requirements.txt b/dev_requirements/linter-requirements.txt index abc5682..0eea353 100644 --- a/dev_requirements/linter-requirements.txt +++ b/dev_requirements/linter-requirements.txt @@ -1,12 +1,12 @@ bandit==1.9.2 black==22.8.0 doc8==1.0.0 -flake8==4.0.1 -flake8-docstrings==1.6.0 -flake8-print==4.0.0 +flake8==5.0.4 +flake8-docstrings==1.7.0 +flake8-print==5.0.0 isort==5.10.1 mock==4.0.3 -pyflakes==2.4.0 +pyflakes==2.5.0 pylint==3.0.3 pytest==7.4.0 pytest-cov==4.1.0 diff --git a/src/aws_encryption_sdk_cli/internal/arg_parsing.py b/src/aws_encryption_sdk_cli/internal/arg_parsing.py index 15a8de8..8926458 100644 --- a/src/aws_encryption_sdk_cli/internal/arg_parsing.py +++ b/src/aws_encryption_sdk_cli/internal/arg_parsing.py @@ -664,6 +664,6 @@ def parse_args(raw_args=None): if parsed_args.caching is not None: parsed_args.caching = _process_caching_config(parsed_args.caching) except ParameterParseError as error: - parser.error(*error.args) # pylint: disable=no-value-for-parameter + parser.error(*error.args) # pylint: disable=no-value-for-parameter return parsed_args diff --git a/src/aws_encryption_sdk_cli/internal/io_handling.py b/src/aws_encryption_sdk_cli/internal/io_handling.py index e3bdc88..fdb0e8b 100644 --- a/src/aws_encryption_sdk_cli/internal/io_handling.py +++ b/src/aws_encryption_sdk_cli/internal/io_handling.py @@ -374,7 +374,8 @@ def process_single_file(self, stream_args, source, destination): operation_result = OperationResult.FAILED raise finally: - if operation_result.needs_cleanup and destination != "-": # pylint: disable=no-member + # pylint: disable=no-member, used-before-assignment + if operation_result.needs_cleanup and destination != "-": _LOGGER.warning("Operation failed: deleting output file: %s", destination) try: os.remove(destination) From a7a23ac1ac5143d585cfd9f12aadea58088a5b06 Mon Sep 17 00:00:00 2001 From: Shubham Chaturvedi Date: Wed, 26 Nov 2025 12:28:01 -0800 Subject: [PATCH 18/18] CI --- src/aws_encryption_sdk_cli/internal/io_handling.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/aws_encryption_sdk_cli/internal/io_handling.py b/src/aws_encryption_sdk_cli/internal/io_handling.py index fdb0e8b..fad7664 100644 --- a/src/aws_encryption_sdk_cli/internal/io_handling.py +++ b/src/aws_encryption_sdk_cli/internal/io_handling.py @@ -374,8 +374,7 @@ def process_single_file(self, stream_args, source, destination): operation_result = OperationResult.FAILED raise finally: - # pylint: disable=no-member, used-before-assignment - if operation_result.needs_cleanup and destination != "-": + if operation_result.needs_cleanup and destination != "-": # pylint:disable=no-member,used-before-assignment _LOGGER.warning("Operation failed: deleting output file: %s", destination) try: os.remove(destination)