Function: use `originalname` in `_getobj` and make it default to `name` (#7035)

This commit is contained in:
Daniel Hahler 2020-05-18 19:08:47 +02:00 committed by GitHub
parent 9310d67773
commit 8b9b81c3c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 13 deletions

View File

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

View File

@ -1395,11 +1395,41 @@ class Function(PyobjMixin, nodes.Item):
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:
@ -1434,12 +1464,6 @@ class Function(PyobjMixin, nodes.Item):
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
"""
@ -1457,11 +1481,7 @@ class Function(PyobjMixin, nodes.Item):
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):

View File

@ -6,6 +6,7 @@ import _pytest._code
import pytest
from _pytest.config import ExitCode
from _pytest.nodes import Collector
from _pytest.pytester import Testdir
class TestModule:
@ -659,16 +660,39 @@ class TestFunction:
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: