diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e6b4f0ea2d7..4cda08650ad 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,45 +1,59 @@ name: deploy on: - push: - tags: - # These tags are protected, see: - # https://github.com/pytest-dev/pytest/settings/tag_protection - - "[0-9]+.[0-9]+.[0-9]+" - - "[0-9]+.[0-9]+.[0-9]+rc[0-9]+" + workflow_dispatch: + inputs: + version: + description: 'Release version' + required: true + default: '1.2.3' # Set permissions at the job level. permissions: {} jobs: - build: + package: runs-on: ubuntu-latest + env: + SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.inputs.version }} timeout-minutes: 10 + steps: - uses: actions/checkout@v3 with: fetch-depth: 0 persist-credentials: false + - name: Build and Check Package uses: hynek/build-and-inspect-python-package@v1.5 deploy: if: github.repository == 'pytest-dev/pytest' - needs: [build] + needs: [package] runs-on: ubuntu-latest + environment: deploy timeout-minutes: 30 permissions: id-token: write steps: + - uses: actions/checkout@v3 - name: Download Package uses: actions/download-artifact@v3 with: name: Packages path: dist + - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@v1.8.5 + - name: Push tag + run: | + git config user.name "pytest bot" + git config user.email "pytestbot@gmail.com" + git tag --annotate --message=v${{ github.event.inputs.version }} v${{ github.event.inputs.version }} ${{ github.sha }} + git push origin v${{ github.event.inputs.version }} + release-notes: # todo: generate the content in the build job @@ -55,11 +69,11 @@ jobs: with: fetch-depth: 0 persist-credentials: false + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.7" - + python-version: "3.10" - name: Install tox run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index eb2dfa85d26..a3c2d9ed5a1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,19 @@ concurrency: permissions: {} jobs: + package: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + persist-credentials: false + - name: Build and Check Package + uses: hynek/build-and-inspect-python-package@v1.5 + build: + needs: [package] + runs-on: ${{ matrix.os }} timeout-minutes: 45 permissions: @@ -60,7 +72,6 @@ jobs: "macos-py310", "macos-py312", - "docs", "doctesting", "plugins", ] @@ -159,10 +170,6 @@ jobs: os: ubuntu-latest tox_env: "plugins" - - name: "docs" - python: "3.7" - os: ubuntu-latest - tox_env: "docs" - name: "doctesting" python: "3.7" os: ubuntu-latest @@ -175,6 +182,12 @@ jobs: fetch-depth: 0 persist-credentials: false + - name: Download Package + uses: actions/download-artifact@v3 + with: + name: Packages + path: dist + - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v4 with: @@ -188,11 +201,13 @@ jobs: - name: Test without coverage if: "! matrix.use_coverage" - run: "tox -e ${{ matrix.tox_env }}" + shell: bash + run: tox run -e ${{ matrix.tox_env }} --installpkg `find dist/*.tar.gz` - name: Test with coverage if: "matrix.use_coverage" - run: "tox -e ${{ matrix.tox_env }}-coverage" + shell: bash + run: tox run -e ${{ matrix.tox_env }}-coverage --installpkg `find dist/*.tar.gz` - name: Generate coverage report if: "matrix.use_coverage" @@ -206,10 +221,3 @@ jobs: fail_ci_if_error: true files: ./coverage.xml verbose: true - - check-package: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Build and Check Package - uses: hynek/build-and-inspect-python-package@v1.5 diff --git a/RELEASING.rst b/RELEASING.rst index b018dc48932..5d49fb5d6d9 100644 --- a/RELEASING.rst +++ b/RELEASING.rst @@ -133,14 +133,11 @@ Releasing Both automatic and manual processes described above follow the same steps from this point onward. -#. After all tests pass and the PR has been approved, tag the release commit - in the ``release-MAJOR.MINOR.PATCH`` branch and push it. This will publish to PyPI:: +#. After all tests pass and the PR has been approved, trigger the ``deploy`` job + in https://github.com/pytest-dev/pytest/actions/workflows/deploy.yml. - git fetch upstream - git tag MAJOR.MINOR.PATCH upstream/release-MAJOR.MINOR.PATCH - git push upstream MAJOR.MINOR.PATCH - - Wait for the deploy to complete, then make sure it is `available on PyPI `_. + This job will require approval from ``pytest-dev/core``, after which it will publish to PyPI + and tag the repository. #. Merge the PR. **Make sure it's not squash-merged**, so that the tagged commit ends up in the main branch. diff --git a/changelog/10337.bugfix.rst b/changelog/10337.bugfix.rst deleted file mode 100644 index 3270016f926..00000000000 --- a/changelog/10337.bugfix.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed bug where fake intermediate modules generated by ``--import-mode=importlib`` would not include the -child modules as attributes of the parent modules. diff --git a/changelog/10702.bugfix.rst b/changelog/10702.bugfix.rst deleted file mode 100644 index 4008cc882ec..00000000000 --- a/changelog/10702.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fixed error assertion handling in :func:`pytest.approx` when ``None`` is an expected or received value when comparing dictionaries. diff --git a/changelog/10811.bugfix.rst b/changelog/10811.bugfix.rst deleted file mode 100644 index aa26414e457..00000000000 --- a/changelog/10811.bugfix.rst +++ /dev/null @@ -1,2 +0,0 @@ -Fixed issue when using ``--import-mode=importlib`` together with ``--doctest-modules`` that caused modules -to be imported more than once, causing problems with modules that have import side effects. diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 914e763bd9e..85dfa0894fe 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-7.4.1 release-7.4.0 release-7.3.2 release-7.3.1 diff --git a/doc/en/announce/release-7.4.1.rst b/doc/en/announce/release-7.4.1.rst new file mode 100644 index 00000000000..efadcf919e8 --- /dev/null +++ b/doc/en/announce/release-7.4.1.rst @@ -0,0 +1,20 @@ +pytest-7.4.1 +======================================= + +pytest 7.4.1 has just been released to PyPI. + +This is a bug-fix release, being a drop-in replacement. To upgrade:: + + pip install --upgrade pytest + +The full changelog is available at https://docs.pytest.org/en/stable/changelog.html. + +Thanks to all of the contributors to this release: + +* Bruno Oliveira +* Florian Bruhin +* Ran Benita + + +Happy testing, +The pytest Development Team diff --git a/doc/en/builtin.rst b/doc/en/builtin.rst index 53305eecded..0d673d0426e 100644 --- a/doc/en/builtin.rst +++ b/doc/en/builtin.rst @@ -22,7 +22,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a cachedir: .pytest_cache rootdir: /home/sweet/project collected 0 items - cache -- .../_pytest/cacheprovider.py:528 + cache -- .../_pytest/cacheprovider.py:532 Return a cache object that can persist state between testing sessions. cache.get(key, default) diff --git a/doc/en/changelog.rst b/doc/en/changelog.rst index 391721df34d..be7e7fabaef 100644 --- a/doc/en/changelog.rst +++ b/doc/en/changelog.rst @@ -28,6 +28,23 @@ with advance notice in the **Deprecations** section of releases. .. towncrier release notes start +pytest 7.4.1 (2023-09-02) +========================= + +Bug Fixes +--------- + +- `#10337 `_: Fixed bug where fake intermediate modules generated by ``--import-mode=importlib`` would not include the + child modules as attributes of the parent modules. + + +- `#10702 `_: Fixed error assertion handling in :func:`pytest.approx` when ``None`` is an expected or received value when comparing dictionaries. + + +- `#10811 `_: Fixed issue when using ``--import-mode=importlib`` together with ``--doctest-modules`` that caused modules + to be imported more than once, causing problems with modules that have import side effects. + + pytest 7.4.0 (2023-06-23) ========================= diff --git a/doc/en/example/reportingdemo.rst b/doc/en/example/reportingdemo.rst index cb59c4b42e1..d4d3d3ce202 100644 --- a/doc/en/example/reportingdemo.rst +++ b/doc/en/example/reportingdemo.rst @@ -554,13 +554,13 @@ Here is a nice run of several failures and how ``pytest`` presents things: E AssertionError: assert False E + where False = ('456') E + where = '123'.startswith - E + where '123' = .f at 0xdeadbeef0029>() - E + and '456' = .g at 0xdeadbeef002a>() + E + where '123' = .f at 0xdeadbeef0006>() + E + and '456' = .g at 0xdeadbeef0029>() failure_demo.py:235: AssertionError _____________________ TestMoreErrors.test_global_func ______________________ - self = + self = def test_global_func(self): > assert isinstance(globf(42), float) @@ -571,18 +571,18 @@ Here is a nice run of several failures and how ``pytest`` presents things: failure_demo.py:238: AssertionError _______________________ TestMoreErrors.test_instance _______________________ - self = + self = def test_instance(self): self.x = 6 * 7 > assert self.x != 42 E assert 42 != 42 - E + where 42 = .x + E + where 42 = .x failure_demo.py:242: AssertionError _______________________ TestMoreErrors.test_compare ________________________ - self = + self = def test_compare(self): > assert globf(10) < 5 @@ -592,7 +592,7 @@ Here is a nice run of several failures and how ``pytest`` presents things: failure_demo.py:245: AssertionError _____________________ TestMoreErrors.test_try_finally ______________________ - self = + self = def test_try_finally(self): x = 1 @@ -603,7 +603,7 @@ Here is a nice run of several failures and how ``pytest`` presents things: failure_demo.py:250: AssertionError ___________________ TestCustomAssertMsg.test_single_line ___________________ - self = + self = def test_single_line(self): class A: @@ -618,7 +618,7 @@ Here is a nice run of several failures and how ``pytest`` presents things: failure_demo.py:261: AssertionError ____________________ TestCustomAssertMsg.test_multiline ____________________ - self = + self = def test_multiline(self): class A: @@ -637,7 +637,7 @@ Here is a nice run of several failures and how ``pytest`` presents things: failure_demo.py:268: AssertionError ___________________ TestCustomAssertMsg.test_custom_repr ___________________ - self = + self = def test_custom_repr(self): class JSON: diff --git a/doc/en/getting-started.rst b/doc/en/getting-started.rst index e295c180454..31cfa68bf38 100644 --- a/doc/en/getting-started.rst +++ b/doc/en/getting-started.rst @@ -22,7 +22,7 @@ Install ``pytest`` .. code-block:: bash $ pytest --version - pytest 7.4.0 + pytest 7.4.1 .. _`simpletest`: diff --git a/doc/en/how-to/tmp_path.rst b/doc/en/how-to/tmp_path.rst index d5573f5847d..3b49d63a5be 100644 --- a/doc/en/how-to/tmp_path.rst +++ b/doc/en/how-to/tmp_path.rst @@ -51,8 +51,8 @@ Running this would result in a passed test except for the last d = tmp_path / "sub" d.mkdir() p = d / "hello.txt" - p.write_text(CONTENT) - assert p.read_text() == CONTENT + p.write_text(CONTENT, encoding="utf-8") + assert p.read_text(encoding="utf-8") == CONTENT assert len(list(tmp_path.iterdir())) == 1 > assert 0 E assert 0 diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index ef7e19c03d0..6e11d385d12 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -1887,11 +1887,12 @@ All the command-line flags can be obtained by running ``pytest --help``:: tests. Optional argument: glob (default: '*'). --cache-clear Remove all cache contents at start of test run --lfnf={all,none}, --last-failed-no-failures={all,none} - With ``--lf``, determines whether to execute tests when there - are no previously (known) failures or when no - cached ``lastfailed`` data was found. - ``all`` (the default) runs the full test suite again. - ``none`` just emits a message about no known failures and exits successfully. + With ``--lf``, determines whether to execute tests + when there are no previously (known) failures or + when no cached ``lastfailed`` data was found. + ``all`` (the default) runs the full test suite + again. ``none`` just emits a message about no known + failures and exits successfully. --sw, --stepwise Exit on test failure and continue from last failing test next time --sw-skip, --stepwise-skip