Skip to content

Commit

Permalink
Function: use originalname in _getobj and make it default to `nam…
Browse files Browse the repository at this point in the history
…e` (#7035)
  • Loading branch information
blueyed authored May 18, 2020
1 parent 9310d67 commit 8b9b81c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 13 deletions.
2 changes: 2 additions & 0 deletions changelog/7035.trivial.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The ``originalname`` attribute of ``_pytest.python.Function`` now defaults to ``name`` if not
provided explicitly, and is always set.
42 changes: 31 additions & 11 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -1395,11 +1395,41 @@ def __init__(
fixtureinfo: Optional[FuncFixtureInfo] = None,
originalname=None,
) -> None:
"""
param name: the full function name, including any decorations like those
added by parametrization (``my_func[my_param]``).
param parent: the parent Node.
param args: (unused)
param config: the pytest Config object
param callspec: if given, this is function has been parametrized and the callspec contains
meta information about the parametrization.
param callobj: if given, the object which will be called when the Function is invoked,
otherwise the callobj will be obtained from ``parent`` using ``originalname``
param keywords: keywords bound to the function object for "-k" matching.
param session: the pytest Session object
param fixtureinfo: fixture information already resolved at this fixture node.
param originalname:
The attribute name to use for accessing the underlying function object.
Defaults to ``name``. Set this if name is different from the original name,
for example when it contains decorations like those added by parametrization
(``my_func[my_param]``).
"""
super().__init__(name, parent, config=config, session=session)
self._args = args
if callobj is not NOTSET:
self.obj = callobj

#: Original function name, without any decorations (for example
#: parametrization adds a ``"[...]"`` suffix to function names), used to access
#: the underlying function object from ``parent`` (in case ``callobj`` is not given
#: explicitly).
#:
#: .. versionadded:: 3.0
self.originalname = originalname or name

# note: when FunctionDefinition is introduced, we should change ``originalname``
# to a readonly property that returns FunctionDefinition.name

self.keywords.update(self.obj.__dict__)
self.own_markers.extend(get_unpacked_marks(self.obj))
if callspec:
Expand Down Expand Up @@ -1434,12 +1464,6 @@ def __init__(
self.fixturenames = fixtureinfo.names_closure
self._initrequest()

#: original function name, without any decorations (for example
#: parametrization adds a ``"[...]"`` suffix to function names).
#:
#: .. versionadded:: 3.0
self.originalname = originalname

@classmethod
def from_parent(cls, parent, **kw): # todo: determine sound type limitations
"""
Expand All @@ -1457,11 +1481,7 @@ def function(self):
return getimfunc(self.obj)

def _getobj(self):
name = self.name
i = name.find("[") # parametrization
if i != -1:
name = name[:i]
return getattr(self.parent.obj, name)
return getattr(self.parent.obj, self.originalname)

@property
def _pyfuncitem(self):
Expand Down
28 changes: 26 additions & 2 deletions testing/python/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import pytest
from _pytest.config import ExitCode
from _pytest.nodes import Collector
from _pytest.pytester import Testdir


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

def test_function_original_name(self, testdir):
def test_function_originalname(self, testdir: Testdir) -> None:
items = testdir.getitems(
"""
import pytest
@pytest.mark.parametrize('arg', [1,2])
def test_func(arg):
pass
def test_no_param():
pass
"""
)
assert [x.originalname for x in items] == ["test_func", "test_func"]
assert [x.originalname for x in items] == [
"test_func",
"test_func",
"test_no_param",
]

def test_function_with_square_brackets(self, testdir: Testdir) -> None:
"""Check that functions with square brackets don't cause trouble."""
p1 = testdir.makepyfile(
"""
locals()["test_foo[name]"] = lambda: None
"""
)
result = testdir.runpytest("-v", str(p1))
result.stdout.fnmatch_lines(
[
"test_function_with_square_brackets.py::test_foo[[]name[]] PASSED *",
"*= 1 passed in *",
]
)


class TestSorting:
Expand Down

0 comments on commit 8b9b81c

Please sign in to comment.