Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

How to organize your plugin project

reszelaz edited this page May 4, 2020 · 12 revisions

Introduction

Used terminology:

  • plugin - any of the Sardana plugin (controller, macro, recorder, widget, complete GUI)
  • project - synonym to repository e.g. git, mercurial, etc. with eventual infrastructure like issue tracker, wiki, etc.
  • python project - top level python package + setup.py, etc.

SEP16 leaves to the plugin developer the decission on how to organize the project. However based on years of experience of developing Sardana plugins we have observed common patterns and questions that emerge to the developer on how to organize the project. This document does not give neither clear answers nor rules but analyzes the possible scenarios and share the lessons learnt.

Discussion

Single project or multiple projects?

Let's analyze an example of the IcePAP motion controller. Currently we have developed one motor controller and one trigger/gate controller as well as a set of macros for the IcePAP motion controller. You could either organize this project(s) in the following way:

  • one project for motor controller, another one for trigger/gate controller and one common for all the macros
  • one project for controller type plugins (both motor and trigger/gate) and another one for macro type plugins
  • only one project for all plugins related to IcePAP

We believe that having all related plugins in one project gives the following benefits

  • reduces the overhead of project administration maintenance
  • facilitates the related plugins discovery - everything in one place
  • no need to handle version dependencies between projects (e.g. a given version of a macro depends on a given version of a controller)

So we could recommend to organize in one single project all types of plugins related to each other by some characteristic. The characteristic examples could be:

  • hardware/instrument type e.g. IcePAP motor controller, HKL
  • specific system e.g. beamline, laboratory
  • generic plugins for a control system e.g. Tango, EPICS, Lima
  • generic plugins for a given type (and family) e.g. pseudo motors, recorders

Plugins as ordinary python modules?

Currently some types of plugins, for example macros, can not be directly imported in python. This is because they are tightly bound to the Sardana plugin system. Furthermore the current plugin system in Sardana does not require the plugins to be python modules - these just need to be files with python code and .py extension.

On the other hand, the controller plugins are actually directly usable in Python:

In [1]: from sardana.pool.poolcontrollers.DummyMotorController import DummyMotorController

In [2]: dmotctrl = DummyMotorController("test", {})

In [3]: dmotctrl.AddDevice(1)

In [4]: dmotctrl.ReadOne(1)
Out[4]: SardanaValue(value=0, timestamp=1563288438.98)

Taking into account our long term plan to unify the plugin system in Taurus and Sardana - see TEP13 and the current Proof-of-Concept implementation of the taurus.qt.qtgui and taurus_pyqtgraph we belive that organizing the projects in the way that plugins itself will reside in orginary python modules is a good step forward.

The module naming is totally open but we strongly recommend to use the top level module name: sardana_<name> where <name> identifies your plugin or family of plugins e.g. sardana_icepap. If in the project there are multiple types of plugins, e.g. macros, controllers and widgets we recommend an intermediate python sub-module per type of plugins:

  • sardana_<name>.macro
  • sardana_<name>.ctrl
  • sardana_<name>.recorder
  • sardana_<name>.gui

Following this recomendation, and the sardana-icepap project example we could imagine the following code:

from sardana_icepap.ctrl import IcePAPMotorController
from sardana_icepap.macro import ipap_homing

In order to enable this plugins in Sardana using the current plugin system you would need to configure the following properties (based on Debian directory structure):

PoolPath = /usr/lib/python/3.5/dist-packages/sardana_<name>/ctrl
MacroPath = /usr/lib/python/3.5/dist-packages/sardana_<name>/macro
RecorderPath = /usr/lib/python/3.5/dist-packages/sardana_<name>/recorder

or of the project is not installed but only cloned:

PoolPath = <workspace>/sardana-name/sardana_<name>/ctrl
MacroPath = <workspace>/sardana_<name>/macro
RecorderPath = <workspace>/sardana_<name>/recorder

where is the directory where you have cloned the project.

Dependencies in the same project?

Sometimes, within the same project, different plugins organized in different files/modules, reuse the same code. A good design decision is to separate this common code into a dedicated python module and use it as a dependency of the plugins. These dependency modules could be still part of the plugin project. This will certainly reduce the project maintenance overhead. But in other cases, where these dependecy is also used by another applications (not Sardana plugins) it has more sense to move them to a dedicated project.

Example of project organization

Taking into account the above discussion, we believe that the following project organization fits pretty well to many scanarios.

The project top directory name (as well as the project name) could be sardana-<name> where is the characteristic which groups the plugins or any other identifying name e.g. sardana-bl01, sardana-icepap, etc.

├──setup.py
└──sardana_<name>
   ├──__init__.py
   ├──ctrl
   │  ├──__init__.py
   │  └──foo.py (with FooMotorCtrl class)
   ├──macro
   │  ├──__init__.py
   │  └──bar.py (with bar_procedure function)
   ├──recorder
   │  ├──__init__.py
   │  └──baz.py (with BazRecorder class)
   ├──gui
   │  ├──__init__.py
   │  └──qux.py (with QuxWidget class)
   └──fred.py (optional)

For very simple cases, we could directly program plugins in the plugin type module e.g. ctrl or macro:

├──setup.py
└──sardana_<name>
   ├──__init__.py
   ├──ctrl.py (with FooMotorCtrl class)
   └──macro.py (with bar_procedure function)