Entry Points

What is an Entry Point?

The setuptools package to which pip is a frontend has a feature called entry points. When a distribution which registers entry points is installed, the entry point specifications are written to a file inside the distribution’s .egg-info folder. setuptools provides a package pkg_resources which can find these entry points by distribution, group and/or name and load the data structure to which it points.

This is the way AiiDA finds plugins and and loads the functionality they provide.

AiiDA Entry Points

AiiDA defines a set of entry point groups that it will search for new functionality provided by plugins. You can list those groups and their contents via:

verdi plugin list  # list all groups
verdi plugin list aiida.calculations  # show contents of one group

Plugin packages can add new entry points through the entry_points field in the setup.json file:

...
entry_points={
   <Entry Point Group>: [
      <Entry Point Specification>,
      ...
   ],
...

Here, <Entry Point Group> can be any of the groups shown in the output of verdi plugin list, and the <Entry Point Specification> contains the entry point name and the path to the Python object it points to:

"mycode.mydat = aiida_mycode.data.mydat:MyData"

We strongly suggest to start the name of each entry point with the name of the plugin package (omitting the ‘aiida-‘ prefix). For a package aiida-mycode, this leads to specifications like "mycode.<something> = <module.path:class>". Exceptions to this rule can be tolerated if required for backwards compatibility.

Below, we list the entry point groups defined and searched by AiiDA.

aiida.calculations

Entry points in this group are expected to be subclasses of aiida.orm.JobCalculation. This replaces the previous method of placing a python module with the class in question inside the aiida/orm/calculation/job subpackage.

Example entry point specification:

entry_points={
   "aiida.calculations": [
      "mycode.mycode = aiida_mycode.calcs.mycode:MycodeCalculation"
   ]
}

aiida_mycode/calcs/mycode.py:

from aiida.orm import JobCalculation
class MycodeCalculation(JobCalculation):
   ...

Will lead to usage:

from aiida.plugins import CalculationFactory
calc = CalculationFactory('mycode.mycode')

aiida.parsers

Aiida expects a subclass of Parser. Replaces the previous approach consisting in placing a parser module under aiida/parsers/plugins.

Example spec:

entry_points={
   "aiida.calculations": [
      "mycode.mycode = aiida_mycode.parsers.mycode:MycodeParser"
   ]
}

aida_mycode/parsers/myparser.py:

from aiida.parsers import Parser
class MycodeParser(Parser)
   ...

Usage:

from aiida.plugins import ParserFactory
parser = ParserFactory('mycode.mycode')

aiida.data

Group for Data subclasses. Previously located in a subpackage of aiida/orm/data.

Spec:

entry_points={
   "aiida.data": [
      "mycode.mydata = aiida_mycode.data.mydat:MyData"
   ]
}

aiida_mycode/data/mydat.py:

from aiida.orm import Data
class MyData(Data):
   ...

Usage:

from aiida.plugins import DataFactory
params = DataFactory('mycode.mydata')

aiida.workflows

Package AiiDA workflows as follows:

Spec:

entry_points={
   "aiida.workflows": [
      "mycode.mywf = aiida_mycode.workflows.mywf:MyWorkflow"
   ]
}

aiida_mycode/workflows/mywf.py:

from aiida.engine.workchain import WorkChain
class MyWorkflow(WorkChain):
   ...

Usage:

from aiida.plugins import WorkflowFactory
wf = WorkflowFactory('mycode.mywf')

Note

For old-style workflows the entry point mechanism of the plugin system is not supported. Therefore one cannot load these workflows with the WorkflowFactory. The only way to run these, is to store their source code in the aiida/workflows/user directory and use normal python imports to load the classes.

aiida.cmdline

verdi uses the click_ framework, which makes it possible to add new subcommands to existing verdi commands, such as verdi data mydata. AiiDA expects each entry point to be either a click.Command or click.CommandGroup.

Spec:

entry_points={
   "aiida.cmdline.data": [
      "mydata = aiida_mycode.commands.mydata:mydata"
   ]
}

aiida_mycode/commands/mydata.py:

import click
@click.group()
mydata():
   """commandline help for mydata command"""

@mydata.command('animate')
@click.option('--format')
@click.argument('pk')
create_fancy_animation(format, pk):
   """help"""
   ...

Usage:

verdi data mydata animate --format=Format PK

aiida.tools.dbexporters

If your plugin package adds support for exporting to an external database, use this entry point to have aiida find the module where you define the necessary functions.

aiida.tools.dbimporters

If your plugin package adds support for importing from an external database, use this entry point to have aiida find the module where you define the necessary functions.

aiida.schedulers

We recommend naming the plugin package after the scheduler (e.g. aiida-myscheduler), so that the entry point name can simply equal the name of the scheduler:

Spec:

entry_points={
   "aiida.schedulers": [
      "myscheduler = aiida_myscheduler.myscheduler:MyScheduler"
   ]
}

aiida_myscheduler/myscheduler.py:

from aiida.schedulers import Scheduler
class MyScheduler(Scheduler):
   ...

Usage: The scheduler is used in the familiar way by entering ‘myscheduler’ as the scheduler option when setting up a computer.

aiida.transports

aiida-core ships with two modes of transporting files and folders to remote computers: ssh and local (stub for when the remote computer is actually the same). We recommend naming the plugin package after the mode of transport (e.g. aiida-mytransport), so that the entry point name can simply equal the name of the transport:

Spec:

entry_points={
   "aiida.transports": [
      "mytransport = aiida_mytransport.mytransport:MyTransport"
   ]
}

aiida_mytransport/mytransport.py:

from aiida.transports import Transport
class MyTransport(Transport):
   ...

Usage:

from aiida.plugins import TransportFactory
transport = TransportFactory('mytransport')

When setting up a new computer, specify mytransport as the transport mode.