fix(cli): Отвечать ошибкой ввода вместо молчаливого открытия GUI - #46
Merged
Merged
Conversation
Разбор аргументов принимал единственный шаблон и на любое отклонение
возвращал handled=False. Процесс проваливался в Qt event loop: из
терминала поднималось пустое окно, а в CI команда висела до таймаута —
ни сообщения, ни usage, ни кода возврата. Опечатка во флаге, перепутанный
порядок, другой регистр, `unpack --help` — всё это выглядело как
зависание, а не как ошибка ввода.
Теперь команда unpack всегда обрабатывается в консоли: при неверном
синтаксисе печатается помощь и возвращается код 2. GUI-режим не тронут —
файл без команды unpack по-прежнему уходит в окно.
- Флаг сверяется строкой, а не argparse: allow_abbrev=False отключает
сокращения только для --опций, и argparse принял бы `-t out` как
-tmplts. Проверено на 3.9.
- Хвост после каталога отклоняется: `unpack a.efd -tmplts out b.efd`
отвечал [OK] с кодом 0, обработав только первый файл.
- --help и -h ищутся по всему argv, а не только в argv[1]. Полный
argparse на верхнем уровне не подходит: main намеренно пропускает
нераспознанные аргументы в Qt.
- Схема efd:// приведена к разбору file://. Ветка делала
parsed.path.lstrip("/"), поэтому абсолютный путь становился
относительным, netloc терялся вместе с буквой диска, а percent-encoding
не раскрывался. Не работала ни одна реалистичная форма, включая команду
прямо из FILE_ASSOCIATION_GUIDE.
- eventFilter на macOS больше не гасит событие не-file схемы: при пустом
toLocalFile() берётся url().toString().
- process_file_argument больше не валидирует и не теряет код ошибки.
Причину показывает set_input_file, который уже ловит исключение и уже
показывает локализованный QMessageBox; две мёртвые ветки показа ошибки
в main() удалены. Сообщение показывается только для аргументов, похожих
на файл или URL, иначе посторонние флаги Qt давали бы ложные отказы.
format_help_text вынесен в application/help_text.py: помощь нужна и слою
CLI, и main, а обратный импорт замкнул бы цикл.
Контракт `unpack <file>` без -tmplts изменён намеренно: docs/CLI.md
называл эту форму «не headless-режимом», но GUI не обещал. Тест на
прежнее поведение переписан, поведение задокументировано.
Тесты: 274 -> 290, сняты два xfail(strict=True).
Closes #15
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
URL всегда несёт прямые слэши, а str(Path) на Windows — обратные: C:/Users/x/a.efd и C:\\Users\\x\\a.efd указывают на один файл, но как строки не равны. Разделители приводит к системным os.path.abspath уже внутри валидатора, так что на поведение это не влияло — только на строгость самих тестов. Заодно два теста на Windows собирали не ту форму URL. as_posix() там начинается с буквы диска, поэтому efd:// + as_posix() давало форму с authority (efd://C:/...) и уходило в ветку разбора буквы диска, а не в форму с тремя слэшами, которую тест заявлял. Теперь URL собирается из as_uri() и одинаков на всех платформах. Тест на localhost по той же причине собирал невалидный netloc "localhostC:" — хост вставляется в готовый file://-URL.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #15.
Главное: неверный ввод выглядел как зависание
Разбор принимал единственный шаблон
argv[1] == "unpack" and argv[3] == "-tmplts"и на любое отклонение возвращалhandled=False. Процесс проваливался в Qt event loop. Сквозной прогонpython3 main.pyподQT_QPA_PLATFORM=offscreen— до и после:unpack f.efd -tmplts out[OK][OK]unpack f.efd --tmplts outunpack -tmplts out f.efdUNPACK f.efd -tmplts outunpack f.efdunpack f.efd -tmplts out EXTRA[OK]— хвост отброшенunpack --help--helpКритерий 4 (
unpack --helpпечатает тот же текст, что--help) проверенdiff— выводы идентичны.GUI-режим не тронут: файл без команды
unpackпо-прежнему уходит в окно, и на это есть отдельный тест.Почему не argparse
Issue предлагал argparse. Отказался по двум причинам, обе проверяемые:
allow_abbrev=Falseне защищает-tmplts. Флаг отключает сокращения только для---опций; argparse всё равно принял бы-t outи-tmp out. Issue это сам отмечает — значит, флаг пришлось бы сверять строкой в любом случае.sys.exit(2)в stderr, а проект печатает через инжектируемыйoutputи возвращаетCLIResult, не завершая процесс. ЛовитьSystemExitради этого — больше кода, чем явный разбор.Явный разбор занимает 15 строк и даёт ровно нужную семантику. Сокращения
-t/-tmpзакрыты отдельными тестами.Схема efd://
Ветка делала
parsed.path.lstrip("/"): абсолютный путь становился относительным,netlocтерялся вместе с буквой диска,unquoteне вызывался. Не работала ни одна реалистичная форма, включая команду прямо изdocs/FILE_ASSOCIATION_GUIDE.md. Теперьfile://иefd://разбираются одним кодом, и тест требует их посимвольного совпадения на пяти именах — ASCII, кириллица, пробел,+,%.Отдельная ветка для
netloc, оканчивающегося на:—efd://C:/dir/f.efdэто буква диска, а не UNC-хост; без неё путь превратился бы в//C:/dir/f.efd.eventFilterна macOS больше не гасит событие не-file схемы: при пустомtoLocalFile()берётсяurl().toString(). Это независимый дефект — починка разбора сама по себе клик поefd://-ссылке не оживила бы.Причина отказа дошла до пользователя
process_file_argumentловилFileValidationErrorи возвращалNone, теряя код. Обе ветки показа причины вmain()были при этом мертвы дважды: до них не доходило исключение, аset_input_fileсам ловит его и сам показывает локализованныйQMessageBox.Убрал валидацию из
process_file_argument(теперь это чистое «URL → путь»),set_input_fileвернулbool, мёртвые ветки удалены. Показ ограничен аргументами, похожими на файл или URL — иначе флаги запуска Qt (-platform,--style) давали бы ложное «файл не существует».format_help_textвынесен вapplication/help_text.py: помощь нужна и слою CLI, иmain, аmainимпортируетcli, так что обратный импорт замкнул бы цикл — плюсmainтянет PyQt5, которого слою CLI не нужно.Изменение контракта
unpack <file>без-tmpltsраньше уводил в GUI.docs/CLI.mdназывал эту форму «не headless-режимом», но GUI не обещал. Теперь это ошибка ввода: код 2 + usage. Тестtest_cli_does_not_handle_incomplete_commandпереписан с объяснением, поведение задокументировано вdocs/CLI.md(новый раздел «Помощь и ошибки ввода»).Проверил, что строгий разбор не сломает релизный конвейер: все пять смоук-вызовов в
build-and-release.yml(строки 191, 238, 258, 321, 381) используют ровно формуunpack <file> -tmplts <dir>.Тесты
274 → 290. Сняты два
xfail(strict=True)наefd://.Обратные мутации:
len(rest) >= 3(хвост отбрасывается)1 failedhandled=Falseна неверном хвосте10 failedlstrip("/")дляefd://12 failed