4.7 KiB
4.7 KiB
План: Decouple polygon v0.2.1
Цель: разнести монолитный app.py (400 строк, 17 роутов) на отдельные blueprint-файлы
по шаблону app-autotest. Никакого инлайн-CSS/HTML — всё в static/ и templates/.
Текущее → Целевое
polygon/site/
├── app.py (400 строк, всё в одном)
├── mock_state.py
├── state_machine.py
├── config_loader.py
└── from_stands.py
↓
polygon/site/
├── app.py # ТОЛЬКО: Flask(), register_blueprint, /health, app.run()
├── routes/
│ ├── root.py # GET / (render_template + style.css)
│ ├── services_routes.py # GET /api/v1/svc/services, GET /services/<id>
│ ├── instances_routes.py # GET/POST /api/v1/svc/instances, GET /instances/<uid>
│ ├── operations_routes.py # POST /instanceOperations, GET default, GET status, POST params, GET validate
│ ├── run.py # POST /instanceOperations/<uid>/run
│ └── mock_routes.py # POST /_mock/reset, GET /_mock/state, GET /_mock/services, POST /_mock/delay
├── state/
│ ├── mock_state.py # MockState (без изменений)
│ └── state_machine.py # apply_effect (без изменений)
├── config/
│ └── loader.py # load_services() (бывший config_loader.py)
├── converter/
│ └── from_stands.py # конвертер (без изменений)
├── utils/
│ ├── pluralize.py # _pluralize() — одна функция
│ └── now.py # _now() — одна функция
├── static/
│ └── style.css # CSS из index() — тёмная тема
├── templates/
│ └── index.html # HTML из index() — Jinja2 с {{ VERSION }}
└── services/
└── ...yaml # без изменений
Пошагово
Шаг 1. Утилиты
utils/now.py—_now()из app.py (одна функция)utils/pluralize.py—_pluralize()из state_machine.py (одна функция)
Шаг 2. CSS и HTML
static/style.css— вынести инлайн-CSS из f-строкиindex()templates/index.html— вынести HTML из f-строки, использовать Jinja2{{ version }},<link rel="stylesheet">
Шаг 3. Маршруты — 6 blueprint-файлов
Каждый blueprint импортирует нужные модули из state/, config/, utils/.
routes/root.py—bp = Blueprint("root", __name__), роут/сrender_templateroutes/services_routes.py—bp = Blueprint("services", __name__), 2 роутаroutes/instances_routes.py—bp = Blueprint("instances", __name__), 3 роутаroutes/operations_routes.py—bp = Blueprint("operations", __name__), 5 роутовroutes/run.py—bp = Blueprint("run", __name__), 1 роутroutes/mock_routes.py—bp = Blueprint("mock", __name__), 4 роута
Шаг 4. app.py — только скелет
import os
from flask import Flask
from routes.root import bp as root_bp
from routes.services_routes import bp as services_bp
# ... все 6 blueprint'ов
from config.loader import load_services
os.environ.setdefault("WEB_CONCURRENCY", "1")
VERSION = "0.2.1"
MOCK_OP_DELAY = float(os.getenv("MOCK_OP_DELAY", "0.1"))
app = Flask(__name__, template_folder="templates", static_folder="static")
app.register_blueprint(root_bp)
app.register_blueprint(services_bp)
# ... все 6
@app.route("/health")
def health():
return "OK"
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000)
Шаг 5. Импорты в state_machine и from_stands
state_machine.py:from utils.pluralize import pluralize(вместо_pluralize()внутри)from_stands.py: импортируетpluralizeизutils/
Что НЕ меняется
state/mock_state.py— как естьstate/state_machine.py— только импортpluralizeconverter/from_stands.py— только импортpluralizeservices/*.yaml— данныеtests/— только поправить пути импорта (site → site.state и т.д.)
Верификация
python -m py_compileна ВСЕХ .py файлахpython -c "from app import app; [print(r.rule) for r in app.url_map.iter_rules()]"→ те же 17 роутовpytest tests/ -v→ 19/19 PASS- Запустить
python app.py→ curl /health, /services, /instances → работает