Developer Guide¶
This page covers everything you need to contribute to DefectPL, manage the documentation website, publish new releases to PyPI, and submit to conda-forge.
1. Development environment¶
git clone https://github.com/Shibu778/defectpl.git
cd defectpl
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[all]"
pip install pytest pytest-cov ruff
Run the test suite:
pytest -q # all tests
pytest -q tests/test_utils.py # single module
pytest -q --cov=defectpl # with coverage
Run the linter:
2. Project structure¶
defectpl/
├── defectpl/ # Python package
│ ├── __init__.py
│ ├── cli.py # Click command-line entry points
│ ├── constants.py # Physical constants
│ ├── data.py # Atomic masses, isotope data
│ ├── defect_utils.py # defect_entry / defect_structure_info generators
│ ├── defectpl.py # Core: Photoluminescence, VibrationalSpectra1D, CCD
│ ├── ks_analysis.py # Kohn–Sham eigenvalue analysis
│ ├── participation_ratio.py
│ ├── phonon.py
│ ├── plot.py # Plotter class
│ ├── utils.py # Pure math
│ ├── vasp.py # VASP file I/O (lazy pymatgen)
│ └── vasp_wrapper.py # High-level VASP wrappers
├── tests/ # pytest test suite
├── docs/ # MkDocs documentation source
├── development/ # Papers, benchmarks, scratch scripts
├── pyproject.toml # Package metadata and dependencies
└── mkdocs.yml # Documentation site configuration
3. Adding a new feature¶
- Create a feature branch:
git checkout -b feat/my-feature - Write the code with numpy-style docstrings (see §6 below).
- Add tests in
tests/test_<module>.py. - If the feature is user-facing, add a CLI command in
cli.pyand document it indocs/command_line_interface.md. - Update
docs/api/<module>.mdto expose the new symbol via mkdocstrings. - Open a pull request against
main.
Docstring style (numpy)¶
def calc_delQ(masses: np.ndarray, dR: np.ndarray) -> float:
"""
Compute the mass-weighted configuration coordinate difference ΔQ.
Parameters
----------
masses : np.ndarray
Atomic masses in AMU, shape ``(natoms,)``.
dR : np.ndarray
Cartesian displacement matrix in Å, shape ``(natoms, 3)``.
Returns
-------
float
ΔQ in units of ``sqrt(amu) · Å``.
Notes
-----
The formula is :math:`\\Delta Q = \\sqrt{\\sum_a m_a |\\Delta\\mathbf{R}_a|^2}`.
Examples
--------
>>> import numpy as np
>>> masses = np.array([12.011, 15.999])
>>> dR = np.array([[0.1, 0.0, 0.0], [0.0, 0.1, 0.0]])
>>> calc_delQ(masses, dR)
0.5744...
"""
4. Managing the documentation¶
Install docs dependencies¶
pip install -r docs/requirements.txt
# mkdocs>=1.6, mkdocs-material>=9.5, mkdocstrings[python]>=0.25
Preview locally¶
Build static HTML¶
Deploy to GitHub Pages¶
One-time setup¶
- Go to GitHub → Settings → Pages.
- Set Source to GitHub Actions.
Automatic deployment (recommended)¶
Create .github/workflows/docs.yml:
name: Deploy docs
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # needed for git-revision-date plugin
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: |
pip install ".[all]"
pip install -r docs/requirements.txt
- name: Deploy
run: mkdocs gh-deploy --force
Push to main — GitHub Actions builds the site and pushes it to the gh-pages branch
automatically. The site will be live at https://Shibu778.github.io/defectpl/.
Manual deployment¶
Versioned docs (optional, using mike)¶
pip install mike
mike deploy 0.2 latest --update-aliases
mike set-default latest
mike serve # preview versioned docs
Then replace mkdocs gh-deploy in the GitHub Action with:
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
mike deploy --push --update-aliases $(python -c "import defectpl; print(defectpl.__version__)") latest
5. Publishing to PyPI¶
Prerequisites¶
- PyPI account at pypi.org
- API token: Account settings → API tokens → Add API token (scope: project
defectpl) - Store as GitHub secret
PYPI_API_TOKEN
Version bump¶
Edit pyproject.toml:
Also update defectpl/__init__.py if it has a __version__ string.
Build and upload¶
pip install build twine
python -m build # creates dist/*.whl and dist/*.tar.gz
twine check dist/* # verify the package
twine upload dist/* # upload (prompts for credentials)
Or with GitHub Actions (create .github/workflows/publish.yml):
name: Publish to PyPI
on:
push:
tags:
- "v*"
jobs:
publish:
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write # OIDC trusted publishing (no token needed)
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install build
- run: python -m build
- uses: pypa/gh-action-pypi-publish@release/v1
Tag a release to trigger:
Trusted publishing
The workflow above uses PyPI's OIDC trusted publishing — no API token secret needed. Configure it at PyPI → Project → Publishing → Add a new publisher → GitHub Actions.
6. Publishing to conda-forge¶
conda-forge uses a feedstock repository that is separate from the main package.
First submission¶
- Ensure the package is already on PyPI.
- Fork staged-recipes.
- Create
recipes/defectpl/meta.yamlfollowing the conda-forge documentation. - Open a pull request — bots will run CI and merge when tests pass.
- You will be added as a maintainer of the new
defectpl-feedstockrepository.
Subsequent releases¶
After a new PyPI release, the regro-cf-autotick-bot usually opens a PR automatically in
defectpl-feedstock within a few hours. Review and merge it:
# Clone your feedstock
git clone https://github.com/<your-gh-username>/defectpl-feedstock
cd defectpl-feedstock
# The bot already made a branch; review meta.yaml, check the SHA256 hash
# matches the new PyPI tarball:
pip download defectpl==0.3.0 --no-deps --dest /tmp/dl/
sha256sum /tmp/dl/defectpl-0.3.0.tar.gz
# Approve and merge the bot's PR on GitHub
If the bot is slow, update manually:
# recipes/meta.yaml — bump version and sha256
{% set version = "0.3.0" %}
source:
url: https://pypi.io/packages/source/d/defectpl/defectpl-{{ version }}.tar.gz
sha256: <new-hash>
7. GitHub Actions CI¶
Create .github/workflows/ci.yml to run tests on every push and pull request:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: pip install ".[all]" pytest pytest-cov
- run: pytest -q --cov=defectpl --cov-report=xml
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
8. Code style¶
- Formatter: Ruff (
ruff format defectpl/) - Linter: Ruff (
ruff check defectpl/) - Docstrings: numpy style
- Type hints: standard Python annotations;
from __future__ import annotationswhere needed - Max line length: 99 characters
Add to pyproject.toml: