Python для ML — мост к PyTorch
PyTorch, scikit-learn и ноутбуки из раздела 6 — ИИ предполагают, что вы уверенно пишете на Python: синтаксис, модули, окружение, работа с таблицами и умение читать traceback. Эта статья — мост между базовым Python и нейросетями: что закрыть до PyTorch и в каком порядке читать материалы энциклопедии.
| Этап | Тема | Где в энциклопедии |
|---|---|---|
| 0 | Синтаксис, функции, модули | Python intro, функции |
| 1 | venv, pip, pyproject | 39, 391 Poetry/uv |
| 2 | NumPy, векторы | 426 NumPy |
| 3 | pandas, таблицы | 427 Pandas |
| 4 | ML-концепции | 6-02 ML |
| 5 | Нейросети, PyTorch | 6-03, 6-04 |
Практикум ниже идёт по шагам — от минимума Python до первого тензора с autograd.
| Шаг | Тема | Зачем |
|---|---|---|
| 1 | Структуры данных и функции | Читать батчи и пайплайны |
| 2 | Окружение и пакеты | PyTorch и CUDA тяжёлые |
| 3 | NumPy | Форма, срезы, broadcasting |
| 4 | pandas | CSV и подготовка признаков |
| 5 | Jupyter и seed | Эксперименты и воспроизводимость |
| 6 | sklearn baseline | train/test до deep learning |
| 7 | Первый PyTorch | autograd и градиенты |
Большие языковые модели — вершина стека. Без NumPy, split данных и понимания overfitting отладка сводится к копипасту. Сначала Iris или MNIST, потом трансформеры.
Шаг 1 — минимум Python для ML
Структуры данных
Списки, словари, множества и comprehensions — без этого не читаются датасеты, конфиги и батчи.
rows = [{"x": 1.0, "y": 0}, {"x": 2.5, "y": 1}, {"x": 0.5, "y": 0}]
positives = [r["x"] for r in rows if r["y"] == 1]
by_label = {r["y"]: r["x"] for r in rows} # осторожно с дубликатами ключей
unique_ys = {r["y"] for r in rows}
Разбор:
- list comprehension фильтрует и преобразует за одно прохождение.
- dict comprehension удобен для маппинга id → объект.
- set даёт уникальные метки классов.
Подробнее:
Функции и модули
ML-код разбивают на функции load_data, train_epoch, evaluate — иначе ноутбук превращается в нечитаемую простыню.
def accuracy(pred, target):
"""Доля совпадений pred и target (0/1 или bool)."""
matches = (pred == target).sum()
total = len(target)
return matches / total if total else 0.0
Для PyTorch позже:
def accuracy_torch(pred, target):
return (pred == target).float().mean().item()
См. функции, импорт и пакеты.
Type hints
Подсказки типов помогают IDE и коллегам:
from typing import Sequence
def normalize(xs: Sequence[float]) -> list[float]:
mean = sum(xs) / len(xs)
return [x - mean for x in xs]
Полный курс типизации — в материалах по Python 3.10+; для ML достаточно базовых list, dict, Optional.
Исключения и отладка
Обучение падает на NaN, shape mismatch, OOM GPU — нужно читать traceback до своей строки, а не только последнюю.
try:
result = risky_operation()
except ValueError as e:
print(f"Неверные данные: {e}")
raise
Отладка — breakpoints, логирование, pdb.
Шаг 2 — виртуальное окружение
PyTorch, CUDA-пакеты и Jupyter тяжёлые — изолируйте каждый проект.
Классический venv
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/macOS
pip install --upgrade pip
pip install torch numpy pandas jupyter scikit-learn
Poetry или uv
Современный вариант — Poetry / uv:
uv init ml-demo
cd ml-demo
uv add numpy pandas scikit-learn jupyter
uv add torch # см. pytorch.org для CUDA-индекса
uv run jupyter lab
На Linux с PEP 668 следите за externally-managed-environment — не ставьте ML-стек в системный Python.
| Пакет | Назначение |
|---|---|
numpy | Массивы, линейная алгебра |
pandas | Таблицы, CSV |
scikit-learn | Классические модели, метрики |
torch | Нейросети, GPU |
jupyterlab | Интерактивные эксперimentы |
matplotlib | Графики — 428 |
Установка PyTorch с CUDA — только с pytorch.org: индекс pip зависит от версии CUDA и ОС.
Шаг 3 — NumPy как фундамент
Тензоры PyTorch похожи на ndarray NumPy: форма, срезы, broadcasting, операции по осям.
import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
print(a.shape) # (2, 3)
b = a.mean(axis=0) # среднее по строкам → shape (3,)
c = np.dot(a, a.T) # (2, 2)
d = a[:, 0] # первый столбец
| Операция | NumPy | Позже в PyTorch |
|---|---|---|
| Форма | a.shape | t.shape |
| Срез | a[:, 0] | t[:, 0] |
| По оси | a.mean(axis=1) | t.mean(dim=1) |
| Тип | dtype=float32 | t.float() |
| Случайность | np.random.default_rng(42) | torch.manual_seed(42) |
Broadcasting
x = np.array([[1], [2], [3]]) # (3, 1)
y = np.array([10, 20, 30]) # (3,)
z = x + y # (3, 3) без явных циклов
Понимание broadcasting обязательно для loss и нормализации батчей.
Глубже:
Шаг 4 — pandas для табличных данных
CSV, пропуски, группировки — до подачи в модель.
import pandas as pd
df = pd.read_csv("train.csv")
print(df.head())
print(df.info())
df = df.dropna(subset=["target"])
df["feature_a"] = df["feature_a"].fillna(df["feature_a"].median())
X = df[["feature_a", "feature_b"]].values # ndarray для sklearn/torch
y = df["target"].values
| Метод | Зачем |
|---|---|
read_csv | Загрузка датасета |
dropna | Убрать строки без метки |
fillna | Заполнить пропуски |
groupby | Агрегации по категориям |
.values / .to_numpy() | Переход в NumPy |
Шаг 5 — Jupyter и воспроизводимость
Ноутбуки удобны для исследования; прод-код выносят в .py модули и пакеты.
pip install jupyterlab
jupyter lab
| Плюс notebook | Минус |
|---|---|
| Графики inline | Порядок ячеек ломает воспроизводимость |
| Быстрые эксперименты | Сложнее code review |
| Документация рядом с кодом | Риск огромных бинарных diff |
Фиксация seed
import random
import numpy as np
SEED = 42
random.seed(SEED)
np.random.seed(SEED)
# после установки torch:
import torch
torch.manual_seed(SEED)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(SEED)
Версии пакетов — в requirements.txt или uv.lock. Перед публикацией результатов сохраняйте lock и seed в README.
Структура учебного репозитория
ml-demo/
pyproject.toml
data/ # или .gitignore для больших файлов
notebooks/
01_eda.ipynb
src/
ml_demo/
data.py
train.py
tests/
Шаг 6 — маршрут к разделу 6 (ИИ)
Рекомендуемый порядок чтения:
- Что такое ИИ
- Машинное обучение — введение
- Нейрон
- Трансформеры и NLP — о разделе
- Модели и инструменты — о разделе
Шаг 7 — scikit-learn перед deep learning
Для табличных задач часто достаточно sklearn — быстрый baseline и понятные метрики.
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
model = LogisticRegression(max_iter=200)
model.fit(X_train, y_train)
pred = model.predict(X_test)
print(accuracy_score(y_test, pred))
Разбор:
train_test_split— отделить validation/test от train.fit/predict— универсальный API sklearn.accuracy_score— простая метрика для классификации.
Это закрепляет train/test split, метрики, overfitting — 6-02 ML.
Шаг 8 — первый шаг к PyTorch
После NumPy — тензор и autograd (автоматическое дифференцирование).
import torch
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = (x ** 2).sum()
y.backward()
print(x.grad) # tensor([2., 4., 6.])
Разбор:
tensor— многомерный массив с опциональным GPU.requires_grad=True— накапливать градиенты приbackward().backward()— обратное распространение; основа обучения нейросетей.
Простая линейная модель
import torch
import torch.nn as nn
X = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
y = torch.tensor([[2.0], [4.0], [6.0], [8.0]]) # y ≈ 2*x
model = nn.Linear(1, 1)
loss_fn = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
for epoch in range(100):
pred = model(X)
loss = loss_fn(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(list(model.parameters()))
| Компонент | Роль |
|---|---|
nn.Linear | Веса и смещение |
loss_fn | Число, которое минимизируем |
optimizer | Обновление весов по градиенту |
zero_grad | Обнулить старые градиенты |
CPU и GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
X = X.to(device)
Полный курс — нейросети; установка CUDA — pytorch.org.
Чек-лист готовности к PyTorch
| # | Умею |
|---|---|
| 1 | Создать venv и установить пакет |
| 2 | Прочитать CSV через pandas |
| 3 | Объяснить shape (N, C, H, W) для батча изображений |
| 4 | Написать функцию с type hints |
| 5 | Прочитать traceback до своей строки |
| 6 | Понимать overfitting и validation split |
| 7 | Объяснить, что делает loss.backward() |
Типичные ошибки новичков
| Ошибка | Что делать |
|---|---|
| Прыжок сразу в LLM | Пройти NumPy + 6-02 + MNIST |
| Глобальный pip без venv | 22, 391 |
| Копипаст ноутбука без seed | Фиксировать версии и SEED |
| Игнор CPU/GPU | Явный device, проверка cuda.is_available() |
| Shape mismatch | Печатать .shape на каждом шаге |
| NaN в loss | Проверить learning rate и нормализацию данных |
| OOM на GPU | Уменьшить batch size |
Осознанная работа с ИИ-инструментами — генерация кода; слепой копипаст — вайб-кодинг.
Учебный проект Iris — полный цикл
Загрузка и EDA
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris(as_frame=True)
df = iris.frame
df["species"] = df["target"].map(dict(enumerate(iris.target_names)))
print(df.describe())
print(df.groupby("species").size())
| Шаг | Действие |
|---|---|
| EDA | describe, groupby, пропуски |
| Features | столбцы sepal length (cm) … |
| Target | species или target |
Baseline sklearn
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", LogisticRegression(max_iter=200)),
])
pipe.fit(X_train, y_train)
print(pipe.score(X_test, y_test))
print(cross_val_score(pipe, X, y, cv=5).mean())
Тот же эксперiment в PyTorch
import torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoader
X_t = torch.tensor(X_train, dtype=torch.float32)
y_t = torch.tensor(y_train, dtype=torch.long)
loader = DataLoader(TensorDataset(X_t, y_t), batch_size=16, shuffle=True)
model = nn.Sequential(
nn.Linear(4, 16),
nn.ReLU(),
nn.Linear(16, 3),
)
opt = torch.optim.Adam(model.parameters(), lr=0.01)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(200):
for xb, yb in loader:
opt.zero_grad()
loss = loss_fn(model(xb), yb)
loss.backward()
opt.step()
Сравните accuracy sklearn pipeline и PyTorch на X_test.
DataLoader и батчи
from torch.utils.data import Dataset, DataLoader
class TabularDataset(Dataset):
def __init__(self, X, y):
self.X = torch.tensor(X, dtype=torch.float32)
self.y = torch.tensor(y, dtype=torch.long)
def __len__(self):
return len(self.y)
def __getitem__(self, idx):
return self.X[idx], self.y[idx]
train_ds = TabularDataset(X_train, y_train)
train_loader = DataLoader(train_ds, batch_size=32, shuffle=True)
| Параметр | Смысл |
|---|---|
batch_size | Сколько примеров за шаг |
shuffle=True | Перемешивание train |
num_workers | Параллельная загрузка (осторожно на Windows) |
Нормализация признаков
mean = X_train.mean(axis=0)
std = X_train.std(axis=0) + 1e-8
X_train_n = (X_train - mean) / std
X_test_n = (X_test - mean) / std
Без нормализации градиентный спуск может сходиться медленно. StandardScaler в sklearn делает то же.
Jupyter — дисциплина воспроизводимости
| Правило | Зачем |
|---|---|
| Restart kernel + Run All перед commit | Порядок ячеек |
%matplotlib inline в первой ячейке | Графики |
| Версии в lock | Одинаковые libs |
| Seed в начале notebook | Сравнимые runs |
Экспорт .py через jupyter nbconvert | Code review |
Маршрут по разделу 6 после Python
| Порядок | Статья | Тема |
|---|---|---|
| 1 | 6-01 intro | Карта ИИ |
| 2 | 6-02 ML | Supervised learning |
| 3 | 6-03 intro | Нейросети |
| 4 | 6-04 intro | PyTorch, HF |
| 5 | 6-05 | Прикладная разработка |
Расширенный чек-лист
| # | Умею | Проверка |
|---|---|---|
| 8 | train_test_split(..., stratify=y) | Баланс классов |
| 9 | CrossEntropyLoss + logits | Shape (N, C) |
| 10 | model.eval() и torch.no_grad() | Inference |
| 11 | Сохранить state_dict | torch.save |
| 12 | Загрузить weights | load_state_dict |
Навигация по блоку Python → ML
- Вы здесь: 392 — Python для ML
- Зависимости: 391 Poetry/uv
- NumPy: 426
- Pandas: 427
- ИИ: 6-01 intro
Шаг 9 — matplotlib для EDA
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
iris = load_iris()
plt.scatter(iris.data[:, 0], iris.data[:, 1], c=iris.target, cmap="viridis")
plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[1])
plt.colorbar()
plt.savefig("iris_scatter.png")
Шаг 10 — train/val/test split
X_train, X_temp, y_train, y_temp = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
X_val, X_test, y_val, y_test = train_test_split(
X_temp, y_temp, test_size=0.5, random_state=42, stratify=y_temp
)
| Набор | Назначение |
|---|---|
| train | обучение весов |
| val | подбор hyperparams |
| test | финальная оценка один раз |
Шаг 11 — overfitting на практике
train_acc = model.score(X_train, y_train)
test_acc = model.score(X_test, y_test)
print(train_acc, test_acc)
Большой разрыв train >> test — overfitting. Решения: regularization, больше данных, проще модель.
Шаг 12 — сохранение модели PyTorch
torch.save(model.state_dict(), "model.pt")
model.load_state_dict(torch.load("model.pt", weights_only=True))
model.eval()
weights_only=True — безопасная загрузка weights (PyTorch 2.0+).
Шаг 13 — type hints в ML-коде
from typing import Tuple
import numpy as np
def split_xy(df) -> Tuple[np.ndarray, np.ndarray]:
X = df.drop(columns=["target"]).to_numpy()
y = df["target"].to_numpy()
return X, y
Шаг 14 — logging вместо print
import logging
logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)
log.info("Epoch %s loss=%s", epoch, loss.item())
Учебные датасеты без download
| Dataset | sklearn |
|---|---|
| Iris | load_iris() |
| Digits | load_digits() |
| Wine | load_wine() |
Практический маршрут на Iris
- pandas — загрузить Iris, посмотреть
describe(). - sklearn —
LogisticRegression, accuracy на test. - PyTorch —
nn.Linear(4, 3), тот же split, сравнить accuracy и время настройки. - Записать seed, версии пакетов и lock в git.
Связанные материалы
| Тема | Материал |
|---|---|
| Анализ данных | раздел 3-11 |
| Визуализация | 428 Matplotlib |
| ML-сервис | FastAPI для ML |
| MLOps | 6-08 AgentOps |
| Poetry/uv | 391 |
На датасете Iris пройдите путь pandas → sklearn baseline → тот же tensor batch в PyTorch Linear. Сравните accuracy, время настройки и объём кода. Зафиксируйте random_state=42 и lock-файл.
Второй проход — inference и отладка (черновик)
Режим inference
model.eval()
with torch.no_grad():
logits = model(X_test_t)
pred = logits.argmax(dim=1)
eval() отключает dropout; no_grad() экономит память без графа autograd.
Сохранение весов
torch.save(model.state_dict(), "iris_model.pt")
model.load_state_dict(torch.load("iris_model.pt", weights_only=True))
Для продакшена — версия torch в имени файла или MLflow — 6-08 AgentOps.
Отладка NaN
if torch.isnan(loss):
raise RuntimeError("NaN loss — уменьшите lr или нормализуйте X")
Типичные причины: слишком большой learning rate, не нормализованные признаки, деление на ноль в кастомном loss.
Jupyter → модуль
Вынесите train_epoch(model, loader, opt, loss_fn) в src/ml_demo/train.py и импортируйте в ноутбук — воспроизводимость и unit-тесты без ячеек out-of-order.
FAQ — полный список
1. С чего начать перед PyTorch?
NumPy, pandas, train/test split — 6-02 ML.
2. Нужен ли GPU?
Для MNIST — CPU достаточно. Для больших моделей — CUDA с pytorch.org.
3. venv или uv?
391 Poetry/uv для изоляции тяжёлых пакетов.
4. Jupyter или .py модули?
Notebook для EDA; prod-код — модули и пакеты.
5. Что такое shape mismatch?
Печатайте .shape на каждом шаге.
6. NaN в loss?
Learning rate, нормализация данных.
7. OOM на GPU?
Уменьшить batch size.
8. random_state зачем?
Воспроизводимость эксперiments — seed + lock.
9. sklearn vs PyTorch?
sklearn — табличные baseline. PyTorch — deep learning.
10. autograd что делает?
Автоматическое дифференцирование — основа обучения.
11. device cpu/cuda?
Явный device и torch.cuda.is_available().
12. Iris датасет где?
sklearn.datasets.load_iris.
13. pandas к NumPy?
.values или .to_numpy().
14. Matplotlib?
428.
15. MLOps дальше?
16. LLM сразу?
Сначала MNIST/Iris — иначе отладка = копипаст.
17. Traceback как читать?
До своей строки — отладка.
Упражнения — расширенный набор
- Iris: pandas describe → sklearn baseline → PyTorch Linear.
- Зафиксировать SEED=42 и lock в git.
- Написать normalize() с type hints.
- Broadcasting exercise в NumPy.
- train_test_split с random_state.
- nn.MSELoss на синтетических данных.
- Перенести notebook код в src/ml_demo/train.py.
- Чек-лист готовности — все 7 пунктов.
- Сравнить accuracy sklearn и PyTorch.
- Документировать версии в README.
Практикум — полный PyTorch Linear на Iris
import torch
import torch.nn as nn
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train = torch.tensor(X_train, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
model = nn.Linear(4, 3)
loss_fn = nn.CrossEntropyLoss()
opt = torch.optim.Adam(model.parameters(), lr=0.01)
for epoch in range(200):
opt.zero_grad()
loss = loss_fn(model(X_train), y_train)
loss.backward()
opt.step()
Практикум — дополнительный блок 1 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 1
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 1"
Практикум — дополнительный блок 2 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 2
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 2"
Практикум — дополнительный блок 3 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 3
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 3"
Практикум — дополнительный блок 4 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 4
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 4"
Практикум — дополнительный блок 5 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 5
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 5"
Практикум — дополнительный блок 6 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 6
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 6"
Практикум — дополнительный блок 7 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 7
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 7"
Практикум — дополнительный блок 8 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 8
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 8"
Практикум — дополнительный блок 9 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 9
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 9"
Практикум — дополнительный блок 10 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 10
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 10"
Практикум — дополнительный блок 11 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 11
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 11"
Практикум — дополнительный блок 12 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 12
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 12"
Практикум — дополнительный блок 13 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 13
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 13"
Практикум — дополнительный блок 14 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 14
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 14"
Практикум — дополнительный блок 15 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 15
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 15"
Практикум — дополнительный блок 16 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 16
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 16"
Практикум — дополнительный блок 17 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 17
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 17"
Практикум — дополнительный блок 18 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 18
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 18"
Практикум — дополнительный блок 19 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 19
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 19"
Практикум — дополнительный блок 20 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 20
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 20"
Практикум — дополнительный блок 21 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 21
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 21"
Практикум — дополнительный блок 22 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 22
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 22"
Практикум — дополнительный блок 23 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 23
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 23"
Практикум — дополнительный блок 24 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 24
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 24"
Практикум — дополнительный блок 25 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 25
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 25"
Практикум — дополнительный блок 26 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 26
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 26"
Практикум — дополнительный блок 27 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 27
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 27"
Практикум — дополнительный блок 28 (392)
| Шаг | Действие | Проверка |
|---|---|---|
| 1 | Повторить базовый сценарий из начала статьи | Команда завершается без ошибок |
| 2 | Запустить тесты или curl smoke | Ожидаемый HTTP-код или green test |
| 3 | Зафиксировать результат в README | Шаги воспроизводимы на другой машине |
Troubleshooting — мини-чеклист 28
| # | Вопрос | Если да |
|---|---|---|
| 1 | Версия runtime совпадает с таблицей требований? | Обновить или зафиксировать в документации |
| 2 | Зависимости установлены из lock-файла? | Переустановить без изменения lock |
| 3 | Порт не занят другим процессом? | Сменить порт или завершить процесс |
| 4 | Переменные окружения заданы? | Проверить .env и секреты на хостинге |
| 5 | Тесты проходят локально? | Только после green — деплой |
# Smoke — адаптируйте под свой стек (392)
echo "Smoke block 28"