Packaging and Installation

The distribution of plugins, patterns and even applications can easily be done by using solutions from Python’s packaging ecosystem. For packaging the library setuptools is recommend. For package installation, the wide known tool pip should be used.

Create a package

You can add as many plugins, patterns and even applications to a single python package as you like.

All you need is a file called setup.py in the root folder of your package. Example:

from setuptools import setup, find_packages

setup(
    name='my_package',
    version="0.1,
    url='http://my_package.readthedocs.org',
    license='MIT',
    author='me',
    author_email='me@me.com',
    description="My awesome package for doing hot stuff",
    long_description="A longer description of my awesome package",
    packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
    include_package_data=True,
    platforms='any',
    install_requires=["groundwork", "Another_Package"],
    entry_points={
        'console_scripts': ["my_app my_package.my_app:start_app"],
        'groundwork.plugin': [
            'my_plugin = my_package.my_plugin:MyPlugin',
            'my_plugin_2" = my_package.my_plugin_2:MyPlugin2']
    }
)

For more details, take a look into the Developer’s Guide of setuptools or read one of the many tutorials about setup.py on the internet.

entry_points

Entry points are used to “advertise” Python objects for use by other distributions.

groundwork uses them to find plugins in installed packages, without the need to use some hard coded imports like from another_package import PluginX.

Therefore groundwork knows all packaged plugins, which are available in system path of the currently used python interpreter. These plugins can be used by activation, without any need to register or import them:

from groundwork import App

my_app = App()

my_app.activate("GwPluginsInfo")
# GwPluginsInfo is provided by an entry_point inside the groundwork package

Note

During activation, the plugins are identified by their names. So the plugin name must be known, which is not necessarily the plugin class name.

The entry_point of a plugin must provide a class, which inherits directly or indirectly from GwBasePattern:

# setup.py from groundwork package

from setuptools import setup, find_packages

setup(
    name='groundwork',
    ...
    entry_points={
       'groundwork.plugin': [
            'gw_plugins_info = groundwork.plugins.gw_plugins_info:GwPluginsInfo',
        ]
    }
)

Package structure

The following structure is recommended for packaging multiple plugins, patters and applications:

my_package
|
|-- setup.py
|
|-- my_package
|   |
|   |-- applications
|   |   |-- my_app
|   |       |-- my_app.py
|   |
|   |-- patterns
|   |   |-- my_pattern
|   |       |-- my_pattern.py
|   |
|   |-- plugins
|       |-- my_plugin
|       |   |-- my_plugin.py
|       |
|       |-- my_plugin_2
|           |-- my_plugin_2.py
|
|-- docs
|   |-- index.rst
|   |-- my_app.rst
|   |-- my_pattern.rst
|   |-- my_plugin.rst
|   |-- my_plugin_2.rst
|
|-- tests
    |-- test_my_app.py
    |-- test_my_pattern.py
    |-- test_my_plugin.py
    |-- test_my_plugin_2.py

Install a package

Local packages

If you store your package locally and do not use PyPI for distribution, you need to use your setup.py file for all installation scenarios.

During development

During development it is recommend to install a package in development mode on your current virtual environment:

python setup.py develop

This lets you make changes on your code without the need to reinstall your package after each code change. This must be done only, if you make some changes to the setup.py file.

Final installation

To finally install your package inside the current used python environment, use install:

python setup.py install

This will copy all files to your python environment and new changes on your plugin do not have any impact on the installed package.

PyPi

PyPI can be used to share your package globally and allows users to use pip for installation:

pip install my_package

The usage of PyPi is already explained in some great tutorials. A short selection: