Contributing
We welcome contributions to Odecast! This guide will help you get started.
Development Setup
First, fork the repository on GitHub and clone your fork:
git clone https://github.com/yourusername/odecast.git
cd odecast
Create a virtual environment and install development dependencies:
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -e ".[dev]"
This installs Odecast in editable mode with all development tools.
Code Quality
We maintain high code quality standards using several tools:
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=odecast
# Run specific test file
pytest tests/test_api.py
# Run with verbose output
pytest -v
Code Formatting
We use Black for code formatting:
# Format all code
black .
# Check formatting without making changes
black --check .
Linting
We use Ruff for fast linting:
# Lint all code
ruff check .
# Fix auto-fixable issues
ruff check --fix .
Type Checking
We use mypy for static type checking:
mypy src/odecast
Pre-commit Hooks
Install pre-commit hooks to automatically run checks:
pre-commit install
# Run hooks manually
pre-commit run --all-files
Testing Guidelines
Test-Driven Development
Odecast follows a test-driven development approach. All functionality should be defined by comprehensive tests before implementation.
Writing Tests
Place tests in the
tests/directoryUse descriptive test names:
test_solve_second_order_with_initial_conditionsTest both success and failure cases
Include edge cases and boundary conditions
Use pytest fixtures for common setup
Example test structure:
import pytest
from odecast import var, Eq, solve
from odecast.errors import ODEValidationError
def test_simple_harmonic_oscillator():
"""Test solving y'' + y = 0 with initial conditions."""
y = var("y")
eq = Eq(y.d(2) + y, 0)
sol = solve(eq, ivp={y: 1, y.d(): 0}, tspan=(0, 1))
assert sol is not None
assert len(sol.t) > 0
assert len(sol[y]) == len(sol.t)
def test_missing_initial_condition_raises_error():
"""Test that missing initial conditions raise validation errors."""
y = var("y")
eq = Eq(y.d(2) + y, 0)
with pytest.raises(ODEValidationError):
solve(eq, ivp={y: 1}, tspan=(0, 1)) # Missing y.d()
Documentation
Code Documentation
Use Google-style docstrings for all public functions and classes
Include parameter types and descriptions
Provide usage examples in docstrings
Document return values and exceptions
Example docstring:
def solve(equations, ivp=None, bvp=None, tspan=None, backend="auto"):
"""Solve a system of ordinary differential equations.
Args:
equations: Single equation or list of equations to solve.
ivp: Initial value conditions as a dictionary.
bvp: Boundary value conditions as a dictionary.
tspan: Time span as a tuple (t_start, t_end).
backend: Solver backend ("scipy", "sympy", or "auto").
Returns:
Solution: Object containing the solution data.
Raises:
ODEValidationError: If initial/boundary conditions are invalid.
ValueError: If equation system is malformed.
Example:
>>> y = var("y")
>>> eq = Eq(y.d(2) + y, 0)
>>> sol = solve(eq, ivp={y: 1, y.d(): 0}, tspan=(0, 10))
"""
Sphinx Documentation
Update relevant .rst files when adding new features
Include examples in the documentation
Build docs locally to test changes:
cd docs
make html
open _build/html/index.html
Contribution Workflow
Create an Issue: Discuss your idea or bug report in a GitHub issue
Fork and Branch: Create a feature branch from main
Implement: Write code following our guidelines
Test: Ensure all tests pass and add new tests for your changes
Document: Update documentation if needed
Submit PR: Create a pull request with a clear description
Pull Request Guidelines
Use descriptive commit messages
Keep changes focused and atomic
Update CHANGELOG.md if applicable
Ensure all CI checks pass
Request review from maintainers
Commit Message Format
Use conventional commit format:
type(scope): description
body (optional)
footer (optional)
Types: feat, fix, docs, test, refactor, perf, ci
Examples:
feat(api): add support for boundary value problems
fix(solve): handle edge case in vector validation
docs: update installation instructions
test: add comprehensive tests for symbolic backend
Types of Contributions
Bug Reports
When reporting bugs, please include:
Clear description of the problem
Minimal reproducible example
Expected vs. actual behavior
Environment details (Python version, OS, package versions)
Feature Requests
For new features, provide:
Clear use case and motivation
Proposed API design
Examples of intended usage
Discussion of alternatives considered
Code Contributions
Areas where contributions are especially welcome:
New example applications
Performance improvements
Additional solver backends
Enhanced error messages
Documentation improvements
Examples and Tutorials
We particularly welcome:
Real-world application examples
Jupyter notebook tutorials
Domain-specific use cases
Performance comparisons
Community Guidelines
Be respectful and inclusive
Help others learn and contribute
Provide constructive feedback
Follow the project’s coding standards
Credit others for their contributions
Getting Help
GitHub Issues: Bug reports and feature requests
GitHub Discussions: General questions and community chat
Documentation: Read the docs for detailed guidance
Recognition
Contributors are recognized in:
CONTRIBUTORS.md file
Release notes for significant contributions
GitHub contributor statistics
Thank you for helping make Odecast better!