diff --git a/src/_pytest/_code/source.py b/src/_pytest/_code/source.py index 9f0f6db312e..b7cae266225 100644 --- a/src/_pytest/_code/source.py +++ b/src/_pytest/_code/source.py @@ -24,23 +24,25 @@ def __init__(self, obj: object = None) -> None: if not obj: self.lines: list[str] = [] self.raw_lines: list[str] = [] - elif isinstance(obj, Source): - self.lines = obj.lines - self.raw_lines = obj.raw_lines - elif isinstance(obj, tuple | list): - self.lines = deindent(x.rstrip("\n") for x in obj) - self.raw_lines = list(x.rstrip("\n") for x in obj) - elif isinstance(obj, str): - self.lines = deindent(obj.split("\n")) - self.raw_lines = obj.split("\n") - else: - try: - rawcode = getrawcode(obj) - src = inspect.getsource(rawcode) - except TypeError: - src = inspect.getsource(obj) # type: ignore[arg-type] - self.lines = deindent(src.split("\n")) - self.raw_lines = src.split("\n") + return + match obj: + case Source(): + self.lines = obj.lines + self.raw_lines = obj.raw_lines + case tuple() | list(): + self.lines = deindent(x.rstrip("\n") for x in obj) + self.raw_lines = list(x.rstrip("\n") for x in obj) + case str(): + self.lines = deindent(obj.split("\n")) + self.raw_lines = obj.split("\n") + case _: + try: + rawcode = getrawcode(obj) + src = inspect.getsource(rawcode) + except TypeError: + src = inspect.getsource(obj) # type: ignore[arg-type] + self.lines = deindent(src.split("\n")) + self.raw_lines = src.split("\n") def __eq__(self, other: object) -> bool: if not isinstance(other, Source): diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 4f168012c36..82aef783725 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -48,6 +48,7 @@ from _pytest.compat import getimfunc from _pytest.compat import is_async_function from _pytest.compat import NOTSET +from _pytest.compat import NotSetType from _pytest.compat import safe_getattr from _pytest.compat import safe_isclass from _pytest.config import Config @@ -1100,21 +1101,26 @@ def _idval_from_hook(self, val: object, argname: str) -> str | None: def _idval_from_value(self, val: object) -> str | None: """Try to make an ID for a parameter in a ParameterSet from its value, if the value type is supported.""" - if isinstance(val, str | bytes): - return _ascii_escaped_by_config(val, self.config) - elif val is None or isinstance(val, float | int | bool | complex): - return str(val) - elif isinstance(val, re.Pattern): - return ascii_escaped(val.pattern) - elif val is NOTSET: - # Fallback to default. Note that NOTSET is an enum.Enum. - pass - elif isinstance(val, enum.Enum): - return str(val) - elif isinstance(getattr(val, "__name__", None), str): - # Name of a class, function, module, etc. - name: str = getattr(val, "__name__") - return name + match val: + case str() | bytes(): + return _ascii_escaped_by_config(val, self.config) + case None | float() | int() | bool() | complex(): + return str(val) + case re.Pattern(): + return ascii_escaped(val.pattern) + # NOTSET falls back to the default; it is an ``enum.Enum``, so it + # must be matched before the ``enum.Enum()`` arm below. A class + # pattern (not the ``NotSetType.token`` value pattern) is used + # because value patterns compare with ``==``, and ``val`` may have + # an ``__eq__`` that raises. + case NotSetType(): + pass + case enum.Enum(): + return str(val) + case _ if isinstance(getattr(val, "__name__", None), str): + # Name of a class, function, module, etc. + name: str = getattr(val, "__name__") + return name return None def _idval_from_value_required(self, val: object, idx: int) -> str: diff --git a/src/_pytest/raises.py b/src/_pytest/raises.py index ef91cc2c9fb..898683a85b9 100644 --- a/src/_pytest/raises.py +++ b/src/_pytest/raises.py @@ -1432,14 +1432,16 @@ def __exit__( def expected_type(self) -> str: subexcs = [] for e in self.expected_exceptions: - if isinstance(e, RaisesExc): - subexcs.append(repr(e)) - elif isinstance(e, RaisesGroup): - subexcs.append(e.expected_type()) - elif isinstance(e, type): - subexcs.append(e.__name__) - else: # pragma: no cover - raise AssertionError("unknown type") + match e: + case RaisesExc(): + subexc = repr(e) + case RaisesGroup(): + subexc = e.expected_type() + case type(): + subexc = e.__name__ + case _: # pragma: no cover + raise AssertionError("unknown type") + subexcs.append(subexc) group_type = "Base" if self.is_baseexception else "" return f"{group_type}ExceptionGroup({', '.join(subexcs)})"