Shared task
fix #7792: consider marks from the mro
PR #10356 ↗ · pytest-dev/pytest · · merged Oct 15, 2022 · +59 −7 · base 3c1534944cbd
what a new run launched now would send
Consider MRO when obtaining marks for classes
When using pytest markers in two baseclasses `Foo` and `Bar`, inheriting from both of those baseclasses will lose the markers of one of those classes. This behavior is present in pytest 3-6, and I think it may as well have been intended. I am still filing it as a bug because I am not sure if this edge case was ever explicitly considered.
If it is widely understood that all markers are part of a single attribute, I guess you could say that this is just expected behavior as per MRO. However, I'd argue that it would be more intuitive to attempt to merge marker values into one, possibly deduplicating marker names by MRO.
```python
import itertools
import pytest
class BaseMeta(type):
@property
def pytestmark(self):
return (
getattr(self, "_pytestmark", []) +
list(itertools.chain.from_iterable(getattr(x, "_pytestmark", []) for x in self.__mro__))
)
@pytestmark.setter
def pytestmark(self, value):
self._pytestmark = value
class Base(object):
# Without this metaclass, foo and bar markers override each other, and test_dings
# will only have one marker
# With the metaclass, test_dings will have both
__metaclass__ = BaseMeta
@pytest.mark.foo
class Foo(Base):
pass
@pytest.mark.bar
class Bar(Base):
pass
class TestDings(Foo, Bar):
def test_dings(self):
# This test should have both markers, foo and bar.
# In practice markers are resolved using MRO (so foo wins), unless the
# metaclass is applied
pass
```
I'd expect `foo` and `bar` to be markers for `test_dings`, but this only actually is the case with this metaclass.
Please note that the repro case is Python 2/3 compatible excluding how metaclasses are added to `Base` (this needs to be taken care of to repro this issue on pytest 6)
Consider MRO when obtaining marks for classes
When using pytest markers in two baseclasses `Foo` and `Bar`, inheriting from both of those baseclasses will lose the markers of one of those classes. This behavior is present in pytest 3-6, and I think it may as well have been intended. I am still filing it as a bug because I am not sure if this edge case was ever explicitly considered.
If it is widely understood that all markers are part of a single attribute, I guess you could say that this is just expected behavior as per MRO. However, I'd argue that it would be more intuitive to attempt to merge marker values into one, possibly deduplicating marker names by MRO.
```python
import itertools
import pytest
class BaseMeta(type):
@property
def pytestmark(self):
return (
getattr(self, "_pytestmark", []) +
list(itertools.chain.from_iterable(getattr(x, "_pytestmark", []) for x in self.__mro__))
)
@pytestmark.setter
def pytestmark(self, value):
self._pytestmark = value
class Base(object):
# Without this metaclass, foo and bar markers override each other, and test_dings
# will only have one marker
# With the metaclass, test_dings will have both
__metaclass__ = BaseMeta
@pytest.mark.foo
class Foo(Base):
pass
@pytest.mark.bar
class Bar(Base):
pass
class TestDings(Foo, Bar):
def test_dings(self):
# This test should have both markers, foo and bar.
# In practice markers are resolved using MRO (so foo wins), unless the
# metaclass is applied
pass
```
I'd expect `foo` and `bar` to be markers for `test_dings`, but this only actually is the case with this metaclass.
Please note that the repro case is Python 2/3 compatible excluding how metaclasses are added to `Base` (this needs to be taken care of to repro this issue on pytest 6)
Fix missing marks when inheritance from multiple classes
<!--
Thanks for submitting a PR, your contribution is really appreciated!
Here is a quick checklist that should be present in PRs.
- [] Include documentation when adding new features.
- [ ] Include new tests or update existing tests when applicable.
- [X] Allow maintainers to push and squash when merging my commits. Please uncheck this if you prefer to squash the commits yourself.
If this change fixes an issue, please:
- [x] Add text like ``closes #XYZW`` to the PR description and/or commits (where ``XYZW`` is the issue number). See the [github docs](https://help.github.com/en/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) for more information.
Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:
- [x] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/main/changelog/README.rst) for details.
Write sentences in the **past or present tense**, examples:
* *Improved verbose diff output with sequences.*
* *Terminal summary statistics now use multiple colors.*
Also make sure to end the sentence with a `.`.
- [x] Add yourself to `AUTHORS` in alphabetical order.
-->
Work only inside this repository checkout. Make the code change the task
describes, keeping the diff focused — no drive-by refactors.
When you are done, leave your changes committed or in the working tree;
they are collected automatically.
Stay on this snapshot checkout (`task/ycb_pytest_pr10356`). Never checkout, pull, or rebase onto `main`. That branch is a README-only orphan.
Stay on this HEAD. Do not fetch another default branch. Push only on the Cursor-created `crazy-cursor/…` side branch from this HEAD.Some past runs of this task were launched with a different prompt (the prompt template changed since, or those runs predate this benchmark's stored prompt). Each run persists the exact prompt it sent at launch — that per-launch record is the audit trail; this page shows only the current one.
| Run | Model | Verdict |
|---|---|---|
| Aug 21, 12:31 UTC · completed | composer-2.5 | PASS |
| Aug 21, 12:31 UTC · completed | grok-4.6 | PASS |
| Aug 21, 12:31 UTC · completed | grok-4.6-low |
Powered by YourCodingBench — benchmark coding models on your own repo's commits. sign in
| Aug 21, 12:31 UTC · completed | grok-4.6-medium | PASS |
| Aug 21, 12:31 UTC · completed | grok-4.6-xhigh | PASS |
Binary verdicts from the pinned judge (D27). Full attempt detail — candidate diff, transcript, timings — lives on each run page's score matrix.