zapretgui/tools/generate_profile_icon_bundle.py
2026-07-06 23:23:23 +03:00

119 lines
4.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Генератор бандла simple-иконок для профилей.
Извлекает из пакета simplepycons ТОЛЬКО те SVG, которые реально используются
каталогом иконок профилей (profile/icons.py), и записывает их в сгенерированный
модуль src/profile/ui/simple_icons_bundle.py.
Зачем: импорт simplepycons тянет ~3400 модулей (~2.6с и десятки МБ памяти),
поэтому в рантайме приложения он не используется вообще. simplepycons нужен
только на машине разработчика для регенерации бандла.
Запуск (из корня репозитория):
PYTHONPATH=src python tools/generate_profile_icon_bundle.py
После добавления нового сервиса с иконкой "simple:<slug>:<fallback>" в
profile/icons.py — перезапустить генератор. Тест
tests/test_profile_icon_bundle.py упадёт, если бандл не покрывает каталог.
"""
from __future__ import annotations
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
PROJECT_SRC = PROJECT_ROOT / "src"
if str(PROJECT_SRC) not in sys.path:
sys.path.insert(0, str(PROJECT_SRC))
BUNDLE_PATH = PROJECT_SRC / "profile" / "ui" / "simple_icons_bundle.py"
_HEADER = '''"""Бандл simple-иконок профилей. СГЕНЕРИРОВАНО — НЕ редактировать вручную.
Источник: пакет simplepycons (Simple Icons, CC0). Здесь лежат только SVG,
которые реально используются каталогом profile/icons.py — благодаря этому
рантайм не импортирует simplepycons (~3400 модулей, ~2.6с).
Регенерация: PYTHONPATH=src python tools/generate_profile_icon_bundle.py
"""
from __future__ import annotations
# slug -> (primary_color_hex, raw_svg)
SIMPLE_ICON_SVGS: dict[str, tuple[str, str]] = {
'''
_FOOTER = '''}
__all__ = ["SIMPLE_ICON_SVGS"]
'''
def collect_catalog_slugs() -> list[str]:
"""Собирает уникальные simple-слаги из каталога иконок профилей."""
import profile.icons as profile_icons
slugs: set[str] = set()
for attr_name in dir(profile_icons):
attr = getattr(profile_icons, attr_name)
if not isinstance(attr, dict):
continue
for value in attr.values():
icon_name = str(getattr(value, "icon_name", "") or "")
if not icon_name.startswith("simple:"):
continue
slug = icon_name.removeprefix("simple:").partition(":")[0]
slug = slug.strip().lower().replace("-", "")
if slug:
slugs.add(slug)
return sorted(slugs)
def extract_icon(all_icons, slug: str) -> tuple[str, str] | None:
try:
icon = all_icons[slug]
except Exception:
getter = getattr(all_icons, f"get_{slug}_icon", None)
if not callable(getter):
return None
try:
icon = getter()
except Exception:
return None
raw_svg = str(getattr(icon, "raw_svg", "") or "").strip()
if not raw_svg:
return None
primary_color = str(getattr(icon, "primary_color", "") or "").lstrip("#").strip()
return (f"#{primary_color}" if primary_color else "", raw_svg)
def main() -> int:
slugs = collect_catalog_slugs()
if not slugs:
print("Каталог иконок не дал ни одного simple-слага — ничего не делаю.", file=sys.stderr)
return 1
from simplepycons import all_icons
lines: list[str] = [_HEADER]
missing: list[str] = []
for slug in slugs:
entry = extract_icon(all_icons, slug)
if entry is None:
missing.append(slug)
continue
primary_color, raw_svg = entry
lines.append(f" {slug!r}: ({primary_color!r}, {raw_svg!r}),\n")
lines.append(_FOOTER)
if missing:
print(f"ОШИБКА: в simplepycons не найдены слаги: {', '.join(missing)}", file=sys.stderr)
return 1
BUNDLE_PATH.write_text("".join(lines), encoding="utf-8")
print(f"Записан {BUNDLE_PATH.relative_to(PROJECT_ROOT)}: {len(slugs)} иконок.")
return 0
if __name__ == "__main__":
raise SystemExit(main())