Package: octo
Octo is a “plugin framework” which allows you to write your application as a
collection of (optionally interconnected) plugins.OverviewOcto is a “plugin framework” which allows you to write your application as a
collection of (optionally interconnected) plugins. For example, octo makes it
easy to write a plugin which runs a basic webserver so you can have other
plugins hooking into that in order to expose API endpoints for various
different tasks.Using a plugin-based approach encourages modularity and makes it easy to add or
remove functionality, or toggle parts on and off as needed. It also makes it
easier for people to share and exchange plugins to satisfy certain needs or to
solve various problems.InstallingOcto may be installed from PyPi using pip or easy_install:pip install octoAlternatively, you can install the latest bleeding-edge master version from GitHub
directly:pip install https://github.com/zoni/octo/archive/master.zipLastly, you could also download the code and runsetup.py:python setup.py installNote: If you wish to work on octo’s code itself, then you will want to install the
development dependencies as well:pip install -r requirements-development.txtRunning octoStarting octo is as simple as runningocto.pywith a list of directories
to scan for plugins:python octo.py -p pluginsOcto will scan the directorypluginsrecursively, loading any configured
plugins that it finds. If you have your plugins spread across more than a
single directory, you can give this option multiple times:python octo.py -p plugins -p more_pluginsYou can stop octo by pressing Ctrl+C, or by sending a SIGINT signal from another
process (for example, kill).Making an example pluginOut of the box, octo won’t be able to do much for you. It will try to activate
any plugins it finds and then drops into an idle loop. To make it do anything
useful, you will have to start writing plugins. Luckily, writing plugins for
octo is really easy!To maintain tradition, lets write a simple“Hello World”plugin. All it will
do is print “Hello world!” to the console when you activate it.For this example, we will assume you have an empty directory calledexampleto store the plugin files in. As we’re writing a “Hello world” plugin, we’ll
be putting our python code intoexample/helloworld.py.The application codeIn order to run, our plugin should have a class which extendsocto.plugin.OctoPlugin. Since the name that we give to this class
does not matter, we’ll simply call itHelloWorld:from octo.plugin import OctoPlugin

class HelloWorld(OctoPlugin):
    """Simple hello world example plugin"""
    passObviously, this is still lacking functionality to greet, so we’ll need to
add a method to our class for that.
Looking atocto.plugin.OctoPlugin, you can see it already
offersocto.plugin.OctoPlugin.on_activationandocto.plugin.OctoPlugin.on_deactivationfor us to override. These two
methods are called on activation and deactivation of a plugin, respectively.Using this, we can complete our plugin as follows:from octo.plugin import OctoPlugin

class HelloWorld(OctoPlugin):
    """Simple hello world example plugin"""

    def on_activation(self):
        """Say hello on plugin activation"""
        print("Hello world!")If you now try to run octo, you’ll notice  that nothing actually happens:$ python octo.py -p example
INFO:root:Initializing with plugin directories: ['example']
^CINFO:root:Interrupt received, shutting downThis is because we haven’t actually told octo there’s a plugin there forit to
load! In order to do this, we must add a plugin file that contains a bit of
metadata about our plugin.The plugin fileLets createexample/helloworld.plugin:[Core]
Name = Hello World
Module = helloworld

[Documentation]
Author = Your Name
Version = 0.1
Website = http://example.com
Description = My first plugin

[Config]
Enable = TrueWhat this file does is it gives octo some metadata about your plugin, such as
the Python module to import for it and whether to activate it or not. Make sure
thatCore.Modulecontains the name of the file you created for your plugin,
as this is how it knows where to find your code.Also make sure thatConfig.EnableisTrue, if it’s anything else, or
missing entirely, then octo won’t enable your plugin, and that would be sad.Lastly, while it’s generally a good practice, you can omit theDocumentationitems and octo won’t care. This is purely a bit of metadata that becomes
especially useful if you end up sharing your plugin with other people.When we run octo again, this time we should see our greeting (we’ll turn all
logging off as well, to make the output easier to read):$ python octo.py -p example -l none
Hello world!Success! You should now know enough to get started writing your own plugins.
However, you’ll probably want to spend a little more time looking at the API
documentation ofocto.plugin.OctoPluginfirst, so you know what
other functionality you can hook into with your own plugins.ContributingOcto is an opensource project, so I would love your involvement. Please feel free
to offer suggestions or criticisms. If you wish to contribute code, I’d be more
than happy to integrate your changes if I feel they make a good addition.In order to make the experience as smooth as possible, please take these
guidelines into consideration:Before submitting changes, make sure all tests still pass.If you add any new code, include tests for it as well. If you need help
writing tests, please do not hesitate to reach out to me for help.Commit any changes you make one change at a time, with a clear commit
message to accompany it. This will ease the review process and makes it easier
for people to figure out what happened when looking back at the git log.Split unrelated changes into seperate pull requests. This again makes
discussion and review easier, and ensures your first change does not block your
other changes from being accepted.LicenseOcto is available under a 2-clause BSD license (the “Simplified BSD License”):Copyright (c) 2013, Nick Groenen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.