Contributing

Colour is open source and we happily welcome contributions. This guide will give you an overview on how to contribute.

There are many ways to help:

Github hosts a First Contributions repository with good information for new comers.

Reporting Issues

The three major issue types one can report on the issue tracker are the following:

We currently use a large set of labels to categorise issues:

  • Defect: Used for any kind of defect reported.

    • Critical: Used for issues either rendering the software unusable, causing loss of data, or preventing people to work. These issues need to be fixed immediately.

    • Major: Used for issues which have significant consequences on the ability of people to work but do not lead to the whole API being unusable.

    • Normal: Used for issues affecting one piece of functionality. Those are usually self-contained and don't impact the overall functionality of the API.

    • Minor: Used for cosmetic issues that don't prevent the API to run properly.

  • Enhancement: Used for an enhancement of an existing feature, can also be used for new feature suggestion, although Feature label should be preferred.

  • Feature: Used for a new feature, functionality suggestion.

    • P1: Used for the highest priority.

    • P2: Used for average priority.

    • P3: Used for the lowest priority.

  • API: Used for issues related to the API.

  • Discarded: Used for a discarded / canceled issue.

  • Discussion: Used to discuss any subject, those issues often turn into features or enhancement.

  • Distribution: Used to discuss distribution and packaging of the API.

  • Documentation: Used for issues related to the documentation.

  • Duplicate: Used for a duplicate issue.

  • Examples: Used for issues related to the examples.

  • Postponed: Used for an issue postponed for a future milestone.

  • Task: Used for a task not directly related to pure programming.

  • Good First Issue: Used for an issue appropriate for a first time contribution.

  • Help Wanted: Used for an issue appropriate for a first time contribution but likely harder than a Good First Issue one.

Defects

You encountered a problem while using Colour, please consider reporting it on the Issue Tracker.

The first thing to do, is to check if there are any existing issues describing your problem, if there is one, you are welcome commenting into it and provide more details. However, please avoid creating duplicates, they add noise to the issue tracker and we will have to label them as Duplicate and close them.

When reporting a defect please provide the output of the following command if possible, and if it makes sense to do so:

python -c "import colour;colour.utilities.describe_environment()"

The typical output is something along those lines:

===============================================================================
*                                                                             *
*   Interpreter :                                                             *
*       python : 3.11.6 (main, Oct  2 2023, 20:46:14) [Clang 14.0.3           *
*   (clang-1403.0.22.14.1)]                                                   *
*                                                                             *
*   colour-science.org :                                                      *
*       colour : v0.4.3-61-gbfc42ac2e                                         *
*                                                                             *
*   Runtime :                                                                 *
*       imageio : 2.31.5                                                      *
*       matplotlib : 3.8.0                                                    *
*       networkx : 2.8.8                                                      *
*       numpy : 1.26.1                                                        *
*       pandas : 1.5.3                                                        *
*       pygraphviz : 1.11                                                     *
*       PyOpenColorIO : 2.3.0                                                 *
*       scipy : 1.11.3                                                        *
*       tqdm : 4.66.1                                                         *
*       trimesh : 3.23.5                                                      *
*       xxhash : 3.4.1                                                        *
*                                                                             *
===============================================================================

If you are reporting an exception, please provide the complete traceback, it will help us understand what happened.

Features & Enhancements

If you would like a new feature to be supported or an enhancement of an existing feature, don't hesitate to link any resources or references you feel like would help its implementation: publications, wikipedia article, etc...

If there is an implementation existing in another language, we will be most likely be able to port it although the licence must be compatible with the BSD-3-Clause terms.

We are also running Matlab, so don't hesitate to provide snippets for it if you have functions you would like to be ported.

Contributing Code

Assuming you have something to work on, you will have to get the code and follow the guidelines.

Development for Colour

Note

If you are on macOS, a dedicated guide on how to setup your environment is available here: Setting Up the Development Environment on macOS.

Here is a succinct overview of the steps you will most likely go through:

Step 1

Fork the Colour repository.

Step 2

Clone the repository locally to your workspace:

git clone git@github.com:$USER/colour.git

Step 3

Navigate to the colour directory:

cd colour

Step 4

Assuming python >= 3.10, < 3.13 is available on your system, the development dependencies are installed with uv as follows:

uv sync --all-extras
Warning

Various Colour unit tests require being able to perform IO with OpenEXR images. You will need to install the FreeImage plugin for Imageio as follows: python -c "import imageio;imageio.plugins.freeimage.download()"

