Writing plugins¶
It is easy to implement local conftest plugins for your own project or pip-installable plugins that can be used throughout many projects, including third party projects. Please refer to How to install and use plugins if you only want to use but not write plugins.
A plugin contains one or multiple hook functions. Writing hooks
explains the basics and details of how you can write a hook function yourself.
pytest implements all aspects of configuration, collection, running and
reporting by calling well specified hooks of the following plugins:
builtin plugins: loaded from pytest’s internal
_pytestdirectory.external plugins: installed third-party modules discovered through entry points in their packaging metadata
conftest.py plugins: modules auto-discovered in test directories
In principle, each hook call is a 1:N Python function call where N is the
number of registered implementation functions for a given specification.
All specifications and implementations follow the pytest_ prefix
naming convention, making them easy to distinguish and find.
Plugin discovery order at tool startup¶
pytest loads plugin modules at tool startup in the following way:
by scanning the command line for the
-p no:nameoption and blocking that plugin from being loaded (even builtin plugins can be blocked this way). This happens before normal command-line parsing.by loading all builtin plugins.
by scanning the command line for the
-p nameoption and loading the specified plugin. This happens before normal command-line parsing.by loading all plugins registered through installed third-party package entry points, unless the
PYTEST_DISABLE_PLUGIN_AUTOLOADenvironment variable is set.by loading all plugins specified through the
PYTEST_PLUGINSenvironment variable.by loading all “initial”
conftest.pyfiles:determine the test paths: specified on the command line, otherwise in
testpathsif defined and running from the rootdir, otherwise the current dirfor each test path, load
conftest.pyandtest*/conftest.pyrelative to the directory part of the test path, if exist. Before aconftest.pyfile is loaded, loadconftest.pyfiles in all of its parent directories. After aconftest.pyfile is loaded, recursively load all plugins specified in itspytest_pluginsvariable if present.
conftest.py: local per-directory plugins¶
Local conftest.py plugins contain directory-specific hook
implementations. Hook Session and test running activities will
invoke all hooks defined in conftest.py files closer to the
root of the filesystem. Example of implementing the
pytest_runtest_setup hook so that is called for tests in the a
sub directory but not for other directories:
a/conftest.py:
def pytest_runtest_setup(item):
# called for running each test in 'a' directory
print("setting up", item)
a/test_sub.py:
def test_sub():
pass
test_flat.py:
def test_flat():
pass
Here is how you might run it:
pytest test_flat.py --capture=no # will not show "setting up"
pytest a/test_sub.py --capture=no # will show "setting up"
Note
If you have conftest.py files which do not reside in a
python package directory (i.e. one containing an __init__.py) then
“import conftest” can be ambiguous because there might be other
conftest.py files as well on your PYTHONPATH or sys.path.
It is thus good practice for projects to either put conftest.py
under a package scope or to never import anything from a
conftest.py file.
Note
Some hooks cannot be implemented in conftest.py files which are not initial due to how pytest discovers plugins during startup. See the documentation of each hook for details.
Writing your own plugin¶
If you want to write a plugin, there are many real-life examples you can copy from:
a custom collection example plugin: A basic example for specifying tests in Yaml files
builtin plugins which provide pytest’s own functionality
many external plugins providing additional features
All of these plugins implement hooks and/or fixtures to extend and add functionality.
Note
Make sure to check out the excellent cookiecutter-pytest-plugin project, which is a cookiecutter template for authoring plugins.
The template provides an excellent starting point with a working plugin, tests running with tox, a comprehensive README file as well as a pre-configured entry-point.
Also consider contributing your plugin to pytest-dev once it has some happy users other than yourself.
Making your plugin installable by others¶
If you want to make your plugin externally available, you
may define a so-called entry point for your distribution so
that pytest finds your plugin module. Entry points are
a feature that is provided by packaging tools.
pytest looks up the pytest11 entrypoint to discover its
plugins, thus you can make your plugin available by defining
it in your pyproject.toml file.
# sample ./pyproject.toml file
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "myproject"
classifiers = [
"Framework :: Pytest",
]
[project.entry-points.pytest11]
myproject = "myproject.pluginmodule"
If a package is installed this way, pytest will load
myproject.pluginmodule as a plugin which can define