85 lines
2.7 KiB
Python
85 lines
2.7 KiB
Python
"""Сервис загрузки справочника команд платы из .csv файлов.
|
||
|
||
Папка commands/ лежит рядом с исполняемым файлом (или рядом с main.py
|
||
при разработке). Каждый .csv файл содержит набор команд с колонками,
|
||
разделёнными точкой с запятой:
|
||
command;name;description
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import csv
|
||
import sys
|
||
from dataclasses import dataclass, field
|
||
from pathlib import Path
|
||
|
||
|
||
@dataclass
|
||
class Command:
|
||
"""Одна команда платы."""
|
||
code: str
|
||
name: str
|
||
description: str
|
||
|
||
|
||
@dataclass
|
||
class CommandSet:
|
||
"""Набор команд из одного CSV-файла."""
|
||
set_name: str
|
||
commands: list[Command] = field(default_factory=list)
|
||
|
||
|
||
def _get_commands_dir() -> Path:
|
||
"""Определить путь к папке commands/.
|
||
|
||
При запуске из .exe (PyInstaller) — рядом с exe-файлом.
|
||
При запуске из исходников — рядом с корнем проекта.
|
||
"""
|
||
if getattr(sys, "frozen", False):
|
||
base = Path(sys.executable).parent
|
||
else:
|
||
base = Path(__file__).resolve().parent.parent.parent
|
||
return base / "commands"
|
||
|
||
|
||
def load_command_set(path: Path) -> CommandSet | None:
|
||
"""Загрузить один .csv файл. Возвращает None при ошибке."""
|
||
try:
|
||
text = path.read_text(encoding="utf-8")
|
||
except Exception:
|
||
return None
|
||
|
||
commands: list[Command] = []
|
||
reader = csv.reader(text.splitlines(), delimiter=";")
|
||
for i, row in enumerate(reader):
|
||
if len(row) < 3:
|
||
continue
|
||
code, name, description = row[0].strip(), row[1].strip(), row[2].strip()
|
||
# Пропускаем заголовок
|
||
if i == 0 and code.lower() == "command":
|
||
continue
|
||
if not code:
|
||
continue
|
||
commands.append(Command(code=code, name=name, description=description))
|
||
|
||
return CommandSet(set_name=path.stem, commands=commands)
|
||
|
||
|
||
def load_all_command_sets() -> list[CommandSet]:
|
||
"""Загрузить все .csv файлы из папки commands/."""
|
||
commands_dir = _get_commands_dir()
|
||
if not commands_dir.is_dir():
|
||
return []
|
||
|
||
sets: list[CommandSet] = []
|
||
for csv_file in sorted(commands_dir.glob("*.csv")):
|
||
cs = load_command_set(csv_file)
|
||
if cs is not None and cs.commands:
|
||
sets.append(cs)
|
||
return sets
|
||
|
||
|
||
def get_commands_dir() -> Path:
|
||
"""Публичный доступ к пути папки (для UI «Открыть папку»)."""
|
||
return _get_commands_dir()
|