Step 5

Install the pre-commit hooks:

uv run pre-commit install

Step 6

Connect your clone to the original upstream repository by adding it as a remote:

git remote add upstream git@github.com:colour-science/colour

Step 7

You should now have two remotes:

git remote -v
origin  https://github.com/$USER/colour (fetch)
origin  https://github.com/$USER/colour (push)
upstream  https://github.com/colour-science/colour (fetch)
upstream  https://github.com/colour-science/colour (push)

Step 8

Pull the latest changes from upstream:

git checkout develop
git pull upstream develop

Step 9

Create a branch for your contribution:

The core developers are using the git flow branching model for most of the development tasks and since the branch name appears in the commit message and for consistency, please use the following branch prefixes:

  • Feature branch prefix: feature/

  • Release branch prefix: release/

  • Hotfix branch prefix: hotfix/

As an example, working to implement Mie Scattering support:

git checkout -b feature/mie_scattering

Step 11

Implement your changes while making sure examples and relevant documentation are written.

Step 12

Check whether the unit tests and doctests are passing:

uv run invoke tests

or alternatively:

source .venv/bin/activate
invoke tests

Step 13

Verify that the static checking from pyright is passing:

uv run invoke quality

Step 14

Commit your changes:

git add mie_scattering.py
git commit -m 'Implement "Mie Scattering" support.'
Note

The pre-commit hooks will run before committing, notably codespell, flynt, isort, ruff, blacken-docs, prettier, thus depending on their status, you might not be able to commit until you have fixed the issues reported.

Step 15

Push your changes to origin, i.e., your own fork:

git push origin feature/mie_scattering

Step 16

Visit your repository fork on Github. Your branch should have a green Pull Request button, this will open a pull request and let us know that we have some code to review :)

Step 17

Check that the continuous integration suite succeeded.

Code Review

Your pull request will be reviewed by the maintainers and any other developer interested by the project.

We review all the code submitted, this is a natural process helping to raise the codebase quality around a friendly and constructive discussion. Comments will be made on various aspects such as the documentation and references, the code style and its implementation. Those can be discouraging, although they are not meant to criticize but aim at improving the quality of your submission. We all learn from that process and the project ultimately benefits from them.

Guidelines

Most of the conventions used in Colour are the same than NumPy, SciPy and scikit-image.

Overview

We follow the Google Python Style Guide and especially the Python Language Rules although with the main exception being the docstrings / documentation formatted with Numpy Docstrings Style.

We use type hints to statically indicate and verify the type of objects in the codebase with mypy.

The code has to be PEP 8 compliant although but before anything else, it needs to be consistent with the Colour Science literature:

For example, the base CIE colourspace is CIE XYZ with upper case notation. It can be converted to chromaticity coordinates xy with lower case notation. If we were to fully abide by the PEP 8 recommendations, we would have written a conversion definition as follows:

def xyz_to_xy(xyz: ArrayLike) -> Tuple:
    x, y, z = np.ravel(xyz)
    x, y = x / (x + y + z), y / (x + y + z)

    return x, y

Abstracting the fact that the above definition is totally undocumented, it can be confusing to understand when we are referencing big X tristimulus value or little x chromaticity coordinate.

For those cases, and there are legions of them in Colour Science, we have decided to go for clarity and consistency with the literature for the object names:

def XYZ_to_xy(XYZ: ArrayLike) -> Tuple:
    X, Y, Z = np.ravel(XYZ)
    x, y = X / (X + Y + Z), Y / (X + Y + Z)

    return x, y

When the reference is using upper case named variables, we try to follow the same convention, it is unfortunately not PEP 8 compliant but has the benefit of a much easier comparison between the implementation and the reference.

We suggest that contributors follow the same rule.

Python Language Rules

  • All the code must be annotated with type hints.

  • All the code must be covered by unit tests and doctests.

  • All the code must be documented to the same standard than NumPy, SciPy and scikit-image.

  • All the code must be checked with the pre-commit hooks.

  • Pull requests should not be merged without being reviewed and ensuring that the Github Actions continuous integration suite succeeded.

  • Examples should be provided for new features.

