As an open source project, all cihai projects accept contributions through GitHub, GitLab and Codeberg. Below you will find resources on the internals of the project.


This guide applies to all cihai projects, not just the cihai repo.

Cihai projects use standard conventions and patterns based on best practices in python.

To be efficient at debugging, developing, testing, documenting, etc. it helps to familiarize yourself with the tool within, independently if needed.

<cihai-project> can be assumed to be an existing or future cihai project, including cihai, cihai-cli, unihan-etl, unihan-db. See GitHub, GitLab and Codeberg.

Development environment

poetry is a required package to develop.

$ git clone<cihai-project>.git
$ cd <cihai-project>

So if <cihai-project> is [cihai]:

$ git clone
$ cd cihai

Install dependencies

$ poetry install -E "docs test coverage lint"

Makefile commands prefixed with watch_ will watch files and rerun.


[pytest] is used for tests.

$ poetry run py.test

Rerun on file change

via pytest-watcher (works out of the box):

$ make start

via entr(1) (requires installation):

$ make watch_test

Manual (just the command, please)

$ poetry run py.test


$ make test

pytest options

For filename / test names within, examples will be for [cihai], if using a different cihai project check the filename and test names accordingly:

PYTEST_ADDOPTS can be set in the commands below. For more information read for the latest documentation.


$ env PYTEST_ADDOPTS="-verbose" make start

Pick a file:

$ env PYTEST_ADDOPTS="tests/" poetry run make start

Drop into test_cihai_version() in tests/

$ env PYTEST_ADDOPTS="-s -x -vv tests/" poetry run make start

Drop into test_cihai_version() in tests/ and stop on first error:

$ env PYTEST_ADDOPTS="-s -x -vv tests/" poetry run make start

Drop into pdb on first error:

$ env PYTEST_ADDOPTS="-x -s --pdb" make start

If you have ipython installed:

$ env PYTEST_ADDOPTS="--pdbcls=IPython.terminal.debugger:TerminalPdb" make start
$ make test

You probably didn’t see anything but tests scroll by.

If you found a problem or are trying to write a test, you can file an on the tracker for the relevant cihai project.

Manual invocation

Test only a file:

$ py.test tests/

will test the tests/ tests.

$ py.test tests/

tests test_cihai_version() inside of tests/

Multiple can be separated by spaces:

$ py.test tests/test_{conversion,exc}.py tests/


sphinx-autobuild will automatically build the docs, watch for file changes and launch a server.

From home directory: make start_docs From inside docs/: make start

Manual documentation (the hard way)

cd docs/ and make html to build. make serve to start http server.

Helpers: make build_docs, make serve_docs

Rebuild docs on file change: make watch_docs (requires entr(1))

Rebuild docs and run server via one terminal: make dev_docs (requires above, and a make(1) with -J support, e.g. GNU Make)

View documentation locally

To find the URL of the preview server, read the terminal, the URL may very depending on the project! An example of what to look for:

[I 220816 14:43:41 server:335] Serving on

Formatting / Linting


black is used for formatting.


$ poetry run black .

If you setup manually:

$ black .
$ make black

In the future, ruff (below) may replace black as formatter.


The project uses ruff to handle sorting imports and linting.


$ poetry run ruff

If you setup manually:

$ ruff .
$ make ruff
$ make watch_ruff

requires entr(1).


$ poetry run ruff . --fix

If you setup manually:

$ ruff . --fix


mypy is used for static type checking.


$ poetry run mypy .

If you setup manually:

$ mypy .
$ make mypy
$ make watch_mypy

requires entr(1).


Since this software used in production projects, we don’t release breaking changes until there’s a major feature release.

Choose what the next version is. Assuming it’s version 0.9.0, it could be:

  • 0.9.0post0: postrelease, if there was a packaging issue

  • 0.9.1: bugfix / security / tweak

  • 0.10.0: breaking changes, new features

Let’s assume we pick 0.9.1

CHANGES: Assure any PRs merged since last release are mentioned. Give a thank you to the contributor. Set the header with the new version and the date. Leave the “current” header and Insert changes/features/fixes for next release here at the top:

## package-name 0.10.x (unreleased)

- _Insert changes/features/fixes for next release here_

## package-name 0.9.1 (2020-10-12)

- :issue:`1`: Fix bug

package_name/ and - Set version

$ git commit -m 'Tag v0.9.1'
$ git push

Important: Create and push the tag. Make sure the version is correct and the pyproject.toml and match the version being deployed.

$ git tag v0.9.1
$ git push --tags

Automated deployment

CI will automatically push to the PyPI index when a tag is pushed.

Manual deployment


This requires PyPI access.

In addition to virtualenv creation and installing dependencies, poetry handles building the package and publishing. Therefore there is no or requirements files.

$ poetry build
$ poetry deploy