Development Guide
This document describes how to set up development environments to begin contributing to caikit projects.
- Development Guide
Managing development environments with Tox
We use the virtual environment manager tox to run our builds. We think of it as Make, but for python. Plenty of public documentation is available for tox, but the quick gist is that for every task, tox manages an isolated virtual environment for that task and those environments all reside in the .tox
directory. These tasks and their environments are describe in the tox.ini
file at the root of each repo.
Installing tox
The tox
tool must be installed on your system in order to run builds, since it is the entrypoint for all build commands. Since tox
is a python module, it may be installed in your favorite python virtual environment of choice and invoked from there. Though it is important to note that the environment where you install tox will not be the environment where builds and tests are run.
You may also use a system package manager to install tox, e.g. on Mac you can run
brew install tox
Building and testing
Running unit tests with tox should always be done against an installation of the library being built. This is the default behavior of tox, but can be disabled with the skip_install
configuration to test against source code directly.
To run unit tests, the py
environment will use your system’s default version of python, and run pytest. Other specific python version can be supplied in the format py39
, py310
, py311
. A python interpreter must be installed and available on your system path in order for tox to pick it up to create the virtual environment. Example usage:
tox -e py311
The [testenv]
section in your tox.ini
file is used to specify the behavior for these test runs. It should always allow passthrough args to the pytest
invocation so that developers can pass args in, like:
tox -e py311 -- tests/some/package/test_file.py
tox -e py311 -- -k some_test_prefix
Format and linting
The fmt
environment should apply all code formatting rules. This should include at least black
and isort
. The lint
environment should apply all static linting, e.g. with pylint
Projects should define pre-commit hooks so that developers can enable pre-commit checks for formatting and linting. Otherwise, train your fingers to
tox -e fmt,lint
before committing.
Publishing a package
The publish
environment should be set up to publish the package to PyPi. We generally use Flit for this, simply because it’s easy.
To test publication, publish to the pypi test instance by setting FLIT_INDEX_URL
to https://test.pypi.org/simple/
.
To publish a package for the first time, a token will need to be used that has user-scoped permissions in order to create the project on pypi. This is a bit dangerous! We generally create a short-lived token for that and add it to the github repo only long enough to run the initial publish. Once the pypi package is created, we replace the user-scoped token with one that has permissions scoped to that specific package.
Default Behavior
By default, the tox
command should run
- Unit tests
- Code formatting
- Linting
For example the top of your tox.ini
should look similar to:
[tox]
envlist = py, lint, fmt
Specifying project dependencies
All dependencies should be specified in extras sets in the pyproject.toml
file. This allows other python environments to be easily built without requiring the use of tox
.
These extras sets are specified in the [project.optional-dependencies]
section of the pyproject.toml file, and should include at least:
dev-test
: Everything required to run unit testsdev-fmt
: Everything required to run formatting and lintingdev-docs
: Everything required to build and publish documentationdev-build
Everything required to build and publish the package itself
How to define a new tox environment
New environments can be set up by adding another
[testenv:{env_name}]
section to the tox.ini file.
They should all include at least a description
, extras
, and commands
field.
For example:
[testenv:joe_cool]
description = A super fun environment that prints hello world
extras = dev-test
commands = python -c 'print("hello world")'
is invoked as:
$ tox -e joe_cool
joe_cool: commands[0]> python -c 'print("hello world")'
hello world
joe_cool: OK (0.20=setup[0.17]+cmd[0.03] seconds)
congratulations :) (0.27 seconds)
If environment variables are required, they must be specified in the passenv
config. If external scripts are invoked, they must be specified in the allowlist_externals
config.
BYO Python Environment
Tox is provided for convenience and consistency for CI actions, but you can easily set up your own virtual environment to develop with.
From the root of a caikit project:
- Use your virtual environment manager of choice (Conda, raw venv, virtualenv, etc.) to create and activate a fresh environment
pip install .
to install the project and its core set of dependencies- Install any other extras with
pip install ".[${extra_name}]
. Check the[project.optional-dependencies]
section of thepyproject.toml
file for all available extras. This may look likepip install ".[dev-test]"
orpip install ".[all-dev]"
to install dependencies required to run tests and formatting.
Setting up your IDE
Both Pycharm (Community Edition) and VS-code are very plug-and-play friendly and only needs minimal configuration. It will need you to specify a python environment to use for indexing, code completion, and run/debug contexts. It may also require some project-specific settings for your python path.
Setting up your IDE’s python env
By default, both VS-Code and PyCharm will try to use your system’s python environment, and you probably don’t want this. Three other easy options are:
1. Use your BYO env
PyCharm
If you’ve used an environment manager like conda
to create a python environment already, you can point PyCharm to it.
From the Settings menu (⌘ ,
on Mac), navigate to Project: {project_name} > Python Interpreter > add interpreter > Add Local Interpreter
Select Environment: existing
Navigate to the python3
executable, for conda installed via homebrew this may look like /opt/homebrew/anaconda3/envs/${env_name}/bin/python3
Save the new interpreter and Apply to the project
VS-Code
Open Command Pallete (⇧ ⌘ P), then type Python: Select interpreter
, then navigate to the python3
executable for your env.
2. Use a tox env
This is not recommended by the tox maintainers, but you can re-use the existing tox
environments for other purposes.
First create a tox environment, e.g. by running tox -e py311
. Follow the above steps for selecting an existing environment, and use ${repo_root}/.tox/py311/bin/python3
3. Let your IDE manage a fresh one
PyCharm
PyCharm can also create a new virtual environment for you. From the Add Local Interpreter
menu, select Environment: new
.
You can choose where the environment is created, by default it will be placed in ${repo_root}/venv
.
VS-Code
VS-Code can also create a new virtual environment for you.
Open Command Pallete (⇧ ⌘ P), then type Python: Create environment
, then select either conda
or venv
. You can also point it to your requirements.txt
file if you have one to install all dependencies automatically.
Adding folders to Python path
For some projects you may need to add directories to your PYTHONPATH to make packages importable. For example, caikit/caikit
has a sample_lib
test fixture which contains a sample implementation of an AI library using caikit. The top-level conftest.py
will take care of adding that fixture to the syspath, but if you want PyCharm to have code-completion and indexing support, you’ll need to configure it.
PyCharm
To do this in PyCharm, right-click the directory in the project explorer and select Mark Directory As > Sources Root
VS-Code
Create a .env
file in the root directory, and add things to that:
PYTHONPATH=tests/fixtures
Running a debugger
With PyCharm
If PyCharm’s environment has been configured correctly, then debugging is pretty straightforward. Breakpoints are set by clicking on the left editor sidebar next to the line numbers. Conditions can be added to breakpoints by right-clicking on them.
Debugging can be run by either:
- Starting a debug session locally: Grab a unit test or
__main__
entrypoint and click the green run flag next to it - Attaching a debugger to a running process: Start a process (e.g.
$ python3 -m caikit.runtime
) and then selectRun > Attach to Process
Remote debugging is available in PyCharm Professional. If you pay for that, you probably know how to use it!
With VS-Code
How to debug python modules is covered in this article: https://code.visualstudio.com/docs/python/debugging
TL;DR
-
Create a
.vscode
directory right next toCaikit
’s home directory, and put thislaunch.json
file within it:{ "version": "0.0.1", "configurations": [ { "name": "Python: Remote Attach", "type": "python", "request": "attach", "connect": { "host": "127.0.0.1", "port": 3000 }, "justMyCode": false } ] }
Note:
justMyCode
is a very cool feature that enables you to debug through external dependencies as well! -
Once you do that, you need to install
debugpy
(Source code link: https://github.com/microsoft/debugpy):pip install debugpy
-
You need to start
Caikit
through debugpy in order to activate the debugger:python3 -m debugpy --listen localhost:3000 --wait-for-client -m caikit.runtime
This should wait for the user to start the debug session through
vs-code
and it should stop on any breakpoints that you have configured.
Updating project documentation
Caikit projects build documentation with Sphinx and host it on readthedocs. A solid tutorial with basic concepts is found here.
The actual documentation builds are run on readthedocs.org, not on github.com. You won’t find a .github/workflows
entry for the documentation. Each repo that hosts docs should contain a .readthedocs.yaml file containing the build config for readthedocs to use. If a repo is not yet hosting documentation, a caikit admin will need to set up the project on readthedocs.org.
We make use of the Sphinx AutoAPI extension to generate docs from the python source code. You can also manually edit the docs by editing the .rst
files. The home page should generally live at docs/source/index.rst
To generate the documentation locally while making changes, use the docs
tox env.
tox -e docs
open docs/source/_build/html/index.html
Sample lib
What is it
https://github.com/caikit/caikit/tree/main/tests/fixtures/sample_lib
The sample_lib
is a very simple non-production Caikit library that exists within the tests/fixtures/sample_lib
directory, and consists of Modules
and Tasks
like a production Caikit
library but with boilerplate code within those Modules
. This library was created only for helping with unit testing.
If you are a new user of Caikit
and you want to explore the gRPC or REST APIs without writing any code, then the sample_lib
library can be a good place to start.
How to play around with it
If you’ve followed the steps for setting up your IDE correctly, sample_lib
should now already be on your python_path
.
There’s a useful README in examples/sample_lib/README.md
that describes how to start the Caikit
runtime with it. It automatically:
- adds
sample_lib
to yourpython_path
(in case you don’t have it) - Dump all gRPC proto files and
openapi.json
for the HTTP server - Create a
sample.json
file for training through gRPC - Starts
Caikit runtime
with the right configurations.