Testing & Environment Requirements

Development Environment

This project manages conflicting binary dependencies through isolated pixi environments. We avoid a monolithic environment to prevent version resolution failures and import-time crashes.

Initial Setup

pixi install

Local Development & Editable Installs

By default, the rgpycrumbs dispatcher runs scripts using uv run. This enforces strict environment isolation by resolving and fetching a script’s PEP 723 inline dependencies on the fly.

While excellent for reproducibility, this behavior bypasses your local Python environment. If you are actively developing a dependent package (e.g., you installed it locally via pip install -e . or pixi add --editable), uv run will ignore your local edits and fetch the published version instead.

To force rgpycrumbs to use your active environment and respect your editable installs, use the --dev flag:

# Standard execution (Isolated: uv resolves dependencies from scratch)
rgpycrumbs mygroup myscript

# Development execution (Active Env: uses sys.executable, respects editable installs)
rgpycrumbs --dev mygroup myscript

Workflow for Dependent Packages

  1. Activate your desired pixi environment (e.g., pixi shell -e test).

  2. Install your dependent package in editable mode if not already managed by pixi (e.g., pip install -e /path/to/local/dependency).

  3. Run your script using the --dev flag to test your local package modifications: rgpycrumbs --dev <group> <script>.

Debugging Execution with Verbose Mode

Because the dispatcher dynamically resolves script paths and environment execution contexts (switching between uv run and sys.executable), it can occasionally be helpful to inspect the underlying commands.

Pass the --verbose (or -v) flag to print the fully resolved path to the PEP 723 script and the exact command array being constructed before it is executed.

# Check standard isolated execution
rgpycrumbs --verbose mygroup myscript

# Check local development execution
rgpycrumbs --dev -v mygroup myscript

Testing Guidelines

The test suite utilizes custom markers to scope tests to specific environments. This prevents ModuleNotFoundError during the pytest collection phase.

Adding New Tests

When creating a new test file, you must protect the collection phase:

Define requirements

Add any required external modules to the ENVIRONMENT_REQUIREMENTS dictionary in tests/conftest.py.

Guard imports

Call skip_if_not_env("marker_name") at the top of your test file. This must occur before you import any package modules that depend on external binaries.

Mark your tests

Assign the corresponding marker to the file or functions.

Example Test Structure

import pytest
from tests.conftest import skip_if_not_env

# Guard collection: prevents imports from executing if dependencies are missing
skip_if_not_env("my_marker")

# Imports are now safe to execute
from rgpycrumbs.submodule.logic import core_feature

def test_feature_execution():
    assert core_feature() is True

Dispatcher Scripts and Test Markers

Scripts under rgpycrumbs/eon/ (and similar groups) declare their own dependencies via PEP 723 inline metadata. These scripts import heavy packages (polars, chemparseplot, ase, etc.) at the top level, because uv run resolves those dependencies before execution.

When writing tests that import these scripts directly (e.g., to test CLI --help output), the test file must use the corresponding marker (e.g., eon, not pure) and the skip_if_not_env guard. Otherwise the top-level imports will fail during collection in environments that lack the script’s dependencies.

import pytest
from tests.conftest import skip_if_not_env

skip_if_not_env("eon")

from rgpycrumbs.eon.plt_neb import main as plt_neb_main  # noqa: E402

pytestmark = pytest.mark.eon


def test_plt_neb_help(runner):
    result = runner.invoke(plt_neb_main, ["--help"])
    assert result.exit_code == 0

The pure marker is reserved for tests that depend only on core packages (numpy, click). The ensure_import and lazy_import tests also run under pure since they mock all optional dependencies. Never place tests that import dispatcher scripts under the pure marker.

Note that [all] is a best-effort convenience extra covering pip-installable optional dependencies only. Conda-only packages (tblite, ovito, ira_mod) require pixi.

Available Markers & Environments

The following markers and their corresponding pixi environments are available:

Marker

Environment

Dependencies

What it tests

pure

test

numpy

Core utilities, basetypes, ensureimport

align

test

ase, numpy

Structure analysis, alignment

fragments

fragments

ase, tblite

Fragment detection with tight-binding

surfaces

surfaces

jax

Surface fitting kernels and models

ptm

ptm

ase, ovito

Polyhedral template matching

eon

eonmlflow

ase, eon, polars, chemparseplot

eOn integration, NEB CLI

ira

(requires ira_mod)

ira_mod

IRA matching and RMSD comparison

Running Tests

Execute tests within the specific environment that provides the necessary dependencies:

# Run tests for a specific suite
pixi run -e <env_name> pytest -m <marker_name>

# Examples
pixi run -e test pytest -m pure
pixi run -e test pytest -m align
pixi run -e surfaces pytest -m surfaces
pixi run -e fragments pytest -m fragments