Contributing Guide
Contributions are welcome and greatly appreciated! Every little bit helps, and credit will always be given.
Types of Contributions
PCMDI Metrics Package (PMP) includes issue templates based on the contribution type: https://github.com/PCMDI/pcmdi_metrics/issues/new/choose. Note, new contributions must be made under the BSD-3-Clause license.
Bug Report
Look through the GitHub Issues for bugs to fix. Any unassigned issues tagged with “Type: Bug” is open for implementation.
Feature Request
Look through the GitHub Issues for feature suggestions. Any unassigned issues tagged with “Type: Enhancement” is open for implementation.
If you are proposing a feature:
Explain in detail how it would work.
Keep the scope as narrow as possible, to make it easier to implement.
Remember that this is a open-source project, and that contributions are welcome :)
Documentation Update
Help improve PMP’s documentation, whether that be the Sphinx documentation or the API docstrings.
Community Discussion
Take a look at the GitHub Discussions page to get involved, share ideas, or ask questions.
Contributing metrics
Developers working on new metrics to contribute to the PMP are highly encouraged to explore the PMP source code and examine how existing metrics are structured. Metrics are grouped into subpackages by topic; for example, the Mean Climate metrics, MJO metrics, and Extremes metrics are different subpackages.
In general each subpackage contains a driver script, additional library code needed to run the driver script, and example parameter files. Each subpackage must output a JSON file containing metrics and may also produce figures or other data files. New contributions may expand existing metrics subpackages or add a new subpackage.
Steps to contributing new metrics:
Open a Feature Request describing the planned metrics.
Follow the instructions in Get Started and Pull Request Guidelines (below) while working on code.
Update the GitHub.io documentation as needed.
Please keep in mind that:
It is never too early to open a Feature Request or contact the PMP team with your idea.
All metrics code must be in Python, and it is the responsibility of the contributor to deliver Python code. The PMP team has limited bandwidth to assist with code conversion to Python.
Current PMP dependencies can be found in dev.yml file. Dependencies cannot be added without the approval of the PMP team.
Input data sets are expected to follow the CF Metadata Conventions (e.g. CMIP, obs4mips).
Providing unit tests is highly encouraged.
Quick links to useful code sections:
See pcmdi_metrics/io and pcmdi_metrics/utils to find functions for tasks like land masking, grid subsetting, and more.
Graphics code for post-processing metrics is found in pcmdi_metrics/graphics
Version Control
The repository uses branch-based (core team) and fork-based (external collaborators) Git workflows with tagged software releases.
Guidelines
main
must always be deployableAll changes are made through support branches
Branch names should follow the pattern “issuenumber_initials_description”
Rebase with the latest
main
to avoid/resolve conflictsMake sure pre-commit quality assurance checks pass when committing (enforced in CI/CD build)
Open a pull request early for discussion
Once the CI/CD build passes and pull request is approved, squash and rebase your commits
Merge pull request into
main
and delete the branch
Things to Avoid
Don’t merge in broken or commented out code
Don’t commit directly to
main
There are branch-protection rules for
main
Don’t merge with conflicts. Instead, handle conflicts upon rebasing
Pre-commit
The repository uses the pre-commit package to manage pre-commit hooks. These hooks help with quality assurance standards by identifying simple issues at the commit level before submitting code reviews.
Get Started
Ready to contribute? Here’s how to set up PMP for local development.
VS Code, the editor of choice
We recommend using VS Code as your IDE because it is open-source and has great Python development support.
Get VS Code here: https://code.visualstudio.com
VS Code Setup
PMP includes a VS Code workspace file (.vscode/pcmdi_metrics.code-setting
). This file automatically configures your IDE with the quality assurance tools, code line-length rulers, and more.
Make sure to follow the Local Development section below.
Recommended VS Code Extensions
Local Development
Download and install Conda
- Linux
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh $ bash ./Miniconda3-latest-Linux-x86_64.sh Do you wish the installer to initialize Miniconda3 by running conda init? [yes|no] yes
- MacOS
$ wget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh $ bash ./Miniconda3-latest-MacOSX-x86_64.sh Do you wish the installer to initialize Miniconda3 by running conda init? [yes|no] yes
Fork the
pcmdi_metrics
repo on GitHub.If you are a maintainer, you can clone and branch directly from the root repository here: https://github.com/PCMDI/pcmdi_metrics
Clone your fork locally:
$ git clone git@github.com:your_name_here/pcmdi_metrics.git
<OPTIONAL> Open
.vscode/pcmdi_metrics.code-settings
in VS CodeCreate and activate Conda development environment:
$ cd pcmdi_metrics $ conda env create -f conda-env/dev.yml $ conda activate pcmdi_metrics_dev
<OPTIONAL> Set VS Code Python interpretor to
pcmdi_metrics_dev
Install pre-commit:
$ pre-commit install pre-commit installed at .git/hooks/pre-commit
Create a branch for local development and make changes:
$ git checkout -b <BRANCH-NAME>
<OPTIONAL> During or after making changes, check for formatting or linting issues using pre-commit:
# Step 9 performs this automatically on staged files in a commit $ pre-commit run --all-files Trim Trailing Whitespace.................................................Passed Fix End of Files.........................................................Passed Check Yaml...............................................................Passed black....................................................................Passed isort....................................................................Passed flake8...................................................................Passed
Commit your changes:
$ git add . $ git commit -m <Your detailed description of your changes> Trim Trailing Whitespace.................................................Passed Fix End of Files.........................................................Passed Check Yaml...............................................................Passed black....................................................................Passed isort....................................................................Passed flake8...................................................................Passed
Make sure pre-commit QA checks pass. Otherwise, fix any caught issues.
Most of the tools fix issues automatically so you just need to re-stage the files.
flake8 and mypy issues must be fixed automatically.
Push changes:
$ git push origin <BRANCH-NAME>
Submit a pull request through the GitHub website.
Pull Request Guidelines
Before you submit a pull request, check that it meets these guidelines:
The pull request should include tests for new or modified code.
Link issues to pull requests.
If the pull request adds functionality, the docs should be updated.
Squash and rebase commits for a clean and navigable Git history.
Style Guide
PMP integrates the Black code formatter for code styling. If you want to learn more, please read about it here.
PMP also leverages Python Type Annotations to help the project scale. mypy performs optional static type checking through pre-commit.
Testing
Testing your local changes are important to ensure long-term maintainability and extensibility of the project. Since PMP is an open source library, we aim to avoid as many bugs as possible from reaching the end-user.
To get started, here are guides on how to write tests using pytest:
In most cases, if a function is hard to test, it is usually a symptom of being too complex (high cyclomatic-complexity).
DOs for Testing
DO write tests for new or refactored code
DO try to follow test-driven-development
DO use the Coverage reports to see lines of code that need to be tested
DO focus on simplistic, small, reusable modules for unit testing
DO cover as many edge cases as possible when testing
DON’Ts for Testing
DON’T push or merge untested code
DON’T introduce tests that fail or produce warnings
Documenting Code
If you are using VS code, the Python Docstring Generator extension can be used to auto-generate a docstring snippet once a function/class has been written.
If you want the extension to generate docstrings in Sphinx format, you must set the "autoDocstring.docstringFormat": "sphinx"
setting, under File > Preferences > Settings.
Note that it is best to write the docstrings once you have fully defined the function/class, as then the extension will generate the full docstring. If you make any changes to the code once a docstring is generated, you will have to manually go and update the affected docstrings.
More info on docstrings here: https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html
DOs for Documenting Code
DO explain why something is done, its purpose, and its goal. The code shows how it is done, so commenting on this can be redundant.
DO explain ambiguity or complexities to avoid confusion
DO embrace documentation as an integral part of the overall development process
DO treat documenting as code and follow principles such as Don’t Repeat Yourself and Easier to Change
DON’Ts for Documenting Code
DON’T write comments as a crutch for poor code
DON’T comment every function, data structure, type declaration
Developer Tips
flake8 will warn you if the cyclomatic complexity of a function is too high.
FAQs
Why squash and rebase commits?
Before you merge a support branch back into main
, the branch is typically squashed down to a single buildable commit, and then rebased on top of the main repo’s main
branch.
Why?
Ensures build passes from the commit
Cleans up Git history for easy navigation
Makes collaboration and review process more efficient
Makes handling conflicts from rebasing simple since you only have to deal with conflicted commits
How do I squash and rebase commits?
Use GitHub’s Squash and Merge feature in the pull request
You still need to rebase on the latest
main
ifmain
is ahead of your branch.
Manually squash and rebase
<OPTIONAL if you are forking> Sync your fork of
main
(akaorigin
) with the rootmain
(akaupstream
)git checkout main git rebase upstream/main git push -f origin main
Get the SHA of the commit OR number of commits to rebase to
git checkout <branch-name> git log --graph --decorate --pretty=oneline --abbrev-commit
Squash commits:
git rebase -i [SHA] # OR git rebase -i HEAD~[NUMBER OF COMMITS]
Rebase branch onto
main
git rebase main git push -f origin <BRANCH-NAME>
Make sure your squashed commit messages are refined
Force push to remote branch
git push -f origin <BRANCH-NAME>