Python Style Rules

  • Ensure consistency with Colour Science literature first.

  • Ensure PEP 8 compliance.

  • Try using a close to LaTeX syntax for variables names so that they are easier to compare to the reference.

    For instance, a variable defined $$D_{uv}$$ in a paper would be defined as D_uv in the code, $$L^*$$ as Lstar and $$X_{ab}^{\prime}$$ as Xp_ab.

  • Try using uppercase for author names in definitions:

def CCT_to_xy_Kang2002(CCT): ...
  • Please use British English words instead of American English ones as the CIE does, the most important of all being colour instead of color. You can consult the CIE Termlist if any doubts.

  • Import NumPy as follows:

import numpy as np
  • Doctests may need ellipsis, don't rely on global nose settings and specify it using the dedicated pragma as follows:

Lab = np.array([100.00000000, -7.41787844, -15.85742105])
Lab_to_LCHab(Lab)  # doctest: +ELLIPSIS
array([ 100.        ,   17.5066479...,  244.9304684...])
  • Numbers in the API are usually rounded as follows:

    • Dataset numbers are kept as is if they are from a known reference or rounded to 15 digits if computed with the API (spectral distributions, chromaticity coordinates, etc...).

    • Unit tests and doctests input numbers are kept as is if they are from a reference or rounded to 8 digits if computed with the API.

    • Unit tests output numbers are rounded to 8 digits.

    • Doctests output numbers trimmed with ellipsis to 7 digits.

  • We recommend a set of values for use with examples and unit tests. A Gist is available with the generating code.

    Priority should be given for CIE Standard Illuminant D Series D65 computed values:

Recommended Values for Use in Colour Examples and Unit Tests

Illuminants "xy"

D65 : array([0.31270000, 0.32900000])
D50 : array([0.34570000, 0.35850000])
A : array([0.44757000, 0.40745000])
E : array([0.33333333, 0.33333333])
F2 : array([0.37208000, 0.37529000])
CC I : array([0.34570000, 0.35850000])


Illuminants "XYZ"

D65 : array([0.95045593, 1.00000000, 1.08905775])
D50 : array([0.96429568, 1.00000000, 0.82510460])
A : array([1.09846607, 1.00000000, 0.35582280])
F2 : array([0.99144661, 1.00000000, 0.67315942])
E : array([1.00000000, 1.00000000, 1.00000000])
CC I : array([0.96429568, 1.00000000, 0.82510460])


ColorChecker 2005 "XYZ" Adapted to "D65"

red : array([0.20654008, 0.12197225, 0.05136952])
green : array([0.14222010, 0.23042768, 0.10495772])
blue : array([0.07818780, 0.06157201, 0.28099326])
cyan : array([0.14525849, 0.19799077, 0.40724370])
yellow : array([0.55676530, 0.58671628, 0.09785344])
magenta : array([0.30795495, 0.20024152, 0.31071274])
neutral 5 (.70 D) : array([0.18182171, 0.19153665, 0.21009620])


ColorChecker 2005 "XYZ" Adapted to "D50"

red : array([0.21638819, 0.12570000, 0.03847493])
green : array([0.14985004, 0.23180000, 0.07900179])
blue : array([0.06857861, 0.05750000, 0.21375591])
cyan : array([0.13605127, 0.19300000, 0.30938736])
yellow : array([0.59342537, 0.59810000, 0.07188823])
magenta : array([0.31084193, 0.20090000, 0.23565391])
neutral 5 (.70 D) : array([0.18438363, 0.19150000, 0.15918203])


ColorChecker 2005 "XYZ" Adapted to "A"

red : array([0.25330530, 0.13765139, 0.01543307])
green : array([0.18673833, 0.23111171, 0.03285972])
blue : array([0.05610693, 0.04992541, 0.09429057])
cyan : array([0.13623492, 0.18062024, 0.13553082])
yellow : array([0.73088905, 0.62177441, 0.02548927])
magenta : array([0.34280970, 0.20770559, 0.10214220])
neutral 5 (.70 D) : array([0.20988974, 0.19141324, 0.06866269])


ColorChecker 2005 "XYZ" Adapted to "E"

red : array([0.21781186, 0.12541048, 0.04697113])
green : array([0.15434689, 0.22960951, 0.09620221])
blue : array([0.07683480, 0.06006092, 0.25833845])
cyan : array([0.14893167, 0.19487065, 0.37427698])
yellow : array([0.59874058, 0.59196415, 0.08899633])
magenta : array([0.31991986, 0.20277158, 0.28536138])
neutral 5 (.70 D) : array([0.19126715, 0.19151544, 0.19291812])


