diff --git a/.github/workflows/bootstrap.yml b/.github/workflows/bootstrap.yml index 583c7a2b..3c955cd9 100644 --- a/.github/workflows/bootstrap.yml +++ b/.github/workflows/bootstrap.yml @@ -16,7 +16,7 @@ jobs: build: strategy: matrix: - python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] + python-version: [ '3.10', '3.11', '3.12', '3.13', '3.14' ] # The type of runner that the job will run on runs-on: ubuntu-22.04 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 43b75bb6..cb874a2e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,7 +15,7 @@ jobs: build: strategy: matrix: - python-version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ] + python-version: [ '3.10', '3.11', '3.12', '3.13', '3.14' ] # The type of runner that the job will run on runs-on: ubuntu-22.04 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9b450243..a37fca3d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v6.0.0 hooks: - id: trailing-whitespace exclude: ^(.*\.age|.*\.gpg) @@ -27,14 +27,14 @@ repos: )$ - repo: https://github.com/pycqa/isort - rev: 5.12.0 + rev: 7.0.0 hooks: - id: isort name: isort (python) args: ["--profile", "black", "--filter-files"] - repo: https://github.com/psf/black - rev: 24.4.2 + rev: 26.1.0 hooks: - id: black exclude: diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 858b9cfc..f00f8247 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -8,7 +8,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.12" + python: "3.14" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" diff --git a/examples/api/requirements.lock b/examples/api/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/api/requirements.lock +++ b/examples/api/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/api/requirements.txt b/examples/api/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/api/requirements.txt +++ b/examples/api/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/django/components/django/component.py b/examples/django/components/django/component.py index 2ce8b45e..aa7097dc 100644 --- a/examples/django/components/django/component.py +++ b/examples/django/components/django/component.py @@ -8,7 +8,7 @@ class Django(Component): def configure(self): self.address = Address(self.host.fqdn, "8081") - self += AppEnv("3.8") + self += AppEnv("3.10") self += SyncDirectory("mysite", source="mysite") diff --git a/examples/django/requirements.lock b/examples/django/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/django/requirements.lock +++ b/examples/django/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/django/requirements.txt b/examples/django/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/django/requirements.txt +++ b/examples/django/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/durations/requirements.lock b/examples/durations/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/durations/requirements.lock +++ b/examples/durations/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/durations/requirements.txt b/examples/durations/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/durations/requirements.txt +++ b/examples/durations/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/errors/requirements.lock b/examples/errors/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/errors/requirements.lock +++ b/examples/errors/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/errors/requirements.txt b/examples/errors/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/errors/requirements.txt +++ b/examples/errors/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/errors2/requirements.lock b/examples/errors2/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/errors2/requirements.lock +++ b/examples/errors2/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/errors2/requirements.txt b/examples/errors2/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/errors2/requirements.txt +++ b/examples/errors2/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/errorsnohost/requirements.lock b/examples/errorsnohost/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/errorsnohost/requirements.lock +++ b/examples/errorsnohost/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/errorsnohost/requirements.txt b/examples/errorsnohost/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/errorsnohost/requirements.txt +++ b/examples/errorsnohost/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/ignores/requirements.lock b/examples/ignores/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/ignores/requirements.lock +++ b/examples/ignores/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/ignores/requirements.txt b/examples/ignores/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/ignores/requirements.txt +++ b/examples/ignores/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/largetempl/requirements.lock b/examples/largetempl/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/largetempl/requirements.lock +++ b/examples/largetempl/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/largetempl/requirements.txt b/examples/largetempl/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/largetempl/requirements.txt +++ b/examples/largetempl/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/package/requirements.lock b/examples/package/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/package/requirements.lock +++ b/examples/package/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/package/requirements.txt b/examples/package/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/package/requirements.txt +++ b/examples/package/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/sensitive-values/requirements.lock b/examples/sensitive-values/requirements.lock index 120d488f..cd4b8693 100644 --- a/examples/sensitive-values/requirements.lock +++ b/examples/sensitive-values/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.8.30 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.8 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/sensitive-values/requirements.txt b/examples/sensitive-values/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/sensitive-values/requirements.txt +++ b/examples/sensitive-values/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/sync_async/requirements.lock b/examples/sync_async/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/sync_async/requirements.lock +++ b/examples/sync_async/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/sync_async/requirements.txt b/examples/sync_async/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/sync_async/requirements.txt +++ b/examples/sync_async/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/tutorial-buildout/requirements.lock b/examples/tutorial-buildout/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/tutorial-buildout/requirements.lock +++ b/examples/tutorial-buildout/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/tutorial-buildout/requirements.txt b/examples/tutorial-buildout/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/tutorial-buildout/requirements.txt +++ b/examples/tutorial-buildout/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/tutorial-component/requirements.lock b/examples/tutorial-component/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/tutorial-component/requirements.lock +++ b/examples/tutorial-component/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/tutorial-component/requirements.txt b/examples/tutorial-component/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/tutorial-component/requirements.txt +++ b/examples/tutorial-component/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/tutorial-helloworld/requirements.lock b/examples/tutorial-helloworld/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/tutorial-helloworld/requirements.lock +++ b/examples/tutorial-helloworld/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/tutorial-helloworld/requirements.txt b/examples/tutorial-helloworld/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/tutorial-helloworld/requirements.txt +++ b/examples/tutorial-helloworld/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/tutorial-parallelize/requirements.lock b/examples/tutorial-parallelize/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/tutorial-parallelize/requirements.lock +++ b/examples/tutorial-parallelize/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/tutorial-parallelize/requirements.txt b/examples/tutorial-parallelize/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/tutorial-parallelize/requirements.txt +++ b/examples/tutorial-parallelize/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/tutorial-provision-container/requirements.lock b/examples/tutorial-provision-container/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/tutorial-provision-container/requirements.lock +++ b/examples/tutorial-provision-container/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/tutorial-provision-container/requirements.txt b/examples/tutorial-provision-container/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/tutorial-provision-container/requirements.txt +++ b/examples/tutorial-provision-container/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/tutorial-secrets/requirements.lock b/examples/tutorial-secrets/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/tutorial-secrets/requirements.lock +++ b/examples/tutorial-secrets/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/tutorial-secrets/requirements.txt b/examples/tutorial-secrets/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/tutorial-secrets/requirements.txt +++ b/examples/tutorial-secrets/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/vagrant-multi/requirements.lock b/examples/vagrant-multi/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/vagrant-multi/requirements.lock +++ b/examples/vagrant-multi/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/vagrant-multi/requirements.txt b/examples/vagrant-multi/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/vagrant-multi/requirements.txt +++ b/examples/vagrant-multi/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/vagrant/requirements.lock b/examples/vagrant/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/vagrant/requirements.lock +++ b/examples/vagrant/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/vagrant/requirements.txt b/examples/vagrant/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/vagrant/requirements.txt +++ b/examples/vagrant/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/venvs/environments/requirements.txt b/examples/venvs/environments/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/venvs/environments/requirements.txt +++ b/examples/venvs/environments/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/examples/venvs/requirements.lock b/examples/venvs/requirements.lock index 97853ff9..cd4b8693 100644 --- a/examples/venvs/requirements.lock +++ b/examples/venvs/requirements.lock @@ -1,19 +1,18 @@ -# appenv-requirements-hash: 92e251bc834f921c996b9af42180afdf00414e12ee57291b199a6127ff5e6897 +# appenv-requirements-hash: c3910787f9454456670405d816954ab6cde3b6a7dcd37bfe1f054cea0e9f2f42 -e ../../ ConfigUpdater==3.2 -Jinja2==3.1.4 -MarkupSafe==2.1.5 -PyYAML==6.0.1 -certifi==2024.7.4 -charset-normalizer==3.3.2 -execnet==2.0.2 -idna==3.7 -importlib-metadata==6.7.0 -importlib-resources==5.12.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +PyYAML==6.0.3 +certifi==2026.1.4 +charset-normalizer==3.4.4 +execnet==2.1.2 +idna==3.11 +importlib_metadata==8.7.1 +importlib_resources==6.5.2 py==1.11.0 remote-pdb==2.1.0 -requests==2.31.0 -setuptools==68.0.0 -typing_extensions==4.7.1 -urllib3==2.0.7 -zipp==3.15.0 +requests==2.32.5 +setuptools==80.10.1 +urllib3==2.6.3 +zipp==3.23.0 diff --git a/examples/venvs/requirements.txt b/examples/venvs/requirements.txt index 4b8c4092..ee5aeacc 100644 --- a/examples/venvs/requirements.txt +++ b/examples/venvs/requirements.txt @@ -1,2 +1,2 @@ -# appenv-python-preference: 3.7,3.8,3.9,3.10,3.11,3.12 +# appenv-python-preference: 3.10,3.11,3.12,3.13,3.14 -e ../../ diff --git a/pyproject.toml b/pyproject.toml index 599f700b..83bf1388 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.black] line-length = 80 -target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] +target-version = ['py310', 'py311', 'py312', 'py313', 'py314'] [tool.isort] profile = "black" diff --git a/requirements-dev.txt b/requirements-dev.txt index 72075c15..a0721d68 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,20 +1,20 @@ -e .[test] appdirs==1.4.4 -cfgv==3.2.0 -distlib==0.3.8 -filelock==3.12.2 -identify==1.5.9 -nodeenv==1.5.0 -packaging==24.0 -pluggy==1.2.0 -pre-commit==2.15.0 +cfgv==3.5.0 +distlib==0.4.0 +filelock==3.20.3 +identify==2.6.16 +nodeenv==1.10.0 +packaging==26.0 +pluggy==1.6.0 +pre-commit==4.5.1 py==1.11.0 -pyparsing==2.4.7 -pyproject-api==1.5.3 -PyYAML==6.0.1 -six==1.15.0 +pyparsing==3.3.2 +pyproject-api==1.10.0 +PyYAML==6.0.3 +six==1.17.0 toml==0.10.2 -tox==4.7.0 -virtualenv==20.26.6 -sphinx==5.3.0 +tox==4.34.1 +virtualenv==20.36.1 +sphinx==8.1.3 # 9.x requires Python 3.12+ recommonmark==0.7.1 diff --git a/setup.py b/setup.py index 95088305..12373fb5 100644 --- a/setup.py +++ b/setup.py @@ -51,17 +51,13 @@ License :: OSI Approved :: BSD 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 +Programming Language :: Python :: 3.13 +Programming Language :: Python :: 3.14 Programming Language :: Python :: 3 :: Only -"""[ - :-1 - ].split( - "\n" - ), +"""[:-1].split("\n"), description=__doc__.strip(), long_description=open("README.md").read(), long_description_content_type="text/markdown", @@ -70,5 +66,5 @@ include_package_data=True, zip_safe=False, test_suite="batou.tests", - python_requires=">=3.6", + python_requires=">=3.10", ) diff --git a/src/batou/deploy.py b/src/batou/deploy.py index f608d60a..ba65a582 100644 --- a/src/batou/deploy.py +++ b/src/batou/deploy.py @@ -317,7 +317,7 @@ def deploy(self): h for h in list(self.environment.hosts.values()) if not h.ignore ][0] - self.loop = asyncio.get_event_loop() + asyncio.set_event_loop(self.loop) self.taskpool = ThreadPoolExecutor(self.jobs) self.loop.set_default_executor(self.taskpool) self._launch_components(reference_node.root_dependencies()) diff --git a/src/batou/lib/buildout.py b/src/batou/lib/buildout.py index 26fadf66..44b173ee 100644 --- a/src/batou/lib/buildout.py +++ b/src/batou/lib/buildout.py @@ -20,6 +20,7 @@ class Buildout(Component): setuptools = None wheel = None pip = None + packaging = None version = None build_env = {} # XXX not frozen. :/ @@ -64,6 +65,9 @@ def configure(self): if self.pip: venv += Package("pip", version=self.pip) + if self.packaging: + venv += Package("packaging", version=self.packaging) + # Install without dependencies (that's just setuptools anyway), since # that could cause pip to pull in the latest version of setuptools, # regardless of the version we wanted to be installed above. diff --git a/src/batou/lib/download.py b/src/batou/lib/download.py index 8f8a9d87..79c1d0e8 100644 --- a/src/batou/lib/download.py +++ b/src/batou/lib/download.py @@ -49,9 +49,7 @@ def update(self): self._update_urllib() target_checksum = batou.utils.hash(self.target, self.checksum_function) - assert ( - self.checksum == target_checksum - ), """\ + assert self.checksum == target_checksum, """\ Checksum mismatch! expected: %s got: %s""" % ( diff --git a/src/batou/lib/mysql.py b/src/batou/lib/mysql.py index 1ccac402..c9e2470d 100644 --- a/src/batou/lib/mysql.py +++ b/src/batou/lib/mysql.py @@ -79,13 +79,11 @@ class Database(Component): admin_password = None def configure(self): - create_db = self.expand( - """\ + create_db = self.expand("""\ CREATE DATABASE IF NOT EXISTS {{component.database}} DEFAULT CHARACTER SET = '{{component.charset}}'; -""" - ) +""") self += Command(create_db, admin_password=self.admin_password) if self.base_import_file: @@ -112,21 +110,17 @@ class User(Component): def configure(self): - create = self.expand( - """\ + create = self.expand("""\ CREATE USER '{{component.user}}'@'{{component.allow_from_hostname}}'; -""" - ) - create_unless = self.expand( - """\ +""") + create_unless = self.expand("""\ SELECT * FROM user WHERE User = '{{component.user}}' AND Host = '{{component.allow_from_hostname}}'; -""" - ) +""") self += Command( create, unless=create_unless, admin_password=self.admin_password ) diff --git a/src/batou/lib/supervisor.py b/src/batou/lib/supervisor.py index fbf696ef..87d19545 100644 --- a/src/batou/lib/supervisor.py +++ b/src/batou/lib/supervisor.py @@ -169,9 +169,10 @@ def configure(self): class Supervisor(Component): address = Attribute(Address, default=ConfigString("localhost:9001")) - buildout_version = Attribute(default="3.0.1") + buildout_version = Attribute(default="5.1.1") setuptools_version = Attribute(default="68.0.0") wheel_version = Attribute(default="0.40.0") + packaging_version = Attribute(default="24.0") buildout_cfg = os.path.join( os.path.dirname(__file__), "resources", "supervisor.buildout.cfg" ) @@ -213,6 +214,7 @@ def configure(self): config=buildout_cfg, python="3", wheel=self.wheel_version, + packaging=self.packaging_version, ) self.program_config_dir = Directory("etc/supervisor.d", leading=True) diff --git a/src/batou/lib/tests/test_cmmi.py b/src/batou/lib/tests/test_cmmi.py index 0a5a0a29..2cfd7c77 100644 --- a/src/batou/lib/tests/test_cmmi.py +++ b/src/batou/lib/tests/test_cmmi.py @@ -76,11 +76,7 @@ def test_make_verifies_against_success_file(root): ''' open('Makefile', 'w').write(Makefile_template) -""".format( - sys.executable -).encode( - "ascii" -) +""".format(sys.executable).encode("ascii") @pytest.fixture diff --git a/src/batou/lib/tests/test_download.py b/src/batou/lib/tests/test_download.py index 14a136b5..a8c3f150 100644 --- a/src/batou/lib/tests/test_download.py +++ b/src/batou/lib/tests/test_download.py @@ -13,9 +13,10 @@ def test_verify_should_pass_checkum_function_to_hash(self): component = Download("url", checksum="foobar:1234") component.configure() - with mock.patch("os.path.exists") as exists, mock.patch( - "batou.utils.hash" - ) as buh: + with ( + mock.patch("os.path.exists") as exists, + mock.patch("batou.utils.hash") as buh, + ): exists.return_value = True try: component.verify() @@ -32,11 +33,11 @@ def test_configure_should_raise_valueerror_if_no_checksum_given(self): def test_update_should_raise_AssertionError_on_checksum_mismatch(self): download = Download("url", checksum="foobar:1234") download.configure() - with mock.patch( - "batou.lib.download.urlretrieve" - ) as retrieve, mock.patch("batou.utils.hash") as buh, self.assertRaises( - AssertionError - ) as err: + with ( + mock.patch("batou.lib.download.urlretrieve") as retrieve, + mock.patch("batou.utils.hash") as buh, + self.assertRaises(AssertionError) as err, + ): retrieve.return_value = "url", [] buh.return_value = "4321" download.update() diff --git a/src/batou/lib/tests/test_file.py b/src/batou/lib/tests/test_file.py index b37445d0..439d1d4b 100644 --- a/src/batou/lib/tests/test_file.py +++ b/src/batou/lib/tests/test_file.py @@ -489,21 +489,13 @@ def test_content_large_diff_logged(output, root): root.component.deploy() log = os.listdir(p.diff_dir)[0] with open(os.path.join(p.diff_dir, log)) as f: - assert ( - f.read() - == """\ + assert f.read() == """\ --- +++ @@ -1,21 +1,21 @@ -""" - + "\n".join(["-bsdf"] * 21) - + "\n" - + "\n".join(["+asdf"] * 21) - + "\n" - ) +""" + "\n".join(["-bsdf"] * 21) + "\n" + "\n".join(["+asdf"] * 21) + "\n" - assert output.backend.output == Ellipsis( - """\ + assert output.backend.output == Ellipsis("""\ 🚀 localhost: MyComponent > Content('work/mycomponent/path') More than 20 lines of diff. Showing first and last 5 lines. see ... for the full diff. @@ -518,21 +510,17 @@ def test_content_large_diff_logged(output, root): path +asdf path +asdf path +asdf -""" - ) +""") def test_json_content_data_given(root): p = JSONContent("target.json", data={"asdf": 1}) root.component += p root.component.deploy() - assert ( - p.content - == b"""\ + assert p.content == b"""\ { "asdf": 1 }""" - ) with open(p.path, "rb") as f: assert f.read() == p.content @@ -547,8 +535,7 @@ def test_json_diff(output, root): p.deploy() - assert output.backend.output == Ellipsis( - """\ + assert output.backend.output == Ellipsis("""\ 🚀 localhost: MyComponent > JSONContent('work/mycomponent/target.json') target.json --- target.json +++ @@ -557,8 +544,7 @@ def test_json_diff(output, root): target.json + "asdf": 1, target.json "bsdf": 2 target.json } -""" - ) +""") def test_json_diff_not_for_sensitive(output, root): @@ -572,12 +558,10 @@ def test_json_diff_not_for_sensitive(output, root): p.deploy() - assert output.backend.output == Ellipsis( - """\ + assert output.backend.output == Ellipsis("""\ 🚀 localhost: MyComponent > JSONContent('work/mycomponent/target.json') Not showing diff as it contains sensitive data. -""" - ) +""") def test_json_content_data_given_compact(root): @@ -597,16 +581,13 @@ def test_json_content_source_given(root): p = JSONContent("target.json", source="source.json") root.component += p root.component.deploy() - assert ( - p.content - == b"""\ + assert p.content == b"""\ [ 1, 2, 3, 4 ]""" - ) with open(p.path, "rb") as f: assert f.read() == p.content @@ -620,16 +601,13 @@ def test_json_content_delayed_source_given(root): f.write(json.dumps([1, 2, 3, 4])) root.component.deploy() - assert ( - p.content - == b"""\ + assert p.content == b"""\ [ 1, 2, 3, 4 ]""" - ) with open(p.path, "rb") as f: assert f.read() == p.content @@ -709,12 +687,9 @@ def test_yaml_content_data_given(root): p = YAMLContent("target.yaml", data={"asdf": 1}) root.component += p root.component.deploy() - assert ( - p.content - == b"""\ + assert p.content == b"""\ asdf: 1 """ - ) with open(p.path, "rb") as f: assert f.read() == p.content @@ -755,12 +730,10 @@ def test_yaml_diff_not_for_sensitive(output, root): p.deploy() - assert output.backend.output == Ellipsis( - """\ + assert output.backend.output == Ellipsis("""\ 🚀 localhost: MyComponent > YAMLContent('work/mycomponent/target.yaml') Not showing diff as it contains sensitive data. -""" - ) +""") def test_yaml_content_source_given(root): diff --git a/src/batou/lib/tests/test_nagios.py b/src/batou/lib/tests/test_nagios.py index bb980ff0..568be2da 100644 --- a/src/batou/lib/tests/test_nagios.py +++ b/src/batou/lib/tests/test_nagios.py @@ -11,8 +11,7 @@ def test_server_template(root): root.component |= service server = NagiosServer() root.component += server - assert ( - b"""\ + assert b"""\ # Generated from template; don't edit manually! # @@ -34,6 +33,4 @@ def test_server_template(root): dependent_service_description http } -""" - == server.sub_components[-1].content - ) +""" == server.sub_components[-1].content diff --git a/src/batou/main.py b/src/batou/main.py index fe90ea8c..a2751466 100644 --- a/src/batou/main.py +++ b/src/batou/main.py @@ -111,11 +111,9 @@ def main(args: Optional[list] = None) -> None: # SECRETS secrets = subparsers.add_parser( "secrets", - help=textwrap.dedent( - """ + help=textwrap.dedent(""" Manage encrypted secret files. Relies on age (or GPG) being installed and - configured correctly. """ - ), + configured correctly. """), ) secrets.set_defaults(func=secrets.print_usage) @@ -123,13 +121,11 @@ def main(args: Optional[list] = None) -> None: p = sp.add_parser( "edit", - help=textwrap.dedent( - """ + help=textwrap.dedent(""" Encrypted secrets file editor utility. Decrypts file, invokes the editor, and encrypts the file again. If called with a non-existent file name, a new encrypted file is created. - """ - ), + """), ) p.set_defaults(func=p.print_usage) @@ -205,13 +201,11 @@ def main(args: Optional[list] = None) -> None: # migrate migrate = subparsers.add_parser( "migrate", - help=textwrap.dedent( - """ + help=textwrap.dedent(""" Migrate the configuration to be compatible with the batou version used. Requires to commit the changes afterwards. Might show some additional upgrade steps which cannot be performed automatically. - """ - ), + """), ) migrate.set_defaults(func=migrate.print_usage) migrate.add_argument( diff --git a/src/batou/migrate/tests/test_migrate.py b/src/batou/migrate/tests/test_migrate.py index 7d997a2d..1f06fc42 100644 --- a/src/batou/migrate/tests/test_migrate.py +++ b/src/batou/migrate/tests/test_migrate.py @@ -54,12 +54,10 @@ def test_migrate__read_config__4(tmp_path): @pytest.fixture(scope="function") def migrations(tmp_path): """Create some simple migrations.""" - TEMPLATE = textwrap.dedent( - """ + TEMPLATE = textwrap.dedent(""" def migrate(output): pass - """ - ) + """) os.chdir(tmp_path) package = tmp_path / "package" package.mkdir() @@ -131,9 +129,7 @@ def test_migrate__main__1(tmp_path, migrations, capsys): """ main() # We explicitly test the output to the TerminalBackend. - assert ( - capsys.readouterr().out - == """\ + assert capsys.readouterr().out == """\ Current version: 0 ⚪ Version: 2299 @@ -145,7 +141,6 @@ def test_migrate__main__1(tmp_path, migrations, capsys): Reached version: 2411 """ - ) assert (tmp_path / CONFIG_FILE_NAME).exists() assert read_config() == 2411 @@ -155,13 +150,10 @@ def test_migrate__main__2(migrations, capsys): write_config(2411) main() # We explicitly test the output to the TerminalBackend. - assert ( - """\ + assert """\ Current version: 2411 Reached version: 2411 -""" - == capsys.readouterr().out - ) +""" == capsys.readouterr().out assert read_config() == 2411 diff --git a/src/batou/provision.py b/src/batou/provision.py index 8e7ed13e..107b51cf 100644 --- a/src/batou/provision.py +++ b/src/batou/provision.py @@ -138,8 +138,7 @@ def _prepare_ssh(self, host): f_target.write(f_packaged.read()) os.chmod(local_insecure_key, 0o600) - self._known_ssh_hosts[host.name] = ( - """ + self._known_ssh_hosts[host.name] = """ Host {hostname} {aliases} HostName {hostname} ProxyJump {target_host} @@ -148,12 +147,11 @@ def _prepare_ssh(self, host): StrictHostKeyChecking no UserKnownHostsFile {known_hosts} """.format( - hostname=host.name, - aliases=" ".join(host._aliases), - target_host=self.target_host, - known_hosts=KNOWN_HOSTS_FILE, - insecure_private_key=local_insecure_key, - ) + hostname=host.name, + aliases=" ".join(host._aliases), + target_host=self.target_host, + known_hosts=KNOWN_HOSTS_FILE, + insecure_private_key=local_insecure_key, ) # Gather all known hosts together - otherwise we can only access @@ -283,16 +281,14 @@ def provision(self, host): if os.path.exists(seed_script_file): output.annotate(f" Including {seed_script_file}") seed_raw_script = open(seed_script_file).read() - seed_script += textwrap.dedent( - f"""\ + seed_script += textwrap.dedent(f"""\ # BEGIN CUSTOM SEED SCRIPT ( cd {seed_basedir} {seed_raw_script} ) # END CUSTOM SEED SCRIPT - """ - ) + """) seed_nixos_file = f"environments/{host.environment.name}/provision.nix" if ( @@ -300,19 +296,14 @@ def provision(self, host): and "provision.nix" not in seed_script ): output.annotate(f" Including {seed_nixos_file}") - seed_script = ( - textwrap.dedent( - f"""\ + seed_script = textwrap.dedent(f"""\ # BEGIN AUTOMATICALLY INCLUDED provision.nix ( cd {seed_basedir} COPY provision.nix /etc/local/nixos/provision-container.nix ) # END AUTOMATICALLY INCLUDED provision.nix - """ - ) - + seed_script - ) + """) + seed_script seed_script = seed_script.strip() if not seed_script: diff --git a/src/batou/remote_core.py b/src/batou/remote_core.py index 7edcf42c..768465f8 100644 --- a/src/batou/remote_core.py +++ b/src/batou/remote_core.py @@ -394,7 +394,7 @@ def deploy(root, predict_only=False): def root_dependencies(): deps = {} for item in deployment.environment.root_dependencies().items(): - (root, dependencies) = item + root, dependencies = item key = (root.host.name, root.name) deps[key] = { "dependencies": [(r.host.name, r.name) for r in dependencies], diff --git a/src/batou/repository.py b/src/batou/repository.py index 397bb358..510f85b1 100644 --- a/src/batou/repository.py +++ b/src/batou/repository.py @@ -244,14 +244,12 @@ def verify(self): try: cmd("hg -q outgoing -l 1", acceptable_returncodes=[1]) except CmdExecutionError: - output.error( - """\ + output.error("""\ Your repository has outgoing changes. I am refusing to deploy in this situation as the results will be unpredictable. Please push first. -""" - ) +""") raise DeploymentError("Outgoing changes") @@ -363,18 +361,14 @@ def verify(self): acceptable_returncodes=[0, 128], ) if outgoing.strip(): - output.error( - """\ + output.error("""\ Your repository has outgoing changes on branch {branch}: {outgoing} I am refusing to deploy in this situation as the results will be unpredictable. Please push first. -""".format( - branch=self.branch, outgoing=outgoing - ) - ) +""".format(branch=self.branch, outgoing=outgoing)) raise DeploymentError() diff --git a/src/batou/secrets/tests/test_editor.py b/src/batou/secrets/tests/test_editor.py index fab1ae6d..6ba3c364 100644 --- a/src/batou/secrets/tests/test_editor.py +++ b/src/batou/secrets/tests/test_editor.py @@ -67,8 +67,7 @@ def _input(): out, err = capsys.readouterr() assert err == "" - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ An error occurred: gpg is broken @@ -139,8 +138,7 @@ def _input(): \tedit -- opens editor with current data again \tencrypt -- tries to encrypt current data again \tquit -- quits and loses your changes -""" - ) +""") def test_edit_file_has_secret_prefix_gpg(tmpdir, encrypted_file): diff --git a/src/batou/secrets/tests/test_manage.py b/src/batou/secrets/tests/test_manage.py index 79299270..740e2264 100644 --- a/src/batou/secrets/tests/test_manage.py +++ b/src/batou/secrets/tests/test_manage.py @@ -79,8 +79,7 @@ def test_manage__summary__1(capsys, monkeypatch): monkeypatch.chdir("examples/errors") assert summary() == 0 # exit code out, err = capsys.readouterr() - expected = textwrap.dedent( - """\ + expected = textwrap.dedent("""\ errors \t members \t\t- 03C7E67FC9FD9364 @@ -88,8 +87,7 @@ def test_manage__summary__1(capsys, monkeypatch): \t secret files \t\t(none) - """ - ) + """) assert out == expected assert err == "" diff --git a/src/batou/tests/test_deploy.py b/src/batou/tests/test_deploy.py index 1a270cbc..b0b7f798 100644 --- a/src/batou/tests/test_deploy.py +++ b/src/batou/tests/test_deploy.py @@ -28,8 +28,7 @@ def test_main_with_errors(capsys): out, err = capsys.readouterr() assert err == "" # save the output to a file to compare it with the expected output - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `errors`... @@ -65,8 +64,7 @@ def test_main_with_errors(capsys): ERROR: Secrets section for unknown component found Component: another-nonexisting-component-section ======================= DEPLOYMENT FAILED (during load) ======================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long def test_main_fails_if_no_host_in_environment(capsys): @@ -91,8 +89,7 @@ def test_main_fails_if_no_host_in_environment(capsys): out, err = capsys.readouterr() assert err == "" - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `errorsnohost`... @@ -102,5 +99,4 @@ def test_main_fails_if_no_host_in_environment(capsys): ERROR: No host found in environment. ====================== DEPLOYMENT FAILED (during connect) ====================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long diff --git a/src/batou/tests/test_endtoend.py b/src/batou/tests/test_endtoend.py index b56e67ce..95945abe 100644 --- a/src/batou/tests/test_endtoend.py +++ b/src/batou/tests/test_endtoend.py @@ -20,8 +20,7 @@ def test_service_early_resource(): def test_example_errors_early(): os.chdir("examples/errors") out, _ = cmd("./batou deploy errors", acceptable_returncodes=[1]) - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `errors`... @@ -57,16 +56,14 @@ def test_example_errors_early(): ERROR: Secrets section for unknown component found Component: another-nonexisting-component-section ======================= DEPLOYMENT FAILED (during load) ======================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long def test_example_errors_gpg_cannot_decrypt(monkeypatch): monkeypatch.setitem(os.environ, "GNUPGHOME", "") os.chdir("examples/errors") out, _ = cmd("./batou deploy errors", acceptable_returncodes=[1]) - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `errors`... @@ -101,15 +98,13 @@ def test_example_errors_gpg_cannot_decrypt(monkeypatch): ERROR: Override section for unknown component found Component: nonexisting-component-section ======================= DEPLOYMENT FAILED (during load) ======================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long def test_example_errors_late(): os.chdir("examples/errors2") out, _ = cmd("./batou deploy errors", acceptable_returncodes=[1]) - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `errors`... @@ -174,15 +169,13 @@ def test_example_errors_late(): ERROR: 11 remaining unconfigured component(s): component1, component2, component4, component5, component6, crontab, cycle1, cycle2, dnsproblem, dnsproblem2, filemode ======================= 12 ERRORS - CONFIGURATION FAILED ======================= ====================== DEPLOYMENT FAILED (during connect) ====================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long def test_example_errors_missing_environment(): os.chdir("examples/errors") out, _ = cmd("./batou deploy production", acceptable_returncodes=[1]) - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `production`... @@ -190,15 +183,13 @@ def test_example_errors_missing_environment(): ERROR: Missing environment Environment: production ======================= DEPLOYMENT FAILED (during load) ======================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long def test_example_ignores(): os.chdir("examples/ignores") out, _ = cmd("./batou deploy ignores") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `ignores`... @@ -214,8 +205,7 @@ def test_example_ignores(): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=...s ============================= DEPLOYMENT FINISHED ============================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long def test_example_async_sync_deployment(): @@ -272,8 +262,7 @@ def test_diff_is_not_shown_for_keys_in_secrets(tmp_path, monkeypatch, capsys): if os.path.exists("work"): shutil.rmtree("work") # shutil.rmtree("work") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `tutorial`... @@ -294,8 +283,7 @@ def test_diff_is_not_shown_for_keys_in_secrets(tmp_path, monkeypatch, capsys): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=...s ============================= DEPLOYMENT FINISHED ============================== -""" - ) # noqa: E501 line too long +""") # noqa: E501 line too long def test_diff_for_keys_in_secrets_overridable(tmp_path, monkeypatch, capsys): @@ -314,8 +302,7 @@ def test_diff_for_keys_in_secrets_overridable(tmp_path, monkeypatch, capsys): finally: if os.path.exists("work"): shutil.rmtree("work") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `local`... @@ -355,15 +342,13 @@ def test_diff_for_keys_in_secrets_overridable(tmp_path, monkeypatch, capsys): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=...s ============================= DEPLOYMENT FINISHED ============================== -""" - ) +""") def test_durations_are_shown_for_components(): os.chdir("examples/durations") out, _ = cmd("./batou deploy default") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `default`... @@ -377,15 +362,13 @@ def test_durations_are_shown_for_components(): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=...s ============================= DEPLOYMENT FINISHED ============================== -""" - ) +""") def test_check_consistency_works(): os.chdir("examples/tutorial-secrets") out, _ = cmd("./batou deploy tutorial --consistency-only") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `tutorial`... @@ -396,15 +379,13 @@ def test_check_consistency_works(): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=∅ ========================== CONSISTENCY CHECK FINISHED ========================== -""" - ) +""") def test_predicting_deployment_works(): os.chdir("examples/tutorial-secrets") out, _ = cmd("./batou deploy tutorial --predict-only") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `tutorial`... @@ -425,15 +406,13 @@ def test_predicting_deployment_works(): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=...s ======================== DEPLOYMENT PREDICTION FINISHED ======================== -""" - ) +""") def test_check_consistency_works_with_local(): os.chdir("examples/tutorial-secrets") out, _ = cmd("./batou deploy gocept --consistency-only --local") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `gocept`... @@ -445,15 +424,13 @@ def test_check_consistency_works_with_local(): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=∅ ====================== CONSISTENCY CHECK (local) FINISHED ====================== -""" - ) +""") def test_predicting_deployment_works_with_local(): os.chdir("examples/tutorial-secrets") out, _ = cmd("./batou deploy gocept --predict-only --local") - assert out == Ellipsis( - """\ + assert out == Ellipsis("""\ batou/2... (cpython 3...) ================================== Preparing =================================== 📦 main: Loading environment `gocept`... @@ -490,5 +467,4 @@ def test_predicting_deployment_works_with_local(): =================================== Summary ==================================== Deployment took total=...s, connect=...s, deploy=...s ==================== DEPLOYMENT PREDICTION (local) FINISHED ==================== -""" - ) +""") diff --git a/src/batou/tests/test_environment.py b/src/batou/tests/test_environment.py index f81cba04..60e28797 100644 --- a/src/batou/tests/test_environment.py +++ b/src/batou/tests/test_environment.py @@ -129,14 +129,12 @@ def test_parse_host_components(): def test_load_hosts_should_merge_single_and_multi_definition(add_root): e = Environment("name") config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [hosts] foo = bar [host:baz] components = bar - """ - ) + """) e.load_hosts(config) assert [ mock.call("bar", e.hosts["foo"], [], False), @@ -148,12 +146,10 @@ def test_load_hosts_should_merge_single_and_multi_definition(add_root): def test_load_hosts_should_load_single_hosts_section(add_root): e = Environment("name") config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [hosts] foo = bar - """ - ) + """) e.load_hosts(config) add_root.assert_called_once_with("bar", e.hosts["foo"], [], False) @@ -163,12 +159,10 @@ def test_load_hosts_should_load_multi_hosts_section(add_root): pass e = Environment("name") config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [host:foo] components = bar - """ - ) + """) e.load_hosts(config) add_root.assert_called_once_with("bar", e.hosts["foo"], [], False) @@ -178,13 +172,11 @@ def test_load_hosts_multi_should_use_ignore_flag(add_root): pass e = Environment("name") config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [host:foo] components = bar ignore = True - """ - ) + """) e.load_hosts(config) assert e.hosts["foo"].ignore @@ -193,14 +185,12 @@ def test_load_hosts_multi_should_use_ignore_flag(add_root): def test_load_hosts_should_break_on_duplicate_definition(add_root): e = Environment("name") config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [hosts] foo = bar [host:foo] components = bar - """ - ) + """) e.load_hosts(config) assert e.exceptions assert "foo" == e.exceptions[0].affected_hostname @@ -211,13 +201,11 @@ def test_load_hosts_multi_should_use_env_platform(add_root): e = Environment("name") e.platform = mock.sentinel.platform config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [host:foo] components = bar ignore = True - """ - ) + """) e.load_hosts(config) assert e.hosts["foo"].platform == mock.sentinel.platform @@ -228,13 +216,11 @@ def test_load_hosts_multi_should_use_host_platform_if_given(add_root): e = Environment("name") e.platform = mock.sentinel.platform config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [host:foo] components = bar platform = specific - """ - ) + """) e.load_hosts(config) assert e.hosts["foo"].platform == "specific" @@ -244,12 +230,10 @@ def test_load_hosts_single_should_use_env_platform(add_root): e = Environment("name") e.platform = mock.sentinel.platform config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [hosts] foo = bar - """ - ) + """) e.load_hosts(config) assert e.hosts["foo"].platform == mock.sentinel.platform @@ -257,13 +241,11 @@ def test_load_hosts_single_should_use_env_platform(add_root): def test_host_data_is_passed_to_host_object(): e = Environment("name") config = Config(None) - config.config.read_string( - """ + config.config.read_string(""" [host:foo] components = bar data-alias = baz - """ - ) + """) e.load_hosts(config) assert "baz" == e.hosts["foo"].data["alias"] @@ -292,27 +274,21 @@ def test_log_in_component_configure_is_put_out(output, sample_service): e.configure() log = "\n".join(c[0][0].strip() for c in output.call_args_list) # Provide is *always* logged first, due to provide/require ordering. - assert ( - """\ + assert """\ Provide Pre sub Sub! -Post sub""" - == log - ) +Post sub""" == log output.reset_mock() for root in e.root_dependencies(): root.component.deploy(True) log = "\n".join(c[0][0].strip() for c in output.call_args_list) - assert ( - """\ + assert """\ localhost: Hello localhost: verify: asdf=None\ -""" - == log - ) +""" == log def test_resolve_overrides(sample_service): diff --git a/src/batou/tests/test_repository.py b/src/batou/tests/test_repository.py index e382431d..327f1278 100644 --- a/src/batou/tests/test_repository.py +++ b/src/batou/tests/test_repository.py @@ -40,24 +40,20 @@ def test_repository_hg_show_upstream(tmpdir): repository.upstream with open(".hg/hgrc", "w") as f: - f.write( - """\ + f.write("""\ [paths] foobar = 1234 -""" - ) +""") with pytest.raises(AssertionError): repository.upstream with open(".hg/hgrc", "w") as f: - f.write( - """\ + f.write("""\ [paths] foobar = 1234 default = ssh://test@example.com/repos -""" - ) +""") assert repository.upstream == "ssh://test@example.com/repos" # Trigger cached access @@ -79,14 +75,10 @@ def test_repository_hg_verify(tmpdir): # Create a second repo as target with open(".hg/hgrc", "w") as f: - f.write( - """\ + f.write("""\ [paths] default = file:///{}/remote -""".format( - tmpdir - ) - ) +""".format(tmpdir)) repository = MercurialRepository(environment) # Clean repositories are fine diff --git a/src/batou/tests/test_template.py b/src/batou/tests/test_template.py index d3e9c7dc..dbea178d 100644 --- a/src/batou/tests/test_template.py +++ b/src/batou/tests/test_template.py @@ -69,15 +69,12 @@ def test_jinja2_large_template_str(output): log = "\n".join(c[0][0].strip() for c in output.call_args_list) - assert ( - """\ + assert """\ ERROR: You are trying to render a template that is bigger than 100KiB we've \ seen that Jinja can crash at large templates and suggest you find \ alternatives for this. The affected template starts with: hello {{hello}}hello {{hello}}hello {{hello}}hello {{hello}}hello \ -{{hello}}hello {{hello}}hello {{he""" - == log - ) +{{hello}}hello {{hello}}hello {{he""" == log def test_jinja2_unknown_variable_should_fail(): diff --git a/src/batou/tests/test_utils.py b/src/batou/tests/test_utils.py index 5d4d997b..66cb9913 100644 --- a/src/batou/tests/test_utils.py +++ b/src/batou/tests/test_utils.py @@ -102,14 +102,11 @@ def link_local_addrinfo_2(*args, **kw): output.backend.output = "" assert resolve_v6("foo.example.com", 80) == "2a02::1" - assert ( - """\ + assert """\ resolving (v6) `foo.example.com` resolved (v6) `foo.example.com` to [(None, None, None, None, ('fe80::feaa:14ff:fe8f:94ba', 80, None, None)), (None, None, None, None, ('2a02::1', 80, None, None))] selected (v6) foo.example.com, 2a02::1 -""" - == output.backend.output - ) # noqa: E501 line too long +""" == output.backend.output # noqa: E501 line too long def test_address_without_implicit_or_explicit_port_fails(): @@ -505,9 +502,7 @@ def test_export_environment_variables(): "_1": "${}", "_ABBA_": r"\\", } - assert ( - export_environment_variables(environ) - == """\ + assert export_environment_variables(environ) == """\ export AB1=''"'"'' export AB=True export B=None @@ -515,7 +510,6 @@ def test_export_environment_variables(): export _A='"' export _ABBA_='\\\\' export a=1""" - ) environ = {"1a": None} with pytest.raises(ValueError) as e: diff --git a/tox.ini b/tox.ini index bf14ef2c..2a2740d0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py38, py39, py310, py311, py312, pre-commit + py310, py311, py312, py313, py314, pre-commit skip_missing_interpreters = true allowlist_externals=git @@ -15,7 +15,7 @@ commands = pytest {posargs} [testenv:pre-commit] -basepython = python3.9 +basepython = python3.10 description = This env runs all linters configured in .pre-commit-config.yaml skip_install = true deps =