Coding Guidelines#
This document describes the coding guidelines for the project.
In general, the simtools project follows the PEP8 style. It uses the same guidelines outlined in the ctapipe style guide and code guidelines
Automatic Formatting#
Linting and code checks are done automatically using the pre-commit functionality using isort
,
black
and pyflakes
. As part of the CI workflow Codacy performs a few additional code checks.
It is recommended for developers to install pre-commit
:
pre-commit install
The configuration of pre-commit
is defined in
.pre-commit-config.yaml.
For testing, pre-commit can be applied locally without commit:
pre-commit run --all-files
In rare cases, one might want to skip pre-commit checks with
git commit --no-verify
Code Linting#
Linters of almost all file types are run by the CI-linter workflow.
To run pylint locally, use:
pylint $(git ls-files 'simtools/*.py')
To run ruff locally, use:
ruff check
Note the options defined in pyproject.toml for both ruff and pylint.
API documentation#
Docstrings following the Numpy style must be added to any public function, class or method. It is also recommended to add docstrings-like comments to private functions.
In applications, the modules should contain docstrings with a general description, command-line parameters, and examples. A typical example should look like:
def a_function(parameter):
"""
Description of what the function is doing.
Parameters
----------
parameter: type
description of parameters
Returns
-------
describe return values
Raises
------
describe exceptions raised
"""
...code
For reference see the numpydoc format documentation.
Logging#
Sufficient logging information should be provided to users and developers. As general guideline, the following logging levels should be used:
INFO: information useful for the general user about the progress, intermediate results, input or output.
WARNING: information for the general user or developer on something they should know but cannot change.
DEBUG: information only interesting for developers or useful for debugging.
ERROR: something which always leads to an exception or program exit.
Use logger.error, logger.warning, logger.debug, logger.info
.
Naming#
Telescope Names#
The telescope names as used by simtools follow the pattern “Site-Class-Type”, where:
“Site” is either “North” or “South”;
“Class” is either “LST”, “MST”, “SCT” or “SST”;
“Type” is a single number ONLY in case of a real telescope existing at the site or a string containing a “D” in case of any other telescope design.
For example:
“North-LST-1” is the first LST commissioned at the La Palma site, while “North-LST-D234” is the current design of the further 3 LSTs.
“North-MST-FlashCam-D” and “North-MST-NectarCam-D” are the two MST designs containing different cameras.
Any input telescope names can (and should) be validated by the function validate_array_element_name (see module utils.names). For the Site field, any different capitalization (e.g “south”) or site names like “paranal” and “lapalma” will be accepted and converted to the standard ones. The same applies to the Class field. For the Type field, any string will be accepted and a selected list of variations will be converted to the standard ones.
Validating names#
Names that are recurrently used along the the package should be validated when given as input. Examples of names are: telescope, site, camera, model version. The functionalities to validate names are found in utils.names. The function _validate_name receives the input string and a name dictionary, that is usually called all_something_names. This dictionary contain the possible names (as keys) and lists of allowed alternatives names as values. In case the input name is found in one of the lists, the key is returned.
The name dictionaries are also defined in util.names. One should also define specific functions named validate_something_names that call the _validate_name with the proper name dictionary. This is only meant to provide a clear interface.
This is an example of a name dictionary:
all_site_names = {
"South": ["paranal", "south"],
"North": ["lapalma", "north"]
}
And this is an example of how the site name is validated in the telescope_model module:
self.site = names.validate_site_name(site)
where site was given as parameter to the TelescopeModel::__init__
function.