Problem Statement
SolarWindPy currently maintains 5 dependency specification files with significant duplication:
pyproject.toml - Package metadata with incomplete optional-dependencies
requirements-dev.txt - De facto source of truth (27 packages, triggers automated sync)
requirements.txt - Frozen pins generated via pip freeze (for ReadTheDocs)
docs/requirements.txt - Generated subset (7 packages) for documentation builds
solarwindpy.yml - Conda environment file (generated from requirements-dev.txt)
Maintenance Burden
Every dependency update triggers the sync-requirements.yml workflow which:
- Regenerates
requirements.txt via freeze_requirements.py
- Regenerates
docs/requirements.txt via generate_docs_requirements.py
- Regenerates
solarwindpy.yml via requirements_to_conda_env.py
- Creates automated PRs with these changes
Recent commit history shows this churn:
cd051cb chore: auto-sync requirements from requirements-dev.txt
f4be657 chore: auto-sync requirements from requirements-dev.txt
5e9222c chore: auto-sync requirements from requirements-dev.txt
Core Issue: requirements-dev.txt acts as the source of truth, not pyproject.toml (which violates PEP 621).
Proposed Solution
Follow PEP 621 standard and modern Python packaging best practices:
Make pyproject.toml the Single Source of Truth
Consolidate all dependencies into [project.optional-dependencies] following the Astropy pattern (de facto standard for scientific Python):
[project.optional-dependencies]
# Testing infrastructure
test = [
"pytest>=7.4.4",
"pytest-cov>=4.1.0",
]
# Documentation building
docs = [
"sphinx",
"sphinx_rtd_theme",
"sphinxcontrib-spelling",
"sphinxcontrib-bibtex",
"doc8",
"numpydoc",
"docstring-inheritance>=2.0",
]
# Code quality tools
dev = [
"black",
"flake8",
"flake8-docstrings",
"pydocstyle",
]
# Optional HDF5 support
hdf5 = [
"tables", # PyTables
]
# Development tools (not for PyPI distribution)
tools = [
"gh", # GitHub CLI
"psutil>=5.9.0",
]
# Complete development environment
all = [
"solarwindpy[test,docs,dev,hdf5,tools]",
]
Rationale: Granular groups allow flexible installation patterns:
- CI testing:
pip install -e .[test,dev]
- Documentation:
pip install -e .[docs]
- Complete dev:
pip install -e .[all]
Implementation Plan
Phase 1: Restructure pyproject.toml
Action: Add complete [project.optional-dependencies] structure as shown above.
Benefit: Establishes true single source of truth per PEP 621.
Phase 2: Update Scripts
Modify scripts/requirements_to_conda_env.py
Current: Reads from requirements-dev.txt
New: Read from pyproject.toml
import tomllib # Python 3.11+
with open("pyproject.toml", "rb") as f:
data = tomllib.load(f)
core_deps = data["project"]["dependencies"]
optional = data["project"]["optional-dependencies"]
# Combine groups (exclude 'tools' - gh not on conda-forge)
all_deps = (
core_deps
+ optional["test"]
+ optional["docs"]
+ optional["dev"]
+ optional["hdf5"]
)
# Continue with existing conda name translation logic...
Update or Remove scripts/freeze_requirements.py
Decision needed: Keep frozen requirements.txt for ReadTheDocs stability?
Option A (recommended): Remove entirely, use live versions from pyproject.toml
Option B: Keep but read from pyproject.toml instead of requirements-dev.txt
Phase 3: Simplify ReadTheDocs Configuration
Update .readthedocs.yaml
Current (uses 2 requirements files):
python:
install:
- requirements: requirements.txt
- requirements: docs/requirements.txt
- method: pip
path: .
New (reads directly from pyproject.toml):
python:
install:
- method: pip
path: .
extra_requirements:
- docs # Reads [project.optional-dependencies] docs group
Benefit: Eliminates 2 generated requirements files, uses source of truth directly.
Reference: https://docs.readthedocs.io/en/stable/config-file/v2.html#packages
Phase 4: Update CI/CD Workflows
.github/workflows/continuous-integration.yml
Change:
# Before
- name: Install dependencies
run: pip install -r requirements-dev.txt
# After
- name: Install dependencies
run: pip install -e .[test,dev]
.github/workflows/sync-requirements.yml
Major Simplification:
Before (generates 3 files):
- run: pip install -r requirements-dev.txt
- run: python scripts/generate_docs_requirements.py
- run: python scripts/freeze_requirements.py
- run: python scripts/requirements_to_conda_env.py --overwrite
After (generates 1 file):
- run: pip install -e .[all]
- run: python scripts/requirements_to_conda_env.py --overwrite
Other Workflows
Update any workflow using requirements-dev.txt:
.github/workflows/publish.yml → pip install -e .[dev,test]
- Check
.github/workflows/release-pipeline.yml for usage
Phase 5: Remove Obsolete Files
Delete:
- ❌
requirements-dev.txt - Replaced by pyproject.toml [project.optional-dependencies]
- ❌
docs/requirements.txt - ReadTheDocs uses pyproject.toml directly via extra_requirements
- ❌
scripts/generate_docs_requirements.py - No longer needed
Keep (generated from pyproject.toml):
- ✅
solarwindpy.yml - Conda users need this for environment creation
- ⚠️
requirements.txt - Decision: Remove or keep for docs stability?
Phase 6: Update Documentation
README.rst
Update development installation section:
Development Installation
------------------------
For complete development environment::
pip install -e .[all]
Or install specific groups::
pip install -e .[test] # Testing only
pip install -e .[docs] # Documentation building
pip install -e .[dev] # Code quality tools
pip install -e .[hdf5] # Optional HDF5 support
docs/source/installation.rst
Update corresponding development setup documentation.
Expected Benefits
Before (Current State)
- 5 dependency files (2 manual, 3 generated)
- requirements-dev.txt is de facto source of truth ❌
- Automated sync creates PR churn
- Duplication across files increases maintenance burden
After (Proposed State)
- 1 source file:
pyproject.toml (PEP 621 standard) ✅
- 1 generated file:
solarwindpy.yml (for conda users)
- Simpler CI workflows
- Follows scientific Python best practices (Astropy pattern)
- Eliminates
generate_docs_requirements.py script
- Standard
pip install -e .[groups] pattern
Decision Points
Q1: Frozen requirements.txt for ReadTheDocs?
Option A (recommended): Remove entirely, always use latest compatible versions
- Pros: Simpler, catches incompatibilities early
- Cons: Docs builds might break on upstream updates
Option B: Keep but generate from pyproject.toml
- Pros: Stable docs builds
- Cons: Additional maintenance
Recommendation: Start with Option A, only revert if docs builds become unstable.
Q2: When to Execute?
Option A: Immediately (before v0.2.0 release)
Option B: Bundle with next feature work
Option C: Make it part of v0.2.0 as infrastructure improvement
Q3: Investigate pyproject2conda?
Option A (current): Keep custom requirements_to_conda_env.py
- Pros: Simple, works well, we control it
- Cons: Manual maintenance of pip→conda name translations
Option B: Migrate to pyproject2conda
- Pros: Industry standard, more features, community maintained
- Cons: Learning curve, requires
[tool.pyproject2conda] configuration
Recommendation: Keep custom script (simpler), revisit pyproject2conda if complexity grows.
Files Modified
Source Files
pyproject.toml - Add complete [project.optional-dependencies]
scripts/requirements_to_conda_env.py - Read from pyproject.toml
scripts/freeze_requirements.py - Update or remove (decision needed)
.readthedocs.yaml - Use extra_requirements method
.github/workflows/continuous-integration.yml - Replace requirements-dev.txt
.github/workflows/sync-requirements.yml - Simplify workflow
.github/workflows/publish.yml - Replace requirements-dev.txt
README.rst - Update installation instructions
docs/source/installation.rst - Update development setup
Files Deleted
requirements-dev.txt
docs/requirements.txt
scripts/generate_docs_requirements.py
Files Generated (Post-Commit)
solarwindpy.yml - Auto-generated by updated script
requirements.txt - Optional, if frozen pins desired
Implementation Checklist
References
Standards
Tools
Examples
Related Issues
- Complements the Python 3.11 minimum version bump (#issue-from-feat-branch)
- Prepares infrastructure for v0.2.0 release
- Addresses technical debt in dependency management
Priority: Medium
Type: Refactoring / Infrastructure Improvement
Breaking Change: No (transparent to users)
Effort: ~4-6 hours (implementation + testing + docs)
Problem Statement
SolarWindPy currently maintains 5 dependency specification files with significant duplication:
pyproject.toml- Package metadata with incomplete optional-dependenciesrequirements-dev.txt- De facto source of truth (27 packages, triggers automated sync)requirements.txt- Frozen pins generated viapip freeze(for ReadTheDocs)docs/requirements.txt- Generated subset (7 packages) for documentation buildssolarwindpy.yml- Conda environment file (generated from requirements-dev.txt)Maintenance Burden
Every dependency update triggers the
sync-requirements.ymlworkflow which:requirements.txtviafreeze_requirements.pydocs/requirements.txtviagenerate_docs_requirements.pysolarwindpy.ymlviarequirements_to_conda_env.pyRecent commit history shows this churn:
Core Issue:
requirements-dev.txtacts as the source of truth, notpyproject.toml(which violates PEP 621).Proposed Solution
Follow PEP 621 standard and modern Python packaging best practices:
Make
pyproject.tomlthe Single Source of TruthConsolidate all dependencies into
[project.optional-dependencies]following the Astropy pattern (de facto standard for scientific Python):Rationale: Granular groups allow flexible installation patterns:
pip install -e .[test,dev]pip install -e .[docs]pip install -e .[all]Implementation Plan
Phase 1: Restructure pyproject.toml
Action: Add complete
[project.optional-dependencies]structure as shown above.Benefit: Establishes true single source of truth per PEP 621.
Phase 2: Update Scripts
Modify
scripts/requirements_to_conda_env.pyCurrent: Reads from
requirements-dev.txtNew: Read from
pyproject.tomlUpdate or Remove
scripts/freeze_requirements.pyDecision needed: Keep frozen
requirements.txtfor ReadTheDocs stability?Option A (recommended): Remove entirely, use live versions from pyproject.toml
Option B: Keep but read from
pyproject.tomlinstead ofrequirements-dev.txtPhase 3: Simplify ReadTheDocs Configuration
Update
.readthedocs.yamlCurrent (uses 2 requirements files):
New (reads directly from pyproject.toml):
Benefit: Eliminates 2 generated requirements files, uses source of truth directly.
Reference: https://docs.readthedocs.io/en/stable/config-file/v2.html#packages
Phase 4: Update CI/CD Workflows
.github/workflows/continuous-integration.ymlChange:
.github/workflows/sync-requirements.ymlMajor Simplification:
Before (generates 3 files):
After (generates 1 file):
Other Workflows
Update any workflow using
requirements-dev.txt:.github/workflows/publish.yml→pip install -e .[dev,test].github/workflows/release-pipeline.ymlfor usagePhase 5: Remove Obsolete Files
Delete:
requirements-dev.txt- Replaced bypyproject.toml [project.optional-dependencies]docs/requirements.txt- ReadTheDocs usespyproject.tomldirectly viaextra_requirementsscripts/generate_docs_requirements.py- No longer neededKeep (generated from pyproject.toml):
solarwindpy.yml- Conda users need this for environment creationrequirements.txt- Decision: Remove or keep for docs stability?Phase 6: Update Documentation
README.rst
Update development installation section:
docs/source/installation.rst
Update corresponding development setup documentation.
Expected Benefits
Before (Current State)
After (Proposed State)
pyproject.toml(PEP 621 standard) ✅solarwindpy.yml(for conda users)generate_docs_requirements.pyscriptpip install -e .[groups]patternDecision Points
Q1: Frozen requirements.txt for ReadTheDocs?
Option A (recommended): Remove entirely, always use latest compatible versions
Option B: Keep but generate from pyproject.toml
Recommendation: Start with Option A, only revert if docs builds become unstable.
Q2: When to Execute?
Option A: Immediately (before v0.2.0 release)
Option B: Bundle with next feature work
Option C: Make it part of v0.2.0 as infrastructure improvement
Q3: Investigate pyproject2conda?
Option A (current): Keep custom
requirements_to_conda_env.pyOption B: Migrate to pyproject2conda
[tool.pyproject2conda]configurationRecommendation: Keep custom script (simpler), revisit pyproject2conda if complexity grows.
Files Modified
Source Files
pyproject.toml- Add complete[project.optional-dependencies]scripts/requirements_to_conda_env.py- Read from pyproject.tomlscripts/freeze_requirements.py- Update or remove (decision needed).readthedocs.yaml- Useextra_requirementsmethod.github/workflows/continuous-integration.yml- Replace requirements-dev.txt.github/workflows/sync-requirements.yml- Simplify workflow.github/workflows/publish.yml- Replace requirements-dev.txtREADME.rst- Update installation instructionsdocs/source/installation.rst- Update development setupFiles Deleted
requirements-dev.txtdocs/requirements.txtscripts/generate_docs_requirements.pyFiles Generated (Post-Commit)
solarwindpy.yml- Auto-generated by updated scriptrequirements.txt- Optional, if frozen pins desiredImplementation Checklist
refactor/single-source-dependenciespyproject.tomlwith complete optional-dependenciesscripts/requirements_to_conda_env.pyto read from pyproject.tomlpython scripts/requirements_to_conda_env.py --overwrite.readthedocs.yamlto useextra_requirementspip install -e .[groups]pip install -e .[all]+ run testsgit rm requirements-dev.txt docs/requirements.txt scripts/generate_docs_requirements.pyREADME.rstanddocs/source/installation.rstReferences
Standards
Tools
Examples
Related Issues
Priority: Medium
Type: Refactoring / Infrastructure Improvement
Breaking Change: No (transparent to users)
Effort: ~4-6 hours (implementation + testing + docs)