Thank you for your interest in contributing to canns-lib! This document provides guidelines and instructions for contributing to the project.
- Code of Conduct
- Getting Started
- Development Environment Setup
- How to Contribute
- Code Style Guidelines
- Testing
- Pull Request Process
- Community
We are committed to providing a welcoming and inclusive environment for all contributors. By participating in this project, you agree to:
- Be respectful and considerate in your interactions
- Welcome newcomers and help them get started
- Accept constructive criticism gracefully
- Focus on what is best for the community
- Show empathy towards other community members
canns-lib is a high-performance computational library for CANNs (Continuous Attractor Neural Networks), written in Rust with Python bindings via PyO3. The project includes:
- Ripser module: Topological data analysis backend
- Spatial module: Spatial navigation and RatInABox-inspired functionality
- Future modules: Planned expansions for dynamics, approximate nearest neighbors, etc.
- Python: 3.9 or higher
- Rust: Latest stable version (install via rustup)
- Maturin: For building Python extensions (
pip install maturin) - Git: For version control
# Fork the repository on GitHub, then clone your fork
git clone https://github.com/YOUR-USERNAME/canns-lib.git
cd canns-lib
# Add upstream remote
git remote add upstream https://github.com/Routhleck/canns-lib.git# Create and activate a virtual environment
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate# Install the package in editable mode with dev dependencies
pip install -e .
pip install pytest black ruff mypy# Debug build (faster compilation, for development)
maturin develop
# Release build (optimized, for testing performance)
maturin develop --release
# Disable default features if needed
maturin develop --release --no-default-features# Run tests to verify everything works
pytest tests -v
# Check Rust code
cargo check
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warningsBefore creating a bug report, please:
- Check existing issues to avoid duplicates
- Use the latest version to ensure the bug hasn't been fixed
- Collect information:
- Operating system and version
- Python and Rust versions
- Full error message and stack trace
- Minimal code to reproduce the issue
Create an issue with:
- Clear, descriptive title
- Detailed description of the problem
- Steps to reproduce
- Expected vs actual behavior
- Any relevant logs or screenshots
Enhancement suggestions are welcome! Please:
- Check existing issues for similar suggestions
- Describe the use case and motivation
- Provide examples of how the feature would be used
- Consider alternatives you've explored
We welcome code contributions! Here's how:
- Find or create an issue describing what you plan to work on
- Discuss your approach in the issue before starting large changes
- Follow the code style guidelines (see below)
- Write tests for new functionality
- Update documentation as needed
- Submit a pull request (see PR process below)
Documentation improvements are highly valued:
- Fix typos or unclear explanations
- Add examples and tutorials
- Improve API documentation
- Translate documentation (if applicable)
-
Formatter: Use
blackfor code formattingblack python/ tests/
-
Linter: Use
rufffor lintingruff check python/ tests/
-
Type hints: Add type hints for public APIs
mypy python/
-
Naming conventions:
- Functions and variables:
snake_case - Classes:
PascalCase - Constants:
UPPER_CASE
- Functions and variables:
-
Formatter: Use
rustfmtcargo fmt --all
-
Linter: Use
clippycargo clippy --all-targets --all-features -- -D warnings
-
Naming conventions:
- Follow Rust API Guidelines
- Functions and variables:
snake_case - Types and traits:
PascalCase - Constants:
UPPER_CASE
-
Documentation:
- Add doc comments (
///) for public APIs - Include examples in doc comments when helpful
- Add doc comments (
Follow Conventional Commits format:
<type>(<scope>): <description>
[optional body]
[optional footer]
Types:
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, etc.)refactor: Code refactoringtest: Adding or updating testschore: Maintenance tasksperf: Performance improvements
Examples:
feat(ripser): add support for sparse distance matrices
fix(spatial): correct wall collision detection in polygonal environments
docs: add examples for drift_velocity usage
test(ripser): add regression tests for cocycles
# Run all Python tests
pytest tests -v
# Run specific test file
pytest tests/test_ripser.py -v
# Run with coverage
pytest tests --cov=canns_lib --cov-report=html
# Run Rust tests
cargo test --release-
Python tests: Use
pytestframework- Place tests in
tests/directory - Name test files
test_*.py - Use descriptive test names:
test_<feature>_<scenario>
- Place tests in
-
Rust tests: Use built-in test framework
- Unit tests: Add
#[cfg(test)]module in source files - Integration tests: Place in
tests/directory - Use
assert_eq!,assert!for assertions
- Unit tests: Add
-
Test coverage: Aim for >80% coverage for new code
-
Edge cases: Test boundary conditions and error cases
-
Regression tests: Add tests for fixed bugs
If your change affects performance:
# Run benchmarks
python benchmarks/compare_ripser.py --n-points 100 --maxdim 2 --trials 5
# Compare before and after your changes-
Update your fork:
git fetch upstream git rebase upstream/master
-
Run all checks:
# Python black python/ tests/ ruff check python/ tests/ pytest tests -v # Rust cargo fmt --all cargo clippy --all-targets --all-features cargo test --release
-
Update documentation:
- Update README.md if adding features
- Add docstrings for new functions/classes
- Update CLAUDE.md if changing architecture
-
Push to your fork:
git push origin your-branch-name
-
Create PR on GitHub:
- Use a clear, descriptive title
- Reference related issues (e.g., "Fixes #123")
- Describe what changed and why
- Include examples of usage if applicable
- Add screenshots for UI changes
- List any breaking changes
-
PR description template:
## Summary Brief description of the changes ## Motivation Why is this change needed? What problem does it solve? ## Changes - List of specific changes made ## Testing - [ ] Added/updated tests - [ ] All tests pass - [ ] Benchmarks run (if performance-related) ## Documentation - [ ] Updated docstrings - [ ] Updated README if needed - [ ] Updated examples if needed ## Related Issues Closes #XXX
- Automated checks: CI will run tests and linters
- Code review: Maintainers will review your code
- Address feedback: Make requested changes
- Approval: Once approved, maintainers will merge
-
Delete your branch:
git branch -d your-branch-name git push origin --delete your-branch-name
-
Update your fork:
git checkout master git pull upstream master git push origin master
# Build wheels for multiple platforms (requires Docker)
maturin build --release --strip --out dist
# Build for specific Python version
maturin build --release --interpreter python3.11# Build with debug symbols
maturin develop
# Use rust-gdb or rust-lldb for debugging
rust-gdb --args python -c "import canns_lib; canns_lib.ripser(...)"# Python profiling
python -m cProfile -o profile.stats your_script.py
python -m pstats profile.stats
# Rust profiling (with perf on Linux)
cargo build --release
perf record --call-graph=dwarf ./target/release/your_binary
perf reportThe codebase is organized as:
canns-lib/
├── src/
│ ├── lib.rs # Main PyO3 module registration
│ ├── ripser/ # Ripser module implementation
│ └── spatial/ # Spatial module implementation
├── python/canns_lib/
│ ├── __init__.py # Python package entry point
│ ├── ripser/ # Ripser Python wrapper
│ └── spatial/ # Spatial Python wrapper
├── tests/ # Python tests
└── benchmarks/ # Performance benchmarks
- GitHub Issues: For bug reports and feature requests
- Discussions: For questions and general discussion
- Email: Contact maintainers directly for sensitive issues
Contributors are recognized in:
- GitHub contributors page
- Release notes
- Project README (for significant contributions)
By contributing, you agree that your contributions will be licensed under the Apache 2.0 License.
Thank you for contributing to canns-lib! Your efforts help make computational neuroscience more accessible and performant for everyone.