Skip to content

Codestyle

YegorK edited this page Feb 24, 2025 · 13 revisions

Commit style

We use tag style for commits:

add or added - if you add changes

refactor - if you remove or replace existing code

test or tests - if you write or change test code

fix or fixed - if you fix a bug

After tag, commit message should containg info about your changes.

For example:

add: new API endpoint for bind

test: new API endpoint

refactor: removed headers from bind endpoint

fix: headers pass for bind endpoint

If you change codestyle/linting:

refactor: linters, fix: lint or refactor: codestyle

Branch name

Should contain info about your changes, with tag, if possible and not complex:

add_new_modify_endpoint

fix_a_complex_bug

refactor_someexternalservice_wrapper

test_someexternalservice_wrapper

Poetry

add sort plugin if you add dependencies

poetry self add poetry-plugin-sort

Codestyle

  1. We use ruff rules to sort imports, config is in pyproject.toml
  2. MyPy and Ruff uses configs from repo
  3. Avoid filter, lambda, replace it with list comprehensions
list(filter(lambda x: x % 2 == 0, range(10)))

[i for i in range(10) if i % 2 == 0]
  1. All funcs/methods args and return statements should be annotated with types
  2. All funcs/methods args and return statements should be annotated with docstrng in sphinx style

Indent style

  1. We use 79 length rows, all developers have different monitors, and review will be much easier from browser, so its important. If row is less than 79 chars, this is a priority to keep it untouched, if row is too complex, for e.g. double-tripple dict-list comprehension, its ok to make line breaks
  2. Line break style on functions and methos, funcs declarations:

Format style

Ruff

Use ruff for code formatting.

ruff format

For vscode, you can use following settings

.vscode/settings.json

{
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
        "source.fixAll": "explicit",
        "source.organizeImports": "explicit"
    },
    "editor.defaultFormatter": "charliermarsh.ruff"
}

Code examples

# long return annotation
def func(
    a: int, 
    b: int, 
    c: int,
) -> Generator[int, None, None]: ...

# if annotation is too big, decompose it to a type variable

type GenFoo = Generator[int, None, None]

# sqlalchemy statements must be written with a sql-like style, 
# use `fmt: skip` comment to prevent ruff format this code block
my_var = (
    somethinglikethis
    .where(we=do_things)
    .where(we=domore)
    .where(we=everdomore)
) # fmt: skip

# if query fits 79 lines, leave it be
await session.execute(select(Foo).where(we=do_things))

await session.execute(
    select(Foo)
    .where(we=do_things)
) # fmt: skip

await session.execute(
    select(Foo)
    .where(we=do_things)
    .where(we=domore)
    .where(or_(
        we=everdomore,
        do=more,
    ))
) # fmt: skip

# mutli argument pass

func(arg1, 'abracadabra abracadabra')

func(
    arg1, 
    'abracadabra abracadabra',
)

foo_func(
    arg1, 
    'abracadabra abracadabra',
    'abracadabra abracadabra',
)