This package implements SNAKES plugin system. SNAKES plugins themselves are available as modules within the package.

Examples below are based on plugin hello that is distributed with SNAKES to be used as an exemple of how to build a plugin. It extends class PetriNet adding a method hello that says hello displaying the name of the net.

Loading plugins

The first example shows how to load a plugin: we load snakes.plugins.hello and plug it into snakes.nets, which results in a new module that is actually snakes.nets extended by snakes.plugins.hello.

>>> import snakes.plugins as plugins
>>> hello_nets = plugins.load('hello', 'snakes.nets')
>>> n = hello_nets.PetriNet('N')
>>> n.hello()
Hello from N
>>> n = hello_nets.PetriNet('N', hello='Hi, this is %s!')
>>> n.hello()
Hi, this is N!

The next example shows how to simulate the effect of import module: we give to load a thrid argument that is the name of the created module, from which it becomes possible to import names or *.

>>> plugins.load('hello', 'snakes.nets', 'another_version')
<module ...>
>>> from another_version import PetriNet
>>> n = PetriNet('another net')
>>> n.hello()
Hello from another net
>>> n = PetriNet('yet another net', hello='Hi, this is %s!')
>>> n.hello()
Hi, this is yet another net!

The last example shows how to load several plugins at once, instead of giving one plugin name, we just need to give a list of plugin names.

>>> plugins.load(['hello', 'pos'], 'snakes.nets', 'mynets')
<module ...>
>>> from mynets import PetriNet
>>> n = PetriNet('a net')
>>> n.hello()  # works thanks to plugin `hello`
Hello from a net
>>> n.bbox()   # works thanks to plugin `pos`
((0, 0), (0, 0))

Function load

def load (plugins, base, name=None) :

Load plugins, plugins can be a single plugin name, a module or a list of such values. If name is not None, the extended module is loaded as name in sys.modules as well as in the global environment from which load was called.

Call API

Creating plugins

We show now how to develop a plugin that allows instances of PetriNet to say hello: a new method PetriNet.hello is added and the constructor PetriNet.__init__ is added a keyword argument hello for the message to print when calling method hello.

Defining a plugins required to write a module with a function called extend that takes as its single argument the module to be extended. Inside this function, extensions of the classes in the module are defined as normal sub-classes. Function extend returns the extended classes. A decorator called plugin must be used, it also allows to resolve plugin dependencies and conflicts.

"""An example plugin that allows instances of `PetriNet` to
say hello. The source code can be used as a starting
example."""

import snakes.plugins

@snakes.plugins.plugin("snakes.nets")
def extend (module) :
    "Extends `module`"
    class PetriNet (module.PetriNet) :
        "Extension of the class `PetriNet` in `module`"
        def __init__ (self, name, **args) :
            """Add new keyword argument `hello`

            >>> PetriNet('N').hello()
            Hello from N
            >>> PetriNet('N', hello='Hi! This is %s...').hello()
            Hi! This is N...

            @param args: plugin options
            @keyword hello: the message to print, with
                `%s` where the net name should appear.
            @type hello: `str`
            """
            self._hello = args.pop("hello", "Hello from %s")
            module.PetriNet.__init__(self, name, **args)
        def hello (self) :
            "Ask the net to say hello"
            print(self._hello % self.name)
    return PetriNet

Note that, when extending an existing method like __init__ above, we have to take care that you may be working on an already extended class, consequently, we cannot know how its arguments have been changed already. So, we must always use those from the unextended method plus **args. Then, we remove from the latter what your plugin needs and pass the remaining to the method of the base class if we need to call it (which is usually the case).

Function plugin

def plugin (base, depends=[], conflicts=[]) :

Decorator for extension functions

Call API