Contributing to EPyR Tools
We welcome contributions to EPyR Tools! This document provides guidelines for contributing code, documentation, and reporting issues.
Getting Started
Setting up Development Environment
Fork and Clone
git clone https://github.com/yourusername/epyrtools.git
cd epyrtools
Install Development Dependencies
pip install -e .[dev]
# Or install all optional dependencies
pip install -e .[all]
Set up Pre-commit Hooks
pre-commit install
This ensures code formatting and quality checks run automatically.
Development Workflow
Create a Feature Branch
git checkout -b feature/your-feature-name
Make Changes
Write code following project conventions
Add tests for new functionality
Update documentation as needed
Test Your Changes
# Run tests
pytest
# Check code formatting
black --check .
isort --check-only .
flake8
Commit and Push
git add .
git commit -m "Add feature: description"
git push origin feature/your-feature-name
Create Pull Request
Describe your changes clearly
Reference any related issues
Ensure all CI checks pass
Code Standards
Style Guidelines
We follow PEP 8 with some specific conventions:
Line Length: Maximum 88 characters (Black default)
Imports: Organized with isort
Formatting: Automatic with Black
Linting: flake8 for code quality
Example:
"""Module for EPR data processing."""
import numpy as np
from pathlib import Path
from typing import Tuple, Optional, List
from epyr.physics import PLANCK, BMAGN
def process_epr_data(
x_data: np.ndarray,
y_data: np.ndarray,
correction_order: int = 1
) -> Tuple[np.ndarray, np.ndarray]:
"""Process EPR data with baseline correction.
Args:
x_data: Field values in Gauss
y_data: EPR signal intensity
correction_order: Polynomial order for baseline
Returns:
Tuple of (corrected_data, baseline)
Raises:
ValueError: If data arrays have different lengths
"""
if len(x_data) != len(y_data):
raise ValueError("Data arrays must have same length")
# Implementation here
return corrected_data, baseline
Documentation
Docstrings: Use Google/NumPy style
Type Hints: Add for all public functions
Examples: Include usage examples in docstrings
Comments: Explain complex algorithms and physics
Testing
Test Structure
Tests are organized in the tests/ directory:
tests/
├── conftest.py # Pytest configuration
├── test_eprload.py # Data loading tests
├── test_baseline.py # Baseline correction tests
├── test_fair.py # FAIR conversion tests
└── data/ # Test data files
├── sample.dsc
└── sample.dta
Writing Tests
Use pytest for all tests:
import pytest
import numpy as np
from epyr.baseline import baseline_polynomial
class TestBaselineCorrection:
"""Test baseline correction functionality."""
def test_polynomial_correction(self):
"""Test polynomial baseline correction."""
# Create test data with known baseline
x = np.linspace(0, 100, 1000)
true_signal = np.exp(-((x - 50)**2) / 100)
true_baseline = 0.1 * x + 5
noisy_data = true_signal + true_baseline + np.random.normal(0, 0.01, 1000)
# Apply correction
corrected, fitted_baseline = baseline_polynomial(
noisy_data, x_data=x, poly_order=1
)
# Check results
np.testing.assert_allclose(fitted_baseline, true_baseline, rtol=0.1)
np.testing.assert_allclose(corrected, true_signal, atol=0.1)
@pytest.mark.parametrize("order", [0, 1, 2, 3])
def test_different_orders(self, order):
"""Test different polynomial orders."""
x = np.linspace(0, 100, 500)
y = np.ones_like(x) + 0.01 * np.random.randn(len(x))
corrected, baseline = baseline_polynomial(y, x_data=x, poly_order=order)
assert len(corrected) == len(y)
assert len(baseline) == len(y)
Running Tests
# Run all tests
pytest
# Run specific test file
pytest tests/test_baseline.py
# Run with coverage
pytest --cov=epyr
# Run tests for specific function
pytest -k "test_polynomial"
Documentation Contributions
Types of Documentation
API Documentation: Automatically generated from docstrings
User Guides: Tutorial and how-to content
Examples: Jupyter notebooks and scripts
Reference: Technical specifications and algorithms
Building Documentation
# Install documentation dependencies
pip install -e .[docs]
# Build documentation
cd docs
make html
# View documentation
open _build/html/index.html
Writing Documentation
Clear Examples: Always include working code examples
Screenshots: Add images for GUI features
Cross-references: Link to related functions and concepts
Math: Use LaTeX for equations when needed
Example RST:
Advanced Baseline Correction
============================
The :func:`epyr.baseline.baseline_polynomial` function supports
advanced baseline correction with signal exclusion.
.. math::
y_{corrected} = y_{original} - P_n(x)
where :math:`P_n(x)` is a polynomial of order :math:`n`.
Example Usage
-------------
.. code-block:: python
from epyr.baseline import baseline_polynomial
# Apply quadratic correction excluding peak region
y_corrected, baseline = baseline_polynomial(
y_data,
x_data=x_data,
poly_order=2,
exclude_regions=[(3300, 3400)]
)
Issue Reporting
Bug Reports
When reporting bugs, please include:
System Information: OS, Python version, EPyR version
Minimal Example: Smallest code that reproduces the issue
Expected vs Actual: What should happen vs what happens
Data Files: If possible, share problem data files
Error Messages: Full traceback and error output
Template:
## Bug Report
**System:**
- OS: macOS 12.0
- Python: 3.9.7
- EPyR Tools: 0.1.6
**Issue:**
Baseline correction fails with 2D data
**Minimal Example:**
```python
import epyr
x, y, params, _ = epyr.eprload('2d_data.dsc')
# Error occurs here:
corrected, baseline = baseline_polynomial(y, x_data=x)
```
**Error:**
```
ValueError: y_data must be a 1D NumPy array.
```
**Expected:** Should handle 2D data or give clear guidance
Feature Requests
For feature requests:
Use Case: Describe the scientific problem
Proposed Solution: How should it work?
Alternatives: What workarounds exist?
Examples: Show expected API usage
EPR Domain Knowledge
Contributing EPR-Specific Features
When adding EPR-specific functionality:
Physical Accuracy: Ensure equations and constants are correct
Units: Be explicit about units (Gauss vs Tesla, etc.)
Conventions: Follow EPR community standards
References: Cite relevant papers and textbooks
Example - g-factor calculation:
def calculate_g_factor(frequency_hz: float, field_gauss: float) -> float:
"""Calculate g-factor from resonance condition.
Uses the EPR resonance condition: hν = gμBB
Args:
frequency_hz: Microwave frequency in Hz
field_gauss: Magnetic field in Gauss
Returns:
Dimensionless g-factor
References:
Weil, J. A., & Bolton, J. R. (2007). Electron paramagnetic
resonance: elementary theory and practical applications.
John Wiley & Sons.
"""
from epyr.physics import PLANCK, BMAGN
# Convert Gauss to Tesla
field_tesla = field_gauss * 1e-4
# g = hν / (μB * B)
return (PLANCK * frequency_hz) / (BMAGN * field_tesla)
Common Contribution Areas
Areas where contributions are especially welcome:
New File Formats: Support for other spectrometer manufacturers
Analysis Algorithms: Advanced peak fitting, simulation
Visualization: Interactive plots, publication templates
Data Processing: Noise reduction, phase correction
Integration: Bridges to other software (Origin, MATLAB)
Code Review Process
What to Expect
Automated Checks: CI runs tests and style checks
Maintainer Review: Core team reviews code and design
Community Feedback: Other users may comment
Iteration: Expect requests for changes or improvements
Review Criteria
Correctness: Does the code work as intended?
Testing: Are there adequate tests?
Documentation: Is it properly documented?
Style: Does it follow project conventions?
Performance: Is it reasonably efficient?
Compatibility: Works with supported Python versions?
Getting Help
If you need help contributing:
GitHub Discussions: Ask questions about implementation
Issues: Tag issues with “help wanted” or “good first issue”
Email: Contact maintainers for major changes
Documentation: Check existing docs and examples
Recognition
Contributors are recognized in:
CHANGELOG.md: Major contributions noted in release notes
AUTHORS: List of all contributors
Git History: Detailed commit attribution
Documentation: Citation in relevant sections
Thank you for contributing to EPyR Tools and supporting the EPR research community!