Files
gnwmanager/.github/contributing.md
2023-08-19 15:52:11 -07:00

2.8 KiB

Environment Setup

  1. We use Poetry for managing virtual environments and dependencies. Once Poetry is installed, run poetry install in this repo to get started.
  2. For managing linters, static-analysis, and other tools, we use pre-commit. Once Pre-commit is installed, run pre-commit install in this repo to install the hooks. Using pre-commit ensures PRs match the linting requirements of the codebase.

Documentation

Whenever possible, please add docstrings to your code! We use numpy-style napoleon docstrings. To confirm docstrings are valid, build the docs by running poetry run make html in the docs/ folder.

I typically write dosctrings first, it will act as a guide to limit scope and encourage unit-testable code. Good docstrings include information like:

  1. If not immediately obvious, what is the intended use-case? When should this function be used?
  2. What happens during errors/edge-cases.
  3. When dealing with physical values, include units.

Unit Tests

We use the pytest framework for unit testing. Ideally, all new code is partners with new unit tests to exercise that code. If fixing a bug, consider writing the test first to confirm the existence of the bug, and to confirm that the new code fixes it.

Unit tests should only test a single concise body of code. If this is hard to do, there are two solutions that can help:

  1. Restructure the code. Keep inputs/outputs to be simple variables. Avoid complicated interactions with state.
  2. Use pytest-mock to mock out external interactions.

Coding Style

In an attempt to keep consistency and maintainability in the code-base, here are some high-level guidelines for code that might not be enforced by linters.

  • Use f-strings.
  • Keep/cast path variables as pathlib.Path objects. Do not use os.path. For public-facing functions, cast path arguments immediately to Path.
  • Use magic-methods when appropriate. It might be better to implement MyClass.__call__() instead of MyClass.run().
  • Do not return sentinel values for error-states like -1 or None. Instead, raise an exception.
  • Avoid deeply nested code. Techniques like returning early and breaking up a complicated function into multiple functions results in easier to read and test code.
  • Consider if you are double-name-spacing and how modules are meant to be imported. E.g. it might be better to name a function read instead of image_read in the module my_package/image.py. Consider the module name-space and whether or not it's flattened in __init__.py.
  • Only use multiple-inheritance if using a mixin. Mixin classes should end in "Mixin".