Skip to content

Development Tools

This guide covers the development tools used in MolPy and their configurations.

Overview

MolPy uses modern Python development tools:

  • pytest - Testing framework
  • Black - Code formatting
  • isort - Import sorting
  • pre-commit - Git hooks
  • mkdocs - Documentation
  • coverage - Code coverage

Testing: pytest

Installation

pip install pytest pytest-cov pytest-mock

Configuration

Configuration in pyproject.toml:

[tool.pytest.ini_options]
markers = [
    "external: tests requiring external tools",
    "slow: slow tests",
]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]

Basic Usage

# Run all tests
pytest

# Verbose output
pytest -v

# Stop on first failure
pytest -x

# Run specific file
pytest tests/test_core/test_frame.py

# Run specific test
pytest tests/test_core/test_frame.py::test_frame_creation

# Run tests matching pattern
pytest -k "lammps"

Advanced Usage

# Parallel execution (requires pytest-xdist)
pytest -n auto

# Show print statements
pytest -s

# Show local variables on failure
pytest -l

# Run last failed tests
pytest --lf

# Run failed tests first, then others
pytest --ff

# Generate JUnit XML report
pytest --junit-xml=report.xml

Markers

Use markers to categorize tests:

import pytest

@pytest.mark.external
def test_lammps():
    """Test requiring LAMMPS."""
    ...

@pytest.mark.slow
def test_large_system():
    """Slow test."""
    ...

Run specific markers:

# Skip external tests
pytest -m "not external"

# Run only slow tests
pytest -m "slow"

# Combine markers
pytest -m "slow and not external"

Fixtures

Define reusable test data:

import pytest

@pytest.fixture
def water_frame():
    """Provide water molecule frame."""
    from molpy.core import Frame, Block
    frame = Frame()
    frame["atoms"] = Block({
        "x": [0.0, 0.757, -0.757],
        "y": [0.0, 0.586, 0.586],
        "z": [0.0, 0.0, 0.0],
    })
    return frame

def test_something(water_frame):
    """Test using water frame."""
    assert len(water_frame["atoms"]) == 3

Coverage

# Run with coverage
pytest --cov=molpy tests/

# Generate HTML report
pytest --cov=molpy --cov-report=html tests/

# Show missing lines
pytest --cov=molpy --cov-report=term-missing tests/

# Fail if coverage below threshold
pytest --cov=molpy --cov-fail-under=80 tests/

Formatting: Black

Installation

pip install black

Configuration

Configuration in pyproject.toml:

[tool.black]
line-length = 88
target-version = ['py312']
include = '\\.pyi?$'
extend-exclude = '''
/(
  \\.eggs
  | \\.git
  | \\.mypy_cache
  | \\.venv
  | build
  | dist
)/
'''

Usage

# Format all files
black .

# Format specific file
black molpy/core/frame.py

# Check without modifying
black --check .

# Show diff
black --diff .

# Exclude files
black --exclude "/(build|dist)/" .

Editor Integration

VS Code:

{
  "python.formatting.provider": "black",
  "editor.formatOnSave": true
}

PyCharm: 1. Install Black plugin 2. Settings → Tools → Black → Enable 3. Settings → Tools → Actions on Save → Reformat code

Import Sorting: isort

Installation

pip install isort

Configuration

Configuration in pyproject.toml:

[tool.isort]
profile = "black"
line_length = 88
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true

Usage

# Sort imports in all files
isort .

# Sort specific file
isort molpy/core/frame.py

# Check without modifying
isort --check .

# Show diff
isort --diff .

Import Groups

isort organizes imports into groups:

# 1. Standard library
import os
import sys
from pathlib import Path

# 2. Third-party
import numpy as np
from igraph import Graph

# 3. Local
from molpy.core import Frame
from molpy.io import read_pdb

Pre-commit Hooks

Installation

pip install pre-commit
pre-commit install

Configuration

Configuration in .pre-commit-config.yaml:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
        args: ['--maxkb=1024']
      - id: check-merge-conflict
      - id: mixed-line-ending
      - id: check-toml
      - id: check-json

  - repo: https://github.com/psf/black
    rev: 25.11.0
    hooks:
    -   id: black

  - repo: https://github.com/kynan/nbstripout
    rev: 0.8.2
    hooks:
      - id: nbstripout
        files: \\.ipynb$
        args: ["--extra-keys=metadata.kernelspec metadata.language_info"]

Usage

# Install hooks
pre-commit install

# Run manually on all files
pre-commit run --all-files

# Run on specific files
pre-commit run --files molpy/core/frame.py

# Update hook versions
pre-commit autoupdate

# Skip hooks for a commit
git commit --no-verify

Hooks Included

  • trailing-whitespace - Remove trailing whitespace
  • end-of-file-fixer - Ensure files end with newline
  • check-yaml - Validate YAML files
  • check-toml - Validate TOML files
  • check-json - Validate JSON files
  • check-added-large-files - Prevent large files
  • black - Format code
  • nbstripout - Strip notebook outputs

