MP Plugs can be used to create modular applications with setup + loop structure common in microcomputer and GUI programming.
Latest release can be found here. This documentation was last updated for version v0.4
.
This documentation is maintained in a docs
folder. If you find an error or a lacking topic please open an issue or a PR.
atom_one_dark
theme was used) Both the package and this documentation are released under MIT license.
pip install mpplugs
git clone https://github.com/Jakub21/mpplugs.git
python setup.py install
MP Plugs can be used to create modular programs. Here's how to do it.
init
method of each plugin is executedupdate
method is executed in loopquit
method is calledMP Plugs enforces coding practices that might be considered unorthodox, beware
First, create main program file program.py
. This code runs in main process. Other processes use this one to communicate with each other.
import mpplugs as plg # Import mp plugs
if __name__ == '__main__':
prog = plg.Program('MyBasicProgram') # Create program
prog.updateSettings({ # Method for changing program settings
'Compiler.pluginDirectories': ['./demoPlugins'], # Add plugins to your program
})
prog.preload() # Prepare plugins
prog.run() # Create plugin instances in separate processes, exec init and start loop
This code creates program instance, then tells compiler where to look for plugins. The preload
method compiles plugins into single-file form. Those files are deleted once your program stops.
Note that run
method is blocking the main process.
Main process is only used to coordinate tasks and will not execute any of your code. For that you need plugins. Plugin consists of 3 mandatory files: Config.py
and Scope.py
and a file that has the same name as your plugin. Those must be placed in a directory that is also named after your plugin. For the program to load the plugin its parent directory must be added in program's settings.
In our example, after adding plugin named FirstDemo
the file structure would look like this:
project/
|- demoPlugins/
| |- FirstDemo/
| | |- Config.py
| | |- FirstDemo.py (main plugin file)
| | |- Scope.py (definitions file)
|- program.py
In FirstDemo.py
there must be a class that, again, has name of the plugin. Also it must inherit from package's Plugin
class that is made available in this file during startup. We also need init
and update
methods that were mentioned on the very start of this guide. Generally empty plugin would look like this:
class FirstDemo(Plugin):
def init(self):
super().init()
def update(self):
super().update()
Note the super
methods calls. Those are required for the program to run correctly.
Next required file is Config.py
This file must contain a class named Config
but it can be left empty. When program starts contents of this class are copied to cnf
property of the plugin. Using this class to store configurable variables is recommended because they can be modified from main program script.
class Config:
pass
Last required file is Scope.py
but it can be left empty. This file is where you can define variables accessible in whole plugin process or import packages. In more complex plugins it matters that you do this in this file.
You can now check if your newly created program runs but at this point it would only print some initialization logs.
MP Plugs has logger that includes information on where in program the log was emitted and a timestamp. The logs are colored depending on their importance. To emit a log use one of the built-in methods.
Debug(plugin, *message) # magenta timestamp, gray origin + message
Info(plugin, *message) # magenta timestamp, white origin + message
Note(plugin, *message) # cyan timestamp + origin, white message
Warn(plugin, *message) # all yellow
Error(plugin, *message) # all red
Colors can be changed or turned off in program settings. This logger will be used later in the guide.
For this section we will need two plugins. Create plugin SecondDemo
by repeating steps from the previous section.
To communicate between processes events system must be used. Every event triggers its handlers in all plugins of the program.
# FirstDemo.py
class FirstDemo(Plugin):
def init(self):
super().init()
self.addEventHandler('Dummy', self.onDummy) # Add handler
def update(self):
super().update()
def onDummy(self, event):
Note(self, f'FirstDemo received Dummy (apples = {event.apples})')
# SecondDemo.py
class SecondDemo(Plugin):
def init(self):
super().init()
self.apples = 4
def update(self):
super().update()
if not(self.__mpplugs__.tick % 60):
Debug(self, f'Emitting Dummy (apples = {self.apples})')
Event(self, 'Dummy', apples=self.apples)
self.apples = (self.apples + 3) % 13
See Plugin class API for more on __mpplugs__
property, it will not be discussed in this guide. It only was used to limit rate at which events are fired.
You could add handler for events with Dummy
ID and it would get called as well. You can see that any keyword argument passed to the event constructor will be added as its property. This has limitation of only allowing picklable objects.
This package has more features that were not described here, this is what you need to get started. For more please refer to the API
sections. You can request that this guide is extended by opening an issue. You can also extend it yourself and open a pull request.