diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8729f14e..1c9fb821 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,9 @@ jobs: - name: '3.12' tox_env: integration-py312 + - name: '3.13' + tox_env: integration-py313 + steps: - name: Checkout uses: actions/checkout@v4 @@ -73,6 +76,7 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.py_version.name }} + allow-prereleases: true - name: Install tox run: | @@ -122,6 +126,9 @@ jobs: - name: '3.12' tox_env: unit-py312 + - name: '3.13' + tox_env: unit-py313 + steps: - name: Checkout uses: actions/checkout@v4 @@ -130,6 +137,7 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.py_version.name }} + allow-prereleases: true - name: Install tox run: | diff --git a/src/ansible_runner/utils/base64io.py b/src/ansible_runner/utils/base64io.py index 0a2422f1..6a65b5ab 100644 --- a/src/ansible_runner/utils/base64io.py +++ b/src/ansible_runner/utils/base64io.py @@ -78,6 +78,10 @@ def __init__(self, wrapped: IO) -> None: :raises TypeError: if ``wrapped`` does not have attributes needed to determine the stream's state """ + # set before the attr check as we may reach close() after that check fails + self.__read_buffer = b"" + self.__write_buffer = b"" + required_attrs = ("read", "write", "close", "closed", "flush") if not all(hasattr(wrapped, attr) for attr in required_attrs): raise TypeError( @@ -85,8 +89,6 @@ def __init__(self, wrapped: IO) -> None: ) super().__init__() self.__wrapped = wrapped - self.__read_buffer = b"" - self.__write_buffer = b"" def __enter__(self): """Return self on enter.""" diff --git a/test/integration/test_transmit_worker_process.py b/test/integration/test_transmit_worker_process.py index 540e5dc6..cc70a6ac 100644 --- a/test/integration/test_transmit_worker_process.py +++ b/test/integration/test_transmit_worker_process.py @@ -193,7 +193,7 @@ def test_keepalive_setting(self, tmp_path, project_fixtures, keepalive_setting): pytest.fail(f'unparseable JSON in output (likely corrupted by keepalive): {line}') else: # account for some wobble in the number of keepalives for artifact gather, etc - assert 1 <= incoming_data.count('"event": "keepalive"') < 5 + assert 1 <= incoming_data.count('"event": "keepalive"') < 15 @pytest.mark.parametrize("job_type", ['run', 'adhoc']) def test_remote_job_by_sockets(self, tmp_path, project_fixtures, job_type): diff --git a/test/requirements.txt b/test/requirements.txt index 565292c1..7ab8f9fc 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -8,4 +8,6 @@ pytest-xdist==2.5.0 types-pyyaml flake8==6.1.0 yamllint==1.32.0 +# cffi pre-release to make cryptography work with python 3.13 (remove when 3.13 is released) +cffi==1.17.0rc1; python_version == "3.13" cryptography diff --git a/tox.ini b/tox.ini index ef540923..fcd81cbb 100644 --- a/tox.ini +++ b/tox.ini @@ -13,17 +13,17 @@ deps = ansible27: ansible<2.8 ansible28: ansible<2.9 ansible29: ansible<2.10 ansible-base: ansible-base - py{,3,39,310,311}: ansible-core - integration{,-py39,-py310,-py311,-py312}: ansible-core - build - -r {toxinidir}/test/requirements.txt + py{,3,39,310,311,312,313}: ansible-core + integration{,-py39,-py310,-py311,-py312,-py313}: ansible-core + build + -r {toxinidir}/test/requirements.txt passenv = HOME RUNNER_TEST_IMAGE_NAME usedevelop = True commands = pytest -vv -n auto {posargs} -[testenv:linters{,-py39,-py310,-py311,-py312}] +[testenv:linters{,-py39,-py310,-py311,-py312,-py313}] description = Run code linters commands = flake8 --version @@ -33,13 +33,14 @@ commands = mypy src/ansible_runner pylint src/ansible_runner test -[testenv:unit{,-py39,-py310,-py311,-py312}] +[testenv:unit{,-py39,-py310,-py311,-py312,-py313}] description = Run unit tests commands = pytest -vv -n auto {posargs:test/unit} {[shared]pytest_cov_args} -[testenv:integration{,-py39,-py310,-py311,-py312}] +[testenv:integration{,-py39,-py310,-py311,-py312,-py313}] description = Run integration tests -commands = pytest -vv -n auto {posargs:test/integration} {[shared]pytest_cov_args} +commands = + pytest -vv -n auto {posargs:test/integration} {[shared]pytest_cov_args} [testenv:docs] description = Build documentation