Developer Guide for AMOCatlas
This guide covers how to contribute to AMOCatlas: setting up an environment, adding a new data reader, code standards, and testing.
Contents:
For a step-by-step Git walkthrough see Git for Beginners: Workflow Guide; for CI/CD and releases see Extra GitHub features: Actions & Pages; for maintenance tasks see Project Maintenance Checklist.
Quickstart
# 1. Fork on GitHub, then clone your fork
git clone https://github.com/YOUR_USERNAME/amocatlas.git
cd amocatlas
# 2. Set up a development environment
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements-dev.txt
pip install -e .
# 3. Branch, change, test
git switch -c yourname-feature
pytest -m "not slow"
ruff check . && ruff format .
# 4. Commit and push, then open a PR on GitHub
git commit -am "feat: describe your change"
git push origin yourname-feature
Project overview
AMOCatlas provides unified access to data from AMOC observing arrays and related estimates, standardising variable names, units, and metadata across sources. It creates no new science data: it re-serves the values published by each source with consistent formatting and provenance.
Core architecture
amocatlas/
├── read.py # Recommended API — read.rapid(), read.osnap(), ...
├── readers.py # Legacy API — load_dataset(), load_sample_dataset()
├── reader_utils.py # Shared helpers for the individual readers
├── data_sources/ # One module per array/product (rapid26n.py, osnap55n.py, ...)
├── metadata/ # Per-array YAML metadata + array_schema.json
├── standardise.py # Naming, units, and metadata standardisation
├── contributors.py # Contributor / institution consolidation
├── convert.py # Conversion to the AC1 output format
├── compliance_checker.py# AC1 format compliance checks
├── defaults.py # Default configs and canonical attribute order
├── utilities.py # Downloads, parsing, validation
├── plotters.py # Visualisation (matplotlib + optional PyGMT)
├── tools.py # Analysis / calculation functions
├── writers.py # Data export
├── report.py # Per-dataset report generator
└── logger.py # Structured logging
Data flow: read.rapid() (or the legacy readers.load_dataset("rapid")) resolves the array
name through _get_reader() in readers.py, which calls the matching read_<array>() function in
data_sources/. That reader downloads and caches the source files, standardises them, and returns
one or more xarray.Dataset objects.
Package-level imports
amocatlas/__init__.py imports the submodules (readers, plotters, compliance_checker,
convert, …) so that from amocatlas import compliance_checker works and attributes like
plotters.HAS_PYGMT are reachable without importing each module by its full path.
Development environment
Prerequisites: Python ≥ 3.10, Git, and (optional) PyGMT for publication figures.
git clone https://github.com/AMOCcommunity/amocatlas.git
cd amocatlas
python3 -m venv venv
source venv/bin/activate
pip install -r requirements-dev.txt # runtime + dev tools
pip install -e . # editable install
pytest -m "not slow" # confirm the setup
Tooling: Ruff (linting, import order, and formatting; 88-char lines), pytest (tests + coverage), Sphinx (docs).
PyGMT is optional and can be awkward to install; prefer conda-forge
(conda install pygmt -c conda-forge) or see the
PyGMT install guide. All non-PyGMT functionality
works without it.
Adding a new data reader
This is the most common contribution. To add an array called newarray:
Create the reader
amocatlas/data_sources/newarray.pywith aread_newarray()function that returns a list of standardised datasets:"""Reader for NEWARRAY data.""" import xarray as xr from amocatlas.logger import log_info def read_newarray(source: str | None = None, **kwargs) -> list[xr.Dataset]: """Read NEWARRAY data and return standardised datasets.""" log_info("Loading NEWARRAY data...") # download, parse, standardise return [dataset]
Export it from
amocatlas/data_sources/__init__.py(add the import and list it in__all__).Expose the modern API in
amocatlas/read.py: importread_newarrayfrom.data_sources, add aread.newarray()wrapper following the existing readers, and add"newarray"to__all__. (The legacyreaders.load_datasetAPI is deprecated; new arrays are exposed only throughread.*.)Add metadata at
amocatlas/metadata/newarray.yml(title, contributors, institutions, licence, citation) so the dataset is enriched and passes the schema inmetadata/array_schema.json.Add tests in
tests/(fast, mocked tests plus an optional@pytest.mark.slowintegration test).
Adding visualisation functions
Add plotting functions to amocatlas/plotters.py. PyGMT functions must call _check_pygmt() for a
graceful fallback when PyGMT is absent, return a pygmt.Figure, and stamp the figure with
_add_amocatlas_timestamp(fig).
Code standards
Type hints on all public function parameters and return values.
NumPy-style docstrings on all public functions (Parameters, Returns, and Raises where relevant).
Naming:
snake_casefor functions/variables;ALL_CAPSfor xarray data variables (e.g.MOC,TRANS,MHT,TIME).Line length 88; imports ordered by Ruff.
Units always live in variable attributes, never in variable names. Use the full word
Sverdrup(notSv, which collides with sieverts).Attributes are
lowercase_with_underscores, following OceanSITES conventions, with a few variable-attribute additions adopted from OceanGliders OG1 where they do not conflict with OceanSITES.
Run before committing:
ruff format amocatlas/ tests/
ruff check amocatlas/ tests/
pytest -m "not slow" --cov=amocatlas
Testing
pytest -m "not slow" # fast tests (CI set)
pytest # all tests, incl. slow integration
pytest --cov=amocatlas --cov-report term-missing # coverage
pytest tests/test_readers.py::test_load_sample_dataset_rapid # a single test
Place tests in tests/ named test_*.py. Fast, mocked tests run in CI; mark network/integration
tests with @pytest.mark.slow (excluded from CI, expected before a PR). Use sample datasets for
fast tests:
from amocatlas import readers
def test_load_sample_dataset():
ds = readers.load_sample_dataset("rapid") # raw sample, original variable names
assert ds is not None
assert "time" in ds.variables
CI runs the fast tests on Windows, macOS, and Linux across supported Python versions on pull
requests and pushes to main; see the Actions tab for results.
Git workflow
Full step-by-step instructions (with screenshots) are in Git for Beginners: Workflow Guide. In short:
# One-time: point at the upstream repo
git remote add upstream https://github.com/AMOCcommunity/amocatlas.git
# Keep your fork current
git switch main && git fetch upstream && git merge upstream/main && git push origin main
# Work on a branch, never on main
git switch -c fix-osnap-metadata
Use conventional commit prefixes in commit messages:
feat:, fix:, docs:, style:, refactor:, test:, chore:. Push your branch and open a PR
targeting AMOCcommunity/amocatlas:main; address review feedback, then merge once approved.