If you:
- 💥 want to report a bug with ampycloud: jump here.
- ❓ have a question about ampycloud: jump here instead.
- 👷 want to contribute to ampycloud, read on !
- Code of conduct
- Scope
- Essential things to know about ampycloud for dev work
- Less-Essential things to know about ampycloud for dev work
This project and everyone participating in it is governed by the ampycloud Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to [email protected].
Please be sure to read (and understand the implications) of the scope of ampycloud.
ampycloud is being developed in a public repository under the MeteoSwiss organization on Github. The documentation, generated using Sphinx, is hosted as Github Pages on the gh-pages
branch of the repo, and is visible at https://MeteoSwiss.github.io/ampycloud.
Please make sure to read the instructions below carefully. In addition, please add your name to the software part of the citation file at the latest before triggering a release(the top part defines the citation for the software, the bottom part defines the citation of the scientific article) and make sure to properly update the CHANGELOG and the documentation if necessary.
The develop
branch is the default one, where all contributions get merged. When a new release is
warranted, a Pull Request to the master
branch is issued. This implies that the master
branch
will always reflect the state of the latest release of the code.
Contributors are required to work in their own branches, and issue Pull Requests into the develop
branch when appropriate.
The master
, develop
, and gh-pages
branches are all protected.
If you intend to actively contribute to ampycloud, you ought to clone the develop
branch of the
repository, and install it from source. In a terminal:
git clone -b develop [email protected]:MeteoSwiss/ampycloud.git some_folder
cd some_folder
pip install -e .[dev]
Note the use of [dev]
to also install the dependencies required for dev work (i.e. sphinx
, pylint
, etc ...).
zsh: no matches found: .[dev]
, add some quotes as follows:
pip install -e '.[dev]'
Automated CI/CD checks are triggered upon Pull Requests being issued towards the develop
and
master
branches. At the time being, they are implemented using dedicated Github Actions specified under .github/workflows
. These checks include:
- code linting using
pylint
- code testing using
pytest
- check that the base computational speed is ok
- check that the CHANGELOG was updated
- check that the Sphinx docs compile
- automatic publication of the Sphinx docs (for a PR to
master
only) - check that the code version was incremented (for PR to
master
only)
To test the latest release of the code with the latest Python developments, a pytest-weekly
workflow runs the
ampycloud tests twice a week using the latest version of Python and of the ampycloud dependencies.
master
branch. Pushing a bug fix to develop
will not be sufficient to make it turn green - a new code release is necessary !
There is another Github action responsible for publishing the code onto pypi, that gets triggered upon a new release or pre-release being published. See the ampycloud release mechanisms for details.
- The following pylint error codes are forbidden in ampycloud:
E, C0303, C0304, C0112, C0114, C0115, C0116, C0411, W0611, W0612.
Every Pull Request todevelop
andmaster
is automatically linted, and these codes will be flagged accordingly. - There is no "automated black formatting" implemented in the repo by choice. We believe that it is up to the contributors to ensure that the quality of their code meets the required standards enforced by the Github Action in this repo.
- We encourage contributors to follow PEP8 as closely as possible/reasonable. You should check
often how well you are doing using the command
pylint some_modified_file.py
.
No handlers/formatters are being defined in ampycloud, with the exception of a NullHandler()
for
when users do not specify any logging handler explicitly. In other words, it is up to the
ampycloud users to decide what logging they wish to see, if any.
Specifically:
-
a dedicated logger gets instantiated in each ampycloud module via:
import logging logger = logging.getLogger(__name__)
-
log calls are then simply done via this module logger:
logger.debug('...') logger.info('...') logger.warning('...') logger.error('...')
-
the function
ampycloud.logger.log_func_call()
can be used to decorate ampycloud functions and automatically log their call at theINFO
level, and the arguments at theDEBUG
level, e.g.:import logging from .logger import log_func_call logger=logging.getLogger(__name__) @log_func_call(logger) some_fct(*args, *kwargs): ...
The class AmpycloudError
defined in errors.py
is a child of the canonical Python Exception
class, and is meant as a general exception for ampycloud. Using it is straightforward:
from .errors import AmpycloudError
raise AmpycloudError('...')
There is also a custom AmpycloudWarning
class for the package, which is a simple child of the
Warning
class. Using it is also simple:
import warnings
from .errors import AmpycloudWarning
warnings.warn('...', AmpycloudWarning)
... should be used in ampycloud. Here's an example:
from typing import Union
from pathlib import Path
def set_prms(pth : Union[str, Path]) -> None:
""" ... """
See the official Python documentation for more info.
Google Style ! Please try to stick to the following example. Note the use of :py:class:...
(or :py:func:...
, py:mod:...
etc ...) with relative import to cleanly link to our own
functions, classes, etc ... :
""" A brief one-liner description in present tense, that finishes with a dot.
Args:
x (float|int): variable x could be of 2 types ... note the use of `|` to say that !
- *float*: x could be a float
- *int*: x could also be an int
y (list[str]|str, optional): variable y info
Returns:
:py:class:`.data.CeiloChunk`: more lorem ipsum ...
Raises:
:py:exc:`.errors.AmpycloudError`: if blah and blah occurs.
Use some
multi-line space for
more detailed info. Refer to the whole module as :py:mod:`ampycloud`.
Do all this **after** the Args, Returns, and Raises sections !
Example:
If needed, you can specify chunks of code using code blocks::
def some_function():
print('hurray!')
Note:
`Source <https://github.com/sphinx-doc/sphinx/issues/3921>`__
Please note the double _ _ after the link !
Important:
Something you're hoping users will read ...
Caution:
Something you're hoping users will read carefully ...
"""
You should of course feel free to use more of the tools offered by sphinx, napoleon, and Google Doc Strings. But if you do, please make sure there are no errors upon generating the docs !
There is a scientific article about the ampycloud algorithm v2.0.0. It complements the Sphinx documentation that contains all the important elements required to use the ampycloud Python package. Scientific changes on top of version v2.0.0 must be added to the corresponding section in the docs.
The Sphinx documentation can be generated manually as follows:
cd ./where/you/placed/ampycloud/docs
sh build_docs.sh
This will create the .html
pages of the compiled documentation under ./build
. In particular,
this bash script will automatically update the help message from the high-level ampycloud entry
point ampycloud_speed_test
, create the demo figure for the main page, compile and ingest all the
docstrings, etc ... . See the ampycloud release mechanisms for more info about
the automated publication of the documentation upon new releases.
A series of test functions are implemented under test
. Their structure mimics that of the module
itself, and they are meant to be used with pytest. To run them all, simply type pytest
in a
terminal from the package root. If you only want to run a specific set of tests, type
pytest test/ampycloud/module/to/test_...py
.
In order to test the different plotting styles without affecting the automated tests on Github
(which cannot do so because they have no access to a local LaTeX installation), a nifty fixture is
defined in conftext.py
, that allows to feed a specific command line argument to the pytest call:
pytest --MPL_STYLE=latex
Doing so, the users can easily test the dynamic.MPL_STYLE
of their choice, e.g. base
, latex
,
or metsymb
.
The tests defined under test/ampycloud/test_scientific_stability.py
are meant to catch any unexpected alteration of the scientific behavior of ampycloud. Specifically, they process real
datasets of reference, and check whether the computed METARs are as expected. The reference
datasets are provided as CSV files under test/ampycloud/ref_dat
. The idea is to keep
this list of scientific tests as short as possible, but as complete as necessary.
If one of these tests fail, it is possible to generate the corresponding diagnostic plot with the following fixture-argument:
pytest --DO_SCIPLOTS
Because the devs care about the look of plots, ampycloud ships with specific matplotlib styles that
will get used by default. For this to work as intended, any plotting function must be wrapped with
the plots.utils.set_mplstyle
decorator, as follows:
# Import from Python
import logging
# Import from this module
from ..logger import log_func_call
from .utils import set_mplstyle
# Instantiate the module logger
logger = logging.getLogger(__name__)
@set_mplstyle
@log_func_call(logger)
def some_plot_function(...):
...
@set_mplstyle
decorator goes above the @log_func_call()
decorator.
With this decorator, all functions will automatically deploy the effects associated to the value of dynamic.AMPYCLOUD_PRMS['MPL_STYLE']
which can take one of the following values:
['base', 'latex', 'metsymb']
.
When changes merged in the develop
branch are stable and deemed worthy, follow these steps to
create a new release of ampycloud:
-
Create a PR from
develop
tomaster
.⚠️ Merge only if all checks pass, including the version check !✅ The live ampycloud documentation will be automatically updated (via the
CI_docs_build_and_publish.yml
Action) when the PR tomaster
is merged. -
Manually create a new release from Github.
⚠️ Make sure to issue it from themaster
branch !⚠️ Make sure to set the same version number as set in the code !✅ The code will be automatically pushed onto pypi (via the
CI_pypi.yml
Action) when the release is published. This will work the same for pre-releases.😏 Side note for (test)pypi: ampycloud will be published under the MeteoSwiss account using an API token. The token is stored as an organization-level Github secret.
-
That's it ! Wait a few seconds/minutes, and you'll see the updates:
- on the release page,
- in the README tags,
- on testpypi and pypi,
- on the
gh-pages
branch, - in the live documentation, and
- on Zenodo (for which the connection to this repo is enabled from Zenodo itself, by the admins of the MeteoSwiss organization on Github).
The ampycloud copyright years may need to be updated if the development goes on beyond 2022 (which it already has 😉). If so, the copyright years will need to be manually updated in the following locations:
docs/source/substitutions.rst
(the copyright tag)docs/source/conf.py
(thecopyright
variable)docs/source/license.rst
README.md
(the copyright section)
The copyright years are also present in all the docstring modules. These can be updated individually if/when a modification is made to a given module.