How to Make a Bio2BEL Package

In this tutorial, we’re going to explain how to make your own Bio2BEL package using miRTarBase as an example. This package already exists and is an excellent example.

Naming the Package

The package should be named bio2bel_XXX with all lowercase letters for the name of the package, even if the source uses stylized capitalization. This means our example package wil be called bio2bel_mirtarbase.

Note that the repository can be named differently from the package. On the Bio2BEL organization on GitHub, we have chosen to use simply a lowercase name of the source to eliminate redundancy in the URL.

Organizing Constants

The package should have a top-level module named constants.py as an easily accesible location for constants. A variable called MODULE_NAME should be defined with the lowercase name of the source. Additionally, the functions bio2bel.get_data_dir() and bio2bel.get_connection() to locate the appropriate directory for data and configuration loading.

# /src/bio2bel_mirtarbase/constants.py

from bio2bel import get_data_dir, get_connection

MODULE_NAME = 'mirtarbase'
DATA_DIRECTORY_PATH = get_data_dir(MODULE_NAME)
DEFAULT_CONNECTION = get_connection(MODULE_NAME)

Making a Manager

There should be a concrete implementation of bio2bel.AbstractManager. For consistent style, we recommend implementing this in a top-level module called manager.py and naming the class Manager. Check the miRTarBase repository for an example of the package structure and an example of the implementation of a Manager.

Mixins

Flask

BEL Namespace

BEL Network

Organizing the Manager

This class should be importable from the top-level. In our example, this means that you can either import the manager class with from bio2bel_mirtarbase import Manager or import bio2bel_mirtarbase.Manager.

This can be accomplished by importing the Manager in the top-level __init__.py.

# /src/bio2bel_mirtarbase/__init__.py

from .manager import Manager

__all__ = ['Manager]

__title__ = 'bio2bel_mirtarbase
...

A full example of the __init__.py for mirTarBase can be found here.

Making a Command Line Interface

The package should include a top-level module called cli.py. Normally, click can be used to build nice Command Line Interfaces like:

import click

@click.group()
def main():
    pass

@main.command()
def command_1()
    pass

However, if you’ve properly implemented an AbstractManager, then you can use AbstractManager.get_cli() to generate the main function and automatically implement several commands.

# /src/bio2bel_mirtarbase/cli.py

from .manager import Manager

main = Manager.get_cli()

if __name__ == '__main__':
    main()

This command line application will automatically have commands for populate, drop, and web. It can be extended like main from the first example as well.

Additionally, if the optional function to_bel is implemented in the manager, then several other commands (e.g., to_bel_file, upload_bel, etc.) become available as well.

Setting up __main__.py

Finally, the top-level __main__.py should import main and should have 3 lines, reading exactly as follows:

# /src/bio2bel_mirtarbase/__main__.py

from .cli import main

if __name__ == '__main__':
    main()

Entry Points in setup.py

Bio2BEL uses the entry points loader to find packages in combination with setuptools’s entry_points argument.

# /setup.py

import setuptools

setuptools.setup(
    ...
    entry_points={
        'bio2bel': [
            'mirtarbase = bio2bel_mirtarbase',
        ],
    }
    ...
)

This directly enables the Bio2BEL CLI to operate using the package’s cli so it’s possible to call things like bio2bel mirtarbase populate or bio2bel mirtarbase drop.

Additionally, a command-line interaface should be registered as well called bio2bel__mirtarbase that directly points to the main function in cli.py.

# /setup.py

import setuptools

setuptools.setup(
    ...
    entry_points={
        'bio2bel': [
            'mirtarbase = bio2bel_mirtarbase',
        ],
        'console_scripts': [
          'bio2bel_mirtarbase = bio2bel_mirtarbase.cli:main',
      ]
    }
    ...
)

Check the miRTarBase repostiroy for a full example of a setup.py.

Testing

Though it’s not a requirement, writing tests is a plus. There are several testing classes available in bio2bel.testing to enable writing tests quickly.

# /tests/constants.py

from bio2bel.testing import make_temporary_cache_class_mixin
from bio2bel_mirtarbase import Manager

TemporaryCacheClassMixin = make_temporary_cache_class_mixin(Manager)

Additionally, this class can also be generated as a subclass directly and used to override the class-level populate function

class PopulatedTemporaryCacheClassMixin(TemporaryCacheClassMixin):
    @classmethod
    def populate(cls)
        cls.manager.populate(url='... test data path ...')

Keep in mind that your populate function will probably have different argument names, especially if there are multiple files necessary to populate. Using test data instead of full source data is preferred for faster testing!