RDFLib developers guide

Introduction

This document describes the process and conventions to follow when developing RDFLib code.

  • Please be as Pythonic as possible (PEP 8).

  • Code should be formatted using black

and we use Black v21.9b0, with the black.toml config file provided. * Code should also pass flake8 linting and mypy type checking. * You must supply tests for new code

If you add a new cool feature, consider also adding an example in ./examples

Tests

Any new functionality being added to RDFLib _must_ have unit tests and should have doc tests supplied.

Typically, you should add your functionality and new tests to a branch of RDFlib and and run all tests locally and see them pass. There are currently close to 4,000 tests with a few extra expected failures and skipped tests. We won’t allow Pull Requests that break any of the existing tests.

Tests that you add should show how your new feature or bug fix is doing what you say it is doing: if you remove your enhancement, your new tests should fail!

Finally, please consider adding simple and more complex tests. It’s good to see the basic functionality of your feature tests and then also any tricky bits or edg cases.

Testing framework

RDFLib uses the pytest testing framework.

Running tests

To run RDFLib’s test suite with pytest:

$ pip install -r requirements.txt -r requirements.dev.txt
$ pytest

Specific tests can be run by file name. For example:

$ pytest test/test_graph.py

Writing tests

New tests should be written for pytest instead of for python’s built-in unittest module as pytest provides advanced features such as parameterization and more flexibility in writing expected failure tests than unittest.

A primer on how to write tests for pytest can be found here.

The existing test that use unittest work well with pytest, but they should ideally be updated to the pytest test-style when they are touched.

Test should go into the test/ directory, either into an existing test file with a name that is applicable to the test being written, or into a new test file with a name that is descriptive of the tests placed in it. Test files should be named test_*.py so that pytest can discover them.

Running static checks

Check formatting with black, making sure you use our black.toml config file:

python -m black --config black.toml --check ./rdflib

Check style and conventions with flake8:

python -m flake8 rdflib

Check types with mypy:

python -m mypy --show-error-context --show-error-codes rdflib

Using tox

RDFLib has a tox config file that makes it easier to run validation on all supported python versions.

# install tox
pip install tox

# list tox environments that run by default
tox -e

# list all tox environments
tox -a

# run default environment for all python versions
tox

# run a specific environment
tox -e py37 # default environment with py37
tox -e py39-mypy # mypy environment with py39

Writing documentation

We use sphinx for generating HTML docs, see Writing RDFLib Documentation.

Continuous Integration

We used Drone for CI, see:

If you make a pull-request to RDFLib on GitHub, Drone will automatically test your code and we will only merge code passing all tests.

Please do not commit tests you know will fail, even if you’re just pointing out a bug. If you commit such tests, flag them as expecting to fail.

Compatibility

RDFlib 6.0.0 release and later only support Python 3.7 and newer.

RDFLib 5.0.0 maintained compatibility with Python versions 2.7, 3.4, 3.5, 3.6, 3.7.

Releasing

Set to-be-released version number in rdflib/__init__.py and README.md. Check date in LICENSE.

Add CHANGELOG.md entry.

Commit this change. It’s preferable make the release tag via https://github.com/RDFLib/rdflib/releases/new :: Our Tag versions aren’t started with ‘v’, so just use a plain 5.0.0 like version. Release title is like “RDFLib 5.0.0”, the description a copy of your CHANGELOG.md entry. This gives us a nice release page like this:: https://github.com/RDFLib/rdflib/releases/tag/4.2.2

If for whatever reason you don’t want to take this approach, the old one is:

Tagging the release commit with::

  git tag -am 'tagged version' X.X.X

When pushing, remember to do::

  git push --tags

No matter how you create the release tag, remember to upload tarball to pypi with:

rm -r dist/X.X.X[.-]*  # delete all previous builds for this release, just in case

rm -r build
python setup.py sdist
python setup.py bdist_wheel
ls dist

# upload with twine
# WARNING: once uploaded can never be modified, only deleted!
twine upload dist/rdflib-X.X.X[.-]*

Set new dev version number in the above locations, i.e. next release -dev: 5.0.1-dev and commit again.

Tweet, email mailing list and inform members in the chat.