Pytest fixtures with conventional import semantics
Project description
pytest-unmagic
Pytest fixtures with conventional import semantics.
Installation
pip install pytest-unmagic
Usage
Define fixtures with the unmagic.fixture decorator, and apply them to other
fixtures or test functions with unmagic.use.
from unmagic import fixture, use
traces = []
@fixture
def tracer():
assert not traces, f"unexpected traces before setup: {traces}"
yield
traces.clear()
@use(tracer)
def test_append():
traces.append("hello")
assert traces, "expected at least one trace"
A fixture must yield exactly once. The @use decorator causes the fixture to be
set up and registered for tear down, but does not pass the yielded value to the
decorated function. This is appropriate for fixtures that have side effects.
The location where a fixture is defined has no affect on where it can be used. Any code that can import it can use it as long as it is executed in the context of running tests and does not violate scope restrictions.
@use shorthand
If a single fixture is being applied to another fixture or test it may be
applied directly as a decorator without @use(). The test in the example above
could have been written as
@tracer
def test_append():
traces.append("hello")
assert traces, "expected at least one trace"
Applying fixtures to test classes
The @use decorator can be used on test classes, which applies the fixture(s)
to every test in the class.
@use(tracer)
class TestClass:
def test_galaxy(self):
traces.append("Is anybody out there?")
Unmagic fixtures on unittest.TestCase tests
Unlike standard pytest fixtures, unmagic fixtures can be applied directly to
unittest.TestCase tests.
Call a fixture to retrieve its value
The value of a fixture can be retrieved within a test function or other fixture
by calling the fixture. This is similar to request.getfixturevalue().
@fixture
def tracer():
assert not traces, f"unexpected traces before setup: {traces}"
yield traces
traces.clear()
def test_append():
traces = tracer()
traces.append("hello")
assert traces, "expected at least one trace"
Fixture scope
Fixtures may declare a scope of 'function' (the default), 'class',
'module', 'package', or 'session'. A fixture will be torn down after all
tests in its scope have run if any in-scope tests used the fixture.
@fixture(scope="class")
def tracer():
traces = []
yield traces
assert traces, "expected at least one trace"
Autouse fixtures
Fixtures may be applied to tests automatically with @fixture(autouse=...). The
value of the autouse parameter may be one of
- A test module or package path (usually
__file__) to apply the fixture to all tests within the module or package. True: apply the fixture to all tests in the session.
A single fixture may be registered for autouse in multiple modules and packages
with unmagic.autouse.
# tests/fixtures.py
from unmagic import fixture
@fixture
def a_fixture():
...
# tests/test_this.py
from unmagic import autouse
from .fixtures import a_fixture
autouse(a_fixture, __file__)
...
# tests/test_that.py
from unmagic import autouse
from .fixtures import a_fixture
autouse(a_fixture, __file__)
...
Magic fixture fence
It is possible to errect a fence around tests in a particular module or package
to ensure that magic fixtures are not used in that namespace except with the
@use(...) decorator.
from unmagic import fence
fence.install(['mypackage.tests'])
This will cause warnings to be emitted for magic fixture usages within
mypackage.tests.
Accessing the pytest request object
The unmagic.get_request() function provides access to the test request object.
Among other things, it can be used to retrieve fixtures defined with
@pytest.fixture.
from unmagic import get_request
def test_output():
capsys = get_request().getfixturevalue("capsys")
print("hello")
captured = capsys.readouterr()
assert captured.out == "hello\n"
@use pytest fixtures
Fixtures defined with @pytest.fixture can be applied to a test or other
fixture by passing the fixture name to @use. None of the built-in fixtures
provided by pytest make sense to use this way, but it is a useful technique for
fixtures that have side effects, such as pytest-django's db fixture.
from unmagic import use
@use("db")
def test_database():
...
Chaining fixtures
Fixtures that use other fixtures should be decorated with @use, so
that fixture dependencies are chained.
@use("db")
def parent_fixture():
daedalus = Person.objects.create(name='Daedalus')
yield daedalus
daedalus.delete()
@use(parent_fixture)
@fixture
def child_fixture():
daedalus = parent_fixture()
icarus = Person.objects.create(name='Icarus', father=daedalus)
yield
@use(child_fixture)
def test_flight():
flyers = Person.objects.all()
...
Running the unmagic test suite
cd path/to/pytest-unmagic
pip install -e .
pytest
Publishing a new verison to PyPI
Push a new tag to Github using the format vX.Y.Z where X.Y.Z matches the version
in __init__.py.
A new version is published to https://test.pypi.org/p/pytest-unmagic on every push to the main branch.
Publishing is automated with Github Actions.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pytest_unmagic-1.0.1.tar.gz.
File metadata
- Download URL: pytest_unmagic-1.0.1.tar.gz
- Upload date:
- Size: 10.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f73e96b31a13041bcd46c3e990f4fb4cedb5b555660d0cb78d8d5d9bc99064a
|
|
| MD5 |
ec41147f4dacd7ee03f3b3d4599444c2
|
|
| BLAKE2b-256 |
4f537aef49cbf746057d6021d78085c6a7f03aced1c332e725ae1156057edcec
|
Provenance
The following attestation bundles were made for pytest_unmagic-1.0.1.tar.gz:
Publisher:
pypi.yml on dimagi/pytest-unmagic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytest_unmagic-1.0.1.tar.gz -
Subject digest:
5f73e96b31a13041bcd46c3e990f4fb4cedb5b555660d0cb78d8d5d9bc99064a - Sigstore transparency entry: 273507882
- Sigstore integration time:
-
Permalink:
dimagi/pytest-unmagic@a0863a380e408d0cae59c61dc09c3ab7c3ec9cde -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/dimagi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@a0863a380e408d0cae59c61dc09c3ab7c3ec9cde -
Trigger Event:
push
-
Statement type:
File details
Details for the file pytest_unmagic-1.0.1-py3-none-any.whl.
File metadata
- Download URL: pytest_unmagic-1.0.1-py3-none-any.whl
- Upload date:
- Size: 10.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54a02d746d20943240c9b84e212a9a7e19bc2707cb176f9b1d66677b28260a13
|
|
| MD5 |
b324172beb8ddfaa9269de6a63357d60
|
|
| BLAKE2b-256 |
219be2c66454df73d1ecbb18089f026666743ef52480e295eb6f9c77998b1a63
|
Provenance
The following attestation bundles were made for pytest_unmagic-1.0.1-py3-none-any.whl:
Publisher:
pypi.yml on dimagi/pytest-unmagic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pytest_unmagic-1.0.1-py3-none-any.whl -
Subject digest:
54a02d746d20943240c9b84e212a9a7e19bc2707cb176f9b1d66677b28260a13 - Sigstore transparency entry: 273507885
- Sigstore integration time:
-
Permalink:
dimagi/pytest-unmagic@a0863a380e408d0cae59c61dc09c3ab7c3ec9cde -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/dimagi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@a0863a380e408d0cae59c61dc09c3ab7c3ec9cde -
Trigger Event:
push
-
Statement type: