Writing third party plugins
See also
project-config discover third party plugins from plugin entrypoints
looking for classes in the entrypoints group project_config.plugins
,
so the first thing is to add the entrypoint to the group:
[project."entry-points"."project_config.plugins"]
my_plugin = "package.subpackage.my_plugin_module:PluginClass"
[tool.poetry.plugins."project_config.plugins"]
my_plugin = "package.subpackage.my_plugin_module:PluginClass"
[options.entry_points]
project_config.plugins =
my_plugin = package.subpackage.my_plugin_module:PluginClass
entry_points = {
"project_config.plugins": [
"my_plugin = package.subpackage.my_plugin_module:PluginClass",
],
}
The name of the entrypoint (my_plugin
in the previous example)
is the name of the plugin, the one that must be defined in plugins (string[])
if the style need it.
Plugin class
A valid plugin class must implement actions, which must be public static methods. For example:
from typing import Any
from project_config import ActionsContext, Rule, Results, tree
class PluginClass:
@staticmethod
def verb( # public method names which do not start with 'if' are verbs
value: Any,
rule: Rule,
context: ActionsContext,
) -> Results:
...
@staticmethod
def ifConditional( # conditional starts with 'if'
value: Any,
rule: Rule,
context: ActionsContext,
) -> Results:
...
- action(value: Any, rule: project_config.types_.Rule, context: project_config.types_.ActionsContext) project_config.types_.Results
Action definition.
- Parameters:
value (Any) – Value that takes the action. It could be of any type, it depends to the action.
rule (
project_config.types_.Rule
) – Complete rule dictionary in which the action is being executed.context (
project_config.types_.ActionsContext
) – Context of the actions. It has a propertyfix
which is used to determine if the user has enabled the fix mode in the current execution and other propertyfiles
which stores the content of thefiles
array of the rule.
- Yield:
Checking results.
- Return type:
project_config.types_.Results
Results
Each action must yield results, which are tuples of two items, defined next as result type - result value:
Error
- Checking error, a dictionary (optionally but recommendably typed asproject_config.types_.ErrorDict
) which must contains the required keysmessage
(error message shown in the report) anddefinition
(definition in which the error has been thrown) and an optional keyfile
(file for which the error has been thrown). If raised from conditionals their behaviour is the same that raising anInterruptingError
.InterruptingError
- The same as a checking error, but this type of error will stop the execution of the subsequent rules during the checking. Useful if the user has passed some unexpected value that could lead to an invalid context in some later rule.
Additionally, conditionals can yield result values, which define if the verbs of the rule should be executed or not.
ResultValue
- A boolean. When a conditional yields it, the execution of the conditional is terminated and, if the yielded value isFalse
, the execution of the verbs of the rule are skipped. If no result values are yielded by a conditional, the verbs of the rule are always executed as if the conditional would returnedTrue
.
You must import these variables from project_config
because their
values can change between versions:
from project_config import Error, InterruptingError, ResultValue
See also
The best way to learn the most common patterns to write plugins is checking the source code of the simplest built-in plugins:
Testing plugins
project-config comes with a built-in pytest fixture to
easily test plugin actions. See
project_config.tests.pytest_plugin.plugin
.