Code Contributions
Note
For the proper way of contributing code to COMPAS, please follow the Development Workflow.
To keep code clean, consistent and readable we try to follow the following guidelines when developing COMPAS. Generally, we try to follow the PEP8 style guide for Python code.
Naming conventions
Note
When naming variables, functions, classes and modules it is important to take the time and choose meaningful names. Names should be short but descriptive and ideally unambiguous in the field they are intended to be used.
Classes should be named using the CamelCase
convention
class MyClass(object):
...
Functions, methods, arguments and local/member variables should be named using the snake_case
convention
def my_function():
...
def add(self, x, y):
result = x + y
return result
Functions, methods and member variables which are intended for internal use only should be prefixed with an _
(underscore)
class Rectangle(object):
def __init__(self, width, lentgh):
self._width = width
self._length = length
self._area = None
self._init_class()
def _init_class():
self._area = self._width * self._length
@staticmethod
def _some_helper_function():
...
Class attributes should be named using all caps and underscores
class MyClass(object):
MY_CONSTANT = 42
def __init__(self):
self.my_attribute = 0
def my_method(self):
return self.my_attribute + self.MY_CONSTANT
Line length
COMPAS uses a line length of 120 characters. While longer than the 80 characters recommended by PEP8
, it is in our opinion a more reasonable limit for modern displays.
This is enforced and can be automatically set using black -l 120
.
Indentations are 4 spaces. Tab to spaces setting can be set in .editorconfig
which is respected by most editors. For more information see EditorConfig.
Imports
Imports are grouped in the following order with a blank line between each group:
Python standard library imports
Third party imports
Local application imports
Single-item imports are preferred over multi-item imports
# use:
from compas.geometry import Frame
from compas.geometry import Point
# instead of:
from compas.geometry import Frame, Point
Star (*
) imports should be avoided.
Second-level imports
To keep the API clean and consistent, any new public functions or classes should be importable from a second-level package.
This is achieved by importing the function or class in the __init__.py
file of the package.
For example:
compas
├── __init__.py
└── my_package
├── __init__.py
└── new_module.py
# new_module.py
class NewClass(object):
...
# compas.my_package.__init__.py
from .new_module import NewClass
__all__ = ['NewClass']
The result should be:
>>> from compas.my_package import NewClass
Docstrings
Docstings in the COMPAS ecosystem follow the NumPy style docstrings. These docstrings are later used by Sphinx to generate the API documentation.
Therefore, it is important that functions and methods have at least the following docstrings:
def my_function(point, line):
"""This is a one-line description of the function.
This is a longer description of the function.
It can span multiple lines.
Parameters
----------
point : :class:`~compas.geometry.Point`
Point to check.
line : :class:`~compas.geometry.Line`
Line to analyze.
Returns
-------
:class:`~compas.geometry.Plane`
The resulting plane of the operation.
"""
...
Python 2.7 compatibility
To keep COMPAS usable in Rhino, we make sure to maintain Python 2.7 compatibility in parts of the package which are used in Rhino. Packages that are not intended to be used in Rhino can utilise Python 3 features.
Comments
The code should be self-explanatory and comments should be used sparingly. However, if a portion of the code is best understood in a certain context, a comment could be added.