Extension Distribution¶
Python Packages¶
Extensions are packaged and distributed as Python packages (Python Wheels). This allows for automatic detection of installed extensions, packaging of static files, and dependency checking.
Extension packages are pretty much like any other Python package. It uses a pyproject.toml file to define your package contents, along with Review Board’s extension build backend.
There are a few additional features that are provided by Review Board, which will be covered in this guide.
Defining an Entry Point¶
To facilitate the auto-detection of installed extensions, a
reviewboard.extensions
Python Entry Point must be defined for each
extension class in your package. These are defined
in your pyproject.toml like so:
[project.entry-points."reviewboard.extensions"]
sample_extension = 'sample_extension.extension:SampleExtension'
This tells the Python packaging system that there’s a Review Board extension
named sample_extension
that points to
sample_extension.extension.SampleExtension
. Once the package is
installed, Review Board will be able to use this registered entry point to
locate your extension.
Here is an example of a full pyproject.toml file defining this entry point:
[build-system]
requires = [
# Update this for the target version of Review Board.
'reviewboard~=7.1',
'reviewboard[extension-packaging]',
]
build-backend = 'reviewboard.extensions.packaging.backend'
[project]
name = 'sample_extension'
version = '1.0'
description = 'Description of your extension package.'
authors = [
{name = 'Your Name', email = 'your-email@example.com'}
]
# Your Python package dependencies go here. Don't include "ReviewBoard" in
# this list.
dependencies = [
]
# For a full list of package classifiers, see
# https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers = [
'Development Status :: 3 - Alpha',
'Environment :: Web Framework',
'Framework :: Review Board',
'Operating System :: OS Independent',
'Programming Language :: Python',
]
# This tells Review Board where to find your extension. You'll need to
# change the "sample_extension = ..." based on your extension ID and
# module/class path.
[project.entry-points."reviewboard.extensions"]
sample_extension = 'sample_extension.extension:SampleExtension'
# This section tells Python where to find your extension. You shouldn't
# need to change these.
[tool.setuptools.packages.find]
where = ['.']
namespaces = false
Packaging Static Media Files¶
Packages that contain CSS or JavaScript should define those in the extension
class’s css_bundles
and
js_bundles
dictionaries.
These bundles will be automatically compiled, minified, and packaged for you.
There’s nothing else you need to do.
See Extension Static Media Files for more information on bundles.
Packaging Templates/Data Files¶
If your package needs to ship templates or other data files, you’ll need
to include these in your package’s MANIFEST.in
file. Please see
the MANIFEST.in documentation for
the format of this file.
This file will live in the same directory as your pyproject.toml.
Your MANIFEST.in
might look something like this:
include sample_extension/templates/*.html
include sample_extension/templates/*.txt
include README
include LICENSE
Dependencies¶
Your package can specify a list of dependencies, which are other packages that
will be installed when your package is installed. This is specified as
dependencies
in pyproject.toml.
Warning
Don’t specify reviewboard
, djblets
, Django
, or any other Review
Board dependency in your own list. While your package may indeed require
Review Board or one of its dependencies, this runs the risk (in certain
cases) of accidentally upgrading all or part of your Review Board install
when installing your package.
For example, your pyproject.toml may include:
[project]
...
dependencies = [
'PythonPackageIDependOn>=0.1'
]
In addition, extensions can have a run-time dependency on another extension,
forcing that extension to be enabled when yours is enabled. This is done by
specifying the required extensions’ IDs in the
requirements
list. For
example:
class SampleExtension(Extension):
requirements = [
'other_extension.extension.OtherExtension',
]
Building a Package¶
You’re now ready to build your package! Just follow these steps:
Make sure you have Python’s build package installed:
$ pip3 install build
You only have to do this once.
Build your source distribution and wheel package from the top of your extension’s source tree:
$ python3 -m build .
That will produce builds in the
dist/
directory.
Developing Against Your Package¶
If you’re actively testing your package against Review Board, you don’t want to keep rebuilding the package every time you make a change. Instead, you’ll want to install your package in “editable” mode:
$ pip3 install -e .
This allows you to make changes to your extension and test it without building and installing new packages. It’s the recommended way to iterate on your package while you test.
We recommend only testing editable packages against a Review Board development server, and not against a production server.