Development¶
Coding style¶
DTCC Platform uses the coding style native to each language or domain. This means, e.g., following the Style Guide for Python code and the C++ Core Guidelines for C++ code.
The following table summarizes the naming conventions used for DTCC Platform.
Python |
C++ |
JavaScript |
|
---|---|---|---|
Variable |
|
|
|
Function |
|
|
|
Class |
|
|
|
Module |
|
In addition to this, DTCC Platform uses kebab-case
for naming API
endpoints, branches and scripts. For JSON snake_case
is used.
Scripts and binaries that are installed on the system should be named
dtcc-foo-bar
. Scripts that are not installed on the system
(typically small utility scripts) should be named foo-bar
(without
dtcc-
).
Code formatting¶
For Python code we use the Black formatter. All Python code should be run through Black with default settings before committing. or instructions on how to set it up for Visual Studio Code, see for example these instructions.
Git practices¶
DTCC Platform uses the following Git practices:
The main (release) branch is named
main
.The development branch is named
develop
.All work should take place in separate branches (not directly in
develop
and certainly not inmain
).Branches for development (new features) should be named
dev/branch-name
wherebranch-name
is a free form descriptive name.Branches for fixes (bugs, small things) should be named
fix/branch-name
wherebranch-name
is a free form descriptive name.Branches that will (likely) not be merged but kept for reference should be named
old/branch-name
wherebranch-name
is a free form descriptive name.Note that hypens should be used for naming (not underscore).
When the work is done, make a pull request for merging the branch into
develop
.When the work has been merged, the branch should be deleted to keep things tidy.
When making a release,
develop
is merged intomain
and a release is made frommain
.
Versioning¶
DTCC Platform uses semantic versioning (SemVer). It uses a three-part number system in the format of MAJOR.MINOR.PATCH, where:
MAJOR version is incremented for incompatible API changes.
MINOR version is incremented for new features that are backwards-compatible.
PATCH version is incremented for backwards-compatible bug fixes.
The version number is set in the pyproject.toml
file for each repo.
During early development (before the release of 1.0.0) API changes are expected to happen often and will not lead to incrementation of the MAJOR number (which stays at 0). During this phase, the MINOR number will work in the same way as the MAJOR version; that is, the MINOR number should be incremented for incompatible API changes. Note that the MINOR number may then advance well beyond 9 (e.g. 0.29.1, 0.31.3, etc) before we release 1.0.0.
During early development, the MINOR number should stay the same for all projects (repos) and post 1.0.0, the MAJOR number should stay the same.
Releasing new versions¶
New versions should be released from the main
branch (after develop
) has been merged into main
. The following steps should be taken:
Update the version number in
pyproject.toml
.Set the correct dependencies in
pyproject.toml
. Note that dependencies should be to released versions of all DTCC packages (not Git branches).Commit the changes with commit message
Release version X.Y.Z
.Add a tag with the version number:
git tag vX.Y.Z
… pypi, announce, etc.
@vasilis: Please expand these instructions.
Writing documentation¶
Documentation is automatically extracted (by Sphinx) from Python docstrings. ChatGPT can assist in writing the docstrings. The following prompt can be helpful when generating the docstrings:
I want you to generate docstrings for Python code. The docstrings should
be consice, consistent, and informative. The docstrings should be in the
format of the Sphinx documentation system (restructured text) and follow
NumPy docstring style according to the following templates from the page
https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html:
def function_with_types_in_docstring(param1, param2):
"""Example function with types documented in the docstring.
:pep:`484` type annotations are supported. If attribute, parameter, and
return types are annotated according to `PEP 484`_, they do not need to be
included in the docstring:
Parameters
----------
param1 : int
The first parameter.
param2 : str
The second parameter.
Returns
-------
bool
True if successful, False otherwise.
"""
def function_with_pep484_type_annotations(param1: int, param2: str) -> bool:
"""Example function with PEP 484 type annotations.
The return type must be duplicated in the docstring to comply
with the NumPy docstring style.
Parameters
----------
param1
The first parameter.
param2
The second parameter.
Returns
-------
bool
True if successful, False otherwise.
"""
class ExampleClass:
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they may be documented here
in an ``Attributes`` section and follow the same formatting as a
function's ``Args`` section. Alternatively, attributes may be documented
inline with the attribute's declaration (see __init__ method below).
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
Attributes
----------
attr1 : str
Description of `attr1`.
attr2 : :obj:`int`, optional
Description of `attr2`.
"""
def __init__(self, param1, param2, param3):
"""Example of docstring on the __init__ method.
The __init__ method may be documented in either the class level
docstring, or as a docstring on the __init__ method itself.
Either form is acceptable, but the two should not be mixed. Choose one
convention to document the __init__ method and be consistent with it.
Note
----
Do not include the `self` parameter in the ``Parameters`` section.
Parameters
----------
param1 : str
Description of `param1`.
param2 : list(str)
Description of `param2`. Multiple
lines are supported.
param3 : :obj:`int`, optional
Description of `param3`.
"""
self.attr1 = param1
self.attr2 = param2
self.attr3 = param3 #: Doc comment *inline* with attribute
#: list(str): Doc comment *before* attribute, with type specified
self.attr4 = ["attr4"]
self.attr5 = None
"""str: Docstring *after* attribute, with type specified."""
def example_method(self, param1, param2):
"""Class methods are similar to regular functions.
Note
----
Do not include the `self` parameter in the ``Parameters`` section.
Parameters
----------
param1
The first parameter.
param2
The second parameter.
Returns
-------
bool
True if successful, False otherwise.
"""
return True
In summary, the docstrings should be formatted as follows:
For classes:
* Start with a short description (one line).
* Then give a detailed description over several lines (if possible).
* List attributes under the Attributes section.
For functions:
* Start with a short description (one line).
* List parameters under the Parameters section.
* Detail the return type and its description under the Returns section (if there's a return value).
For methods:
* Start with a short description (one line).
* List parameters under the Parameters section (excluding self for class methods).
* Detail the return type and its description under the Returns section (if there's a return value).
For properties:
* Start with a short description (one line).
* Detail the return type and its description under the Returns section.
I will supply a number of functions and class definitions and want you to return
the corresponding docstrings. Please provide docstrings for all the provided
code (not just some of it) and don't forget to document class attributes under
the Attributes section.
Use ChatGPT to generate the docstrings but make sure to check that the docstrings make sense and are consistent with the templates above. Also be careful to only copy the docstrings into the code (don’t modify the code itself).
Generating the UML class diagrams¶
The UML class diagrams are stored as part of the top-level dtcc
package in the files docs/images/uml_diagram_*.rst
.
To update the diagrams after changes to the
data model (implemented as part of the dtcc-model
package), run the
following command in the dtcc-model
repository:
utils/generate-uml-diagrams
Note that pylint
must be installed for this to work. This will
generate .puml
files in the current directory.
Go to the online PlantUML
server. For each of the .puml
files, copy the contents into the
text box to generate the UML diagram. Click the SVG button and
download the SVG file. Rename and move the file to docs/images/
in
the dtcc
repo.
Tips & tricks¶
Remote development in VS Code¶
In the left-side menu, go to Remote Explorer and press the + sign on the SSH line. Add your SSH connection in the following format:
user@develop.dtcc.chalmers.se
This should add the develop server to the connection list and you may connect to it by clicking on the right arrow next to its name.
You may then open files on the remote server using the regular Open command. You may also open a remote terminal using the top menu: Terminal –> New Terminal.
Handling line endings on Windows¶
If you are using Windows, you might want to make sure that Git does not convert Unix-style file endings on checkout. This can be accomplished by:
git config --global dtcc-builder.autocrlf false