Contributing Guide
We welcome contributions to MarrmotFlow! This guide will help you get started with contributing to the project.
Types of Contributions
We welcome several types of contributions:
Bug reports: Help us identify and fix issues
Feature requests: Suggest new functionality
Code contributions: Implement bug fixes or new features
Documentation improvements: Enhance or expand documentation
Examples: Add new usage examples
Testing: Improve test coverage
Getting Started
Development Setup
Fork the repository on GitHub
Clone your fork locally:
git clone https://github.com/your-username/marrmotflow.git
cd marrmotflow
Create a virtual environment:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
Install in development mode:
pip install -e ".[dev]"
Install pre-commit hooks:
pre-commit install
Development Workflow
Create a new branch for your changes:
git checkout -b feature/your-feature-name
# or
git checkout -b fix/your-bug-fix
Make your changes following the coding standards below
Run tests to ensure everything works:
pytest
Run code quality checks:
black src/ tests/
flake8 src/ tests/
mypy src/
Commit your changes:
git add .
git commit -m "Add feature: description of your changes"
Push to your fork:
git push origin feature/your-feature-name
Create a Pull Request on GitHub
Coding Standards
Code Style
We use several tools to maintain code quality:
Black: Code formatting
Flake8: Linting
MyPy: Type checking
Pre-commit: Automated checks
Configuration files are included in the repository:
.pre-commit-config.yamlpyproject.toml(Black and pytest configuration)setup.cfg(Flake8 and MyPy configuration)
Python Style Guidelines
Follow these guidelines when writing code:
# Use descriptive variable names
catchment_boundaries = gpd.read_file("catchments.shp") # Good
gdf = gpd.read_file("catchments.shp") # Avoid
# Add type hints
def process_forcing_data(
forcing_file: PathLike,
variables: Dict[str, str]
) -> xr.Dataset:
"""Process forcing data from file."""
pass
# Use docstrings for all public functions
def calculate_pet(
temperature: np.ndarray,
method: str = "penman_monteith"
) -> np.ndarray:
"""
Calculate potential evapotranspiration.
Parameters
----------
temperature : np.ndarray
Daily temperature values in Celsius
method : str, optional
PET calculation method, by default "penman_monteith"
Returns
-------
np.ndarray
Daily PET values in mm/day
"""
pass
Documentation Style
Use NumPy-style docstrings:
def example_function(param1: str, param2: int = 10) -> bool:
"""
Brief description of the function.
Longer description if needed, explaining the purpose
and usage of the function.
Parameters
----------
param1 : str
Description of param1
param2 : int, optional
Description of param2, by default 10
Returns
-------
bool
Description of return value
Raises
------
ValueError
Description of when this exception is raised
Examples
--------
>>> result = example_function("test", 5)
>>> print(result)
True
"""
return True
Testing Guidelines
Test Structure
Tests are located in the tests/ directory and follow this structure:
tests/
├── __init__.py
├── test_core.py
├── test_templating.py
├── test_default_dicts.py
└── data/
├── test_catchments.shp
└── test_climate.nc
Writing Tests
Use pytest for testing:
import pytest
import numpy as np
from marrmotflow import MARRMOTWorkflow
def test_workflow_creation():
"""Test basic workflow creation."""
workflow = MARRMOTWorkflow(
name="TestWorkflow",
cat="tests/data/test_catchments.shp",
forcing_files="tests/data/test_climate.nc",
forcing_vars={"precip": "precipitation", "temp": "temperature"}
)
assert workflow.name == "TestWorkflow"
assert workflow.model_number == [7, 37] # Default models
def test_invalid_model_number():
"""Test that invalid model numbers raise appropriate errors."""
with pytest.raises(ValueError, match="Unsupported model number"):
MARRMOTWorkflow(
name="TestWorkflow",
cat="tests/data/test_catchments.shp",
forcing_files="tests/data/test_climate.nc",
forcing_vars={"precip": "precipitation", "temp": "temperature"},
model_number=999 # Invalid model number
)
@pytest.fixture
def sample_workflow():
"""Fixture providing a sample workflow for testing."""
return MARRMOTWorkflow(
name="SampleWorkflow",
cat="tests/data/test_catchments.shp",
forcing_files="tests/data/test_climate.nc",
forcing_vars={"precip": "precipitation", "temp": "temperature"}
)
def test_workflow_with_fixture(sample_workflow):
"""Test using a pytest fixture."""
assert sample_workflow.name == "SampleWorkflow"
Running Tests
Run tests with different options:
# Run all tests
pytest
# Run with coverage
pytest --cov=marrmotflow
# Run specific test file
pytest tests/test_core.py
# Run specific test
pytest tests/test_core.py::test_workflow_creation
# Run with verbose output
pytest -v
Documentation Contributions
Building Documentation
The documentation is built using Sphinx:
cd docs/
make html
The built documentation will be in docs/_build/html/.
Documentation Standards
When writing documentation:
Use clear, concise language
Include code examples for complex concepts
Test all code examples to ensure they work
Use proper reStructuredText formatting
Link to related sections when appropriate
Adding Examples
When adding new examples:
Create a new
.rstfile indocs/examples/Follow the existing example structure
Include complete, runnable code
Add the example to
docs/examples/index.rstTest the example thoroughly
Pull Request Process
Before Submitting
Ensure your pull request:
Passes all tests:
pytestFollows code style:
black,flake8,mypyIncludes appropriate tests for new functionality
Updates documentation if needed
Has a clear commit message
Pull Request Template
Use this template for your pull request description:
## Description
Brief description of the changes made.
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation update
- [ ] Code refactoring
- [ ] Other (please describe)
## Testing
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I have run the code quality checks (black, flake8, mypy)
## Documentation
- [ ] I have updated the documentation accordingly
- [ ] I have added docstrings to new functions/classes
## Additional Notes
Any additional information about the implementation or considerations.
Review Process
After submitting your pull request:
Automated checks will run (tests, code quality)
Maintainers will review your code
Address feedback by making additional commits
Final approval and merge by maintainers
Issue Reporting
Bug Reports
When reporting bugs, please include:
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Environment:**
- OS: [e.g. macOS 12.0]
- Python version: [e.g. 3.9.7]
- MarrmotFlow version: [e.g. 0.1.0]
- Relevant package versions: [e.g. pandas 1.3.0]
**Additional context**
Add any other context about the problem here.
Feature Requests
When requesting features:
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is.
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
Communication
GitHub Issues: For bug reports and feature requests
GitHub Discussions: For questions and general discussion
Pull Requests: For code contributions
Code of Conduct
By participating in this project, you agree to abide by our Code of Conduct:
Be respectful and inclusive
Be collaborative
Be patient with newcomers
Give constructive feedback
Focus on what is best for the community
Recognition
All contributors will be recognized in:
CONTRIBUTORS.md file
Release notes for significant contributions
Documentation for major feature additions
Thank you for contributing to MarrmotFlow!