Перейти к содержанию

Разработка

Настройка окружения

git clone https://github.com/bqio/raclib.git
cd raclib
pip install -e ".[dev]"

Для работы над документацией:

pip install -e ".[docs]"
mkdocs serve            # предпросмотр на http://127.0.0.1:8000
mkdocs build --strict   # так же, как в CI, — падает на предупреждениях

Тесты

Тесты написаны на стандартном unittest и не требуют внешних зависимостей:

python -m unittest discover -s tests -t .   # без установки пакета
pytest -q                                   # то же самое через pytest

Сквозные тесты запускают настоящий подпроцесс (интерпретатор Python вместо rac), поэтому проверяются реальное декодирование вывода, коды возврата и таймауты.

Линтер

ruff check src tests tools
ruff format src tests tools

Настроен набор правил pydocstyle (D): у публичных классов и методов должен быть докстринг. Это не формальность — именно докстринги формируют справочник API, и без них новая команда появится в документации без описания.

Сверка параметров с реальным rac

Имена параметров нельзя проверить по документации: RAC молча игнорирует неизвестный параметр, поэтому команда уходит без нужной настройки, и ошибку никто не видит. Поэтому есть отдельный инструмент:

python tools/audit_rac_help.py           # найти rac автоматически
python tools/audit_rac_help.py --check   # код 1 при расхождениях

Он разбирает rac help <режим> и сравнивает описание каждой команды с набором --флагов, который собирает соответствующий метод. Так были найдены две ошибки:

  • --safe-working-processess-memory-limit вместо ...processes... — опечатка в имени параметра, RAC такой параметр не применял;
  • --db-user и --db-pwd у Infobase.drop — этих параметров у rac infobase drop нет: учётные данные сервера СУБД берутся из самой информационной базы.

Тест tests/test_rac_help.py запускает ту же проверку и пропускается, если rac на машине нет, — поэтому в CI она не выполняется, а на машине администратора работает.

Асинхронная ветка генерируется

Каталог src/raclib/asynchronous/ не редактируется вручную. Командные модули генерируются из синхронных исходников:

python tools/generate_async.py           # перегенерировать
python tools/generate_async.py --check   # проверить актуальность

Единственный источник правды для команд — src/raclib/cmd/. Если поправить файл в asynchronous/cmd/, тест tests/test_generator.py это покажет, а CI упадёт на шаге generate_async.py --check.

Почему так

Раньше обе ветки были ручными копиями и успели разойтись: регекс разбора вывода в асинхронной ветке требовал \r в конце строки, поэтому на Linux-выводе to_list() молча возвращал пустой список. Ошибку не ловил ни один тест — регекс был скопирован, а не выведен из общего кода.

Что остаётся ручным

Файл Почему
asynchronous/_transport.py запуск процесса через asyncio, а не subprocess
asynchronous/session.py await, семафор, псевдонимы exec/call
asynchronous/errors.py реэкспорт общего модуля ошибок
asynchronous/__init__.py публичный API пакета

Общая логика (разбор вывода, таблица ошибок, утилиты) лежит в src/raclib/_shared.py и используется обеими ветками.

Докстринги команд

Все 89 методов команд описаны докстрингами, которые проставляются скриптом tools/add_docstrings.py: описания хранятся в его таблице, а привязка идёт по AST с реальными сигнатурами.

python tools/add_docstrings.py           # проставить и обновить
python tools/add_docstrings.py --check   # проверить покрытие

Если у метода изменится набор параметров, --check сообщит, что описание отсутствует — в документации не появится устаревший список аргументов.

Что проверяет CI

.github/workflows/ci.yml на матрице Linux/Windows × Python 3.12/3.13:

  1. ruff check src tests tools;
  2. python tools/generate_async.py --check — асинхронное дерево актуально;
  3. pytest -q;
  4. импорт пакета и сборка колеса;
  5. отдельный job — прогон тестов вообще без pytest.

.github/workflows/docs.yml собирает документацию и публикует её на GitHub Pages при пуше в main.

Выпуск релиза

  1. Обновить version в pyproject.toml.
  2. Обновить раздел с изменениями, если он есть.
  3. Поставить тег vX.Y.Z и запушить его:
git tag v1.2.0
git push origin v1.2.0

Тег v* запускает .github/workflows/publish.yml: сборка, GitHub Release и публикация на PyPI через Trusted Publishing.

Версия в pyproject.toml и тег должны совпадать

PyPI не позволяет перезаписать уже опубликованную версию. Если номер в pyproject.toml не совпадает с тегом, публикация завершится ошибкой, а номер версии будет занят.