ColorChecker 2005 "XYZ" Adapted to "F2"

red : array([0.22545552, 0.12877805, 0.03103172])
green : array([0.15832594, 0.23204226, 0.06406107])
blue : array([0.06385467, 0.05509729, 0.17506386])
cyan : array([0.13364947, 0.18951306, 0.25307753])
yellow : array([0.62718558, 0.60525456, 0.05690008])
magenta : array([0.31720246, 0.20226568, 0.19243480])
neutral 5 (.70 D) : array([0.18952683, 0.19147512, 0.12987334])


Luminance "XYZ" Adapted to "D65"

red : 12.19722535
green : 23.04276781
blue : 6.15720079
cyan : 19.79907683
yellow : 58.67162787
magenta : 20.02415243
neutral 5 (.70 D) : 19.15366501


Luminance "XYZ" Adapted to "D50"

red : 12.57000000
green : 23.18000000
blue : 5.75000000
cyan : 19.30000000
yellow : 59.81000000
magenta : 20.09000000
neutral 5 (.70 D) : 19.15000000


Luminance "XYZ" Adapted to "A"

red : 13.76513858
green : 23.11117127
blue : 4.99254109
cyan : 18.06202404
yellow : 62.17744084
magenta : 20.77055938
neutral 5 (.70 D) : 19.14132354


Luminance "XYZ" Adapted to "E"

red : 12.54104823
green : 22.96095053
blue : 6.00609174
cyan : 19.48706483
yellow : 59.19641488
magenta : 20.27715822
neutral 5 (.70 D) : 19.15154358


Luminance "XYZ" Adapted to "F2"

red : 12.87780528
green : 23.20422641
blue : 5.50972884
cyan : 18.95130571
yellow : 60.52545632
magenta : 20.22656850
neutral 5 (.70 D) : 19.14751195


ColorChecker 2005 "sRGB - Linear" under "D65"

red : array([0.45620519, 0.03081071, 0.04091952])
green : array([0.05433312, 0.29879493, 0.07185472])
blue : array([0.01862364, 0.05140184, 0.28880425])
cyan : array([-0.03667845, 0.24755074, 0.39815738])
yellow : array([0.85356364, 0.56517342, 0.01475279])
magenta : array([0.53522616, 0.09013008, 0.30472718])
neutral 5 (.70 D) : array([0.19002735, 0.19183638, 0.19312568])


ColorChecker 2005 "sRGB - OETF" under "D65"

red : array([0.70573936, 0.19248268, 0.22354168])
green : array([0.25847007, 0.58276101, 0.29718877])
blue : array([0.14565317, 0.25130933, 0.57378757])
cyan : array([-0.47388561, 0.53467479, 0.66380090])
yellow : array([0.93264474, 0.77675390, 0.12708884])
magenta : array([0.75809823, 0.33206288, 0.58800664])
neutral 5 (.70 D) : array([0.47315229, 0.47524148, 0.47672343])


ColorChecker 2005 "Munsell Value"

red : 4.08244375
green : 5.39132685
blue : 2.97619312
cyan : 5.06675596
yellow : 8.04387670
magenta : 5.10225899
neutral 5 (.70 D) : 4.98656896


ColorChecker 2005 "ASTM D1535-08e1 Luminance"

red : 12.23634268
green : 22.89399987
blue : 6.29022535
cyan : 19.86282567
yellow : 58.37987916
magenta : 20.18160934
neutral 5 (.70 D) : 19.15426585
  • Some commonly used dataset elements have aliases like 'cie_2_1931' for 'CIE 1931 2 Degree Standard Observer'. Those are provided for convenience and are reserved for external usage, please use the long form for consistency across the API.

  • In the same way as above, some computation methods are using a title case like 'Ohno 2013', while the mapping object holding them is case insensitive, please use the title case form for consistency across the API.

  • Some very big lines sometimes cannot be wrapped (doctests, html links), you can use the # noqa pragma in those cases, although do it in last resort, we have already too much of them.

  • Avoid / to wrap lines, prefer using the parenthesis ().

  • The code formatting is performed using ruff via a pre-commit hook.

  • Inline comments must have two spaces.

  • Ensure that you have blank line at the end of the files.

  • Ensure that trailing whitespaces are stripped.

  • Prefix unused variable with an underscore:

_L, a, b = tsplit(Lab)

Citations

