Developer Guide

This section contains some rules and best practices developers for rivapy should consider. It is not meant to be a strict rule set and there may be good reasons why someone decides to deviate from some rule. But please think about the points here when developing. And if you think one of the rules should be modified or deleted, just rais an issue ;-)

Styleguide

We try to follow the Google Python Style Guide writing the code. We cite some of the points in the aformentioned document that we think are most relevant for developers of rivapy in the following but if you are interested in more depth, read the original document.

Imports

Use import statements for packages and modules only, not for individual types, classes, or functions. Exemptions from this rule: Symbols from typing may be directly imported

Type Annotation

Use type annotation with type hints from the module typing for function or method arguments and return types. You may also use it to declare a type of a variable. Use type checkers like pytype during development (for VSCode users we recommend to enable the built-in type checking tool).

Docstrings

Python uses docstrings to document code. A docstring is a string that is the first statement in a package, module, class or function. A docstring is mandatory for every function or method that has one or more of the following properties:

  • being part of the public API

  • nontrivial size

  • non-obvious logic

The docstring of class constructors describe also the principle working of the class and it should the thoroughly documented. As a sample docstring, we provide a template by the documentation of the

class rivapy.tools.example_docstring.DocStringExample(a: int, b: float)[source]

Example for a docstring. Here a short description

Here you may write a longer description of class functionality. It may include formulas such as

Parameters:
  • a (int) – _description_

  • b (float) – _description_

Note

Here you can insert soem note, such as: Be careful, it may be dangerous, see rivapy.marketdata.DiscountCurve.

See also

Refer to other places where one may find this class or refer to classes simliar to this one (e.g. rivapy.marketdata.DiscountCurve).

Example

>>> depp = DocStringExample(1.0,2.0)

TODO Comments

Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect.

Naming

module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_CONSTANT_NAME, global_var_name, instance_var_name, function_parameter_name, local_var_name, query_proper_noun_for_thing, send_acronym_via_https.

Function names, variable names, and filenames should be descriptive; avoid abbreviation. In particular, do not use abbreviations that are ambiguous or unfamiliar to readers outside your project, and do not abbreviate by deleting letters within a word.

Unit Testing

Please write as many unittests as possible. The tests are located in the folder tests and use the python unittest framework.

Logging

For logging functions that expect a pattern-string (with %-placeholders) as their first argument: Always call them with a string literal (not an f-string!) as their first argument with pattern-parameters as subsequent arguments.

To log, just import the logger from the _logger.py file in the respective module you are currently developing for. So, if you are currently working in rivapy.pricing, just use the following line in your file

>>> from rivapy.pricing._logger import logger

to retrieve the correct logger.

Logging Usage

The rivapy package provides logging using the standard python logging module. Here, a separate logger for each submodule exists:

  • rivapy.instruments

  • rivapy.marketdata

  • rivapy.models

  • rivapy.numerics

  • rivapy.pricing

  • rivapy.sample_data

  • rivapy.tools

So if you just want to switch on logging globally, you may just use the usual logic

>>> import logging
>>> logging.basicConfig(level=logging.DEBUG, format="%(asctime)s  - %(levelname)s - %(filename)s:%(lineno)s - %(message)s ")

In some circumstances, it may be useful to set different loglevels for the different modules. Here, one can use the usual logic, e.g.

>>> logger = logging.getLogger('rivapy.pricing')
>>> logger.setLevel(logging.ERROR)

to set the loglevel of the rivapy.pricing module.