Contributing to Pycytominer

First of all, thank you for contributing to Pycytominer! 🎉 💯

This document contains guidelines on how to most effectively contribute to the Pycytominer codebase.

If you are stuck, please feel free to ask any questions or ask for help.

Table of contents

Code of conduct

Quick links

How can I contribute?

Code Quality

Code of conduct

This project and everyone participating in it is governed by our code of conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to cytodata.info@gmail.com.

How can I contribute?

Roles and responsibilities

There are two primary roles with regards to developing Pycytominer:

  • Contributors: individuals without direct commit access to the main branch who make contributions in the form of communication, issues, or pull requests. We welcome anyone interested in additions to the project to be a contributor.

  • Maintainers: individuals with direct commit access who make contributions as outlined by the contributors role and also have the ability to make commits on the main branch through the development process (for example, by merging pull requests). Maintainers are also involved with decision-making procedures and the technical roadmap for Pycytominer.

Becoming a maintainer

Maintainers are prior contributors who receive extended privileges based on a decision by existing maintainers. To become a Pycytominer maintainer you must be championed by an existing maintainer. The championing maintainer consults with other maintainers about the addition of the new maintainer. After the current maintainers have considered the qualifications of the new maintainer they communicate their preferences internally. If there are no vetos the champion maintainer will grant maintainer access to the new maintainer.

Maintainer offboarding

Maintainer access may be removed under the following circumstances:

  • Voluntary step-down (when a maintainer no longer wishes to remain in that role)

  • In the unfortunate event of a maintainer’s passing

  • Code of conduct violations (in addition to other procedures specified by the code of conduct itself)

Bug reporting

We love hearing about use-cases when our software does not work. This provides us an opportunity to improve. However, in order for us to fix a bug, you need to tell us exactly what went wrong.

When you report a bug, please be prepared to tell us as much pertinent information as possible. This information includes:

  • The Pycytominer version you’re using

  • The format of input data

  • Copy and paste two pieces of information: 1) your command and 2) the specific error message

  • What you’ve tried to overcome the bug

Please provide this information as an issue in the repository: https://github.com/cytomining/pycytominer/issues

Please also search the issues (and documentation) for an existing solution. It’s possible we solved your bug already! If you find an issue already describing your bug, please add a comment to the issue instead of opening a new one.

Suggesting enhancements

We’re deeply committed to a simple, intuitive user experience, and to support core profiling pipeline data processing. This commitment requires a good relationship, and open communication, with our users.

We encourage you to propose enhancements to improve the Pycytominer package.