It's likely that the code you contribute will be based upon references, we are using a slightly modified APA 7th Edition citation style available for download and generating citations as follows:

Davis, W., & Ohno, Y. (2010). Color quality scale. Optical Engineering, 49(3), 033602. doi:10.1117/1.3360335
Wyszecki, G., & Stiles, W. S. (2000). Table I(6.5.3) Whiteness Formulae (Whiteness Measure Denoted by W). In Color Science: Concepts and Methods, Quantitative Data and Formulae (pp. 837–839). Wiley. ISBN:978-0-471-39918-6
Lindbloom, B. (2014). RGB Working Space Information. Retrieved April 11, 2014, from http://www.brucelindbloom.com/WorkingSpaceInfo.html

We are storing all our citations in a database maintained by Zotero and it is recommended that you are given a citation key by us.

Commits

A good committing strategy implies that separated commits should be done for any particular changes: One should not commit multiple bugs fixes or large change sets at once.

This unnecessarily increase complexity for any code merge or rollbacks needs and prevent a grainier control over the version control. One exception to this rule is for the initial design steps when creating a new sub-package or feature (please consider squashing the commits), but once the said sub-package is in production, a regular committing strategy should be applied.

Commit messages need to use imperative syntax, the first commit line must be a quick description of the modification content finished by a punctuation mark and can be followed by a detailed description separated by one line break. If the commit fixes a particular issue in the issue tracker, it's advised to state it in the commit message using the following syntax: Closes #32.

Yes:

Implement "Yoshi Ohno" correlated colour temperature calculation.

This implementation allows for a more precise correlated colour temperature
calculation by using a two solutions hybrid approach.

Closes #32.
No:

Coded new cool cct method

Feature Branches & History

History should never be re-written, although while working on your local feature branch, you may want to provide a cleaner commits history before submitting a pull request. It is perfectly fine to modify your local branch as you wish.

However, if you need to change history on a public and used feature branch, please inform the Colour Developers in order to avoid commit losses or a merging disaster.

Releasing Colour

The following stages help maintainers navigate through the release of a new version of Colour, some automation is provided by Invoke:

  • Github - Stage 1

  • Zenodo - Stage 1

  • Colour - Stage 1

    • TODOCheck codacy status
    • TODOCheck documentation build warnings
      uv run invoke docs
    • Rebuild a clean uv environment
      • TODORemove the current uv environment
        rm -rf .venv
      • TODOCreate a pristine uv environment
        rm uv.lock && uv sync --all-extras
      • TODORun the examples task with figures: They need to be visually assessed for correctness
        uv run invoke examples --plots
      • TODORun the build task: It cleans the project, runs the pre-commit hooks, the examples, the unit tests, etc...
         invoke build
  • Pypi - Stage 1

    • TODORun the virtualise task: It deploys the project to a virtual environment and run the unit tests
      uv run invoke virtualise
  • Colour - Stage 2

    • Raise the package version
      • TODO__init__.py
      • TODOpyproject.toml
      • A typical commit message for version raise is as follows:
        Raise package version to 0.3.16.
    • Update the Zenodo DOI
      • TODOREADME.rst
  • Git

    • TODORun the tag task: It should prompt for tagging the repository accordingly to the defined version using git-flow
      uv run invoke tag
    • A typical tag message for a Colour version is as follows:
      • Create Colour v0.3.16 version.
    • In the eventuality where the tag creation failed, it might be created manually as follows:
      git tag -a -m "Create Colour v0.3.16 version." v0.3.16
    • Push the master and develop branches along with the newly created tag:
      git push upstream master develop --tags
  • Github - Stage 2

  • Pypi - Stage 2

    • TODORun the release task: It releases the project to Pypi with Twine
      uv run invoke release
  • Zenodo - Stage 2

    • TODOUpload the Pypi package and create new version in Zenodo
  • Conda-Forge

    • TODOCreate new conda-forge version. The sha256 attribute must be updated and can be computed with the sha256 task:
      uv run invoke sha256
  • colour-science.org

    • Update the release links
      • TODOconf.py
      • TODOindex.rst
    • Update the documentation links
      • TODOapi-reference.rst
    • Update the Zenodo badge
      • TODOconf.py
      • TODOapi-status-and-badges.rst
  • Propaganda & Announcement

    • TODO3D-Pro
    • TODOBuffer (Facebook / Linkedin / Twitter)
    • TODOHacker News
    • TODOReddit