Skip to content
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

Merged
merged 16 commits into from
May 17, 2018
Merged
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 81 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Copy link
Contributor

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 versus implementer (maybe just plugin?) versus user (or client) code should look like and how it fits into the pluggy use-case model.

Also, too many references to pluggy in a few places when we already know what's being referenced.

Copy link
Member

@nicoddemus nicoddemus Apr 21, 2018

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 of implementer, I think it will make the text clearer (people who come looking for pluggy are already looking how to implement/integrate plugins IMHO).


* The `hoster` - the person who wants to add extensibility to their program
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The host - the program or project to be extended and augmented with plugins

* The `implementer` - the person who wants to extend the `host` functionality by writing a plugin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementer - the plugin itself which extends or modifies the hosts functionality and/or behaviour

* the `user` - the person who installed the `host` and now wants to extend its functionality by using a plugin
Copy link
Contributor

@goodboy goodboy Apr 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the user - the program who depends on the host project and now wants to extend its functionality by installing and using a plugin

Copy link
Member Author

Choose a reason for hiding this comment

The 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
Copy link
Contributor

@goodboy goodboy Apr 18, 2018

Choose a reason for hiding this comment

The 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:
The host enables an arbitrary number of plugins to extend its behaviour

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This snippet seems out of place?

Copy link
Member Author

Choose a reason for hiding this comment

The 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:
Expand Down