First, figure out if your proposal is already implemented, by reading the documentation! Next, check the issues (https://github.com/cytomining/pycytominer/issues) to see if someone else has already proposed the enhancement you have in mind. If you do find the suggestion, please comment on the existing issue noting that you are also interested in this functionality. If you do not find the suggestion, please open a new issue and clearly document the specific enhancement and why it would be helpful for your particular use case.

Please provide your enhancement suggestions as an issue in the repository:

Your first code contribution

Contributing code for the first time can be a daunting task. However, in our community, we strive to be as welcoming as possible to newcomers, while ensuring rigorous software development practices.

The first thing to figure out is exactly what you’re going to contribute! We have specifically tagged beginner issues, but we describe all future work as individual github issues.

If you want to contribute code that we haven’t already outlined, please start a discussion in a new issue before actually writing any code. A discussion will clarify the new code and reduce merge time. Plus, it’s possible that your contribution belongs in a different code base, and we do not want to waste your time (or ours)!

Pull requests

After you’ve decided to contribute code and have written it up, now it is time to file a pull request. We specifically follow a forked pull request model. Please create a fork of the Pycytominer repository, clone the fork, and then create a new, feature-specific branch. Once you make the necessary changes on this branch, you should file a pull request to incorporate your changes into the main Pycytominer repository.

The content and description of your pull request are directly related to the speed at which we are able to review, approve, and merge your contribution into Pycytominer. To ensure an efficient review process please perform the following steps:

  1. Follow all instructions in the pull request template

  2. Triple check that your pull request is only adding one specific feature. Small, bite-sized pull requests move so much faster than large pull requests.

  3. After submitting your pull request, ensure that your contribution passes all status checks (e.g. passes all tests)

All pull requests must be reviewed and approved by at least one project maintainer in order to be merged. We will do our best to review the code addition in a timely fashion. Ensuring that you follow all steps above will increase our speed and ability to review. We will check for accuracy, style, code coverage, and scope.

Documentation

We use Sphinx for documentation, with the following setup:

Building docs locally

First install the docs dependencies:

uv sync --all-extras --group docs

Then build the HTML output:

uv run sphinx-build ./docs/ ./docs/build

Open ./docs/build/index.html in your browser to preview the result.

Previewing docs on a pull request

Every pull request automatically triggers two complementary checks:

  • GitHub Actions (docs-build.yml): runs sphinx-build in CI to verify the docs compile without errors. The job must pass before a PR can be merged.

  • ReadTheDocs preview: once the PR is opened, ReadTheDocs builds and deploys a live preview of the docs for that branch. A bot posts a comment on the PR with a link like https://pycytominer--<PR-number>.org.readthedocs.build/. The preview is rebuilt automatically on every new commit pushed to the PR branch.

In short: the GitHub Action confirms the docs build, and ReadTheDocs confirms they deploy correctly.

API documentation

Pycytominer automatically pulls docstrings into the API reference via sphinx.ext.autodoc. Write docstrings in NumPy format and they will appear at cytomining.github.io/pycytominer/ under the API section after the next build.

See docs/conf.py for the full Sphinx configuration.

uv

We use uv to manage dependencies, virtual environments, and packaging. Changes in dependencies are managed through pyproject.toml and uv.lock. Run these commands from the repository root (the directory containing pyproject.toml). Run uv sync --all-extras --group dev --group docs to create the project’s virtual environment. Use uv run to execute commands in that environment without activating it manually. For example, to run the test suite, you can use uv run pytest.

Running tests

We use pytest to help organize, configure, and run tests for this project. We expect that all tests must pass in order for new contributions to be accepted into production code. pytest configuration may be found within the pyproject.toml file under tool.pytest.ini_options. We include the marker large_data_tests for tests which involve large amounts of data downloaded from the internet (these tests could take time). We recommend invoking pytest through the command: uv run pytest. You may temporarily deselect the large_data_tests marked tests during development using, for example: uv run pytest -m "not large_data_tests".

Dev environments

Local devcontainer

Instructions for setting up a local development environment using VSCode DevContainers:

  1. Install VSCode

  2. Install the Remote - Containers extension

  3. Open the repository in VSCode

  4. Click on the green “Reopen in Container” button in the lower left corner of the window

  5. Wait for the container to build and install the required dependencies

Cloud environment

We’ve set up cloud development configurations with Github Codespaces. These development environments include the project dependencies pre-installed via uv. Prior to commit, pre-installed git hooks auto-format any changed code. When you are ready to make a pull request, use the pre-configured test suite in VSCode or run uv run pytest to ensure that your changes pass all tests. You can create a codespace by clicking on the following link:

Open in GitHub Codespaces

Beginner’s Guide to Codespaces

Manual setup

We recommend using either the local devcontainer or cloud dev environment approaches above. However, we also provide general guidance for setting up a dev environment in Linux, MacOS, or Windows (WSL) below.

# Install uv (Linux, MacOS, Windows - WSL)
python -m pip install uv
# Checkout the repository
git clone https://github.com/cytomining/pycytominer.git
cd pycytominer
# Install pycytominer, dev dependencies, and pre-commit hooks
bash .devcontainer/postCreateCommand.sh

Releases

Project maintainers are responsible for releasing new versions of Pycytominer. We use Git tag-based dynamic versioning through the build backend to abide by PEP 440 for version specifications. Note: we use a slightly different specification for versioning our Docker image (please see the relevant section below). Creating a new release includes the following steps:

  1. Create a new branch from main for the release (e.g. release-v1.0.0)

  2. Review the commit history from the last release and check whether it includes commits that don’t follow the conventional commit standard. If all changes follow conventional commits, skip to step 5.

  3. Run the command uv run cz bump --files-only to update the version number in CITATION.cff and pyproject.toml:tool.commitizen and generate the draft changelog. If cz bump reports [NO_COMMITS_TO_BUMP] because commits don’t follow the conventional commit standard, pass --increment with the intended bump type instead: uv run cz bump --files-only --increment <PATCH|MINOR|MAJOR>.

  4. Review the changes to CHANGELOG.md. If necessary, add descriptions of missing changes and modify descriptions to match conventional commits standard.

  5. git add any manual changes and run uv run cz bump to create the release commit (or uv run cz bump --increment <PATCH|MINOR|MAJOR> if step 3 required --increment). Push the changes to the release branch.

  6. Create a pull request for the release branch into main.

  7. Request a review from another maintainer.

  8. Once the pull request is approved, merge it into main.

  9. Create a new release on GitHub using the release draft feature.

  10. Publish the release.

  11. The release will be automatically published to PyPI via Github Actions.

  12. Approve automatically generated release under conda-forge/pycytominer.

Docker Hub Image Releases

We automate image pushes for pycytominer under the cytomining organization on Docker Hub using GitHub Actions workflows. These pushes are defined within .github/workflows/integration-test.yml.

  • Scheduled: We create new Docker image releases on a weekly basis to incorporate the latest updates from external dependencies (such as OS updates, Python versions, etc.). An image tag published this way may appear as cytomining/pycytominer:1.1.0.post2.dev0_892dee2_240320, where the dynamic version of pycytominer is referenced alongside a date in the format YYMMDD.

  • Push (to main): We generate new Docker image releases on pushes or merges to the main branch. An image tag published this way might appear as either cytomining/pycytominer:1.1.0 (for a release) or cytomining/pycytominer:1.1.0.post2.dev0_892dee2 (for a non-release).

Code Quality

Please follow the below quality guides to the best of your abilities. If you have configured your dev environment as described above, the formatting and linting rules will also be enforced automatically using the installed pre-commit hooks.

Formatting

We use ruff for formatting Python code, and prettier for formatting markdown, json and yaml files. Ruff includes a python code formatter similar to Black. We include ruff in the dev dependency group so it can be run manually using uv run ruff format Prettier (which is not python-based) is not included in the project dependency groups, but can be installed and run manually. Alternately, both ruff format and prettier will be run automatically at commit time with the pre-commit hooks installed.

Linting

For python code linting, we also use ruff, which can perform same linting checks as Flake8. You can use the command ruff check to check for linting errors. The list of linting rules and exceptions are defined in the pyproject.toml file under the [tool.ruff.lint] section. We also include some commented-out rules in that section that we are working towards enabling in the future. All linting checks will also be run automatically at commit time with the pre-commit hooks as described above.

Git commit messages

Pycytominer uses Conventional Commits standard for commit messages to aid in automatic changelog generation. We prepare commit messages that follow this standard using commitizen, which comes with the dev dependency group.