Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions src/_pytest/_code/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
36 changes: 21 additions & 15 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
18 changes: 10 additions & 8 deletions src/_pytest/raises.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)})"

Expand Down