Function: use `originalname` in `_getobj` and make it default to `name` (#7035)
This commit is contained in:
parent
9310d67773
commit
8b9b81c3c0
|
@ -0,0 +1,2 @@
|
||||||
|
The ``originalname`` attribute of ``_pytest.python.Function`` now defaults to ``name`` if not
|
||||||
|
provided explicitly, and is always set.
|
|
@ -1395,11 +1395,41 @@ class Function(PyobjMixin, nodes.Item):
|
||||||
fixtureinfo: Optional[FuncFixtureInfo] = None,
|
fixtureinfo: Optional[FuncFixtureInfo] = None,
|
||||||
originalname=None,
|
originalname=None,
|
||||||
) -> 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)
|
super().__init__(name, parent, config=config, session=session)
|
||||||
self._args = args
|
self._args = args
|
||||||
if callobj is not NOTSET:
|
if callobj is not NOTSET:
|
||||||
self.obj = callobj
|
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.keywords.update(self.obj.__dict__)
|
||||||
self.own_markers.extend(get_unpacked_marks(self.obj))
|
self.own_markers.extend(get_unpacked_marks(self.obj))
|
||||||
if callspec:
|
if callspec:
|
||||||
|
@ -1434,12 +1464,6 @@ class Function(PyobjMixin, nodes.Item):
|
||||||
self.fixturenames = fixtureinfo.names_closure
|
self.fixturenames = fixtureinfo.names_closure
|
||||||
self._initrequest()
|
self._initrequest()
|
||||||
|
|
||||||
#: original function name, without any decorations (for example
|
|
||||||
#: parametrization adds a ``"[...]"`` suffix to function names).
|
|
||||||
#:
|
|
||||||
#: .. versionadded:: 3.0
|
|
||||||
self.originalname = originalname
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_parent(cls, parent, **kw): # todo: determine sound type limitations
|
def from_parent(cls, parent, **kw): # todo: determine sound type limitations
|
||||||
"""
|
"""
|
||||||
|
@ -1457,11 +1481,7 @@ class Function(PyobjMixin, nodes.Item):
|
||||||
return getimfunc(self.obj)
|
return getimfunc(self.obj)
|
||||||
|
|
||||||
def _getobj(self):
|
def _getobj(self):
|
||||||
name = self.name
|
return getattr(self.parent.obj, self.originalname)
|
||||||
i = name.find("[") # parametrization
|
|
||||||
if i != -1:
|
|
||||||
name = name[:i]
|
|
||||||
return getattr(self.parent.obj, name)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _pyfuncitem(self):
|
def _pyfuncitem(self):
|
||||||
|
|
|
@ -6,6 +6,7 @@ import _pytest._code
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.config import ExitCode
|
from _pytest.config import ExitCode
|
||||||
from _pytest.nodes import Collector
|
from _pytest.nodes import Collector
|
||||||
|
from _pytest.pytester import Testdir
|
||||||
|
|
||||||
|
|
||||||
class TestModule:
|
class TestModule:
|
||||||
|
@ -659,16 +660,39 @@ class TestFunction:
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(["* 3 passed in *"])
|
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(
|
items = testdir.getitems(
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@pytest.mark.parametrize('arg', [1,2])
|
@pytest.mark.parametrize('arg', [1,2])
|
||||||
def test_func(arg):
|
def test_func(arg):
|
||||||
pass
|
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:
|
class TestSorting:
|
||||||
|
|
Loading…
Reference in New Issue