Documentation: MkDocs

Installation

pip install mkdocs mkdocs-material mkdocstrings[python] mkdocs-jupyter

Configuration

Configuration in mkdocs.yml:

site_name: molpy
theme:
  name: material
  features:
    - navigation.tabs
    - navigation.instant
    - content.code.copy

plugins:
  - search
  - mkdocstrings:
      handlers:
        python:
          paths: [src]
          options:
            docstring_style: google
            show_source: true
  - mkdocs-jupyter:
      execute: true

markdown_extensions:
  - admonition
  - pymdownx.highlight
  - pymdownx.superfences
  - pymdownx.tabbed

Usage

# Serve documentation locally
mkdocs serve

# Build static site
mkdocs build

# Deploy to GitHub Pages
mkdocs gh-deploy

# Validate configuration
mkdocs build --strict

Writing Documentation

Markdown files:

# Page Title

Regular markdown content.

## Code Examples

```python
from molpy.core import Frame
frame = Frame()

Admonitions

Note

This is a note.

Warning

This is a warning.

**API documentation:**
```markdown
# API Reference

::: molpy.core.Frame
    options:
      show_source: true
      members: true

Coverage: coverage.py

Installation

pip install coverage pytest-cov

Usage with pytest

# Run tests with coverage
pytest --cov=molpy tests/

# Generate HTML report
pytest --cov=molpy --cov-report=html tests/

# Generate XML report (for CI)
pytest --cov=molpy --cov-report=xml tests/

# Show missing lines
pytest --cov=molpy --cov-report=term-missing tests/

Standalone Usage

# Run tests with coverage
coverage run -m pytest

# Generate report
coverage report

# Generate HTML report
coverage html

# Erase previous data
coverage erase

Configuration

Configuration in pyproject.toml:

[tool.coverage.run]
source = ["molpy"]
omit = [
    "*/tests/*",
    "*/test_*.py",
]

[tool.coverage.report]
exclude_lines = [
    "pragma: no cover",
    "def __repr__",
    "raise AssertionError",
    "raise NotImplementedError",
    "if __name__ == .__main__.:",
]

Type Checking: mypy (Optional)

Installation

pip install mypy

Configuration

Configuration in pyproject.toml:

[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

[[tool.mypy.overrides]]
module = "igraph.*"
ignore_missing_imports = true

Usage

# Check all files
mypy molpy

# Check specific file
mypy molpy/core/frame.py

# Generate HTML report
mypy --html-report mypy-report molpy

Linting: Ruff (Optional)

Installation

pip install ruff

Configuration

Configuration in pyproject.toml:

[tool.ruff]
line-length = 88
target-version = "py312"

[tool.ruff.lint]
select = [
    "E",  # pycodestyle errors
    "W",  # pycodestyle warnings
    "F",  # pyflakes
    "I",  # isort
]
ignore = [
    "E501",  # line too long (handled by black)
]

Usage

# Check all files
ruff check .

# Fix auto-fixable issues
ruff check --fix .

# Check specific file
ruff check molpy/core/frame.py

Build Tools

Building Packages

# Install build tools
pip install build

# Build source distribution and wheel
python -m build

# Output in dist/
ls dist/
# molcrafts-molpy-0.3.0.tar.gz
# molcrafts_molpy-0.3.0-py3-none-any.whl

Publishing to PyPI

# Install twine
pip install twine

# Upload to Test PyPI
twine upload --repository testpypi dist/*

# Upload to PyPI
twine upload dist/*

Continuous Integration

GitHub Actions

Example workflow (.github/workflows/test.yml):

name: Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.12"]

    steps:
      - uses: actions/checkout@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install dependencies
        run: |
          pip install -e ".[dev]"

      - name: Run tests
        run: |
          pytest --cov=molpy --cov-report=xml

      - name: Upload coverage
        uses: codecov/codecov-action@v3

Editor Configuration

VS Code

Recommended .vscode/settings.json:

{
  "python.linting.enabled": true,
  "python.formatting.provider": "black",
  "python.testing.pytestEnabled": true,
  "python.testing.pytestArgs": ["tests"],
  "editor.formatOnSave": true,
  "editor.rulers": [88],
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": true
    }
  }
}

Recommended extensions: - Python (Microsoft) - Pylance - Jupyter - autoDocstring

PyCharm

Settings: 1. Code Style → Python → Line length: 88 2. Tools → Python Integrated Tools → Testing: pytest 3. Tools → Black: Enable 4. Editor → Code Style → Python → Imports: Use isort

Summary

Essential Tools

  • pytest - Testing
  • Black - Formatting
  • isort - Import sorting
  • pre-commit - Git hooks

Optional Tools

  • mypy - Type checking
  • ruff - Fast linting
  • coverage - Code coverage

Quick Setup

# Install all dev tools
pip install -e ".[dev]"

# Install pre-commit hooks
pre-commit install

# Run tests
pytest

# Format code
black .
isort .

# Build docs
mkdocs serve

Further Reading