# Coding Standards The house standards every Rethink Studios project follows. They keep our code consistent, readable, and predictable across the whole suite. ## Files and style - Files end with a **single trailing newline** (LF / Unix line endings), and carry **no trailing whitespace** on any line. - **4 spaces** for indentation by default. Respect language norms — TS/JS use **2 spaces**, Go uses **tabs** — and when editing an existing file, follow that file's existing indentation. - **flake8 clean**, max line length **120**. **Type hints** on public functions. A well-formed module — module docstring, type hints, lowercase-start docstring: ```python """async key/value store backed by a single json file""" from pathlib import Path def load_state(path: Path) -> dict[str, str]: """read the json state file, returning an empty dict if it's missing""" if not path.exists(): return {} return _read_json(path) ``` flake8 tells you the moment you drift — keep the tree clean: ```text $ flake8 ./aiokv/store.py:14:80: E501 line too long (96 > 79 characters) ./aiokv/store.py:22:1: F401 'json' imported but unused ./aiokv/store.py:31:5: E303 too many blank lines (3) ``` !!! tip "Run it locally" Wire the shared config into an alias so every project lints the same way: `alias flake8='flake8 --config ~/.config/flake8'` (max line 120). See the [Workflow](workflow.md#handy-shell-setup) page. ## Documentation - Public functions get a **docstring** — **lowercase-start, no trailing period**. - Keep inline comments minimal; prefer docstrings. Use an inline comment only where the code is genuinely complex. - Each module/file states its scope and purpose via a **module docstring** (header string) — **not** a license or copyright header. - Every library and project has a **README** with the install line, what it does, and a usage example. !!! note "Licensing — no per-file headers" Don't prepend license/copyright boilerplate to source files. If a repo needs a license, it's a single top-level **`LICENSE`** file — never repeated per file. Most internal repos don't carry one; add it only when a repo is meant for outside use and the terms are decided. === "Do" ```python def mask_secret(value: str, keep: int = 4) -> str: """mask all but the last ``keep`` characters of a secret""" if len(value) <= keep: return "*" * len(value) return "*" * (len(value) - keep) + value[-keep:] ``` === "Don't" ```python # Masks a secret. <- license-header-style noise, capitalized, trailing period def mask_secret(value, keep=4): # no type hints # loop over the chars and hide them return "*" * (len(value) - keep) + value[-keep:] # crashes if short ``` ## Quality and error handling **Fail loud** — never swallow exceptions. Catch the **specific** exception and **log** it; don't paper over failures with a bare `except`. === "Do" ```python import logging log = logging.getLogger(__name__) def fetch(url: str) -> bytes: """fetch ``url``, logging and re-raising on failure""" try: return _client.get(url).content except TimeoutError: log.warning("fetch timed out: %s", url) raise ``` === "Don't" ```python def fetch(url): try: return _client.get(url).content except Exception: pass # swallowed — the caller has no idea anything broke ``` When something does break, a loud failure gives you a real traceback to act on: ```python-traceback Traceback (most recent call last): File "run.py", line 42, in data = fetch("https://example.test/feed") File "aioweb/session.py", line 88, in fetch return self._client.get(url).content TimeoutError: request timed out after 30s ``` …and the log line that precedes it tells you where to look: ```text 2026-06-29 14:03:11,204 WARNING aioweb.session fetch timed out: https://example.test/feed ``` !!! note "Logging belongs to the app, not the library" Libraries **emit only** — `log = logging.getLogger(__name__)` and nothing else. Handlers, levels, and formatting are configured once at the application entry point, so a lib never dictates how its host logs.