fix #5
This commit is contained in:
parent
6b9f5ded0f
commit
f19627ef33
|
@ -34,6 +34,7 @@ pytest 6.2.5 (2021-08-29)
|
|||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#9175 <https://github.com/pytest-dev/pytest/issues/9175>`_: Fix duplicate parametrizes in the same module.
|
||||
- `#7792 <https://github.com/pytest-dev/pytest/issues/7792>`_: Fix missing marks when inheritance from multiple classes.
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import attr
|
|||
|
||||
from .._code import getfslineno
|
||||
from ..compat import ascii_escaped
|
||||
from ..compat import cached_property
|
||||
from ..compat import final
|
||||
from ..compat import NOTSET
|
||||
from ..compat import NotSetType
|
||||
|
@ -259,6 +260,11 @@ class Mark:
|
|||
_ispytest=True,
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def unique_name(self):
|
||||
# For "parametrize" mark, the name value is "parametrize" and not the name that the user was wrote
|
||||
return str(self.args[0] if self.name == "parametrize" else self.name)
|
||||
|
||||
|
||||
# A generic parameter designating an object to which a Mark may
|
||||
# be applied -- a test function (callable) or class.
|
||||
|
@ -370,17 +376,18 @@ def get_unpacked_marks(obj: object) -> Iterable[Mark]:
|
|||
|
||||
def get_mro_marks(cls: type):
|
||||
if cls is object or cls is None or hasattr(cls, "mro_markers"):
|
||||
return getattr(cls, "mro_markers", [])
|
||||
return getattr(cls, "mro_markers", {})
|
||||
|
||||
# markers = list(mark for mark in get_unpacked_marks(cls) if mark.name != "parametrize")
|
||||
markers = list(mark for mark in get_unpacked_marks(cls))
|
||||
mro_markers = {mark.unique_name: mark for mark in get_unpacked_marks(cls)}
|
||||
for parent_obj in cls.__mro__[1:]:
|
||||
if parent_obj is not object:
|
||||
markers.extend(get_mro_marks(parent_obj))
|
||||
for unique_name, mark in get_mro_marks(parent_obj).items():
|
||||
if unique_name not in mro_markers:
|
||||
mro_markers[unique_name] = mark
|
||||
|
||||
# To not extract the marks for each item's classes, I store the variable in "cls" as variable cached.
|
||||
setattr(cls, "mro_markers", list({str(mark): mark for mark in markers}.values()))
|
||||
return markers
|
||||
setattr(cls, "mro_markers", mro_markers)
|
||||
return mro_markers
|
||||
|
||||
|
||||
def normalize_mark_list(
|
||||
|
|
|
@ -382,9 +382,9 @@ class Node(metaclass=NodeMeta):
|
|||
for node in reversed(self.listchain()):
|
||||
for mark in node.own_markers:
|
||||
if name is None or getattr(mark, "name", None) == name:
|
||||
mark_to_str = str(mark)
|
||||
if mark_to_str not in duplicate_marks:
|
||||
duplicate_marks[mark_to_str] = mark
|
||||
mark_to_name = str(mark)
|
||||
if mark_to_name not in duplicate_marks:
|
||||
duplicate_marks[mark_to_name] = mark
|
||||
yield node, mark
|
||||
|
||||
@overload
|
||||
|
|
|
@ -1620,7 +1620,12 @@ class Function(PyobjMixin, nodes.Item):
|
|||
self.keywords.update(self.obj.__dict__)
|
||||
self.own_markers.extend(get_unpacked_marks(self.obj))
|
||||
if self.cls:
|
||||
self.own_markers.extend(get_mro_marks(self.cls))
|
||||
self.own_markers = list(
|
||||
dict(
|
||||
get_mro_marks(self.cls),
|
||||
**{mark.unique_name: mark for mark in self.own_markers},
|
||||
).values()
|
||||
)
|
||||
if callspec:
|
||||
self.callspec = callspec
|
||||
# this is total hostile and a mess
|
||||
|
|
|
@ -1130,6 +1130,7 @@ def test_marker_expr_eval_failure_handling(pytester: Pytester, expr) -> None:
|
|||
|
||||
|
||||
def test_markers_from_multiple_inheritances(pytester: Pytester) -> None:
|
||||
# https://github.com/pytest-dev/pytest/issues/7792
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
|
@ -1150,3 +1151,34 @@ def test_markers_from_multiple_inheritances(pytester: Pytester) -> None:
|
|||
)
|
||||
result = pytester.inline_run()
|
||||
result.assertoutcome(passed=1)
|
||||
|
||||
|
||||
def test_duplicate_fixtures_in_same_class(pytester: Pytester) -> None:
|
||||
# https://github.com/pytest-dev/pytest/issues/9175
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def some_fixture(request) -> Any:
|
||||
return request.param
|
||||
|
||||
|
||||
# I apply to all test methods
|
||||
@pytest.mark.parametrize("some_fixture", [{"b": "b"}], indirect=True)
|
||||
class TestMultiParameterization:
|
||||
# I apply to just this one test method
|
||||
@pytest.mark.parametrize("some_fixture", [{"a": "a"}], indirect=True)
|
||||
def test_local_some_fixture(self, some_fixture: Any) -> None:
|
||||
assert "a" in some_fixture
|
||||
|
||||
def test_global_some_fixture(self, some_fixture: Any) -> None:
|
||||
assert "b" in some_fixture
|
||||
|
||||
"""
|
||||
)
|
||||
result = pytester.inline_run()
|
||||
result.assertoutcome(passed=2)
|
||||
|
|
Loading…
Reference in New Issue