def add_numbers(*args):
return sum(args)
Contribute
ReLax
This library uses nbdev for development. We love great flexibility offered by jupyter notebook, and nbdev in addressing limitations of using Notebook in developing large-scale projects (e.g., sync between notebooks and python modules, documentations).
Here, we only cover basis of our development procedure. For an in-depth use of nbdev, please refer to the nbdev tutorial. Following links are particularly useful:
Set up the working environment
Refer to installation guidance for installing ReLax. For running ReLax
in CPU, you should
pip install "jax-relax[dev]"
Next, install Quarto for the documentation system. See nbdev docs for more details.
nbdev_install_quarto
Next, install hooks for cleaning Jupyter Notebooks.
nbdev_install_hooks
Write Code in Jupyter Notebook
Note that nbdev provides a best practice guidline to writing code in Jupyter Notebooks. Here, we present some of the most important steps.
Export Cell to Python Module
#| export
marks code cells (in Notebook; .ipynb
) to be exported to Python Module (.py
). By default, this cell will be exported to the file defined in #| default_exp file_name
(usually presented upfront).
For example, the below function will be exported to the Python module.
#| export
def func(args):
...
We can also specify files to be exported.
#| export file_name.py
def func(args):
...
For private functions/objects, we can use #| exporti
. In this way, the code will still be exported to the file, but not included in __all__
.
More about directives.
Two-way Sync between Notebooks (.ipynb
) and Python Code (.py
)
To update code written in Jupyter Notebook to Python Module (i.e., .ipynb
-> .py
)
nbdev_export
To sync code updated in Python Module back to Jupyter Notebook (i.e., .py
-> .ipynb
)
nbdev_update
If you write a new function/object in .py
, nbdev_update
will not include this function in __all__
. The best practice is to write functions/objects in Jupyter Notebook, and debug in Python Module (via IDE).
Code Style
ReLax
follows the black code style. See black’s code style document.
Write Test Cases in Jupyter Notebook
It is desirable to write some unit tests for each function and object. nbdev recommends to write test cases after implementing a feature. A normal cell is considered for testing.
For example, let’s consider a function which adds up all the inputs:
To test this function, we write unit tests via assert
.
# check correctness
assert add_numbers(1, 2, 3) == 6
# check types
assert type(add_numbers(1, 2, 3)) == int
assert type(add_numbers(1., 2, 3)) == float
Note that all the test cases should be quickly run. If a cell takes a long time to run (e.g., model training), mark the cell as #| eval: false
to skip this cell.
Write Documentations in Jupyter Notebook
Doc string
To write documentations in nbdev, it is recommended to
- use simple type annotations
- describe each arguments with short comments
- provide code examples and explanations in separate cells
Union typing is introduced after Python 3.10. For Python 3.7 - 3.9 users, you should
from __future__ import annotations
def validate_configs(
dict|BaseParser, # A configuration of the model/data.
configs: # The desired configuration class.
config_cls: BaseParser -> BaseParser:
) """return a valid configuration object."""
...
nbdev will automatically render the documentation:
validate_configs
validate_configs (configs, config_cls)
return a valid configuration object.
Parameters:
- configs (
dict | BaseParser
) – A configuration of the model/data. - config_cls (
BaseParser
) – The desired configuration class.
Returns:
(BaseParser
)
Next, we elaborate the use of this function with more descriptions and code examples.
We define a configuration object (which inherent BaseParser
) to manage training/model/data configurations. validate_configs
ensures to return the designated configuration object.
For example, we define a configuration object:
class LearningConfigs(BaseParser):
float lr:
A configuration can be LearningConfigs
, or the raw data in dictionary.
= dict(lr=0.01) configs
validate_configs
will return a designated configuration object.
validate_configs(configs, LearningConfigs)
LearningConfigs(lr=0.01)
Callout
We can also use callout for clear documentations.
:::{.callout-note}
Note that there are five types of callouts, including:`note`, `warning`, `important`, `tip`, and `caution`.
:::
which renders:
Note that there are five types of callouts, including: note
, warning
, important
, tip
, and caution
.
Preparing a Code Commit
Preview the documentation system
nbdev_preview
If everything is in your satisfaction, prepare code before commit to GitHub
nbdev_prepare
Summary
- Install all required packages based on installation guidance
- Install the git hook
nbdev_install_hooks
- Write code in Jupyter Notebooks; add approprate directives, e.g.,
#| export
- Write tests after the code in the Notebooks; test the code via
nbdev_test
- Write documents directly in the Notebooks; preview the docs
nbdev_preview
- Prepare changes with
nbdev_prepare
- Create pull requests and push changes to GitHub