Python code must be formated using black
with maximum line length of 120 characters
(-l 120
). All Python files submitted for PR MUST be formatted with black
formatter. It's STRONGLY RECOMMENDED to
configure your text editor/IDE of your choice to reformat the Python code when saving using black
.
There are certain rules for import
rules, which are:
-
The order of imports are: Python standard library (
typing
has specialized rules, see (7)), 3rd-party libraries, current project relative import, andtyping
classes. Separated by empty lines. -
For Python standard library and 3rd-party libraries, the only accepted notation is
import ...
.from ... import ...
is strongly prohibited even if this means increasing the column length significantly. -
For current project relative import, if the Python file reside inside the project, then use
from ... import ...
notation. If the Python file is outside the project, but still part of the project (e.g. Python scripts inexternal/
), then the standardimport ...
notation is used. -
When using
from ... import ...
notation (only for current project relative import), it's not allowed to import the individual variable, function, and/or classes. Always import the whole module directly. -
On name conflicts with import, use
as
keyword to rename the import module or try to prevent name conflicts when possible. An example for this situation can be seen innpps4/game/lbonus.py
. -
The order of each imports in their respective category are in lexicographic order. For
from ... import ...
notation, it first ordered by thefrom ...
then theimport ...
. See below for valid example. -
typing
module is specialized in this rule.- For type hint classes, import the needed classes or function directly using
from typing import ...
notation. As per (1),typing
import goes last after everything else. - When using the introspection function such as
get_args
, thetyping
module is treated as Python standard library. Note thatoverload
andcast
are not introspection functions.
- For type hint classes, import the needed classes or function directly using
-
Functions parameters must be type-annotated properly. While it's currently not enforced at runtime, this may change in the future. Function return value may be type-annotated if your IDE or text editor cannot infer the return type.
-
Type-annotate variables when your IDE or text editor cannot infer them correctly. Example on this one is having variable that may contain list of integers (
list[int]
) but initialized as empty list ([]
) to be populated later.
This is an example of well-formed imports.
# Python standard library
import dataclasses
import json
# 3rd-party library
import pydantic
import sqlalchemy
# Current project relative import
from . import idol
from .config import config
from .system import background
# typing
from typing import Any, TypeVar, cast
When changing the main database tables, run migration:
alembic revision --autogenerate -m "your message revision here"
If your changes alter the database fields/tables, please state them in the Pull Request and don't send the alembic migration file. If by accident you sent the alembic migration file, then they'll be deleted or altered significantly on next commit.
OK
def foo[T](a: T):
...
class Foo[T]:
val: T
Not OK
from typing import Generics, TypeVar
T = TypeVar("T")
def foo(a: T):
...
class Foo(Generics[T]):
val: T
This is true for Iterable
and Awaitable
. Since collections.abc
is a standard library, then the standard import
ordering rules apply.
OK
import collections.abc
from typing import Callable
async def foo(f: Callable[[collections.abc.Iterable[int]], collections.abc.Awaitable[int]]):
await f(...)
Not OK
from typing import Awaitable, Callable, Iterable
async def foo(f: Callable[[Iterable[int]], Awaitable[int]]):
await f(...)