pytest-dev / pytest-dev/pytest

Typing and public API

Open
#7,469 41 comments 63 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

pytest's "official" public API is exported by the pytest package, and everything else is defined in the _pytest package.

Currently, pytest only contains APIs that users need to use directly: functions to be called, decorators, classes to be instantiated or subclasssed, globals. Other objects, which the user doesn't interact with directly, are not exported.

Typing extends the range of cases in which some object needs to be referred to by name. As long as the user can somehow reach an object, directly or indirectly, through some public API, they need to be able to refer to its type by name, due to type annotations.

To come up with a list of reachable but unexported types, I used the following categories:

  1. Fixtures: built-in fixtures that are dependency-injected. To benefit from the types the user needs to type annotate them, for example:

    def test_it(monkeypatch: MonkeyPatch) -> None:
        ...
    
  2. Hooks: the user needs to be able to type annotate the arguments and return values of any hook.

  3. Transitive: types that are referred to transitively by some other public API, e.g. return value of a function, method, context manager, public attribute etc.

See below for the list I came up with.

Questions for discussion:

  1. Is this a problem we want to fix?

  2. Most of these types are classes, that are not intended to be instantiated and/or subclassed by users, only internally.

    2.1. Do we want to enforce this?
    2.2. How do we enforce this?

  3. How do we want to officialy declare something as public API?

  4. Which types from the list below are we actually ready to export?

  5. Is there a category or specific types I missed?

I'll add my own thoughts on these questions in a separate reply.


Fixtures:

  • _pytest.fixtures.FixtureRequest -> pytest.FixtureRequest
  • _pytest.fixtures.SubRequest
  • _pytest.cacheprovider.Cache -> pytest.Cache
  • _pytest.capture.CaptureFixture -> pytest.CaptureFixture
  • _pytest.logging.LogCaptureFixture -> pytest.LogCaptureFixture
  • _pytest.pytester.Pytester -> pytest.Pytester
  • _pytest.pytester.Testdir -> pytest.Testdir
  • _pytest.tmpdir.TempdirFactory -> pytest.TempdirFactory
  • _pytest.tmpdir.TempPathFactory -> pytest.TempPathFactory
  • _pytest.monkeypatch.MonkeyPatch -> pytest.MonkeyPatch
  • _pytest.recwarn.WarningsRecorder -> pytest.WarningsRecorder

Hooks:

  • _pytest.config.Config -> pytest.Config
  • _pytest.config.PytestPluginManager -> pytest.PytestPluginManager
  • _pytest.config.argparsing.Parser -> pytest.Parser
  • _pytest.reports.CollectReport -> pytest.CollectReport
  • _pytest.python.PyCollector (Made private #9264)
  • _pytest.python.Metafunc -> pytest.Metafunc
  • _pytest.runner.CallInfo -> pytest.CallInfo
  • _pytest.reports.TestReport -> pytest.TestReport
  • _pytest.fixtures.SubRequest
  • _pytest.fixtures.FixtureDef
  • _pytest.terminal.TerminalReporter
  • _pytest._code.code.ExceptionRepr
  • _pytest.code.ExceptionInfo -> pytest.ExceptionInfo

API:

  • _pytest.mark.structures.ParameterSet

Transitive:

  • _pytest.fixtures.FuncFixtureInfo (thru Metafunc)
  • _pytest.fixtures.FixtureFunctionMarker
  • _pytest.mark.structures.MarkGenerator -> pytest.MarkGenerator
  • _pytest.mark.structures.MarkDecorator -> pytest.MarkDecorator
  • _pytest.mark.structures.Mark -> pytest.Mark
  • _pytest.mark.structures.NodeKeywords (thru Node) - only exposed as a MutableMapping instead.
  • _pytest.code._code.TerminalRepr
  • _pytest.python.CallSpec2
  • _pytest.python_api.ApproxBase -> pytest.Approx (#14164)
  • _pytest.python_api.RaisesContext - Not worth exposing, just a context manager.
  • _pytest.recwarn.WarningsRecorder -> pytest.WarningsRecorder
  • _pytest._io.TerminalWriter
  • _pytest.config.argparsing.OptionGroup -> pytest.OptionGroup
  • _pytest.pytester.ParsedCall -> pytest.RecordedHookCall
  • _pytest.pytester.HookRecorder -> pytest.HookRecorder
  • _pytest.pytester.RunResult -> pytest.RunResult
  • _pytest.pytester.LineMatcher -> pytest.LineMatcher

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 reviewing the listed _pytest modules and the pytest package exports, then read the discussion to determine which reachable types still need public names. Define the public-API policy and export decisions before changing the relevant modules; done requires agreed exports and tests covering their availability and typing use.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.