Plugin Core¶
Minimal Plugin¶
# -*- coding: utf-8 -*-
__plugin_name__ = "Demo"
__author__ = "Mr.tao <[email protected]>"
__version__ = "0.1.1"
def register():
return {}
However, this plugin doesn’t make any sense, it just means a valid plugin content, whether it’s a local plugin or a third-party plugin, the core part is the same.
The mini plugin above, which starts and ends with __
, is called metadata,
which is the most important information for getting plugins.
The register
function is used to return the extension point.
Let’s explain it one by one.
Plugin Structure¶
The most minimal plugin needs to have at least it’s own directory.
The directory must contain the __init__.py
file, otherwise
it is not considered a plugin!
The core code of the plugin can be written in other modules of the package,
then returned in __init__.py using the register
function, and
this file contains the metadata required to register the plugin.
In __init__.py, you can write your plugin code all in. Of course, the recommended way is to create a module with another name under the plugin package. Write your functions, class, variable, and so on, then import the module in __init__.py and use register to return the extension point.
The project structure of a complete plugin web application is probably like this:
your_project/
├── app.py
├── config.py
├── libs
│ └── __init__.py
├── LICENSE
├── plugins
│ ├── __init__.py
│ └── local_plugin_demo # A local plugin
│ ├── _core.py
│ ├── __init__.py
│ ├── license.txt
│ ├── readme.txt
│ ├── static
│ │ └── demo.css
│ ├── template
│ │ └── demo
│ │ └── demo.html
│ └── _util.py
├── README.md
├── requirements.txt
├── utils
│ └── __init__.py
└── views
└── __init__.py
metadata¶
Below are all supported metadata configuration items, please note that the first three are required:
__plugin_name__
Your plugin name is not strictly required to be consistent with the plugin directory name.
__author__
Plugin Author
__version__
Plugin Version, compliance with Semantic Version 2.0 Rules.
__description__
What is the use of plugin description information.
__url__
Plugin Homepage
__license__
Plugin LICENSE
__license_file__
The plugin LICENSE detail file. Your plugin directory should have a LICENSE file.
__readme_file__
The plugin profile should have a README description file in your plugin directory.
__state__
The plugin Status, enabled (default) or disabled.
register¶
This function is also required, it should be defined or imported in __init__.py. Flask-PluginKit will call this function when loading, return data is dict, contains various types of extension points, such as:
def register():
return dict(
bep=dict(),
hep=dict(),
tep=dict(),
errhandler=dict(),
filter=dict(),
tcp=dict(),
)
For the extension points returned, please see the following sections.
Enabling and Disabling Plugins¶
This extension, uses a different approach for handling plugins.
Anyway, local plugins (a subdirectory located in the application, such as plugins, is a package) or third-party plugins (which can be pypi or from git, svn, etc.), should be installed in the local environment.
Plugins are enabled by default, and there are two ways to enable or disable a plugin.
The first method is to set the metadata __state__
value to enabled
or disabled.
The second method is to add the ENABLED
or DISABLED
file in the
plugin’s root directory, without changing the source code.
This can either be done by hand or with the method provided
by disable_plugin()
or
enable_plugin()
.
Note
The second method has a higher priority than the first one, and the DISABLED file has a higher priority than the ENABLED file.
The directory structure of a disabled plugin is shown below.
my_plugin
|-- DISABLED # Just add a empty file named "DISABLED"
|-- __init__.py
Warning
The server needs to be restarted or reloaded to disable the plugin. This is a limitation of Flask. However, it is possible, to restart the application by sending a HUP signal to the application server.
The following code snippets, are showing how this can be done with
the WSGI server gunicorn. Gunicorn has be to started in
daemon (--daemon
) mode in order for this to work.
You can use the command to manually reload:
$ kill -HUP Your_APP_Gunicorn_master_pid
or direct restart (kill, then start).
In web applications, according to previous tests, it should
use os.getppid()
instead of os.getpid()
to get the master pid of gunicorn, and send SIGHUP signal to master pid.
For security, the process name should be verified!
@app.route('/reload')
def reload():
os.kill(os.getppid(), signal.SIGHUP)
This feature is implemented in v3.3.0, reference document Web Manager