First, some basic development guidelines to ensure clean code that can be used by other prople to.
- All required python packages should be listed in requirements.txt
- Pushing to the main branch is discouraged (only if collaborating)
- To add a new feature, the workflow is envisioned as follows:
(1) Create a new issue
(2) Create a branch and a merge request draft belonging to that issue
(3) Once the feature is implemented, mark the merge request as ready and assign a reviewer
(4) After the merge request is reviewed, it is merged into the main branch, the feature branch is deleted, and the corresponding issue is marked as resolved.
To maintain high-quality code that will be used in production, please adhere to the following style guidelines from the Google Python Style Guide.
To help format your code correctly, consider using the Black auto-formatter. You can install it using the following command:
pip install "black[jupyter]"
or
pip install "black"
To auto-format your code, simply run:
black <<Filename>>
- Test files need to contain string: test_ for example basic_test.py
- unittest should be imported and a class of MyTestCase(unittest.TestCase) defined, in which test functions will be written
- for running prehooks run in terminal locally:
pip install pre-commit
pre-commit install
- if pipeline fails it might be due to a formatting error check logs and adjust code accordingly
- Import only modules, not classes or functions
- Minimize the use of exceptions
- Avoid using global variables from inside functions
- Avoid nesting classes and functions
- Use list comprehensions only for simple cases (one for loop and one if statement)
- Use default iterators (e.g., for x in dict instead of dict.keys())
- Use only conditional expressions only in simple cases (e.g., XY if func(ABC) else D)
- Avoid mutable values in default arguments (e.g., use func(a=()) but not of func(b=[]))
- Use implicit False whenever possible (and useful)
- Use annotations (func(a:int) -> list[str])
- Limit each line to 80 characters (break lines with )
- Align code vertically and indent with 4 spaces
- Use two blank lines between top-level definitions and one between methods and docstrings
- Avoid spaces before/after = for arguments and avoid aligning with spaces
-
- Define constants at the beginning of the file if they won't change (e.g., paths)
- Include docstrings for non-obvious functions and methods (i.e. almost all)
- Organize docstrings in the following order: summary, description, args, returns, raises, examples
- Include documentation for class attributes
- Avoid unnecessary information in docstrings (e.g., stating that a class is a class)
- For complex, multi-line code, add comments before the code; for single-line complex code, add comments at the end (2 spaces)
¶ Strings and Error Messages
- Always use f-strings, even if all variables are strings (exception: single join, e.g., a + b)
- Use either " or ' consistently throughout the code to avoid escaping
- Use precise and short error messages
- Explicitly close files when done with them
- Use TODO comments for non-perfect code that works, and include a due date/event if critical
- Order imports from most to least generic (future, standard, 3rd party, repository, task-specific)
- Group imports
- Use descriptive variable names, avoid abbreviations if possible
- Avoid single-character variable names (exceptions: iterators (i, j), exceptions (e), file handlers (f))
- Keep descriptiveness proportional to complexity
- Avoid dashes in module names
- Avoid unnecessarily including the variable type in the name
- Use _ for internal/protected variables within a class/method
- Capitalize global variables and the first letter of classes and exceptions
- Short variable names may be acceptable for mathematically heavy code if they follow the notation of the paper; document all namings in docstrings or comments
¶ Functions and Classes
- Define a main function for the main functionality and use if name == "main":
- If possible, use small functions (max. 40 lines)
- Use annotations to make complex code more readable
- Use explicit None for function annotations (e.g., func(x: str | None))
- Add type comments for difficult-to-understand variables
For additional code quality checks, you can use pylint. pylint is a tool that helps find bugs and style problems in Python source code. Some errors may be incorrect, to supress them just use:
def do_PUT(self):
# WSGI name, so pylint: disable=invalid-name
...
If the reason for the suppression is not clear from the symbolic name, add an explanation.