# Python Style Guide
Этот раздел отвечает за то, как должен выглядеть код на Python.
## Форматирование кода
Отступ: 4 пробела.
Максимальное количество символов на строку: 80.
Максимальное количество символов на doc-string: 72.
Количество пустых строк между функциями:
- вне класса — 2;
- в классе — 1.
Количество пустых строк между классами: 2
Количество пустых строк после импорта зависимостей: 2.
Не оставляйте "повисших" запятых.
Пример "повисшей" запятой:
```python
[
path('question/all/', QuestionListApiView.as_view()),
path('question/group/all/', QuestionGroupListApiView.as_view()),
path('question/block/all/', QuestionBlockListApiView.as_view()),
]
```
Эта запятая тут явно не нужна. Избегайте таких моментов.
Файл должен кончаться пустой строкой.
Весь код в MR будет проверяться ровно по этому формату. Если он не будет ему соответствовать — MR будет отправлен на доработку.
## Переменные
Каждая переменная должна чётко отражать то значение, которое в ней будет находиться.
Все булевые (флаговые) переменные начинаются с префикса «is», например: «is_active». В идеале, всё должно прийти к тому состоянию, когда мы во всех местах имеем флаги, которые будут работать одинаково и принимать значения True/False внезависимости от того, в каком месте кода они используются.
Все переменные для подсчёта чего-либо должны иметь постфикс «count», например: «experts_count».
Мы должны стремиться к декларативности и читаемости, поэтому каждая переменная должна быть обдуманной.
Все значения строковых переменных должны браться в **двойные кавычки**. Все константные переменные набираются в верхнем регистре.
## Интерполяция строк
Поскольку подход к интерполяции строк надо унифицировать будем использовать f-строки.
Пример интерполяции строк с использованием f-строк:
```python
HOURS_A_DAY = 24
message = f"We have only {HOURS_A_DAY} hours..."
```
Складывать строки запрещено. Можно пользоваться только интерполяцией.
## Условия
По-хорошему, в условиях избегать двух вещей:
1) [Магических значений](https://ru.hexlet.io/blog/posts/magic-numbers)
2) Прямых сравнений в самом условии. Что я под этим подразумеваю? Я предлагаю заводить отдельную булевую переменную, которая будет использоваться в условии.
Пример хорошего условия:
```python
HOURS_A_DAY = 24
current_hours = 23
is_day_over = current_hours == HOURS_A_DAY
if is_day_over:
...
```
## Функции
Название каждой функции должно чётко отражать суть самой функции. Не должно возникать ситуаций, когда нужно прочесть всю функцию, чтобы понять, для чего она нужна. Получение, изменение и отображение — это три разных функции. Функция получения/изменения каких-то параметров должна возвращать конечный результат — изменённые параметры. Функция отображения должна обращаться к функциям получения/изменения и отображать эти изменения. Никаких неявных преобразований. Входные и выходные параметры всех функций должны быть описаны по pydoc. Пример есть [тут](https://pythonchik.ru/osnovy/dokumentirovanie-koda-v-python). Кроме того, должны быть обозначены типы для входных и выходных параметров функции, пример:
```python
def _get_hash(self, _code: int) -> str:
# переведём в строку
code = str(_code)
# переведём в bytes
code = code.encode()
# переведём в hash
_hash = md5(code)
return _hash.hexdigest()
```
Помните, что каждая функция должна выполнять одну **небольшую** задачу.
## Классы
Если вы заводите класс, то его методы должны быть именно **его** методами. Они не должны работать как обычные функции. Вы должны предусмотреть какую-то стандартную конфигурацию для класса. Пользуйтесь плюсами ООП и не забывайте про наследование: хорошо, когда у вас есть базовый класс для взаимодействия с чем-либо, но если вы хотите его **расширить**, то стоит подумать насколько тот метод, который вы хотите добавить является **необходимым** для базового класса. Если он не является таковым, то вписывайте этот метод в новый экземпляр класса, который будет являться расширением для базового класса. Требования по неймингу такие же, как и для переменных и функций.
## TODO и FIXME
В коде стоит разделять задачи, которые вы хотите зафискировать во время процесса на TODO — что предстоит сделать и FIXME — что предстоит исправить.
Обе подобные метки означают, что вы заводите техдолг. Вы должны обозначить, кроме прочего, что техдолг принадлежит вам.
Пример:
```python
# TODO: 02.04.21, Родион
# написать метод для получения списка конкурсов
```
## Git
Каждая отдельная задача — отдельная ветка, которая удаляется после закрытия задачи.
Каждый коммит — законченная мысль. Шаг к выполнению задачи. Один коммит приходится на одно изменение. То есть изменение трёх функций — это три коммита (но, например, если ты меняешь название метода, то логично, что следом в этом же коммите название этого метода должно измениться во всех местах, где он вызывается). Таким образом мы всегда сможем нормально откатиться к любой интересующей нас версии проекта. Сообщения коммитов пишутся в нормальной форме, например: Add src/components/NewFile.vue.
Цикл разработки должен прийти к следующему состоянию: feature, refactoring, documentarion, fixing.
Каждый коммит должен начинаться с соответствующего префикса: «[feat]», «[ref]», «[doc]», «[fix]».
Названия веток подчиняются следующему правилу:
`{project}-{issue_number}--{service_slug}`
Где в качестве service_slug выступает конкретный репозиторий того или иного проекта.
Примеры service_slug:
1) QS - questionnaire-service
2) RB - refbook-service
3) QWT - questionnaire-wagtail
Пример названия ветки:
`EXAMPLE-9--RB`