documentation/PYGUIDE.md

176 lines
4.8 KiB
Markdown
Raw Normal View History

2022-11-14 14:15:37 -05:00
# Cerc Python Style Guide
## What's coding style and why it matters.
Coding style is just how the code looks, it's incredibly personal, and everyone has their style.
Your preferred architectures, variable and function naming style all of then impacts in your code style and how the others read and understand it, so it could become a significant burden if everyone is coding on his or her own.
At CERC, we are following the [PEP8](https://www.python.org/dev/peps/pep-0008/) with two spaces indentation instead of four.
## Tools.
We use [PyCharm](https://www.jetbrains.com/pycharm/) as an integrated development environment and follow the tool's overall advice but the space indentation, which we set to two spaces instead of default four spaces.
For code analysis, we enforce the usage of [pylint](https://www.pylint.org/) with our own [custom style definition](pylintrc). This file will be downloaded with the project the first time you clone it.
## Naming convention.
* Name your folders and files in lowercase and use _ (underscore) to separate words.
* Your class names must start in capital letters and follow the python CapWords pattern.
* Methods and properties that return lists must end in "s". Therefore, those that return single values, must be singular.
* Methods and variables should be lowercase and use _ (underscore) as a word separator.
* Constant names must be all capitals.
* Avoid the usage of "get_" and "set_" methods whenever it is possible, use @property and @variable.setter decorators instead.
* "Private" methods, variables and properties start with _ (underscore).
## Imports.
Place your imports at the top of the file, after the license and contact information
comment.
```python
"""
MyClass module
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Concordia CERC group
Project Coder name name@concordia.ca
"""
import sys
```
Ensure that your imports are used and remove any unused.
## Object attributes and methods.
Use properties whenever it is possible. Encapsulate the access to all the calculated object attributes to avoid recalculating each time the property is called.
```python
@property
def object_attribute(self):
if self._object_attribute is None:
self._object_attribute = ...
...
return self._object_attribute
```
And like in the following example for read and write properties:
```python
@property
def object_changeable_attribute(self):
return self._object_changeable_attribute
@object_changeable_attribute.setter
def object_changeable_attribute(self, value):
self._object_changeable_attribute = value
```
If your method or attribute returns a complex object, use type hints as in this example:
```python
@property
def complex_object(self) -> ComplexObject:
return self._object_changeable_attribute
def new_complex_object(self, first_param, second_param) -> ComplexObject:
other_needed_property = self.other_needed_property
return ComplexObject(first_param, second_param, other_needed_property)
```
Always access your variable through the method and avoid to access directly.
```python
@property
def object_attribute(self):
return self._object_attribute
def operation(self, first_param, second_param):
return self.object_attribute * 2
```
### Comments.
#### Code documentation.
All public classes, properties, and methods must have code comments. Code comments start with capital letters and end without period:
```python
class MyClass
"""
MyClass class perform models class operations
"""
def __init__(self):
@property
def object_attribute(self):
"""
Get my class object attribute
:return: int
"""
return self._object_attribute
def operation(self, first_param, second_param):
"""
Multiplies object_attribute by two
:return: int
"""
return self.object_attribute * 2
```
Comments at getters and setters always start with Get and Set, and identity the type of variable at return (at getter) or the value (at setter):
```python
@property
def object_attribute(self):
"""
Get object attribute
:return: int
"""
return self._object_attribute
@object_attribute.setter
def object_attribute(self, value):
"""
Set object attribute
:param value: int
"""
self._object_attribute = value
```
Attributes with known units should be explicit in method's comment.
```python
@property
def distance(self):
"""
My class distance in meters
:return: float
"""
return self._distance
```
#### To do's.
Pending to implement operations should be indicated with todo comments to highlight the missing functionality.
```python
# todo: right now extracted at the city level, in the future should be extracted also at building level if exist
```