Contributing¶
Branching model¶
mainReleased, stable code. Documentation published to GitHub Pages is built from this branch.
devIntegration branch. Feature branches merge here first, and
devis merged intomainwhen a release is cut.- Feature branches
Named after the issue they address, e.g.
30-read-the-docs-hook-up. Branch fromdevand open the pull request againstdev.
Making a change¶
Open (or claim) an issue describing the change.
Branch from
dev.Make the change, with tests for anything that could regress.
Run the checks locally:
pytest ruff check . ruff format .
See Testing and Code style for what these enforce.
Update the documentation if behaviour or configuration keys changed, and add an entry to the
Unreleasedsection ofCHANGELOG.md.Open a pull request against
devand reference the issue.
Every pull request runs the test suite, the lint and format checks, and a documentation build. All three must pass.
Coding conventions¶
Formatting and lint rules are enforced by ruff and described in Code style. Beyond what a linter can check, the codebase follows a few consistent patterns. Match them rather than the style you would choose in a new project:
Class names are lowerCamelCase (
tomographicReconstructor,dmParameters). This is unusual for Python but consistent throughout, and changing it would break every existing configuration script. The naming lint rules are switched off for this reason.Parameters are validated in property setters. Each configuration class exposes properties that raise
TypeErrorfor the wrong type andValueErrorfor out-of-range values, with a message naming the parameter. New configuration keys should follow suit.Derived quantities are properties, not stored state, so that changing an input updates everything downstream (
atmParams.r0recomputes fromr0_zenithand the zenith angle each time it is read).Docstrings are NumPy style —
Parameters,Returns,Raises,Notessections with underlines. These are rendered directly into API reference, so a good docstring is a documentation contribution.Logging, not printing. Use the module-level
logger; the reconstructor threads a logger through to the fitting object.CPU and GPU kernels stay in lockstep.
tomographyUtilsCPUandtomographyUtilsGPUexpose the same private function names and signatures; a change to one needs the matching change in the other.Module names never collide with the classes they define.
pyTomoAO.reconstructordefinestomographicReconstructorandpyTomoAO.dm_fittingdefinesfitting, so bothfrom pyTomoAO import fitting(the class, re-exported) andimport pyTomoAO.dm_fitting(the module) mean what they look like. Keep it that way when adding a module: a module that shares its name with one of its classes shadows it in the package namespace, which breaksunittest.mockstring targets andimportlibalike.
Adding a configuration parameter¶
Add the key to the relevant
*ParametersClass, with a validating property setter.Read it in that class’s
_initialize_properties.Add it to the
__str__output so it shows up when a user prints the object.Document it in Configuration reference, including units and the valid range.
Add it to the example configurations under
examples/benchmark/if it is not optional.Note it in the
Unreleasedsection ofCHANGELOG.md.
Reporting a bug¶
Useful bug reports include:
The configuration file, or the part of it that matters.
The full traceback.
Whether CUDA was detected — the log line emitted at import when logging is enabled at
INFO(logging.basicConfig(level=logging.INFO)).pyTomoAO.__version__, NumPy version, and Python version.
Sandbox scripts¶
sandbox/ holds exploratory work — comparison scripts, prototypes for SLODAR, WFS map
utilities. It is deliberately outside the package and is not tested or packaged. Anything
there that becomes load-bearing should move into pyTomoAO/ with tests.