refactor(dags): перенесён pandas в функции, исправлен баг occupations, добавлены docstring

- Зачем:
  - обратная связь от менти: pandas в шапке DAG замедляет парсинг scheduler,
    отсутствие описаний затрудняет изучение, баг с неиспользуемой переменной.
- Что:
  - import pandas as pd перенесён из шапки внутрь функций (file_operations, csv_to_postgres, data_processing).
  - исправлен баг: переменная occupations в file_operations_dag.py теперь включена в DataFrame.
  - добавлены docstring с описанием шагов DAG для csv_to_postgres.py, csv_to_postgres_dq.py, data_processing_dag.py.
  - расширен docstring file_operations_dag.py.
  - удалён educational-setup-plan.md (технический файл, не для менти).
- Проверка:
  - airflow DagBag: все 8 DAG загружаются без ошибок.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
ddadminandClaude Opus 4.6 committed 2026-03-26 22:50:55 +03:00
1 parent eaea33e761
commit 72d5968d01
5 files changed
+54 -159

No files matched your search

+15 -1
View File
@@ -1,3 +1,15 @@
"""
DAG для загрузки CSV-данных в PostgreSQL
Уровень: Средний
Этот DAG демонстрирует типичный паттерн загрузки данных из файлов в БД:
1. Создание целевой таблицы public.orders (если не существует)
2. Генерация CSV с заказами (order_id, order_ts, customer_id, amount) через pandas
3. Предпросмотр CSV (head + describe) для контроля
4. Загрузка в PostgreSQL через временную таблицу и anti-join (защита от дубликатов)
Результат: данные в таблице public.orders учебной БД postgres_training.
"""
from __future__ import annotations
import logging
@@ -5,7 +17,7 @@ import os
import random
from datetime import UTC, datetime, timedelta
from pathlib import Path
import pandas as pd
from airflow.operators.python import PythonOperator
from airflow.providers.postgres.hooks.postgres import PostgresHook
@@ -42,6 +54,7 @@ def _create_table() -> None:
def _generate_csv(rows: int, csv_dir: Path) -> str:
"""Генерирует CSV c заказами с помощью pandas и сохраняет на диск."""
import pandas as pd
csv_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
csv_path = csv_dir / f"orders_{timestamp}.csv"
@@ -80,6 +93,7 @@ def _generate_csv(rows: int, csv_dir: Path) -> str:
def _preview_csv(csv_path: str, sample_rows: int = 5) -> None:
"""Отображает предпросмотр CSV через pandas (head и describe)."""
import pandas as pd
df = pd.read_csv(csv_path)
df["order_ts"] = pd.to_datetime(df["order_ts"], errors="coerce")
logging.info(
+13
View File
@@ -1,3 +1,16 @@
"""
DAG для проверки качества данных (Data Quality) после загрузки в PostgreSQL
Уровень: Средний
Этот DAG запускается после csv_to_postgres и проверяет таблицу public.orders:
1. Существование таблицы
2. Соответствие схемы (колонки и типы данных)
3. Наличие данных (таблица не пуста)
4. Отсутствие дубликатов по order_id
5. Итоговая сводка по результатам проверок
Результат: логи с результатами каждой проверки. При ошибке — ValueError с описанием проблемы.
"""
from __future__ import annotations
import logging
+15 -1
View File
@@ -1,12 +1,20 @@
"""
DAG для демонстрации ETL процессов в Airflow
Уровень: Средний-Продвинутый
Этот DAG реализует классический ETL-пайплайн:
1. Создание тестовых данных (клиенты + заказы) в CSV
2. Параллельное извлечение (Extract) клиентов и заказов
3. Трансформация (Transform) — объединение таблиц, вычисляемые поля
4. Загрузка (Load) — подготовка SQL для вставки в БД
5. Генерация текстового отчёта со статистикой
Результат: файлы в /opt/airflow/data/output/ (extracted_*, transformed_data.csv, report.txt).
"""
from datetime import datetime, timedelta
from airflow import DAG
from airflow.operators.python import PythonOperator
from airflow.providers.postgres.operators.postgres import PostgresOperator
import pandas as pd
# Определение DAG
default_args = {
@@ -30,6 +38,7 @@ dag = DAG(
def create_sample_data():
"""Создание примерных данных для ETL процесса"""
import pandas as pd
# Создаем файлы с данными клиентов и заказов
customers_data = {
'customer_id': [1, 2, 3, 4, 5],
@@ -55,6 +64,7 @@ def create_sample_data():
def extract_customers():
"""Извлечение данных клиентов"""
import pandas as pd
df = pd.read_csv('/opt/airflow/data/input/customers.csv')
print(f"Извлечено {len(df)} записей клиентов")
@@ -64,6 +74,7 @@ def extract_customers():
def extract_orders():
"""Извлечение данных заказов"""
import pandas as pd
df = pd.read_csv('/opt/airflow/data/input/orders.csv')
print(f"Извлечено {len(df)} записей заказов")
@@ -73,6 +84,7 @@ def extract_orders():
def transform_data():
"""Преобразование данных - объединение клиентов и заказов"""
import pandas as pd
customers_df = pd.read_csv('/opt/airflow/data/input/customers.csv')
orders_df = pd.read_csv('/opt/airflow/data/input/orders.csv')
@@ -91,6 +103,7 @@ def transform_data():
def load_to_database():
"""Загрузка данных в базу данных (симуляция)"""
import pandas as pd
df = pd.read_csv('/opt/airflow/data/output/transformed_data.csv')
# В реальном сценарии здесь был бы код для загрузки в базу данных
@@ -120,6 +133,7 @@ def load_to_database():
def generate_report():
"""Генерация отчета"""
import pandas as pd
df = pd.read_csv('/opt/airflow/data/output/transformed_data.csv')
# Создаем простой отчет
+11 -6
View File
@@ -2,13 +2,14 @@
DAG для демонстрации работы с файлами в Airflow
Уровень: Средний
Этот DAG генерирует русскоязычные данные с использованием библиотеки mimesis, включая:
- ФИО (с учетом пола)
- Возраст
- Зарплату
- Адрес проживания
Этот DAG показывает полный цикл работы с файлами:
1. Генерация русскоязычных данных (ФИО, возраст, профессия, зарплата, адрес) с помощью mimesis
2. Валидация CSV-файла (проверка колонок, диапазонов, пустых значений)
3. Трансформация (добавление категорий зарплат, возрастных групп, извлечение города)
4. Формирование текстовой сводки со статистикой
Результат: файлы sample_data.csv, processed_data.csv и summary.txt в /opt/airflow/data/
"""
import pandas as pd
import os
from datetime import datetime, timedelta
from airflow import DAG
@@ -56,6 +57,7 @@ def generate_sample_data():
'id': range(1, 101),
'name': names,
'age': ages,
'occupation': occupations,
'salary': [max(30000, min(150000, ages[i] * 1200 + (hash(names[i]) % 15000) - 5000)) for i in range(100)],
'address': [address.address() for _ in range(100)]
}
@@ -68,6 +70,7 @@ def generate_sample_data():
def read_and_validate_data():
"""Чтение и валидация CSV файла"""
import pandas as pd
df = pd.read_csv('/opt/airflow/data/input/sample_data.csv')
print(f"Прочитан файл: {len(df)} строк, {len(df.columns)} столбцов")
print(f"Колонки: {list(df.columns)}")
@@ -87,6 +90,7 @@ def read_and_validate_data():
def transform_data():
"""Преобразование данных"""
import pandas as pd
import os
df = pd.read_csv('/opt/airflow/data/input/sample_data.csv')
@@ -115,6 +119,7 @@ def transform_data():
def write_summary():
"""Создание сводки по обработанным данным"""
import pandas as pd
df = pd.read_csv('/opt/airflow/data/output/processed_data.csv')
summary = {