Merge pull request #9171 from bluetech/optimize-keywords-init
Optimizations/fixes around Function `keywords`
This commit is contained in:
commit
888026f7a6
|
@ -303,6 +303,9 @@ class PyobjMixin(nodes.Node):
|
|||
# used to avoid Function marker duplication
|
||||
if self._ALLOW_MARKERS:
|
||||
self.own_markers.extend(get_unpacked_marks(self.obj))
|
||||
# This assumes that `obj` is called before there is a chance
|
||||
# to add custom keys to `self.keywords`, so no fear of overriding.
|
||||
self.keywords.update((mark.name, mark) for mark in self.own_markers)
|
||||
return obj
|
||||
|
||||
@obj.setter
|
||||
|
@ -1634,7 +1637,7 @@ class Function(PyobjMixin, nodes.Item):
|
|||
config: Optional[Config] = None,
|
||||
callspec: Optional[CallSpec2] = None,
|
||||
callobj=NOTSET,
|
||||
keywords=None,
|
||||
keywords: Optional[Mapping[str, Any]] = None,
|
||||
session: Optional[Session] = None,
|
||||
fixtureinfo: Optional[FuncFixtureInfo] = None,
|
||||
originalname: Optional[str] = None,
|
||||
|
@ -1655,31 +1658,20 @@ class Function(PyobjMixin, nodes.Item):
|
|||
# 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:
|
||||
self.callspec = callspec
|
||||
# this is total hostile and a mess
|
||||
# keywords are broken by design by now
|
||||
# this will be redeemed later
|
||||
for mark in callspec.marks:
|
||||
# feel free to cry, this was broken for years before
|
||||
# and keywords can't fix it per design
|
||||
self.keywords[mark.name] = mark
|
||||
self.own_markers.extend(normalize_mark_list(callspec.marks))
|
||||
if keywords:
|
||||
self.keywords.update(keywords)
|
||||
self.own_markers.extend(callspec.marks)
|
||||
|
||||
# todo: this is a hell of a hack
|
||||
# https://github.com/pytest-dev/pytest/issues/4569
|
||||
|
||||
self.keywords.update(
|
||||
{
|
||||
mark.name: True
|
||||
for mark in self.iter_markers()
|
||||
if mark.name not in self.keywords
|
||||
}
|
||||
)
|
||||
# Note: the order of the updates is important here; indicates what
|
||||
# takes priority (ctor argument over function attributes over markers).
|
||||
# Take own_markers only; NodeKeywords handles parent traversal on its own.
|
||||
self.keywords.update((mark.name, mark) for mark in self.own_markers)
|
||||
self.keywords.update(self.obj.__dict__)
|
||||
if keywords:
|
||||
self.keywords.update(keywords)
|
||||
|
||||
if fixtureinfo is None:
|
||||
fixtureinfo = self.session._fixturemanager.getfixtureinfo(
|
||||
|
|
|
@ -7,6 +7,7 @@ from typing import Dict
|
|||
from typing import Iterable
|
||||
from typing import Iterator
|
||||
from typing import List
|
||||
from typing import Mapping
|
||||
from typing import Optional
|
||||
from typing import Tuple
|
||||
from typing import Type
|
||||
|
@ -254,7 +255,7 @@ class TestReport(BaseReport):
|
|||
self,
|
||||
nodeid: str,
|
||||
location: Tuple[str, Optional[int], str],
|
||||
keywords,
|
||||
keywords: Mapping[str, Any],
|
||||
outcome: "Literal['passed', 'failed', 'skipped']",
|
||||
longrepr: Union[
|
||||
None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr
|
||||
|
|
|
@ -881,6 +881,36 @@ class TestNodeKeywords:
|
|||
assert item.keywords["kw"] == "method"
|
||||
assert len(item.keywords) == len(set(item.keywords))
|
||||
|
||||
def test_unpacked_marks_added_to_keywords(self, pytester: Pytester) -> None:
|
||||
item = pytester.getitem(
|
||||
"""
|
||||
import pytest
|
||||
pytestmark = pytest.mark.foo
|
||||
class TestClass:
|
||||
pytestmark = pytest.mark.bar
|
||||
def test_method(self): pass
|
||||
test_method.pytestmark = pytest.mark.baz
|
||||
""",
|
||||
"test_method",
|
||||
)
|
||||
assert isinstance(item, pytest.Function)
|
||||
cls = item.getparent(pytest.Class)
|
||||
assert cls is not None
|
||||
mod = item.getparent(pytest.Module)
|
||||
assert mod is not None
|
||||
|
||||
assert item.keywords["foo"] == pytest.mark.foo.mark
|
||||
assert item.keywords["bar"] == pytest.mark.bar.mark
|
||||
assert item.keywords["baz"] == pytest.mark.baz.mark
|
||||
|
||||
assert cls.keywords["foo"] == pytest.mark.foo.mark
|
||||
assert cls.keywords["bar"] == pytest.mark.bar.mark
|
||||
assert "baz" not in cls.keywords
|
||||
|
||||
assert mod.keywords["foo"] == pytest.mark.foo.mark
|
||||
assert "bar" not in mod.keywords
|
||||
assert "baz" not in mod.keywords
|
||||
|
||||
|
||||
COLLECTION_ERROR_PY_FILES = dict(
|
||||
test_01_failure="""
|
||||
|
|
Loading…
Reference in New Issue