diff options
author | Ran Benita <ran@unusedvar.com> | 2020-09-27 22:20:31 +0300 |
---|---|---|
committer | Ran Benita <ran@unusedvar.com> | 2020-11-13 11:25:09 +0200 |
commit | f1e6fdcddbfe8991935685ccc5049dd957ec4382 (patch) | |
tree | 854c010eef3a9accb203ccbf114b12648dc5b997 /src/_pytest/fixtures.py | |
parent | b0505788821604f0b0787683d47a0ca693fd0426 (diff) | |
download | pytest-f1e6fdcddbfe8991935685ccc5049dd957ec4382.tar.gz |
Export types of builtin fixture for type annotations
In order to allow users to type annotate fixtures they request, the
types need to be imported from the `pytest` namespace. They are/were
always available to import from the `_pytest` namespace, but that is
not guaranteed to be stable.
These types are only exported for the purpose of typing. Specifically,
the following are *not* public:
- Construction (`__init__`)
- Subclassing
- staticmethods and classmethods
We try to combat them being used anyway by:
- Marking the classes as `@final` when possible (already done).
- Not documenting private stuff in the API Reference.
- Using `_`-prefixed names or marking as `:meta private:` for private
stuff.
- Adding a keyword-only `_ispytest=False` to private constructors,
warning if False, and changing pytest itself to pass True. In the
future it will (hopefully) become a hard error.
Hopefully that will be enough.
Diffstat (limited to 'src/_pytest/fixtures.py')
-rw-r--r-- | src/_pytest/fixtures.py | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index cef998c03..273bcafd3 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -49,6 +49,7 @@ from _pytest.compat import safe_getattr from _pytest.config import _PluggyPlugin from _pytest.config import Config from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest from _pytest.deprecated import FILLFUNCARGS from _pytest.deprecated import YIELD_FIXTURE from _pytest.mark import Mark @@ -367,7 +368,7 @@ def _fill_fixtures_impl(function: "Function") -> None: assert function.parent is not None fi = fm.getfixtureinfo(function.parent, function.obj, None) function._fixtureinfo = fi - request = function._request = FixtureRequest(function) + request = function._request = FixtureRequest(function, _ispytest=True) request._fillfixtures() # Prune out funcargs for jstests. newfuncargs = {} @@ -429,7 +430,8 @@ class FixtureRequest: indirectly. """ - def __init__(self, pyfuncitem) -> None: + def __init__(self, pyfuncitem, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) self._pyfuncitem = pyfuncitem #: Fixture for which this request is being performed. self.fixturename: Optional[str] = None @@ -674,7 +676,9 @@ class FixtureRequest: if paramscopenum is not None: scope = scopes[paramscopenum] - subrequest = SubRequest(self, scope, param, param_index, fixturedef) + subrequest = SubRequest( + self, scope, param, param_index, fixturedef, _ispytest=True + ) # Check if a higher-level scoped fixture accesses a lower level one. subrequest._check_scope(argname, self.scope, scope) @@ -751,7 +755,10 @@ class SubRequest(FixtureRequest): param, param_index: int, fixturedef: "FixtureDef[object]", + *, + _ispytest: bool = False, ) -> None: + check_ispytest(_ispytest) self._parent_request = request self.fixturename = fixturedef.argname if param is not NOTSET: @@ -769,6 +776,8 @@ class SubRequest(FixtureRequest): return f"<SubRequest {self.fixturename!r} for {self._pyfuncitem!r}>" def addfinalizer(self, finalizer: Callable[[], object]) -> None: + """Add finalizer/teardown function to be called after the last test + within the requesting test context finished execution.""" self._fixturedef.addfinalizer(finalizer) def _schedule_finalizers( |