Contributing

We welcome feedback and contributions, including suggestions for new features, bug reports, and code contributions. To share feedback, you can:

If you would like to contribute code, then please read the developer guide below.

Code of Conduct

All contributions to - and interactions surrounding- this project should abide by the USGS code of conduct.

Developer Guide

Git Workflow

You should use a forking workflow to develop ocelote. In brief, you should make a fork of the official repository, and then create merge requests from the fork to the main branch of the official repository. These requests will then be reviewed before merging. We recommend not developing on the main branch of the fork, as this can help prevent merge conflicts. Instead, develop and merge your code from a development branch, and use the main branch to sync your fork with the upstream repository.

Developer Installation

Prerequisites

Ocelote requires Python 3.11 or 3.12, and these instructions also require git.

We recommend using poetry to install ocelote. This will provide various command line scripts useful for developing the project.

You can install poetry using:

pip install poetry

and read also the poetry documentation for alternative installation instructions.

Next, clone your fork of the project and navigate to the cloned repository. Then, use:

poetry install --all-groups

which will install ocelote and various development libraries.

pyproject.toml

The pyproject.toml file is the foundation for most developer tasks. The file defines project metadata, package dependencies, and command line scripts useful for developing the project. Refer to the poetry spec for details on the layout of this file. Developer scripts are implemented using the poethepoet interface, and are defined at the end of pyproject.toml.

Package Dependencies

As an operational product, ocelote’s dependencies should be strictly pinned to the dependency versions used to test the package. If you think a sub-dependency might break, then consider pinning the sub-dependency as well. If you want to update the dependency versions, then you should run:

poe update

and re-run the tests. If the tests pass, then determine the new dependency versions using a tool like pip list, and pin the new version numbers in pyproject.toml.

You can test the package dependencies for security vulnerabilities using:

poe audit

which relies on the pip-audit package.

Formatting

This project uses isort and black to format the code. You can apply these formatters using:

poe format

This should format the code within the ocelote and tests directories. We also note that many IDEs include tools to automatically apply these formats.

You can also use:

poe lint

to verify that all code is formatted correctly. The Gitlab pipeline requires that this check passes before code can be merged.

Testing

This project uses the pytest framework to implement tests. Before adding new code, the Gitlab pipeline requires:

  1. All tests passing, and

  2. 100% test coverage

So as a rule, all new code should include accompanying tests. The tests should follow a parallel structure to the ocelote package, and the tests for a given module should be named test_<module>.py or test_<folder>_<module>.py in the case of duplicate module names.

Within a test module, multiple tests for the same function should be grouped into a class. Test class names should use capitalized camel-case. Underscores are discouraged, except when needed to distinguish between public and private routines with the same name. Individual tests should be named using standard Python snakecase (lowercase separated by underscores).

You can check the status of the tests using:

poe tests

and you can open an HTML coverage report in a web browser using:

poe htmlcov

Note that several tests make live web requests (usually to download data). These tests are marked with the web mark, and are disabled by default. You can use:

poe webtests

to run only these tests.

Documentation

The documentation is built using sphinx with the furo theme. The content is written in reStructuredText Markup (reST). You can find a nice introduction to reST in the sphinx documentation, and the full documentation is here: reST Specification.

The docs use the sphinx_design extension to enable dropdowns and tabbed panels within the content. The final website is deployed using Gitlab Pages via a manual job in the Gitlab pipeline. You must trigger this job manually to deploy new docs.

You can build the docs locally using:

poe docs

This will create the documentation HTML pages within the public folder of the repository. You can open these docs in a browser using:

poe open-docs

Important

The path to the data spec archive is recorded by data spec DOIs. As such, the path to the archive should never change. Note that the poe docs command includes a check to verify that this is the case.

Gitlab Pipeline

The .gitlab-ci.yml file defines the Gitlab pipeline. This pipeline runs various tasks whenever code is pushed, merged, or tagged. In general, the pipeline requires that:

  • Code dependencies do not have security vulnerabilities,

  • All code is formatted correctly, and

  • The tests pass with 100% coverage

The pipeline also includes a job to update the published documentation, which must be triggered manually.

Finally, the pipeline includes a job that will publish ocelote to the USGS package registry whenever a new release is tagged.

Developer Scripts

Development scripts are available via the poethepoet interface, and are defined at the end of the pyproject.toml file.

The following table provides a complete list of available scripts:

Script Name

Description

audit

Checks dependencies for security vulnerabilities

update

Rebuilds the package from the latest dependencies and updates poetry.lock

format

Applies formatters to wildcat and tests

lint

Checks that wildcat and tests are formatted correctly

tests

Runs tests and requires 100% coverage

webtests

Runs tests that make live web requests

coverage

Prints a testing coverage report.

htmlcov

Builds an HTML coverage report and opens in a browser.

docs

Rebuilds the docs locally

open-docs

Opens locally built docs in a web browser