Skip to content

Commit 8b9b81c

Browse files
authored
Function: use originalname in _getobj and make it default to name (#7035)
1 parent 9310d67 commit 8b9b81c

File tree

3 files changed

+59
-13
lines changed

3 files changed

+59
-13
lines changed

changelog/7035.trivial.rst

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The ``originalname`` attribute of ``_pytest.python.Function`` now defaults to ``name`` if not
2+
provided explicitly, and is always set.

src/_pytest/python.py

+31-11
Original file line numberDiff line numberDiff line change
@@ -1395,11 +1395,41 @@ def __init__(
13951395
fixtureinfo: Optional[FuncFixtureInfo] = None,
13961396
originalname=None,
13971397
) -> None:
1398+
"""
1399+
param name: the full function name, including any decorations like those
1400+
added by parametrization (``my_func[my_param]``).
1401+
param parent: the parent Node.
1402+
param args: (unused)
1403+
param config: the pytest Config object
1404+
param callspec: if given, this is function has been parametrized and the callspec contains
1405+
meta information about the parametrization.
1406+
param callobj: if given, the object which will be called when the Function is invoked,
1407+
otherwise the callobj will be obtained from ``parent`` using ``originalname``
1408+
param keywords: keywords bound to the function object for "-k" matching.
1409+
param session: the pytest Session object
1410+
param fixtureinfo: fixture information already resolved at this fixture node.
1411+
param originalname:
1412+
The attribute name to use for accessing the underlying function object.
1413+
Defaults to ``name``. Set this if name is different from the original name,
1414+
for example when it contains decorations like those added by parametrization
1415+
(``my_func[my_param]``).
1416+
"""
13981417
super().__init__(name, parent, config=config, session=session)
13991418
self._args = args
14001419
if callobj is not NOTSET:
14011420
self.obj = callobj
14021421

1422+
#: Original function name, without any decorations (for example
1423+
#: parametrization adds a ``"[...]"`` suffix to function names), used to access
1424+
#: the underlying function object from ``parent`` (in case ``callobj`` is not given
1425+
#: explicitly).
1426+
#:
1427+
#: .. versionadded:: 3.0
1428+
self.originalname = originalname or name
1429+
1430+
# note: when FunctionDefinition is introduced, we should change ``originalname``
1431+
# to a readonly property that returns FunctionDefinition.name
1432+
14031433
self.keywords.update(self.obj.__dict__)
14041434
self.own_markers.extend(get_unpacked_marks(self.obj))
14051435
if callspec:
@@ -1434,12 +1464,6 @@ def __init__(
14341464
self.fixturenames = fixtureinfo.names_closure
14351465
self._initrequest()
14361466

1437-
#: original function name, without any decorations (for example
1438-
#: parametrization adds a ``"[...]"`` suffix to function names).
1439-
#:
1440-
#: .. versionadded:: 3.0
1441-
self.originalname = originalname
1442-
14431467
@classmethod
14441468
def from_parent(cls, parent, **kw): # todo: determine sound type limitations
14451469
"""
@@ -1457,11 +1481,7 @@ def function(self):
14571481
return getimfunc(self.obj)
14581482

14591483
def _getobj(self):
1460-
name = self.name
1461-
i = name.find("[") # parametrization
1462-
if i != -1:
1463-
name = name[:i]
1464-
return getattr(self.parent.obj, name)
1484+
return getattr(self.parent.obj, self.originalname)
14651485

14661486
@property
14671487
def _pyfuncitem(self):

testing/python/collect.py

+26-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pytest
77
from _pytest.config import ExitCode
88
from _pytest.nodes import Collector
9+
from _pytest.pytester import Testdir
910

1011

1112
class TestModule:
@@ -659,16 +660,39 @@ def test_passed(x):
659660
result = testdir.runpytest()
660661
result.stdout.fnmatch_lines(["* 3 passed in *"])
661662

662-
def test_function_original_name(self, testdir):
663+
def test_function_originalname(self, testdir: Testdir) -> None:
663664
items = testdir.getitems(
664665
"""
665666
import pytest
667+
666668
@pytest.mark.parametrize('arg', [1,2])
667669
def test_func(arg):
668670
pass
671+
672+
def test_no_param():
673+
pass
669674
"""
670675
)
671-
assert [x.originalname for x in items] == ["test_func", "test_func"]
676+
assert [x.originalname for x in items] == [
677+
"test_func",
678+
"test_func",
679+
"test_no_param",
680+
]
681+
682+
def test_function_with_square_brackets(self, testdir: Testdir) -> None:
683+
"""Check that functions with square brackets don't cause trouble."""
684+
p1 = testdir.makepyfile(
685+
"""
686+
locals()["test_foo[name]"] = lambda: None
687+
"""
688+
)
689+
result = testdir.runpytest("-v", str(p1))
690+
result.stdout.fnmatch_lines(
691+
[
692+
"test_function_with_square_brackets.py::test_foo[[]name[]] PASSED *",
693+
"*= 1 passed in *",
694+
]
695+
)
672696

673697

674698
class TestSorting:

0 commit comments

Comments
 (0)