Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pytest for openSUSE:Factory checked in at 2023-11-08 22:16:42 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pytest (Old) and /work/SRC/openSUSE:Factory/.python-pytest.new.17445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pytest" Wed Nov 8 22:16:42 2023 rev:82 rq:1123974 version:7.4.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pytest/python-pytest.changes 2023-10-15 19:25:59.453548501 +0200 +++ /work/SRC/openSUSE:Factory/.python-pytest.new.17445/python-pytest.changes 2023-11-08 22:16:54.505366893 +0100 @@ -1,0 +2,11 @@ +Tue Nov 7 12:01:50 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 7.4.3: + * Markers are now considered in the + reverse mro order to ensure base class markers are + considered first -- this resolves a regression. + * Fixed ``:=`` in asserts impacting unrelated test cases. + * Handled an edge case where :data:`sys.stderr` might already + be closed when :ref:`faulthandler` is tearing down. + +------------------------------------------------------------------- Old: ---- pytest-7.4.2.tar.gz New: ---- pytest-7.4.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pytest.spec ++++++ --- /var/tmp/diff_new_pack.1kbbak/_old 2023-11-08 22:16:55.357398194 +0100 +++ /var/tmp/diff_new_pack.1kbbak/_new 2023-11-08 22:16:55.357398194 +0100 @@ -33,7 +33,7 @@ %{?sle15_python_module_pythons} Name: python-pytest%{psuffix} -Version: 7.4.2 +Version: 7.4.3 Release: 0 Summary: Simple powerful testing with Python License: MIT ++++++ pytest-7.4.2.tar.gz -> pytest-7.4.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/.github/workflows/deploy.yml new/pytest-7.4.3/.github/workflows/deploy.yml --- old/pytest-7.4.2/.github/workflows/deploy.yml 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/.github/workflows/deploy.yml 2023-10-24 21:07:09.000000000 +0200 @@ -36,8 +36,10 @@ timeout-minutes: 30 permissions: id-token: write + contents: write steps: - uses: actions/checkout@v3 + - name: Download Package uses: actions/download-artifact@v3 with: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/.readthedocs.yml new/pytest-7.4.3/.readthedocs.yml --- old/pytest-7.4.2/.readthedocs.yml 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/.readthedocs.yml 2023-10-24 21:07:09.000000000 +0200 @@ -9,6 +9,10 @@ path: . - requirements: doc/en/requirements.txt +sphinx: + configuration: doc/en/conf.py + fail_on_warning: true + build: os: ubuntu-20.04 tools: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/AUTHORS new/pytest-7.4.3/AUTHORS --- old/pytest-7.4.2/AUTHORS 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/AUTHORS 2023-10-24 21:07:09.000000000 +0200 @@ -231,6 +231,7 @@ Maik Figura Mandeep Bhutani Manuel Krebber +Marc Mueller Marc Schlaich Marcelo Duarte Trevisani Marcin Bachry @@ -336,6 +337,7 @@ Seth Junot Shantanu Jain Shubham Adep +Simon Blanchard Simon Gomizelj Simon Holesch Simon Kerr diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/PKG-INFO new/pytest-7.4.3/PKG-INFO --- old/pytest-7.4.2/PKG-INFO 2023-09-07 20:44:07.151998800 +0200 +++ new/pytest-7.4.3/PKG-INFO 2023-10-24 21:07:28.929523500 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest -Version: 7.4.2 +Version: 7.4.3 Summary: pytest: simple powerful testing with Python Home-page: https://docs.pytest.org/en/latest/ Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/RELEASING.rst new/pytest-7.4.3/RELEASING.rst --- old/pytest-7.4.2/RELEASING.rst 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/RELEASING.rst 2023-10-24 21:07:09.000000000 +0200 @@ -134,7 +134,8 @@ 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, trigger the ``deploy`` job - in https://github.com/pytest-dev/pytest/actions/workflows/deploy.yml. + in https://github.com/pytest-dev/pytest/actions/workflows/deploy.yml, using the ``release-MAJOR.MINOR.PATCH`` branch + as source. This job will require approval from ``pytest-dev/core``, after which it will publish to PyPI and tag the repository. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/doc/en/announce/index.rst new/pytest-7.4.3/doc/en/announce/index.rst --- old/pytest-7.4.2/doc/en/announce/index.rst 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/doc/en/announce/index.rst 2023-10-24 21:07:09.000000000 +0200 @@ -6,6 +6,7 @@ :maxdepth: 2 + release-7.4.3 release-7.4.2 release-7.4.1 release-7.4.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/doc/en/announce/release-7.4.3.rst new/pytest-7.4.3/doc/en/announce/release-7.4.3.rst --- old/pytest-7.4.2/doc/en/announce/release-7.4.3.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/pytest-7.4.3/doc/en/announce/release-7.4.3.rst 2023-10-24 21:07:09.000000000 +0200 @@ -0,0 +1,19 @@ +pytest-7.4.3 +======================================= + +pytest 7.4.3 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 +* Marc Mueller + + +Happy testing, +The pytest Development Team diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/doc/en/changelog.rst new/pytest-7.4.3/doc/en/changelog.rst --- old/pytest-7.4.2/doc/en/changelog.rst 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/doc/en/changelog.rst 2023-10-24 21:07:09.000000000 +0200 @@ -28,6 +28,21 @@ .. towncrier release notes start +pytest 7.4.3 (2023-10-24) +========================= + +Bug Fixes +--------- + +- `#10447 <https://github.com/pytest-dev/pytest/issues/10447>`_: Markers are now considered in the reverse mro order to ensure base class markers are considered first -- this resolves a regression. + + +- `#11239 <https://github.com/pytest-dev/pytest/issues/11239>`_: Fixed ``:=`` in asserts impacting unrelated test cases. + + +- `#11439 <https://github.com/pytest-dev/pytest/issues/11439>`_: Handled an edge case where :data:`sys.stderr` might already be closed when :ref:`faulthandler` is tearing down. + + pytest 7.4.2 (2023-09-07) ========================= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/doc/en/getting-started.rst new/pytest-7.4.3/doc/en/getting-started.rst --- old/pytest-7.4.2/doc/en/getting-started.rst 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/doc/en/getting-started.rst 2023-10-24 21:07:09.000000000 +0200 @@ -22,7 +22,7 @@ .. code-block:: bash $ pytest --version - pytest 7.4.2 + pytest 7.4.3 .. _`simpletest`: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/doc/en/reference/customize.rst new/pytest-7.4.3/doc/en/reference/customize.rst --- old/pytest-7.4.2/doc/en/reference/customize.rst 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/doc/en/reference/customize.rst 2023-10-24 21:07:09.000000000 +0200 @@ -90,7 +90,7 @@ setup.cfg ~~~~~~~~~ -``setup.cfg`` files are general purpose configuration files, used originally by :doc:`distutils <python:distutils/configfile>`, and can also be used to hold pytest configuration +``setup.cfg`` files are general purpose configuration files, used originally by ``distutils`` (now deprecated) and `setuptools <https://setuptools.pypa.io/en/latest/userguide/declarative_config.html>`__, and can also be used to hold pytest configuration if they have a ``[tool:pytest]`` section. .. code-block:: ini diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/scripts/prepare-release-pr.py new/pytest-7.4.3/scripts/prepare-release-pr.py --- old/pytest-7.4.2/scripts/prepare-release-pr.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/scripts/prepare-release-pr.py 2023-10-24 21:07:09.000000000 +0200 @@ -31,10 +31,16 @@ SLUG = "pytest-dev/pytest" PR_BODY = """\ -Created automatically from manual trigger. +Created by the [prepare release pr](https://github.com/pytest-dev/pytest/actions/workflows/prepare-release-pr.yml) +workflow. -Once all builds pass and it has been **approved** by one or more maintainers, the build -can be released by pushing a tag `{version}` to this repository. +Once all builds pass and it has been **approved** by one or more maintainers, +start the [deploy](https://github.com/pytest-dev/pytest/actions/workflows/deploy.yml) workflow, using these parameters: + +* `Use workflow from`: `release-{version}`. +* `Release version`: `{version}`. + +After the `deploy` workflow has been approved by a core maintainer, the package will be uploaded to PyPI automatically. """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/_pytest/_version.py new/pytest-7.4.3/src/_pytest/_version.py --- old/pytest-7.4.2/src/_pytest/_version.py 2023-09-07 20:44:06.000000000 +0200 +++ new/pytest-7.4.3/src/_pytest/_version.py 2023-10-24 21:07:28.000000000 +0200 @@ -1,4 +1,16 @@ # file generated by setuptools_scm # don't change, don't track in version control -__version__ = version = '7.4.2' -__version_tuple__ = version_tuple = (7, 4, 2) +TYPE_CHECKING = False +if TYPE_CHECKING: + from typing import Tuple, Union + VERSION_TUPLE = Tuple[Union[int, str], ...] +else: + VERSION_TUPLE = object + +version: str +__version__: str +__version_tuple__: VERSION_TUPLE +version_tuple: VERSION_TUPLE + +__version__ = version = '7.4.3' +__version_tuple__ = version_tuple = (7, 4, 3) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/_pytest/assertion/rewrite.py new/pytest-7.4.3/src/_pytest/assertion/rewrite.py --- old/pytest-7.4.2/src/_pytest/assertion/rewrite.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/src/_pytest/assertion/rewrite.py 2023-10-24 21:07:09.000000000 +0200 @@ -13,6 +13,7 @@ import sys import tokenize import types +from collections import defaultdict from pathlib import Path from pathlib import PurePath from typing import Callable @@ -56,6 +57,10 @@ astNum = ast.Num +class Sentinel: + pass + + assertstate_key = StashKey["AssertionState"]() # pytest caches rewritten pycs in pycache dirs @@ -63,6 +68,9 @@ PYC_EXT = ".py" + (__debug__ and "c" or "o") PYC_TAIL = "." + PYTEST_TAG + PYC_EXT +# Special marker that denotes we have just left a scope definition +_SCOPE_END_MARKER = Sentinel() + class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader): """PEP302/PEP451 import hook which rewrites asserts.""" @@ -645,6 +653,8 @@ .push_format_context() and .pop_format_context() which allows to build another %-formatted string while already building one. + :scope: A tuple containing the current scope used for variables_overwrite. + :variables_overwrite: A dict filled with references to variables that change value within an assert. This happens when a variable is reassigned with the walrus operator @@ -666,7 +676,10 @@ else: self.enable_assertion_pass_hook = False self.source = source - self.variables_overwrite: Dict[str, str] = {} + self.scope: tuple[ast.AST, ...] = () + self.variables_overwrite: defaultdict[ + tuple[ast.AST, ...], Dict[str, str] + ] = defaultdict(dict) def run(self, mod: ast.Module) -> None: """Find all assert statements in *mod* and rewrite them.""" @@ -732,9 +745,17 @@ mod.body[pos:pos] = imports # Collect asserts. - nodes: List[ast.AST] = [mod] + self.scope = (mod,) + nodes: List[Union[ast.AST, Sentinel]] = [mod] while nodes: node = nodes.pop() + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): + self.scope = tuple((*self.scope, node)) + nodes.append(_SCOPE_END_MARKER) + if node == _SCOPE_END_MARKER: + self.scope = self.scope[:-1] + continue + assert isinstance(node, ast.AST) for name, field in ast.iter_fields(node): if isinstance(field, list): new: List[ast.AST] = [] @@ -1005,7 +1026,7 @@ ] ): pytest_temp = self.variable() - self.variables_overwrite[ + self.variables_overwrite[self.scope][ v.left.target.id ] = v.left # type:ignore[assignment] v.left.target.id = pytest_temp @@ -1048,17 +1069,20 @@ new_args = [] new_kwargs = [] for arg in call.args: - if isinstance(arg, ast.Name) and arg.id in self.variables_overwrite: - arg = self.variables_overwrite[arg.id] # type:ignore[assignment] + if isinstance(arg, ast.Name) and arg.id in self.variables_overwrite.get( + self.scope, {} + ): + arg = self.variables_overwrite[self.scope][ + arg.id + ] # type:ignore[assignment] res, expl = self.visit(arg) arg_expls.append(expl) new_args.append(res) for keyword in call.keywords: - if ( - isinstance(keyword.value, ast.Name) - and keyword.value.id in self.variables_overwrite - ): - keyword.value = self.variables_overwrite[ + if isinstance( + keyword.value, ast.Name + ) and keyword.value.id in self.variables_overwrite.get(self.scope, {}): + keyword.value = self.variables_overwrite[self.scope][ keyword.value.id ] # type:ignore[assignment] res, expl = self.visit(keyword.value) @@ -1094,12 +1118,14 @@ def visit_Compare(self, comp: ast.Compare) -> Tuple[ast.expr, str]: self.push_format_context() # We first check if we have overwritten a variable in the previous assert - if isinstance(comp.left, ast.Name) and comp.left.id in self.variables_overwrite: - comp.left = self.variables_overwrite[ + if isinstance( + comp.left, ast.Name + ) and comp.left.id in self.variables_overwrite.get(self.scope, {}): + comp.left = self.variables_overwrite[self.scope][ comp.left.id ] # type:ignore[assignment] if isinstance(comp.left, namedExpr): - self.variables_overwrite[ + self.variables_overwrite[self.scope][ comp.left.target.id ] = comp.left # type:ignore[assignment] left_res, left_expl = self.visit(comp.left) @@ -1119,7 +1145,7 @@ and next_operand.target.id == left_res.id ): next_operand.target.id = self.variable() - self.variables_overwrite[ + self.variables_overwrite[self.scope][ left_res.id ] = next_operand # type:ignore[assignment] next_res, next_expl = self.visit(next_operand) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/_pytest/compat.py new/pytest-7.4.3/src/_pytest/compat.py --- old/pytest-7.4.2/src/_pytest/compat.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/src/_pytest/compat.py 2023-10-24 21:07:09.000000000 +0200 @@ -380,15 +380,24 @@ def get_user_id() -> int | None: - """Return the current user id, or None if we cannot get it reliably on the current platform.""" - # win32 does not have a getuid() function. - # On Emscripten, getuid() is a stub that always returns 0. - if sys.platform in ("win32", "emscripten"): + """Return the current process's real user id or None if it could not be + determined. + + :return: The user id or None if it could not be determined. + """ + # mypy follows the version and platform checking expectation of PEP 484: + # https://mypy.readthedocs.io/en/stable/common_issues.html?highlight=platform#python-version-and-system-platform-checks + # Containment checks are too complex for mypy v1.5.0 and cause failure. + if sys.platform == "win32" or sys.platform == "emscripten": + # win32 does not have a getuid() function. + # Emscripten has a return 0 stub. return None - # getuid shouldn't fail, but cpython defines such a case. - # Let's hope for the best. - uid = os.getuid() - return uid if uid != -1 else None + else: + # On other platforms, a return value of -1 is assumed to indicate that + # the current process's real user id could not be determined. + ERROR = -1 + uid = os.getuid() + return uid if uid != ERROR else None # Perform exhaustiveness checking. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/_pytest/faulthandler.py new/pytest-7.4.3/src/_pytest/faulthandler.py --- old/pytest-7.4.2/src/_pytest/faulthandler.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/src/_pytest/faulthandler.py 2023-10-24 21:07:09.000000000 +0200 @@ -1,4 +1,3 @@ -import io import os import sys from typing import Generator @@ -51,7 +50,7 @@ if fileno == -1: raise AttributeError() return fileno - except (AttributeError, io.UnsupportedOperation): + except (AttributeError, ValueError): # pytest-xdist monkeypatches sys.stderr with an object that is not an actual file. # https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors # This is potentially dangerous, but the best we can do. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/_pytest/mark/structures.py new/pytest-7.4.3/src/_pytest/mark/structures.py --- old/pytest-7.4.2/src/_pytest/mark/structures.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/src/_pytest/mark/structures.py 2023-10-24 21:07:09.000000000 +0200 @@ -373,7 +373,9 @@ if not consider_mro: mark_lists = [obj.__dict__.get("pytestmark", [])] else: - mark_lists = [x.__dict__.get("pytestmark", []) for x in obj.__mro__] + mark_lists = [ + x.__dict__.get("pytestmark", []) for x in reversed(obj.__mro__) + ] mark_list = [] for item in mark_lists: if isinstance(item, list): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/_pytest/pathlib.py new/pytest-7.4.3/src/_pytest/pathlib.py --- old/pytest-7.4.2/src/_pytest/pathlib.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/src/_pytest/pathlib.py 2023-10-24 21:07:09.000000000 +0200 @@ -623,8 +623,9 @@ # Use the parts for the relative path to the root path. path_parts = relative_path.parts - # Module name for packages do not contain the __init__ file. - if path_parts[-1] == "__init__": + # Module name for packages do not contain the __init__ file, unless + # the `__init__.py` file is at the root. + if len(path_parts) >= 2 and path_parts[-1] == "__init__": path_parts = path_parts[:-1] return ".".join(path_parts) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/pytest.egg-info/PKG-INFO new/pytest-7.4.3/src/pytest.egg-info/PKG-INFO --- old/pytest-7.4.2/src/pytest.egg-info/PKG-INFO 2023-09-07 20:44:06.000000000 +0200 +++ new/pytest-7.4.3/src/pytest.egg-info/PKG-INFO 2023-10-24 21:07:28.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytest -Version: 7.4.2 +Version: 7.4.3 Summary: pytest: simple powerful testing with Python Home-page: https://docs.pytest.org/en/latest/ Author: Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/src/pytest.egg-info/SOURCES.txt new/pytest-7.4.3/src/pytest.egg-info/SOURCES.txt --- old/pytest-7.4.2/src/pytest.egg-info/SOURCES.txt 2023-09-07 20:44:07.000000000 +0200 +++ new/pytest-7.4.3/src/pytest.egg-info/SOURCES.txt 2023-10-24 21:07:28.000000000 +0200 @@ -234,6 +234,7 @@ doc/en/announce/release-7.4.0.rst doc/en/announce/release-7.4.1.rst doc/en/announce/release-7.4.2.rst +doc/en/announce/release-7.4.3.rst doc/en/announce/sprint2016.rst doc/en/example/attic.rst doc/en/example/conftest.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/testing/conftest.py new/pytest-7.4.3/testing/conftest.py --- old/pytest-7.4.2/testing/conftest.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/testing/conftest.py 2023-10-24 21:07:09.000000000 +0200 @@ -21,6 +21,15 @@ sys.settrace(orig_trace) +@pytest.fixture(autouse=True) +def set_column_width(monkeypatch: pytest.MonkeyPatch) -> None: + """ + Force terminal width to 80: some tests check the formatting of --help, which is sensible + to terminal width. + """ + monkeypatch.setenv("COLUMNS", "80") + + @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_collection_modifyitems(items): """Prefer faster tests. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/testing/logging/test_fixture.py new/pytest-7.4.3/testing/logging/test_fixture.py --- old/pytest-7.4.2/testing/logging/test_fixture.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/testing/logging/test_fixture.py 2023-10-24 21:07:09.000000000 +0200 @@ -1,5 +1,7 @@ # mypy: disable-error-code="attr-defined" +# mypy: disallow-untyped-defs import logging +from typing import Iterator import pytest from _pytest.logging import caplog_records_key @@ -9,8 +11,8 @@ sublogger = logging.getLogger(__name__ + ".baz") -@pytest.fixture -def cleanup_disabled_logging(): +@pytest.fixture(autouse=True) +def cleanup_disabled_logging() -> Iterator[None]: """Simple fixture that ensures that a test doesn't disable logging. This is necessary because ``logging.disable()`` is global, so a test disabling logging @@ -27,7 +29,7 @@ result.stdout.fnmatch_lines(["*caplog*"]) -def test_change_level(caplog): +def test_change_level(caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.INFO) logger.debug("handler DEBUG level") logger.info("handler INFO level") @@ -42,7 +44,7 @@ assert "CRITICAL" in caplog.text -def test_change_level_logging_disabled(caplog, cleanup_disabled_logging): +def test_change_level_logging_disabled(caplog: pytest.LogCaptureFixture) -> None: logging.disable(logging.CRITICAL) assert logging.root.manager.disable == logging.CRITICAL caplog.set_level(logging.WARNING) @@ -85,9 +87,7 @@ result.stdout.no_fnmatch_line("*log from test2*") -def test_change_disabled_level_undo( - pytester: Pytester, cleanup_disabled_logging -) -> None: +def test_change_disabled_level_undo(pytester: Pytester) -> None: """Ensure that '_force_enable_logging' in 'set_level' is undone after the end of the test. Tests the logging output themselves (affected by disabled logging level). @@ -144,7 +144,7 @@ result.assert_outcomes(passed=3) -def test_with_statement(caplog): +def test_with_statement(caplog: pytest.LogCaptureFixture) -> None: with caplog.at_level(logging.INFO): logger.debug("handler DEBUG level") logger.info("handler INFO level") @@ -159,7 +159,7 @@ assert "CRITICAL" in caplog.text -def test_with_statement_logging_disabled(caplog, cleanup_disabled_logging): +def test_with_statement_logging_disabled(caplog: pytest.LogCaptureFixture) -> None: logging.disable(logging.CRITICAL) assert logging.root.manager.disable == logging.CRITICAL with caplog.at_level(logging.WARNING): @@ -198,8 +198,8 @@ ], ) def test_force_enable_logging_level_string( - caplog, cleanup_disabled_logging, level_str, expected_disable_level -): + caplog: pytest.LogCaptureFixture, level_str: str, expected_disable_level: int +) -> None: """Test _force_enable_logging using a level string. ``expected_disable_level`` is one level below ``level_str`` because the disabled log level @@ -218,7 +218,7 @@ assert test_logger.manager.disable == expected_disable_level -def test_log_access(caplog): +def test_log_access(caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.INFO) logger.info("boo %s", "arg") assert caplog.records[0].levelname == "INFO" @@ -226,7 +226,7 @@ assert "boo arg" in caplog.text -def test_messages(caplog): +def test_messages(caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.INFO) logger.info("boo %s", "arg") logger.info("bar %s\nbaz %s", "arg1", "arg2") @@ -247,14 +247,14 @@ assert "Exception" not in caplog.messages[-1] -def test_record_tuples(caplog): +def test_record_tuples(caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.INFO) logger.info("boo %s", "arg") assert caplog.record_tuples == [(__name__, logging.INFO, "boo arg")] -def test_unicode(caplog): +def test_unicode(caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.INFO) logger.info("bū") assert caplog.records[0].levelname == "INFO" @@ -262,7 +262,7 @@ assert "bū" in caplog.text -def test_clear(caplog): +def test_clear(caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.INFO) logger.info("bū") assert len(caplog.records) @@ -273,7 +273,9 @@ @pytest.fixture -def logging_during_setup_and_teardown(caplog): +def logging_during_setup_and_teardown( + caplog: pytest.LogCaptureFixture, +) -> Iterator[None]: caplog.set_level("INFO") logger.info("a_setup_log") yield @@ -281,7 +283,9 @@ assert [x.message for x in caplog.get_records("teardown")] == ["a_teardown_log"] -def test_caplog_captures_for_all_stages(caplog, logging_during_setup_and_teardown): +def test_caplog_captures_for_all_stages( + caplog: pytest.LogCaptureFixture, logging_during_setup_and_teardown: None +) -> None: assert not caplog.records assert not caplog.get_records("call") logger.info("a_call_log") @@ -290,25 +294,31 @@ assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"] # This reaches into private API, don't use this type of thing in real tests! - assert set(caplog._item.stash[caplog_records_key]) == {"setup", "call"} + caplog_records = caplog._item.stash[caplog_records_key] + assert set(caplog_records) == {"setup", "call"} -def test_clear_for_call_stage(caplog, logging_during_setup_and_teardown): +def test_clear_for_call_stage( + caplog: pytest.LogCaptureFixture, logging_during_setup_and_teardown: None +) -> None: logger.info("a_call_log") assert [x.message for x in caplog.get_records("call")] == ["a_call_log"] assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"] - assert set(caplog._item.stash[caplog_records_key]) == {"setup", "call"} + caplog_records = caplog._item.stash[caplog_records_key] + assert set(caplog_records) == {"setup", "call"} caplog.clear() assert caplog.get_records("call") == [] assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"] - assert set(caplog._item.stash[caplog_records_key]) == {"setup", "call"} + caplog_records = caplog._item.stash[caplog_records_key] + assert set(caplog_records) == {"setup", "call"} logging.info("a_call_log_after_clear") assert [x.message for x in caplog.get_records("call")] == ["a_call_log_after_clear"] assert [x.message for x in caplog.get_records("setup")] == ["a_setup_log"] - assert set(caplog._item.stash[caplog_records_key]) == {"setup", "call"} + caplog_records = caplog._item.stash[caplog_records_key] + assert set(caplog_records) == {"setup", "call"} def test_ini_controls_global_log_level(pytester: Pytester) -> None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/testing/test_assertrewrite.py new/pytest-7.4.3/testing/test_assertrewrite.py --- old/pytest-7.4.2/testing/test_assertrewrite.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/testing/test_assertrewrite.py 2023-10-24 21:07:09.000000000 +0200 @@ -1531,6 +1531,28 @@ result.stdout.fnmatch_lines(["*assert 4 > 5", "*where 5 = add_one(4)"]) +class TestIssue11239: + @pytest.mark.skipif(sys.version_info[:2] <= (3, 7), reason="Only Python 3.8+") + def test_assertion_walrus_different_test_cases(self, pytester: Pytester) -> None: + """Regression for (#11239) + + Walrus operator rewriting would leak to separate test cases if they used the same variables. + """ + pytester.makepyfile( + """ + def test_1(): + state = {"x": 2}.get("x") + assert state is not None + + def test_2(): + db = {"x": 2} + assert (state := db.get("x")) is not None + """ + ) + result = pytester.runpytest() + assert result.ret == 0 + + @pytest.mark.skipif( sys.maxsize <= (2**31 - 1), reason="Causes OverflowError on 32bit systems" ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/testing/test_mark.py new/pytest-7.4.3/testing/test_mark.py --- old/pytest-7.4.2/testing/test_mark.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/testing/test_mark.py 2023-10-24 21:07:09.000000000 +0200 @@ -1130,6 +1130,41 @@ all_marks = get_unpacked_marks(C) - assert all_marks == [xfail("c").mark, xfail("a").mark, xfail("b").mark] + assert all_marks == [xfail("b").mark, xfail("a").mark, xfail("c").mark] assert get_unpacked_marks(C, consider_mro=False) == [xfail("c").mark] + + +# @pytest.mark.issue("https://github.com/pytest-dev/pytest/issues/10447") +def test_mark_fixture_order_mro(pytester: Pytester): + """This ensures we walk marks of the mro starting with the base classes + the action at a distance fixtures are taken as minimal example from a real project + + """ + foo = pytester.makepyfile( + """ + import pytest + + @pytest.fixture + def add_attr1(request): + request.instance.attr1 = object() + + + @pytest.fixture + def add_attr2(request): + request.instance.attr2 = request.instance.attr1 + + + @pytest.mark.usefixtures('add_attr1') + class Parent: + pass + + + @pytest.mark.usefixtures('add_attr2') + class TestThings(Parent): + def test_attrs(self): + assert self.attr1 == self.attr2 + """ + ) + result = pytester.runpytest(foo) + result.assert_outcomes(passed=1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/testing/test_parseopt.py new/pytest-7.4.3/testing/test_parseopt.py --- old/pytest-7.4.2/testing/test_parseopt.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/testing/test_parseopt.py 2023-10-24 21:07:09.000000000 +0200 @@ -291,7 +291,8 @@ def test_argcomplete(pytester: Pytester, monkeypatch: MonkeyPatch) -> None: try: - encoding = locale.getencoding() # New in Python 3.11, ignores utf-8 mode + # New in Python 3.11, ignores utf-8 mode + encoding = locale.getencoding() # type: ignore[attr-defined] except AttributeError: encoding = locale.getpreferredencoding(False) try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pytest-7.4.2/testing/test_pathlib.py new/pytest-7.4.3/testing/test_pathlib.py --- old/pytest-7.4.2/testing/test_pathlib.py 2023-09-07 20:43:41.000000000 +0200 +++ new/pytest-7.4.3/testing/test_pathlib.py 2023-10-24 21:07:09.000000000 +0200 @@ -28,6 +28,7 @@ from _pytest.pathlib import safe_exists from _pytest.pathlib import symlink_or_skip from _pytest.pathlib import visit +from _pytest.pytester import Pytester from _pytest.tmpdir import TempPathFactory @@ -592,6 +593,10 @@ result = module_name_from_path(tmp_path / "src/app/__init__.py", tmp_path) assert result == "src.app" + # Unless __init__.py file is at the root, in which case we cannot have an empty module name. + result = module_name_from_path(tmp_path / "__init__.py", tmp_path) + assert result == "__init__" + def test_insert_missing_modules( self, monkeypatch: MonkeyPatch, tmp_path: Path ) -> None: @@ -663,6 +668,22 @@ mod = import_path(init, root=tmp_path, mode=ImportMode.importlib) assert len(mod.instance.INSTANCES) == 1 + def test_importlib_root_is_package(self, pytester: Pytester) -> None: + """ + Regression for importing a `__init__`.py file that is at the root + (#11417). + """ + pytester.makepyfile(__init__="") + pytester.makepyfile( + """ + def test_my_test(): + assert True + """ + ) + + result = pytester.runpytest("--import-mode=importlib") + result.stdout.fnmatch_lines("* 1 passed *") + def test_safe_exists(tmp_path: Path) -> None: d = tmp_path.joinpath("some_dir")