General Rules
- Google Python style, 80 column limit
- Commit messages should have the module name or recipe prefix instead of something like “fix:” or “[fix]”
- Yes: “checkout: Fix spelling error”
- No: “fix: Fix spelling error”
- No: “[checkout] Fix spelling error”
- Use Python type annotations where possible
- Use ‘list’ and ‘dict’ instead of ‘typing.List’ and ‘typing.Dict’
- Use ‘from typing import ...’ and ‘from collections.abc import ...’ instead of ‘import typing’ and ‘import collections.abc’
- Use ‘from future import annotations’
- Function and method arguments should use generic types if possible, like ‘Sequence’
- Return values should use specific types, like ‘list’
- In most cases, don't hide type annotation imports under ‘if TYPE_CHECKING:’
- Yes: from typing import Callable
- No: from typing import TYPE_CHECKING ... if TYPE_CHECKING: from typing import Callable
- Exception: imports used only for annotations that look like “from RECIPE_MODULES.repo.module import ...” where “repo/module” is not in ‘DEPS’ should be hidden behind ‘if TYPE_CHECKING:’—this will allow a reference to a type defined in another module without taking a full dependency on that module
- If “repo/module” is in ‘DEPS’, then don't hide with ‘if TYPE_CHECKING:’
- Make sure any “if TYPE_CHECKING:” lines that do exist have a “# pragma: no cover” comment
- Make sure things pass pylint
- Recipe testing often requires ‘test_data’ or ‘step_test_data’ arguments in what otherwise looks like production code—leave these arguments alone
- Don't include comments on import lines
- Don't have any trailing whitespace at the end of lines
- The ‘api’ object passed into a recipe's ‘RunScripts’ function is of type ‘recipe_api.RecipeScriptApi’
- Indentation in docstrings should be independent of the length of the variable name
- Yes: Args: very_long_variable_name: Description takes multiple lines.
- No: Args: very_long_variable_name: Description takes multiple lines.
- Use dataclasses instead of attrs
- Exceptions ok for when using attrs features not in dataclasses
Module Dependencies
- Recipe modules contain a single class that is a subclass of recipe_api.RecipeApi
- Recipes can list their dependencies in a module-level ‘DEPS’ variable
- Dependencies without a “/” refer to the current repo, and if they do have a “/” the part in front is a repository name
- The remote for that repository can be found in “infra/config/recipes.cfg”
- Recipe modules list their dependencies in a ‘DEPS’ variable in ‘init.py’
- Recipes can access an object that is an instance of the subclass of recipe_api.RecipeApi using ‘api.’
- Recipe modules can access that same object using ‘self.m.’
- If necessary, modules themselves can be imported with lines like this: ‘from RECIPE_MODULES.. import api as -api’
- Prefer this structure over other ways to import modules directly