-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve docs: introduce roles and add another example #136
Changes from 7 commits
fcdc245
26f8a94
2f6831b
0381424
5b77f41
e51039d
a58b8b0
2b39339
6283b3b
ffe2caa
c2286a9
d2bacee
115f1fc
653a1e9
e84fdfa
a20a667
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,17 +3,95 @@ | |
|
||
The ``pytest`` plugin system | ||
**************************** | ||
|
||
``pluggy`` is the crystallized core of `plugin management and hook | ||
calling`_ for `pytest`_. | ||
calling`_ for `pytest`_. It gives users the possibility to extend or modify | ||
the behaviour of a host program (e.g. `pytest`_, `tox`_ or `devpi`_) by | ||
installing a `plugin` for that program. The plugin code will run as part of | ||
normal program execution changing or enhancing certain aspects of it. | ||
|
||
In fact, ``pytest`` is itself composed as a set of ``pluggy`` plugins | ||
which are invoked in sequence according to a well defined set of protocols. | ||
Some `200+ plugins`_ use ``pluggy`` to extend and customize ``pytest``'s default behaviour. | ||
|
||
In essence, ``pluggy`` enables function `hooking`_ so you can build "pluggable" systems. | ||
|
||
How's it work? | ||
-------------- | ||
Introduction | ||
------------ | ||
|
||
To explain how pluggy can be put to use we need to introduce three roles and explain their interaction with pluggy: | ||
|
||
* The `hoster` - the person who wants to add extensibility to their program | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
* The `implementer` - the person who wants to extend the `host` functionality by writing a plugin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
* the `user` - the person who installed the `host` and now wants to extend its functionality by using a plugin | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's the only one that feels a bit wonky to me, but I already got it covered: I will apply the "Why not both?"-paradigm. Roles do not necessary have to be all programs or all humans. So we have actual 3 program roles and 1 human role (host, plugin and pluggy connecting both) + the poor little human user having to get this all to work in their venv. |
||
|
||
Hoster | ||
++++++ | ||
|
||
The `hoster` wants to enable an arbitrary number of `implementers` to extend | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we go with my suggestion the language will have to change a bit, eg: |
||
or modify some aspects of their programs execution. They write hook specifications, | ||
register them with a :py:class:`pluggy.PluginManager` and instantiate a marker | ||
object for the `implementer` - a :py:class:`~pluggy.HookimplMarker` - used | ||
to `decorate <https://www.python.org/dev/peps/pep-0318/#current-syntax>` hook | ||
implementation functions. This marker is usually called `hookimpl` and | ||
importable from the root package of the `host` project. They then add | ||
calls to their specified hooks in appropriate phases of program execution. | ||
``pluggy`` will then do all the magic. | ||
|
||
To avoid compatibility issues with other pluggy hosts installed in the same | ||
environment we recommend to not specify specific version ranges or keep them | ||
as broad as possible (at time of writing (Spring 2018) this would be | ||
>=0.3,<1.0). | ||
|
||
Necessary knowledge about ``pluggy``: | ||
|
||
They need to learn about ``pluggy`` and its capabilities and should at least | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This snippet seems out of place? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its structured in a way that the last paragraph always gives info about the needed pluggy knowledge. I will make this explicit then. |
||
loosely follow the development of the ``pluggy`` project. | ||
|
||
Implementer | ||
+++++++++++ | ||
|
||
The `implementer` wants to modify or extend the program execution of a | ||
host project. They install the project and import it wherever they want | ||
to use the `hookimpl` marker. They create one or more hook implementation functions | ||
matching the exact name of the `hookspec` functions defined in the host project | ||
and decorate them with `@<hoster>.<hookimpl>`. They only need to declare the | ||
subset of parameters they actually use in their hook implementation. | ||
To make their plugin discoverable by the `hoster` they define an | ||
`entry point <https://packaging.python.org/specifications/entry-points/>`_ in | ||
their `setup.py <https://docs.python.org/3.6/distutils/setupscript.html>`_ | ||
(defined by the hoster (e.g. `pytest11`, `tox` or `devpi_server`). The result | ||
of this is called a plugin for a certain project. The plugin project naming rule | ||
is `<host>-<implementation>` (e.g. `pytest-sugar`, `tox-conda` or `devpi-ldap`). | ||
|
||
Necessary knowledge about ``pluggy``: | ||
|
||
Depending on how involved the modifications are, they need to learn about how | ||
the host project works and about the parameters the hook functions provide. | ||
They also might have to learn a bit more about how ``pluggy`` executes hooks | ||
regarding ordering and other behavioral details. | ||
|
||
User | ||
++++ | ||
|
||
The `user` wants to use new or changed features made available by `implementers` | ||
as so-called `plugins` for a host project. They install the host | ||
project and the `plugin` they want to use. Through the magic of entry points | ||
the host project will discover the `plugin` hooks and start calling them as part | ||
of their normal program execution. | ||
|
||
If a `user` doesn't need the changed behaviour of a `plugin` anymore, they | ||
uninstall it and all is back to normal. | ||
|
||
Necessary knowledge about ``pluggy``: | ||
|
||
`Users` don't need any knowledge about pluggy as such, but they need to know | ||
that they can extend the behaviour of the host program by installing plugins | ||
through their package manager. | ||
|
||
Technical overview | ||
------------------ | ||
|
||
A `plugin` is a `namespace`_ which defines hook functions. | ||
|
||
``pluggy`` manages *plugins* by relying on: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To explain how ``pluggy`` is best utilized we need to introduce three use cases
:A suggestion: reading this over again I think it might be more clear to talk about the code/programs themselves instead of people who write or use the code. This way we talk about what
host
versusimplementer
(maybe justplugin
?) versususer
(orclient
) code should look like and how it fits into thepluggy
use-case model.Also, too many references to
pluggy
in a few places when we already know what's being referenced.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good suggestions, I agree. 👍
Also 👍 to use
plugin
instead ofimplementer
, I think it will make the text clearer (people who come looking forpluggy
are already looking how to implement/integrate plugins IMHO).