API Policy#
This page defines how the pyCSAMT v2 API is structured, how contributors should expose new functionality, and what compatibility promises users can expect. It is the development contract for the project: before adding a new module, function, class, CLI command, agent, or pipeline step, check this page.
pyCSAMT v2 is larger than a single numerical package. It contains scientific data containers, EM processing tools, inversion interfaces, AI models, AI-assisted agents, declarative pipelines, plotting helpers, a command-line interface, and application-facing view objects. The API policy keeps those parts discoverable without making every internal implementation detail permanent.
API design goals#
The v2 API follows six principles.
Principle |
Meaning for contributors |
|---|---|
Stable imports |
Users should import from documented public namespaces, not from private implementation files. |
Scientific clarity |
Public functions must make units, coordinate assumptions, array shapes, and impedance/resistivity conventions explicit. |
Composable workflows |
Processing, inversion, agents, and CLI commands should share structured inputs and outputs so they can be chained. |
Optional heavy dependencies |
AI, LLM, plotting, GIS, and backend-specific features must fail lazily and clearly when optional dependencies are missing. |
Reproducibility |
User-facing results should carry enough metadata to recreate the operation: parameters, versions, backend, warnings, output paths, and diagnostics. |
Compatibility discipline |
Public names should not be renamed, moved, or removed casually. When a change is required, use a documented deprecation path. |
Public namespace map#
Use this table when deciding where a new API belongs.
Namespace |
Role |
Stability expectation |
|---|---|---|
|
Top-level convenience imports such as version, backend helpers, and the most common pipeline symbols. |
Stable. Keep small and intentional. |
|
Public configuration, result wrappers, style controls, CLI option helpers, plotting configuration, and lightweight view helpers. |
Stable public facade. |
|
AI-assisted workflow agents, lazy-loaded to avoid hard LLM dependency at import time. |
Public, but individual agent capabilities may be marked experimental. |
|
Declarative processing engine, steps, presets, and pipeline runtime configuration. |
Stable public workflow API. |
|
Click-based command-line application and command groups. |
Stable at command and option level once documented. |
|
Physics-based inversion interfaces, models, results, backends, and workflow helpers. |
Stable for documented classes and functions. |
|
File builders, runners, result readers, and configuration objects for engines such as Occam2D and ModEM. |
Public for documented engine-facing objects. |
|
Neural inversion models, training utilities, AI processing tools, and AI plotting helpers. |
Experimental-to-stable depending on page and docstring status. |
|
Electromagnetic processing, diagnostics, source effects, tensor tools, plots, and legacy-compatible helpers. |
Stable for documented functions; legacy aliases follow deprecation rules. |
|
Format-specific readers, writers, parsers, transforms, and survey objects. |
Stable for documented readers and data objects. |
|
Site, survey, profile, location, selection, export, and reporting helpers. |
Stable for documented site and survey interfaces. |
|
Geological, lithological, hydrological, petrophysical, uncertainty, and export interpretation APIs. |
Stable for documented interpretation workflows. |
|
Backend detection and backend selection for AI/neural runtimes. |
Stable for selection helpers; backend implementations may evolve. |
|
Shared utilities, compatibility shims, and migration helpers. |
Public only when explicitly documented or exported through
|
Public, private, experimental, deprecated#
Every API must fall into one of these categories.
Category |
How to recognize it |
Compatibility promise |
Developer action |
|---|---|---|---|
Public stable |
Documented in |
Keep compatible across v2 minor releases. |
Add tests, docstring, docs entry, and release note. |
Public experimental |
Documented as experimental or provisional. Common for young AI, backend, and agent features. |
May change, but changes must be explained. |
Add warnings in docs and prefer keyword-only extension points. |
Private |
Name starts with |
No compatibility promise. |
Do not document as an import target. Re-export stable wrappers instead. |
Deprecated |
Emits |
Must remain available until the announced removal version. |
Provide replacement guidance and tests for the warning. |
Removed |
Not importable, or guarded by an explanatory |
No runtime support. |
Keep migration guidance where useful. |
The import rule#
Users should not need to know the internal file layout. Public imports should come from stable package-level facades.
Preferred public imports:
1from pycsamt.api import read_edis, configure_style
2from pycsamt.pipeline import Pipeline, Step, list_steps
3from pycsamt.agents import DataQCAgent, WorkflowOrchestratorAgent
4from pycsamt.backends import set_backend, get_backend
Avoid exposing internal implementation paths as the primary documented import:
1# Avoid in user documentation unless the module itself is the public API.
2from pycsamt.pipeline._registry import STEP_REGISTRY
3from pycsamt.agents._base import BaseAgent
There are valid exceptions. Some submodules, such as
pycsamt.models.occam2d.builder or pycsamt.inversion.workflow, are
domain-specific public entry points. When that is intended, document the
module and include its public names in __all__.
Top-level pycsamt policy#
The top-level package is for the most common cross-package shortcuts only. It currently exposes:
__version__core subpackages such as
interp,inversion, andtdempipeline shortcuts such as
Pipeline,Step,configure_pipe,reset_pipe, andPYCSAMT_PIPEbackend helpers such as
auto_detect,get_backend,get_backend_instance,list_backends, andset_backend
Do not add every new class to pycsamt.__all__. Add a top-level shortcut
only when all of these are true:
the object is broadly useful across workflows;
importing it does not force optional heavy dependencies;
the name is stable enough to support through v2;
the object already has a natural package-level home.
Good example:
1from pycsamt import Pipeline, Step
More specific example:
1from pycsamt.models.occam2d import InputBuilder, OccamRunner
The pycsamt.api facade#
pycsamt.api is the public facade for cross-cutting configuration and
application-facing helpers. Use it for stable objects that are not tied to one
scientific algorithm but affect how pyCSAMT behaves or returns data.
Examples include:
global style configuration;
plotting/export configuration;
CLI option and parameter helpers;
result wrappers such as
APIResult;data-view helpers such as
read_ediandread_edis;agent LLM configuration such as
configure_agents;pipeline runtime configuration such as
configure_pipe.
When adding to pycsamt.api:
keep objects lightweight at import time;
avoid importing AI, GIS, plotting, or inversion engines unless needed;
define an explicit
__all__in the source module;re-export from
pycsamt/api/__init__.pyonly for stable public names;include examples in the relevant guide page.
Pattern:
1# pycsamt/api/example.py
2from dataclasses import dataclass
3
4@dataclass
5class ExampleConfig:
6 enabled: bool = True
7
8PYCSAMT_EXAMPLE = ExampleConfig()
9
10def configure_example(**kwargs):
11 for key, value in kwargs.items():
12 setattr(PYCSAMT_EXAMPLE, key, value)
13 return PYCSAMT_EXAMPLE
14
15def reset_example():
16 global PYCSAMT_EXAMPLE
17 PYCSAMT_EXAMPLE = ExampleConfig()
18 return PYCSAMT_EXAMPLE
19
20__all__ = ["ExampleConfig", "PYCSAMT_EXAMPLE",
21 "configure_example", "reset_example"]
Agents API policy#
Agents are public workflow components. They must be usable from Python, coordinators, orchestrators, notebooks, and eventually web/CLI workflows.
Public agents live under pycsamt.agents and are lazy-loaded through
pycsamt/agents/__init__.py. New agents should follow the existing
BaseAgent and AgentResult contract.
Required behavior for every public agent:
inherit from
BaseAgentunless there is a strong architectural reason not to;implement
execute(...)with a dictionary-like input contract;return an
AgentResultor a compatible mapping withsuccess,data,warnings,figures, andmetadatasemantics;support
dry_runwhen the operation can be planned without execution;keep LLM calls optional;
report missing optional dependencies through clear exceptions or failed
AgentResultobjects;document input keys, output data keys, examples, and typical chained usage.
Recommended minimal agent skeleton:
1from pycsamt.agents import AgentResult, BaseAgent
2
3class MyAgent(BaseAgent):
4 """Short scientific purpose of the agent."""
5
6 def execute(self, inputs, *, dry_run=False, **kwargs):
7 config = dict(inputs or {})
8
9 if dry_run:
10 return AgentResult(
11 success=True,
12 data={"planned": True, "steps": ["load", "qc"]},
13 metadata={"agent": self.__class__.__name__},
14 )
15
16 # Run the concrete operation here.
17 return AgentResult(
18 success=True,
19 data={"result": "..."},
20 warnings=[],
21 metadata={"agent": self.__class__.__name__},
22 )
23
24__all__ = ["MyAgent"]
After creating an agent:
add it to the lazy map in
pycsamt.agents;add it to the catalogue docs;
add focused tests under
pycsamt/agents/tests;update coordinator or orchestrator routing only when the agent is intended for automatic workflow selection.
Pipeline API policy#
The pipeline package is the declarative processing layer. Its public API is
Pipeline, Step, registry discovery helpers, presets, and runtime
configuration.
Pipeline steps must be stable, inspectable, and serializable. A user should be able to move between Python, YAML/JSON configuration, CLI execution, and agent execution without changing the meaning of a step.
Recommended user-facing pattern:
1from pycsamt.pipeline import Pipeline, Step
2
3pipe = Pipeline([
4 ("notch", Step("NR001", mains_hz=50)),
5 ("band", Step("FREQ001", fmin=1e-3, fmax=1.0)),
6 ("static_shift", Step("SS001", method="spatial_median")),
7])
8
9result = pipe.run(sites, outdir="results/willy")
When adding pipeline functionality:
register steps with stable codes and descriptive names;
keep step parameters JSON/YAML serializable where possible;
include category, description, required inputs, outputs, and failure modes;
add the step to presets only after it has focused tests;
preserve backward compatibility for existing step codes.
Do not rename a step code once documented. If a step must be replaced, keep the old code as an alias, emit a deprecation warning, and document the new code.
Inversion and model API policy#
Inversion APIs sit at the boundary between pyCSAMT objects and external engines. They must be explicit about what is computed inside pyCSAMT and what is delegated to an external executable or backend.
Public inversion objects should document:
supported data type: AMT, CSAMT, MT, EMAP, TDEM, or mixed;
dimensionality: 1-D, 2-D, or 3-D;
required input format and units;
mesh/model assumptions;
backend or executable requirements;
output files and result object fields;
reproducibility metadata.
Typical import style:
1from pycsamt.inversion import InversionConfig
2from pycsamt.models.occam2d import InputBuilder, OccamRunner
3from pycsamt.models.modem import ModEmConfig, ModEmRunner
Backend wrappers must not hide external failures. If Occam2D, ModEM, PyGIMLi, PyTorch, or TensorFlow is missing, raise a clear error or return a failed structured result that names the missing backend.
AI and backend policy#
AI APIs are allowed to depend on optional packages, but importing pyCSAMT must not require those packages. Heavy imports should happen inside methods, factory functions, or backend adapters.
Rules:
use
pycsamt.backendsfor neural backend selection where possible;keep model configuration serializable;
expose training history and inference metadata;
document tensor shapes and scaling conventions;
never silently switch backend in a way that changes numerical results without recording it in metadata;
keep pretrained model downloads explicit.
Example:
1from pycsamt.backends import set_backend
2from pycsamt.agents import Inv2DAgent
3
4set_backend("torch")
5result = Inv2DAgent().execute({
6 "edi_dir": "data/willy",
7 "output_dir": "results/willy_inv2d",
8})
CLI API policy#
The command-line interface is a public API. Users may depend on command names, options, exit codes, output files, and machine-readable output.
When adding or changing a CLI command:
keep command groups aligned with package domains, such as
avg,edi,forward,invert,pipe,site,tdem, andtransform;reuse shared option decorators and parameter types from
pycsamt.api.cli;support
--helpwith concrete examples where possible;return non-zero exit codes for failures;
do not change existing option names without deprecation;
keep Python API and CLI behavior consistent.
Preferred structure:
1# pycsamt/cli/commands/example/run.py
2import click
3
4from pycsamt.api.cli import output_dir_option, verbose_option
5
6@click.command()
7@output_dir_option
8@verbose_option
9def run(output_dir, verbose):
10 """Run the example workflow."""
11 ...
Data and result contracts#
Public workflows should return structured objects rather than unlabelled
tuples. pyCSAMT uses several result styles, including AgentResult,
PipelineResult, APIResult, inversion result objects, and dictionaries
with explicit keys.
For new public APIs, prefer one of these patterns:
dataclass result for domain objects with a stable schema;
AgentResultfor agents;PipelineResultorStepResultfor pipeline execution;APIResultfor application-facing wrappers;xarray, pandas, NumPy, or pathlib objects only when the data type is obvious from the function name and docstring.
Avoid returning long positional tuples from public functions. If a tuple is unavoidable for compatibility, document the order and provide a named alternative.
Result metadata should include:
pyCSAMT version when available;
input paths or source identifiers;
major parameter values;
backend and optional dependency versions when relevant;
warnings and quality flags;
output paths for generated files;
random seed for stochastic workflows.
Docstring and documentation requirements#
A public API is not considered stable until it has documentation.
Minimum documentation for a public function:
one-sentence summary;
parameter section with types, units, and defaults;
return section with shape and type;
raises/warns section when important;
at least one example for workflow-level APIs;
API page entry through autosummary or explicit documentation.
Minimum documentation for a public class:
summary of purpose;
constructor parameters;
important attributes;
method examples;
notes about optional dependencies;
stability label if experimental.
Use the conventions in Docstring Style.
Deprecation policy#
Deprecation is allowed, but silent breakage is not. Use deprecation when a public name, argument, command, return field, or behavior must be replaced.
Required deprecation information:
old name or behavior;
replacement;
version where deprecation starts;
planned removal version;
migration note in changelog or release notes;
test that the warning is emitted.
Runtime warnings should use FutureWarning for user-facing deprecations.
Example:
1import warnings
2
3def old_reader(*args, **kwargs):
4 warnings.warn(
5 "old_reader is deprecated since v2.0.0 and will be removed in "
6 "v2.2.0. Use read_edis instead.",
7 FutureWarning,
8 stacklevel=2,
9 )
10 return read_edis(*args, **kwargs)
Deprecation windows:
API type |
Minimum support window |
|---|---|
Python function, class, or argument |
At least one minor release after warning appears. |
CLI command or option |
At least one minor release, preferably two for common commands. |
Pipeline step code |
Keep as alias for at least two minor releases. |
File format reader behavior |
Keep compatibility unless the old behavior is scientifically wrong or unsafe. Document migration carefully. |
Private API |
No deprecation window required. |
Optional dependency policy#
Optional dependencies must be imported lazily and fail with actionable messages. This applies especially to:
LLM clients: Anthropic, OpenAI, Google Gemini;
neural frameworks: PyTorch, TensorFlow;
GIS/export libraries: GDAL, rasterio, geopandas, shapely;
plotting stacks beyond base matplotlib;
external inversion executables.
Good pattern:
1def run_torch_model(config):
2 try:
3 import torch
4 except ImportError as exc:
5 raise ImportError(
6 "This operation requires PyTorch. Install pycsamt with the "
7 "AI extras or install torch manually."
8 ) from exc
9
10 ...
Do not import optional heavy dependencies in pycsamt.__init__ or in a
facade module unless the dependency is required for base installation.
Testing requirements#
New public APIs need tests at the correct level.
Change type |
Required tests |
|---|---|
New pure function or data class |
Unit tests for normal input, edge cases, and invalid input. |
New reader/writer |
Round-trip or fixture-based tests with small sample files. |
New agent |
Dry-run test, success-path test with small or mocked data, missing optional dependency test, and LLM-disabled test. |
New pipeline step |
Registry lookup test, parameter validation test, execution test, and serialization test if applicable. |
New CLI command |
|
New inversion/backend feature |
Backend availability test plus a small deterministic run or a mocked backend test. |
Deprecation |
Warning test and replacement behavior test. |
Contributor checklist#
Before opening a pull request for a public API change, verify:
1[ ] The public import path is intentional.
2[ ] The name is included in __all__ only where it should be public.
3[ ] Optional dependencies are imported lazily.
4[ ] Inputs, units, shapes, and defaults are documented.
5[ ] Return type is structured and documented.
6[ ] Errors and warnings are actionable.
7[ ] Tests cover normal, edge, and failure paths.
8[ ] CLI behavior is consistent with Python API behavior, if applicable.
9[ ] Agent or pipeline metadata is reproducible, if applicable.
10[ ] Deprecation notes exist for renamed or removed public behavior.
11[ ] Autosummary/API docs build without new warnings.
12[ ] Release notes or changelog mention user-visible changes.
Decision guide#
Use this quick guide when unsure where to put a new feature.
Feature |
Put it here |
|---|---|
Global plotting, style, CLI, agent, or pipeline configuration |
|
A reusable processing operation that can be sequenced |
|
A natural-language or automated workflow component |
|
A declarative workflow composition |
|
A command-line entry point |
|
A specific external inversion engine interface |
|
A scientific inversion abstraction independent of one engine |
|
A format-specific reader or writer |
|
Site, station, profile, coordinate, or survey organization |
|
A compatibility alias from older code |
|
In short#
The public pyCSAMT v2 API should be small at the top level, clear at package boundaries, rich in documentation, conservative about compatibility, and honest about optional dependencies. Internal modules can evolve quickly, but documented public imports are a promise to users building scientific workflows on top of pyCSAMT.