pytest-dev / pytest-dev/pytest

type-safe markers

Open
#11,602 1 comment 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

topic: marks topic: typing
Dominant language
Python
Stars
14.5k
Forks
3.4k
Avg merge
2d 9h
Merged PRs (30d)
35

Description

What's the problem this feature will solve?

currently when creating a custom marker, there's no way for the type checker to ensure the arguments are correct. the builtin markers work around this by having type-checking only subtypes of MarkDecorator like so (in _pytest/mark./structures.py):

# Typing for builtin pytest marks. This is cheating; it gives builtin marks
# special privilege, and breaks modularity. But practicality beats purity...
if TYPE_CHECKING:
    from _pytest.scope import _ScopeName

    class _SkipMarkDecorator(MarkDecorator):
        @overload  # type: ignore[override,misc,no-overload-impl]
        def __call__(self, arg: Markable) -> Markable:
            ...

        @overload
        def __call__(self, reason: str = ...) -> "MarkDecorator":
            ...
Describe the solution you'd like

a way to define markers in a type-safe way, similar to how the builtin markers are defined. maybe something like this:

# conftest.py
class Foo(MarkDecorator):
    @override
    def __call__(self, value: int) -> MarkDecorator: ...
# test_foo.py
from conftest import Foo

@Foo("asdf")  # error: expected int, got str
def test_asdf(): ...
Alternative Solutions

remove the @final from MarkGenerator and allow plugins to subtype it with their custom markers:

# conftest.py
from pytest import MarkGenerator

class CustomMarkers(MarkGenerator):
    foo: Callable[[int], MarkDecorator]
# test_foo.py
from conftest import CustomMarkers

mark = CustomMarkers()

@mark.foo("asdf")  # error: expected int, got str
def test_asdf(): ...

this solution probably isn't the best though since there'd be no way to enforce that users use your subtype. whereas making each marker separate classes would at least allow you to enforce that @Foo is used over @mark.foo using --strict-markers

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading _pytest/mark./structures.py, especially MarkDecorator and the builtin marker typing definitions. Compare the proposed custom MarkDecorator and MarkGenerator approaches, then determine and document a supported type-safe API with coverage for incorrect marker argument types and marker usage.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.