diff --git a/.gitignore b/.gitignore index d905abf..76ec387 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ #### joe made this: http://goel.io/joe +.devin metrics/reports/diagrams *.dist *build diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..87d4c12 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,15 @@ +# Argenta + +## Agent skills + +### Issue tracker + +Issues live as GitHub issues in `koloideal/Argenta` (uses the `gh` CLI). See `docs/agents/issue-tracker.md`. + +### Triage labels + +Five canonical labels used as-is: `needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix`. See `docs/agents/triage-labels.md`. + +### Domain docs + +Single-context — one `CONTEXT.md` + `docs/adr/` at the repo root. See `docs/agents/domain.md`. diff --git a/docs/agents/domain.md b/docs/agents/domain.md new file mode 100644 index 0000000..b548c53 --- /dev/null +++ b/docs/agents/domain.md @@ -0,0 +1,51 @@ +# Domain Docs + +How the engineering skills should consume this repo's domain documentation when exploring the codebase. + +## Before exploring, read these + +- **`CONTEXT.md`** at the repo root, or +- **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic. +- **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src//docs/adr/` for context-scoped decisions. + +If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved. + +## File structure + +Single-context repo (most repos): + +``` +/ +├── CONTEXT.md +├── docs/adr/ +│ ├── 0001-event-sourced-orders.md +│ └── 0002-postgres-for-write-model.md +└── src/ +``` + +Multi-context repo (presence of `CONTEXT-MAP.md` at the root): + +``` +/ +├── CONTEXT-MAP.md +├── docs/adr/ ← system-wide decisions +└── src/ + ├── ordering/ + │ ├── CONTEXT.md + │ └── docs/adr/ ← context-specific decisions + └── billing/ + ├── CONTEXT.md + └── docs/adr/ +``` + +## Use the glossary's vocabulary + +When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids. + +If the concept you need isn't in the glossary yet, that's a signal — either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`). + +## Flag ADR conflicts + +If your output contradicts an existing ADR, surface it explicitly rather than silently overriding: + +> _Contradicts ADR-0007 (event-sourced orders) — but worth reopening because…_ diff --git a/docs/agents/issue-tracker.md b/docs/agents/issue-tracker.md new file mode 100644 index 0000000..82cfbf5 --- /dev/null +++ b/docs/agents/issue-tracker.md @@ -0,0 +1,45 @@ +# Issue tracker: GitHub + +Issues and PRDs for this repo live as GitHub issues. Use the `gh` CLI for all operations. + +## Conventions + +- **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies. +- **Read an issue**: `gh issue view --comments`, filtering comments by `jq` and also fetching labels. +- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters. +- **Comment on an issue**: `gh issue comment --body "..."` +- **Apply / remove labels**: `gh issue edit --add-label "..."` / `--remove-label "..."` +- **Close**: `gh issue close --comment "..."` + +Infer the repo from `git remote -v` — `gh` does this automatically when run inside a clone. + +## Pull requests as a triage surface + +**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/triage` reads this flag.)_ + +When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents: + +- **Read a PR**: `gh pr view --comments` and `gh pr diff ` for the diff. +- **List external PRs for triage**: `gh pr list --state open --json number,title,body,labels,author,authorAssociation,comments` then keep only `authorAssociation` of `CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`, or `NONE` (drop `OWNER`/`MEMBER`/`COLLABORATOR`). +- **Comment / label / close**: `gh pr comment`, `gh pr edit --add-label`/`--remove-label`, `gh pr close`. + +GitHub shares one number space across issues and PRs, so a bare `#42` may be either — resolve with `gh pr view 42` and fall back to `gh issue view 42`. + +## When a skill says "publish to the issue tracker" + +Create a GitHub issue. + +## When a skill says "fetch the relevant ticket" + +Run `gh issue view --comments`. + +## Wayfinding operations + +Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets. + +- **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`. +- **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #` at the top of the child body. Labels: `wayfinder:` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev. +- **Blocking**: GitHub's **native issue dependencies** — the canonical, UI-visible representation. Add an edge with `gh api --method POST repos///issues//dependencies/blocked_by -F issue_id=`, where `` is the blocker's numeric **database id** (`gh api repos///issues/ --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only — the live gate). Where dependencies aren't available, fall back to a `Blocked by: #, #` line at the top of the child body. A ticket is unblocked when every blocker is closed. +- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins. +- **Claim**: `gh issue edit --add-assignee @me` — the session's first write. +- **Resolve**: `gh issue comment --body ""`, then `gh issue close `, then append a context pointer (gist + link) to the map's Decisions-so-far. diff --git a/docs/agents/triage-labels.md b/docs/agents/triage-labels.md new file mode 100644 index 0000000..b716855 --- /dev/null +++ b/docs/agents/triage-labels.md @@ -0,0 +1,15 @@ +# Triage Labels + +The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. + +| Label in mattpocock/skills | Label in our tracker | Meaning | +| -------------------------- | -------------------- | ---------------------------------------- | +| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue | +| `needs-info` | `needs-info` | Waiting on reporter for more information | +| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent | +| `ready-for-human` | `ready-for-human` | Requires human implementation | +| `wontfix` | `wontfix` | Will not be actioned | + +When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table. + +Edit the right-hand column to match whatever vocabulary you actually use. diff --git a/docs/locales/en/LC_MESSAGES/root/cli.po b/docs/locales/en/LC_MESSAGES/root/cli.po index 98e3eed..8bd79f9 100644 --- a/docs/locales/en/LC_MESSAGES/root/cli.po +++ b/docs/locales/en/LC_MESSAGES/root/cli.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Argenta \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-07-25 18:00+0300\n" +"POT-Creation-Date: 2026-08-03 18:51+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: en\n" @@ -18,248 +18,583 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.17.0\n" -#: ../../root/cli.rst:3 -msgid "Командная строка" -msgstr "Command Line Interface" +#: ../../root/cli.rst:4 +msgid "CLI" +msgstr "CLI" -#: ../../root/cli.rst:5 +#: ../../root/cli.rst:6 msgid "" -"Помимо библиотеки, ``Argenta`` поставляется с собственным CLI-инструментом, " -"который помогает создавать проекты, запускать приложения, инспектировать " -"маршруты и собирать бинарники." +"Помимо библиотеки, ``Argenta`` поставляется с собственным " +"CLI-инструментом. Он берёт на себя рутину, которая сопровождает " +"разработку CLI-приложений: создаёт каркас проекта, запускает приложение, " +"инспектирует зарегистрированные маршруты и собирает standalone-бинарник." msgstr "" -"In addition to the library, ``Argenta`` ships with its own CLI tool that " -"helps scaffold projects, run applications, inspect routes, and build binaries." +"In addition to the library, ``Argenta`` ships with its own CLI tool. It " +"takes over the routine that surrounds CLI app development: scaffolds a " +"project, runs the application, inspects registered routes, and builds a " +"standalone binary." #: ../../root/cli.rst:8 +msgid "" +"CLI поставляется как опциональная зависимость — основная библиотека " +"остаётся лёгкой, а инструмент доступен только тем, кому он нужен." +msgstr "" +"The CLI is shipped as an optional dependency — the core library stays " +"light, and the tool is available only to those who need it." + +#: ../../root/cli.rst:11 msgid "Установка" msgstr "Installation" -#: ../../root/cli.rst:10 -msgid "CLI доступен как опциональная зависимость:" -msgstr "The CLI is available as an optional dependency:" +#: ../../root/cli.rst:13 +msgid "CLI доступен как опциональная зависимость ``[cli]``:" +msgstr "The CLI is available as the optional ``[cli]`` dependency:" -#: ../../root/cli.rst:16 +#: ../../root/cli.rst:23 +msgid "После установки команда ``argenta`` доступна в терминале:" +msgstr "After installation, the ``argenta`` command is available in the terminal:" + +#: ../../root/cli.rst:34 msgid "" -"После установки команда ``argenta`` доступна в терминале:" +"Если ``argenta`` установлена без extras, команда ``argenta`` не будет " +"доступна. Установите с ``[cli]``, чтобы получить доступ к " +"CLI-инструменту." msgstr "" -"After installation, the ``argenta`` command is available in the terminal:" +"If ``argenta`` is installed without extras, the ``argenta`` command will " +"not be available. Install with ``[cli]`` to get access to the CLI tool." -#: ../../root/cli.rst:22 -msgid "" -"Если вы устанавливали ``argenta`` без extras, CLI-инструмент не будет " -"доступен. Установите с ``[cli]`` для доступа к команде ``argenta``." -msgstr "" -"If you installed ``argenta`` without extras, the CLI tool will not be " -"available. Install with ``[cli]`` to access the ``argenta`` command." - -#: ../../root/cli.rst:25 +#: ../../root/cli.rst:37 msgid "Флаг ``--version``" msgstr "The ``--version`` flag" -#: ../../root/cli.rst:27 +#: ../../root/cli.rst:39 msgid "Показать установленную версию ``Argenta``:" msgstr "Show the installed ``Argenta`` version:" -#: ../../root/cli.rst:35 -msgid "Создание проектов" -msgstr "Scaffolding Projects" - -#: ../../root/cli.rst:38 -msgid "Команда ``new``" -msgstr "The ``new`` command" - -#: ../../root/cli.rst:40 -msgid "Создаёт новую директорию проекта с boilerplate-кодом." -msgstr "Creates a new project directory with boilerplate code." - -#: ../../root/cli.rst:44 -msgid "``project_name`` — имя директории проекта (обязательный аргумент)." -msgstr "``project_name`` — project directory name (required argument)." - #: ../../root/cli.rst:45 -msgid "``--with-arch`` — архитектура проекта: ``flat`` (по умолчанию) или ``src``." -msgstr "``--with-arch`` — project architecture: ``flat`` (default) or ``src``." +msgid "Аналогично через короткий флаг:" +msgstr "Equivalently, via the short flag:" -#: ../../root/cli.rst:53 -msgid "При архитектуре ``flat`` создаётся следующая структура:" -msgstr "With the ``flat`` architecture, the following structure is created:" +#: ../../root/cli.rst:56 +msgid "Формат entrypoint" +msgstr "Entrypoint format" -#: ../../root/cli.rst:59 -msgid "При архитектуре ``src``:" -msgstr "With the ``src`` architecture:" +#: ../../root/cli.rst:58 +msgid "" +"Команды ``run``, ``routes`` и ``build`` принимают **entrypoint** — " +"указатель на объект внутри проекта, который нужно запустить, " +"инспектировать или собрать. Единый формат описан здесь, чтобы не " +"повторяться в каждой команде." +msgstr "" +"The ``run``, ``routes`` and ``build`` commands accept an **entrypoint** —" +" a pointer to an object inside the project to run, inspect, or build. The" +" shared format is documented here once instead of repeating it in each " +"command." + +#: ../../root/cli.rst:60 +msgid "Формат entrypoint:" +msgstr "Entrypoint format:" #: ../../root/cli.rst:67 -msgid "Команда ``init``" -msgstr "The ``init`` command" +msgid "Поддерживаются два способа адресации:" +msgstr "Two addressing styles are supported:" #: ../../root/cli.rst:69 msgid "" -"Инициализирует boilerplate в текущей директории. Удобно, когда проект уже " -"существует и нужно добавить структуру Argenta." +"**Путь к файлу** — ``app/main.py:main``. Удобно при работе с конкретным " +"файлом." msgstr "" -"Initializes boilerplate in the current directory. Useful when the project " -"already exists and you need to add Argenta structure." +"**File path** — ``app/main.py:main``. Convenient when working with a " +"specific file." -#: ../../root/cli.rst:75 +#: ../../root/cli.rst:70 msgid "" -"Команда ``init`` не перезаписывает существующие файлы — они будут пропущены." +"**Dotted-модуль** — ``my_project.application:main``. Естественно для " +"установленных пакетов." msgstr "" -"The ``init`` command does not overwrite existing files — they will be skipped." +"**Dotted module** — ``my_project.application:main``. Natural for " +"installed packages." -#: ../../root/cli.rst:80 -msgid "Запуск приложений" -msgstr "Running Applications" +#: ../../root/cli.rst:72 +msgid "" +"Если передан путь к директории с ``__main__.py``, он разрешается " +"автоматически — указывать файл явно не нужно." +msgstr "" +"If a directory path containing ``__main__.py`` is passed, it is resolved " +"automatically — no need to name the file explicitly." -#: ../../root/cli.rst:83 +#: ../../root/cli.rst:74 +msgid "**Примеры валидных entrypoint-ов:**" +msgstr "**Examples of valid entrypoints:**" + +#: ../../root/cli.rst:84 +msgid "" +"Тип объекта зависит от команды: ``run`` и ``build`` ожидают callable, " +"``routes`` — инстанс ``App`` или callable, возвращающий ``App``." +msgstr "" +"The expected object type depends on the command: ``run`` and ``build`` " +"expect a callable, ``routes`` expects an ``App`` instance or a callable " +"returning ``App``." + +#: ../../root/cli.rst:89 +msgid "Создание проектов" +msgstr "Scaffolding projects" + +#: ../../root/cli.rst:92 +msgid "Команда ``new``" +msgstr "The ``new`` command" + +#: ../../root/cli.rst:94 +msgid "" +"Создаёт новую директорию проекта с boilerplate-кодом. Это отправная " +"точка: вместо ручной настройки структуры — готовый каркас за одну " +"команду." +msgstr "" +"Creates a new project directory with boilerplate code. It is the starting" +" point: instead of setting up the structure by hand, a ready-made " +"skeleton in a single command." + +#: ../../root/cli.rst:100 +msgid "``project_name`` — имя директории проекта (обязательный аргумент)." +msgstr "``project_name`` — project directory name (required argument)." + +#: ../../root/cli.rst:101 ../../root/cli.rst:133 +msgid "``--arch`` — архитектура проекта: ``flat`` (по умолчанию) или ``src``." +msgstr "``--arch`` — project architecture: ``flat`` (default) or ``src``." + +#: ../../root/cli.rst:103 ../../root/cli.rst:135 ../../root/cli.rst:161 +#: ../../root/cli.rst:191 +msgid "**Примеры:**" +msgstr "**Examples:**" + +#: ../../root/cli.rst:110 +msgid "При архитектуре ``flat`` создаётся следующая структура:" +msgstr "With the ``flat`` architecture, the following structure is created:" + +#: ../../root/cli.rst:115 +msgid "При архитектуре ``src``:" +msgstr "With the ``src`` architecture:" + +#: ../../root/cli.rst:125 +msgid "Команда ``init``" +msgstr "The ``init`` command" + +#: ../../root/cli.rst:127 +msgid "" +"Делает то же, что и ``new``, но в текущей директории. Удобно, когда " +"проект уже существует и нужно добавить структуру Argenta, не создавая " +"лишний уровень вложенности." +msgstr "" +"Does the same as ``new``, but in the current directory. Convenient when " +"the project already exists and the Argenta structure needs to be added " +"without introducing an extra level of nesting." + +#: ../../root/cli.rst:143 +msgid "" +"Команда ``init`` не перезаписывает существующие файлы — они будут " +"пропущены." +msgstr "The ``init`` command does not overwrite existing files — they are skipped." + +#: ../../root/cli.rst:148 +msgid "Запуск приложения" +msgstr "Running an application" + +#: ../../root/cli.rst:151 msgid "Команда ``run``" msgstr "The ``run`` command" -#: ../../root/cli.rst:85 +#: ../../root/cli.rst:153 msgid "" -"Запускает оркестратор ``Argenta`` из callable-ентрипойнта. Это альтернатива " -"прямому вызову ``python main.py``, но с автоматической настройкой окружения." +"Запускает оркестратор ``Argenta`` из callable-entrypoint. Это " +"альтернатива прямому вызову ``python main.py``, но с автоматической " +"настройкой окружения." msgstr "" -"Starts the ``Argenta`` orchestrator from a callable entrypoint. This is an " -"alternative to directly calling ``python main.py``, but with automatic " +"Starts the ``Argenta`` orchestrator from a callable entrypoint. It is an " +"alternative to calling ``python main.py`` directly, but with automatic " "environment setup." -#: ../../root/cli.rst:89 -msgid "" -"``entrypoint`` — путь к callable в формате " -"``:`` или ``:``." -msgstr "" -"``entrypoint`` — path to a callable in the format " -"``:`` or ``:``." +#: ../../root/cli.rst:159 ../../root/cli.rst:189 ../../root/cli.rst:249 +msgid "Формат entrypoint — см. :ref:`Формат entrypoint `." +msgstr "Entrypoint format — see :ref:`Entrypoint format `." -#: ../../root/cli.rst:99 +#: ../../root/cli.rst:173 msgid "" "Команда ``run`` устанавливает переменную окружения " -"``RUN_FROM_ARGENTA_RUNNER=1``, что отключает парсинг аргументов командной " -"строки в ``ArgParser``. Это позволяет запустить REPL без конфликтов с " -"CLI-аргументами ``argenta``." +"``RUN_FROM_ARGENTA_RUNNER=1``. ``ArgParser`` видит этот флаг и пропускает" +" парсинг ``sys.argv``, поэтому аргументы самого ``argenta`` (типа " +"``--help``, ``--version``) не конфликтуют с аргументами запускаемого " +"приложения. REPL стартует чисто, без ошибок про неизвестные флаги." msgstr "" "The ``run`` command sets the ``RUN_FROM_ARGENTA_RUNNER=1`` environment " -"variable, which disables command-line argument parsing in ``ArgParser``. " -"This allows starting the REPL without conflicts with ``argenta`` CLI arguments." +"variable. ``ArgParser`` sees this flag and skips parsing ``sys.argv``, so" +" the ``argenta`` arguments themselves (such as ``--help``, ``--version``)" +" do not conflict with the arguments of the application being launched. " +"The REPL starts cleanly, with no errors about unknown flags." -#: ../../root/cli.rst:104 +#: ../../root/cli.rst:178 msgid "Инспекция маршрутов" -msgstr "Inspecting Routes" +msgstr "Inspecting routes" -#: ../../root/cli.rst:107 +#: ../../root/cli.rst:181 msgid "Команда ``routes``" msgstr "The ``routes`` command" -#: ../../root/cli.rst:109 +#: ../../root/cli.rst:183 msgid "" -"Отображает все зарегистрированные роутеры, команды, алиасы и флаги в виде " -"дерева. Принимает как инстанс ``App``, так и callable, возвращающий ``App``." +"Отображает все зарегистрированные роутеры, команды, алиасы и флаги в виде" +" дерева. Принимает как инстанс ``App``, так и callable, возвращающий " +"``App``." msgstr "" "Displays all registered routers, commands, aliases, and flags as a tree. " "Accepts either an ``App`` instance or a callable returning ``App``." -#: ../../root/cli.rst:113 +#: ../../root/cli.rst:198 msgid "" -"``entrypoint`` — путь к ``App`` или callable в формате " -"``:``." +"Инстанс ``App`` передаётся напрямую, если роутеры подключены на уровне " +"модуля:" msgstr "" -"``entrypoint`` — path to an ``App`` or callable in the format " -"``:``." +"An ``App`` instance is passed directly when routers are registered at the" +" module level:" -#: ../../root/cli.rst:125 -msgid "Если передан инстанс ``App``:" -msgstr "If an ``App`` instance is passed:" - -#: ../../root/cli.rst:131 +#: ../../root/cli.rst:204 msgid "" -"Если передан callable (фабрика), он будет вызван, и результат будет " -"использован для отображения маршрутов:" +"Фабрика ``create_app`` передаётся, если роутеры регистрируются внутри " +"функции — например, зависят от конфига или DI:" msgstr "" -"If a callable (factory) is passed, it will be called, and the result will " -"be used to display routes:" +"A ``create_app`` factory is passed when routers are registered inside a " +"function — for example, when they depend on config or DI:" -#: ../../root/cli.rst:139 +#: ../../root/cli.rst:211 msgid "" -"При использовании callable-ентрипойнта (например, ``create_app``) REPL не " -"запускается — фабрика вызывается, и маршруты считываются из возвращённого " -"``App``. Это полезно, когда роутеры подключаются внутри функции, а не на " -"уровне модуля." +"При использовании callable-entrypoint REPL не запускается — фабрика " +"вызывается, и маршруты считываются из возвращённого ``App``." msgstr "" -"When using a callable entrypoint (e.g., ``create_app``), the REPL is not " -"started — the factory is called, and routes are read from the returned " -"``App``. This is useful when routers are registered inside a function " -"rather than at the module level." +"When a callable entrypoint is used, the REPL is not started — the factory" +" is called, and routes are read from the returned ``App``." -#: ../../root/cli.rst:144 -msgid "Сборка бинарников" -msgstr "Building Binaries" +#: ../../root/cli.rst:213 ../../root/cli.rst:325 +msgid "Пример вывода:" +msgstr "Example output:" -#: ../../root/cli.rst:147 +#: ../../root/cli.rst:238 +msgid "Сборка бинарника" +msgstr "Building a binary" + +#: ../../root/cli.rst:241 msgid "Команда ``build``" msgstr "The ``build`` command" -#: ../../root/cli.rst:149 -msgid "Компилирует проект в standalone-бинарник с помощью `Nuitka `_." -msgstr "Compiles a project into a standalone binary using `Nuitka `_." - -#: ../../root/cli.rst:153 +#: ../../root/cli.rst:243 msgid "" -"``entrypoint`` — путь к callable в формате " -"``:``." +"Компилирует проект в standalone-бинарник с помощью `Nuitka " +"`_, которая входит в ``[cli]`` extra." msgstr "" -"``entrypoint`` — path to a callable in the format " -"``:``." +"Compiles a project into a standalone binary using `Nuitka " +"`_, which is included in the ``[cli]`` extra." -#: ../../root/cli.rst:154 +#: ../../root/cli.rst:251 msgid "" -"``--output`` / ``-o`` — имя выходного бинарника (по умолчанию — имя файла " -"или пакета)." +"``--output`` / ``-o`` — имя выходного бинарника (по умолчанию — имя файла" +" или пакета)." msgstr "" -"``--output`` / ``-o`` — output binary name (defaults to the file or package name)." +"``--output`` / ``-o`` — output binary name (defaults to the file or " +"package name)." -#: ../../root/cli.rst:166 +#: ../../root/cli.rst:252 msgid "" -"Для использования команды ``build`` необходимо установить ``Nuitka``:" +"``--`` — разделитель, после которого передаются **произвольные флаги " +"Nuitka**. Они добавляются к вызову Nuitka после аргументов Argenta, " +"поэтому могут переопределять дефолты и добавлять любые опции, которые " +"Nuitka поддерживает." msgstr "" -"To use the ``build`` command, you must install ``Nuitka``:" +"``--`` — a separator after which **arbitrary Nuitka flags** are passed." +" They are appended to the Nuitka invocation after Argenta's arguments," +" so they can override defaults and add any options Nuitka supports." -#: ../../root/cli.rst:174 +#: ../../root/cli.rst:254 +#, fuzzy +msgid "**Базовые примеры:**" +msgstr "**Basic examples:**" + +#: ../../root/cli.rst:262 +msgid "**Примеры с флагами Nuitka:**" +msgstr "**Examples with Nuitka flags:**" + +#: ../../root/cli.rst:271 +msgid "Что делает Argenta по умолчанию" +msgstr "What Argenta does by default" + +#: ../../root/cli.rst:273 +msgid "Команда ``build`` формирует вызов Nuitka со следующими аргументами:" +msgstr "The ``build`` command assembles a Nuitka invocation with the following arguments:" + +#: ../../root/cli.rst:275 +msgid "" +"``--standalone --onefile`` — собирает единый бинарник со всеми " +"зависимостями внутри." +msgstr "" +"``--standalone --onefile`` — builds a single binary with all dependencies" +" bundled inside." + +#: ../../root/cli.rst:276 +msgid "" +"``--output-filename=`` — имя выходного файла (из ``--output`` или " +"имени entrypoint)." +msgstr "" +"``--output-filename=`` — output file name (from ``--output`` or the" +" entrypoint name)." + +#: ../../root/cli.rst:277 +msgid "``--jobs=`` — параллельная компиляция на всех ядрах." +msgstr "``--jobs=`` — parallel compilation across all cores." + +#: ../../root/cli.rst:278 +msgid "" +"``--lto=no`` — LTO отключён по умолчанию (быстрее сборка, медленнее " +"запуск)." +msgstr "" +"``--lto=no`` — LTO is disabled by default (faster build, slower startup)." + +#: ../../root/cli.rst:279 +msgid "" +"``--include-windows-runtime-dlls=no`` — на Windows не включает runtime " +"DLL в бинарник." +msgstr "" +"``--include-windows-runtime-dlls=no`` — on Windows, runtime DLLs are not" +" bundled into the binary." + +#: ../../root/cli.rst:280 +msgid "" +"``--python-flag=-m`` — добавляется автоматически, если entrypoint " +"указывает на ``__main__.py``." +msgstr "" +"``--python-flag=-m`` — added automatically when the entrypoint points at" +" a ``__main__.py``." + +#: ../../root/cli.rst:282 +msgid "" +"Все эти дефолты можно переопределить, передав соответствующий флаг после " +"``--``. Например, ``-- --lto=yes`` включит LTO, а ``-- --jobs=1`` " +"отключит параллельную сборку." +msgstr "" +"Any of these defaults can be overridden by passing the corresponding flag" +" after ``--``. For example, ``-- --lto=yes`` enables LTO, and ``--" +" --jobs=1`` disables parallel compilation." + +#: ../../root/cli.rst:285 +msgid "Основные флаги Nuitka и их нюансы" +msgstr "Key Nuitka flags and their trade-offs" + +#: ../../root/cli.rst:287 +msgid "" +"Полный список флагов — в `документации Nuitka `_. Ниже — те, с которыми чаще всего " +"сталкиваются при сборке CLI-приложений." +msgstr "" +"The full flag list is in the `Nuitka documentation `_. Below are the ones most often" +" encountered when building CLI applications." + +#: ../../root/cli.rst:289 +#, python-brace-format +msgid "``--lto={yes,no,auto}``" +msgstr "``--lto={yes,no,auto}``" + +#: ../../root/cli.rst:290 +msgid "" +"Link-Time Optimization. ``yes`` — бинарник меньше и быстрее запускается, " +"но сборка длится заметно дольше. ``no`` (дефолт Argenta) — сборка " +"быстрее, бинарник больше. ``auto`` — Nuitka выбирает сам. Для " +"production-сборки имеет смысл ``yes``, для итеративной разработки — " +"``no``." +msgstr "" +"Link-Time Optimization. ``yes`` — the binary is smaller and starts" +" faster, but the build takes noticeably longer. ``no`` (Argenta's" +" default) — faster build, larger binary. ``auto`` — Nuitka decides. For" +" production builds ``yes`` makes sense; for iterative development, ``no``." + +#: ../../root/cli.rst:292 +msgid "``--include-package=``" +msgstr "``--include-package=``" + +#: ../../root/cli.rst:293 +msgid "" +"Явно включает пакет в бинарник. Nuitka отслеживает импорты статически, " +"поэтому пакеты, которые импортируются динамически (через ``importlib``, " +"плагины, ``__import__``), в бинарник не попадают — их нужно добавлять " +"вручную. Типичные кандидаты: ``numpy``, ``pandas``, ``rich``, " +"``prompt_toolkit``." +msgstr "" +"Explicitly includes a package in the binary. Nuitka tracks imports" +" statically, so packages imported dynamically (via ``importlib``, plugins," +" ``__import__``) do not end up in the binary — they must be added by hand." +" Common candidates: ``numpy``, ``pandas``, ``rich``, ``prompt_toolkit``." + +#: ../../root/cli.rst:295 +msgid "``--include-data-files==``" +msgstr "``--include-data-files==``" + +#: ../../root/cli.rst:296 +msgid "" +"Включает файлы данных (шаблоны, конфиги, ассеты) в бинарник. Формат: " +"``--include-data-files=assets/logo.png=assets/logo.png``. Для директорий " +"целиком — ``--include-data-dir=assets=assets``. Без этого файлы, которые " +"приложение читает во время выполнения, не будут найдены в собранном " +"бинарнике." +msgstr "" +"Includes data files (templates, configs, assets) into the binary. Format:" +" ``--include-data-files=assets/logo.png=assets/logo.png``. For whole" +" directories — ``--include-data-dir=assets=assets``. Without this, files" +" the application reads at runtime will not be found inside the built binary." + +#: ../../root/cli.rst:298 +msgid "``--enable-plugin=``" +msgstr "``--enable-plugin=``" + +#: ../../root/cli.rst:299 +msgid "" +"Включает `плагин Nuitka `_ для поддержки фреймворков, требующих специальной " +"обработки. Распространённые: ``anti-bloat`` (вырезает ненужные части " +"тяжёлых пакетов), ``numpy`` (корректная сборка с numpy), ``tk-inter`` " +"(Tkinter GUI), ``triton`` (PyTorch triton kernels)." +msgstr "" +"Enables a `Nuitka plugin `_ for frameworks that need special handling. Common" +" ones: ``anti-bloat`` (strips unneeded parts of heavy packages), ``numpy``" +" (correct numpy bundling), ``tk-inter`` (Tkinter GUI), ``triton`` (PyTorch" +" triton kernels)." + +#: ../../root/cli.rst:301 +msgid "``--onefile`` / ``--standalone``" +msgstr "``--onefile`` / ``--standalone``" + +#: ../../root/cli.rst:302 +msgid "" +"``--onefile`` (дефолт Argenta) — единый бинарник, удобный для " +"дистрибуции. При запуске распаковывается во временную директорию, поэтому" +" стартует медленнее. ``--standalone`` — папка с бинарником и " +"зависимостями, стартует быстрее, но дистрибуция — это вся папка целиком. " +"Чтобы переключиться: ``-- --standalone`` (переопределит дефолтный " +"``--onefile``)." +msgstr "" +"``--onefile`` (Argenta's default) — a single binary, convenient for" +" distribution. It unpacks into a temporary directory on startup, so it" +" starts slower. ``--standalone`` — a folder with the binary and its" +" dependencies; starts faster, but distribution means shipping the whole" +" folder. To switch: ``-- --standalone`` (overrides the default ``--onefile``)." + +#: ../../root/cli.rst:304 +msgid "``--jobs=``" +msgstr "``--jobs=``" + +#: ../../root/cli.rst:305 +msgid "" +"Количество параллельных процессов компиляции. Дефолт Argenta — все ядра " +"(``os.cpu_count()``). На машинах с малым объёмом памяти имеет смысл " +"ограничить: ``-- --jobs=2``." +msgstr "" +"Number of parallel compilation processes. Argenta's default is all cores" +" (``os.cpu_count()``). On memory-constrained machines it makes sense to" +" limit it: ``-- --jobs=2``." + +#: ../../root/cli.rst:314 msgid "Информация об окружении" -msgstr "Environment Information" +msgstr "Environment information" -#: ../../root/cli.rst:177 +#: ../../root/cli.rst:317 msgid "Команда ``info``" msgstr "The ``info`` command" -#: ../../root/cli.rst:179 +#: ../../root/cli.rst:319 msgid "" "Отображает версию ``Argenta``, версию Python, платформу и ссылку на " "документацию." msgstr "" -"Displays the ``Argenta`` version, Python version, platform, and a link to " -"the documentation." +"Displays the ``Argenta`` version, Python version, platform, and a link to" +" the documentation." -#: ../../root/cli.rst:187 -msgid "Формат ентрипойнтов" -msgstr "Entrypoint Format" +#~ msgid "Командная строка" +#~ msgstr "Command Line Interface" -#: ../../root/cli.rst:190 -msgid "" -"Все команды, принимающие ентрипойнт (``run``, ``routes``, ``build``), " -"используют единый формат:" -msgstr "" -"All commands that accept an entrypoint (``run``, ``routes``, ``build``) " -"use a unified format:" +#~ msgid "Создаёт новую директорию проекта с boilerplate-кодом." +#~ msgstr "Creates a new project directory with boilerplate code." -#: ../../root/cli.rst:196 -msgid "" -"Поддерживаются как пути к файлам, так и dotted-модули. Если передан путь к " -"директории с ``__main__.py``, он будет разрешён автоматически." -msgstr "" -"Both file paths and dotted modules are supported. If a directory path " -"containing ``__main__.py`` is passed, it will be resolved automatically." +#~ msgid "" +#~ "``entrypoint`` — путь к callable в " +#~ "формате ``:`` или " +#~ "``:``." +#~ msgstr "" +#~ "``entrypoint`` — path to a callable " +#~ "in the format ``:`` " +#~ "or ``:``." + +#~ msgid "" +#~ "Команда ``run`` устанавливает переменную " +#~ "окружения ``RUN_FROM_ARGENTA_RUNNER=1``, что " +#~ "отключает парсинг аргументов командной строки" +#~ " в ``ArgParser``. Это позволяет запустить" +#~ " REPL без конфликтов с CLI-аргументами " +#~ "``argenta``." +#~ msgstr "" +#~ "The ``run`` command sets the " +#~ "``RUN_FROM_ARGENTA_RUNNER=1`` environment variable, " +#~ "which disables command-line argument " +#~ "parsing in ``ArgParser``. This allows " +#~ "starting the REPL without conflicts with" +#~ " ``argenta`` CLI arguments." + +#~ msgid "" +#~ "``entrypoint`` — путь к ``App`` или " +#~ "callable в формате " +#~ "``:``." +#~ msgstr "" +#~ "``entrypoint`` — path to an ``App`` " +#~ "or callable in the format " +#~ "``:``." + +#~ msgid "Если передан инстанс ``App``:" +#~ msgstr "If an ``App`` instance is passed:" + +#~ msgid "" +#~ "Если передан callable (фабрика), он " +#~ "будет вызван, и результат будет " +#~ "использован для отображения маршрутов:" +#~ msgstr "" +#~ "If a callable (factory) is passed, " +#~ "it will be called, and the result" +#~ " will be used to display routes:" + +#~ msgid "" +#~ "``entrypoint`` — путь к callable в " +#~ "формате ``:``." +#~ msgstr "" +#~ "``entrypoint`` — path to a callable " +#~ "in the format ``:``." + +#~ msgid "Для использования команды ``build`` необходимо установить ``Nuitka``:" +#~ msgstr "To use the ``build`` command, you must install ``Nuitka``:" + +#~ msgid "Формат ентрипойнтов" +#~ msgstr "Entrypoint Format" + +#~ msgid "" +#~ "Все команды, принимающие ентрипойнт (``run``," +#~ " ``routes``, ``build``), используют единый " +#~ "формат:" +#~ msgstr "" +#~ "All commands that accept an entrypoint" +#~ " (``run``, ``routes``, ``build``) use a " +#~ "unified format:" + +#~ msgid "" +#~ "Поддерживаются как пути к файлам, так" +#~ " и dotted-модули. Если передан путь к" +#~ " директории с ``__main__.py``, он будет " +#~ "разрешён автоматически." +#~ msgstr "" +#~ "Both file paths and dotted modules " +#~ "are supported. If a directory path " +#~ "containing ``__main__.py`` is passed, it " +#~ "will be resolved automatically." -#: ../../root/cli.rst:199 -msgid "Примеры валидных ентрипойнтов:" -msgstr "Examples of valid entrypoints:" diff --git a/docs/locales/en/LC_MESSAGES/root/testing.po b/docs/locales/en/LC_MESSAGES/root/testing.po index cf97512..e201227 100644 --- a/docs/locales/en/LC_MESSAGES/root/testing.po +++ b/docs/locales/en/LC_MESSAGES/root/testing.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Argenta \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-12-04 20:39+0300\n" +"POT-Creation-Date: 2026-08-03 17:30+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language: en\n" @@ -82,8 +82,9 @@ msgid "E2E-тестирование цикла" msgstr "E2E Testing of the Loop" #: ../../root/testing.rst:48 +#, fuzzy msgid "" -"Полный запуск цикла ``start_polling`` можно покрывать через подпроцесс с " +"Полный запуск цикла ``run_repl`` можно покрывать через подпроцесс с " "передачей строк в ``stdin``. Это тяжелее и обычно не требуется. Если всё " "же необходимо — пример ниже." msgstr "" diff --git a/docs/root/cli.rst b/docs/root/cli.rst index 739ee93..c0973d7 100644 --- a/docs/root/cli.rst +++ b/docs/root/cli.rst @@ -1,33 +1,39 @@ .. _root_cli: -Командная строка -================== +CLI +=== -Помимо библиотеки, ``Argenta`` поставляется с собственным CLI-инструментом, который помогает создавать проекты, запускать приложения, инспектировать маршруты и собирать бинарники. +Помимо библиотеки, ``Argenta`` поставляется с собственным CLI-инструментом. Он берёт на себя рутину, которая сопровождает разработку CLI-приложений: создаёт каркас проекта, запускает приложение, инспектирует зарегистрированные маршруты и собирает standalone-бинарник. + +CLI поставляется как опциональная зависимость — основная библиотека остаётся лёгкой, а инструмент доступен только тем, кому он нужен. Установка --------- -CLI доступен как опциональная зависимость: +CLI доступен как опциональная зависимость ``[cli]``: .. code-block:: shell pip install argenta[cli] +.. code-block:: shell + + uv add argenta[cli] + После установки команда ``argenta`` доступна в терминале: .. code-block:: shell argenta --help -.. image:: _static/cli/help.png +.. image:: https://i.ibb.co/p60T7fvh/image.png :alt: Argenta CLI help .. note:: - Если вы устанавливали ``argenta`` без extras, CLI-инструмент не будет доступен. Установите с ``[cli]`` для доступа к команде ``argenta``. + Если ``argenta`` установлена без extras, команда ``argenta`` не будет доступна. Установите с ``[cli]``, чтобы получить доступ к CLI-инструменту. Флаг ``--version`` -~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~ Показать установленную версию ``Argenta``: @@ -35,33 +41,70 @@ CLI доступен как опциональная зависимость: argenta --version +Аналогично через короткий флаг: + .. code-block:: shell argenta -v ----- +.. _cli_entrypoint: + +Формат entrypoint +----------------- + +Команды ``run``, ``routes`` и ``build`` принимают **entrypoint** — указатель на объект внутри проекта, который нужно запустить, инспектировать или собрать. Единый формат описан здесь, чтобы не повторяться в каждой команде. + +Формат entrypoint: + +.. code-block:: text + + : + : + +Поддерживаются два способа адресации: + +* **Путь к файлу** — ``app/main.py:main``. Удобно при работе с конкретным файлом. +* **Dotted-модуль** — ``my_project.application:main``. Естественно для установленных пакетов. + +Если передан путь к директории с ``__main__.py``, он разрешается автоматически — указывать файл явно не нужно. + +**Примеры валидных entrypoint-ов:** + +.. code-block:: text + + app/main.py:main + app/main.py:app + app/main.py:create_app + my_project.application:main + my_project/application/__main__.py:main + +Тип объекта зависит от команды: ``run`` и ``build`` ожидают callable, ``routes`` — инстанс ``App`` или callable, возвращающий ``App``. + +----- + Создание проектов ----------------- Команда ``new`` ~~~~~~~~~~~~~~~~ -Создаёт новую директорию проекта с boilerplate-кодом. +Создаёт новую директорию проекта с boilerplate-кодом. Это отправная точка: вместо ручной настройки структуры — готовый каркас за одну команду. .. code-block:: shell - argenta new [--with-arch flat|src] + argenta new [--arch flat|src] * ``project_name`` — имя директории проекта (обязательный аргумент). -* ``--with-arch`` — архитектура проекта: ``flat`` (по умолчанию) или ``src``. +* ``--arch`` — архитектура проекта: ``flat`` (по умолчанию) или ``src``. **Примеры:** .. code-block:: shell argenta new my-app - argenta new my-app --with-arch src + argenta new my-app --arch src При архитектуре ``flat`` создаётся следующая структура: @@ -73,45 +116,45 @@ CLI доступен как опциональная зависимость: .. literalinclude:: ../code_snippets/cli/src_structure.txt :language: text -.. image:: _static/cli/new_command.png +.. image:: https://i.ibb.co/gY6zTQd/image.png :alt: argenta new command output Команда ``init`` ~~~~~~~~~~~~~~~~~ -Инициализирует boilerplate в текущей директории. Удобно, когда проект уже существует и нужно добавить структуру Argenta. +Делает то же, что и ``new``, но в текущей директории. Удобно, когда проект уже существует и нужно добавить структуру Argenta, не создавая лишний уровень вложенности. .. code-block:: shell - argenta init [--with-arch flat|src] + argenta init [--arch flat|src] -* ``--with-arch`` — архитектура проекта: ``flat`` (по умолчанию) или ``src``. +* ``--arch`` — архитектура проекта: ``flat`` (по умолчанию) или ``src``. **Примеры:** .. code-block:: shell argenta init - argenta init --with-arch src + argenta init --arch src .. note:: Команда ``init`` не перезаписывает существующие файлы — они будут пропущены. ----- -Запуск приложений +Запуск приложения ----------------- Команда ``run`` ~~~~~~~~~~~~~~~~ -Запускает оркестратор ``Argenta`` из callable-ентрипойнта. Это альтернатива прямому вызову ``python main.py``, но с автоматической настройкой окружения. +Запускает оркестратор ``Argenta`` из callable-entrypoint. Это альтернатива прямому вызову ``python main.py``, но с автоматической настройкой окружения. .. code-block:: shell argenta run -* ``entrypoint`` — путь к callable в формате ``:`` или ``:``. +Формат entrypoint — см. :ref:`Формат entrypoint `. **Примеры:** @@ -120,11 +163,11 @@ CLI доступен как опциональная зависимость: argenta run app/main.py:main argenta run my_project.application:main -.. image:: _static/cli/run_command.png +.. image:: https://i.ibb.co/fVPzxWxp/image.png :alt: argenta run command output .. note:: - Команда ``run`` устанавливает переменную окружения ``RUN_FROM_ARGENTA_RUNNER=1``, что отключает парсинг аргументов командной строки в ``ArgParser``. Это позволяет запустить REPL без конфликтов с CLI-аргументами ``argenta``. + Команда ``run`` устанавливает переменную окружения ``RUN_FROM_ARGENTA_RUNNER=1``. ``ArgParser`` видит этот флаг и пропускает парсинг ``sys.argv``, поэтому аргументы самого ``argenta`` (типа ``--help``, ``--version``) не конфликтуют с аргументами запускаемого приложения. REPL стартует чисто, без ошибок про неизвестные флаги. ----- @@ -140,7 +183,7 @@ CLI доступен как опциональная зависимость: argenta routes -* ``entrypoint`` — путь к ``App`` или callable в формате ``:``. +Формат entrypoint — см. :ref:`Формат entrypoint `. **Примеры:** @@ -149,42 +192,62 @@ CLI доступен как опциональная зависимость: argenta routes app/main.py:app argenta routes app/main.py:create_app -Если передан инстанс ``App``: +Инстанс ``App`` передаётся напрямую, если роутеры подключены на уровне модуля: .. literalinclude:: ../code_snippets/cli/app_instance.py :language: python :linenos: -Если передан callable (фабрика), он будет вызван, и результат будет использован для отображения маршрутов: +Фабрика ``create_app`` передаётся, если роутеры регистрируются внутри функции — например, зависят от конфига или DI: .. literalinclude:: ../code_snippets/cli/app_factory.py :language: python :linenos: -.. image:: _static/cli/routes_command.png - :alt: argenta routes command output - .. note:: - При использовании callable-ентрипойнта (например, ``create_app``) REPL не запускается — фабрика вызывается, и маршруты считываются из возвращённого ``App``. Это полезно, когда роутеры подключаются внутри функции, а не на уровне модуля. + При использовании callable-entrypoint REPL не запускается — фабрика вызывается, и маршруты считываются из возвращённого ``App``. + +Пример вывода: + +.. code-block:: text + + ────────────────────────────────────────── + App Stats + ────────────────────────────────────────── + Total Routers: 1 + Total Commands: 1 + Total Aliases: 0 + Total Flags: 0 + ────────────────────────────────────────── + + 📦 App object: + └── 📁 Router: Example + └── ⚡ hello + 📝 description: Say hello + +.. image:: https://i.ibb.co/wNFvKcqM/image.png + :alt: argenta routes command output ----- -Сборка бинарников ------------------ +Сборка бинарника +---------------- Команда ``build`` ~~~~~~~~~~~~~~~~~~ -Компилирует проект в standalone-бинарник с помощью `Nuitka `_. +Компилирует проект в standalone-бинарник с помощью `Nuitka `_, которая входит в ``[cli]`` extra. .. code-block:: shell - argenta build [--output ] + argenta build [--output ] [-- ...] + +Формат entrypoint — см. :ref:`Формат entrypoint `. -* ``entrypoint`` — путь к callable в формате ``:``. * ``--output`` / ``-o`` — имя выходного бинарника (по умолчанию — имя файла или пакета). +* ``--`` — разделитель, после которого передаются **произвольные флаги Nuitka**. Они добавляются к вызову Nuitka после аргументов Argenta, поэтому могут переопределять дефолты и добавлять любые опции, которые Nuitka поддерживает. -**Примеры:** +**Базовые примеры:** .. code-block:: shell @@ -192,14 +255,52 @@ CLI доступен как опциональная зависимость: argenta build app/main.py:main --output myapp argenta build app/__main__.py:main -o myapp -.. warning:: - Для использования команды ``build`` необходимо установить ``Nuitka``: +**Примеры с флагами Nuitka:** - .. code-block:: shell +.. code-block:: shell - pip install nuitka + argenta build app/main.py:main -- --lto=yes + argenta build app/main.py:main -- --include-package=numpy + argenta build app/main.py:main -o myapp -- --lto=auto --include-data-files=assets/*=assets/ -.. image:: _static/cli/build_command.png +Что делает Argenta по умолчанию +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Команда ``build`` формирует вызов Nuitka со следующими аргументами: + +* ``--standalone --onefile`` — собирает единый бинарник со всеми зависимостями внутри. +* ``--output-filename=`` — имя выходного файла (из ``--output`` или имени entrypoint). +* ``--jobs=`` — параллельная компиляция на всех ядрах. +* ``--lto=no`` — LTO отключён по умолчанию (быстрее сборка, медленнее запуск). +* ``--include-windows-runtime-dlls=no`` — на Windows не включает runtime DLL в бинарник. +* ``--python-flag=-m`` — добавляется автоматически, если entrypoint указывает на ``__main__.py``. + +Все эти дефолты можно переопределить, передав соответствующий флаг после ``--``. Например, ``-- --lto=yes`` включит LTO, а ``-- --jobs=1`` отключит параллельную сборку. + +Основные флаги Nuitka и их нюансы +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Полный список флагов — в `документации Nuitka `_. Ниже — те, с которыми чаще всего сталкиваются при сборке CLI-приложений. + +``--lto={yes,no,auto}`` + Link-Time Optimization. ``yes`` — бинарник меньше и быстрее запускается, но сборка длится заметно дольше. ``no`` (дефолт Argenta) — сборка быстрее, бинарник больше. ``auto`` — Nuitka выбирает сам. Для production-сборки имеет смысл ``yes``, для итеративной разработки — ``no``. + +``--include-package=`` + Явно включает пакет в бинарник. Nuitka отслеживает импорты статически, поэтому пакеты, которые импортируются динамически (через ``importlib``, плагины, ``__import__``), в бинарник не попадают — их нужно добавлять вручную. Типичные кандидаты: ``numpy``, ``pandas``, ``rich``, ``prompt_toolkit``. + +``--include-data-files==`` + Включает файлы данных (шаблоны, конфиги, ассеты) в бинарник. Формат: ``--include-data-files=assets/logo.png=assets/logo.png``. Для директорий целиком — ``--include-data-dir=assets=assets``. Без этого файлы, которые приложение читает во время выполнения, не будут найдены в собранном бинарнике. + +``--enable-plugin=`` + Включает `плагин Nuitka `_ для поддержки фреймворков, требующих специальной обработки. Распространённые: ``anti-bloat`` (вырезает ненужные части тяжёлых пакетов), ``numpy`` (корректная сборка с numpy), ``tk-inter`` (Tkinter GUI), ``triton`` (PyTorch triton kernels). + +``--onefile`` / ``--standalone`` + ``--onefile`` (дефолт Argenta) — единый бинарник, удобный для дистрибуции. При запуске распаковывается во временную директорию, поэтому стартует медленнее. ``--standalone`` — папка с бинарником и зависимостями, стартует быстрее, но дистрибуция — это вся папка целиком. Чтобы переключиться: ``-- --standalone`` (переопределит дефолтный ``--onefile``). + +``--jobs=`` + Количество параллельных процессов компиляции. Дефолт Argenta — все ядра (``os.cpu_count()``). На машинах с малым объёмом памяти имеет смысл ограничить: ``-- --jobs=2``. + +.. image:: https://i.ibb.co/VsVXxf7/image.png :alt: argenta build command output ----- @@ -216,29 +317,14 @@ CLI доступен как опциональная зависимость: argenta info -.. image:: _static/cli/info_command.png +Пример вывода: + +.. code-block:: text + + Argenta 1.2.0 + Python 3.13.0 + Platform Linux-7.1.5-zen1-2-zen-x86_64-with-glibc2.40 + Docs https://argenta.readthedocs.io + +.. image:: https://i.ibb.co/B5k8Ftyg/image.png :alt: argenta info command output - ------ - -Формат ентрипойнтов -------------------- - -Все команды, принимающие ентрипойнт (``run``, ``routes``, ``build``), используют единый формат: - -.. code-block:: text - - : - : - -Поддерживаются как пути к файлам, так и dotted-модули. Если передан путь к директории с ``__main__.py``, он будет разрешён автоматически. - -**Примеры валидных ентрипойнтов:** - -.. code-block:: text - - app/main.py:main - app/main.py:app - app/main.py:create_app - my_project.application:main - my_project/application/__main__.py:main diff --git a/src/argenta/_cli/__main__.py b/src/argenta/_cli/__main__.py index aa33690..205399b 100644 --- a/src/argenta/_cli/__main__.py +++ b/src/argenta/_cli/__main__.py @@ -1,7 +1,7 @@ from importlib.metadata import version import typer -from typer import Typer +from typer import Context, Typer from .commands import ( build_handler, @@ -53,23 +53,23 @@ def _run(entrypoint_path: str = typer.Argument(help="Entrypoint as None: - init_handler(with_arch=with_arch) # type: ignore[arg-type] +def _init(arch: str = typer.Option("flat", "--arch", help="Architecture: flat or src")) -> None: + init_handler(arch=arch) # type: ignore[arg-type] @app.command( "new", help="Create a new project directory with a flat or src boilerplate.", short_help="Create a new project with boilerplate", - epilog="Example: argenta new my-app --with-arch src", + epilog="Example: argenta new my-app --arch src", ) def _new( project_name: str = typer.Argument(help="Name of the new project directory"), - with_arch: str = typer.Option("flat", "--with-arch", help="Architecture: flat or src"), + arch: str = typer.Option("flat", "--arch", help="Architecture: flat or src"), ) -> None: - new_handler(project_name=project_name, with_arch=with_arch) # type: ignore[arg-type] + new_handler(project_name=project_name, arch=arch) # type: ignore[arg-type] @app.command( @@ -93,15 +93,23 @@ def _info() -> None: @app.command( name="build", - help="Compile a project entrypoint into a standalone binary using Nuitka.", + help="Compile a project entrypoint into a standalone binary using Nuitka. " + "Any Nuitka flags can be passed after a `--` separator, e.g. " + "`argenta build app/main.py:main -- --lto=yes --include-package=numpy`.", short_help="Build a standalone binary", - epilog="Example: argenta build app/main.py:main --output myapp", + epilog=( + "Examples:\n" + " argenta build app/main.py:main --output myapp\n" + " argenta build app/main.py:main -- --lto=yes --include-data-files=assets/*=assets/" + ), + context_settings={"allow_extra_args": True, "ignore_unknown_options": True}, ) def _build( + ctx: Context, entry_point: str = typer.Argument(help="Entrypoint as :"), output_name: str | None = typer.Option(None, "--output", "-o", help="Output binary name"), ) -> None: - build_handler(entry_point=entry_point, output_name=output_name) + build_handler(entry_point=entry_point, output_name=output_name, extra_nuitka_args=ctx.args) def main() -> None: diff --git a/src/argenta/_cli/commands/build.py b/src/argenta/_cli/commands/build.py index d6c7a61..40e528f 100644 --- a/src/argenta/_cli/commands/build.py +++ b/src/argenta/_cli/commands/build.py @@ -8,7 +8,11 @@ from pathlib import Path from rich.console import Console -def build_handler(entry_point: str, output_name: str | None = None) -> None: +def build_handler( + entry_point: str, + output_name: str | None = None, + extra_nuitka_args: list[str] | None = None, +) -> None: console = Console() file_path, _, callable_name = entry_point.partition(":") @@ -47,6 +51,12 @@ def build_handler(entry_point: str, output_name: str | None = None) -> None: if is_main_module: args.append("--python-flag=-m") + # User-provided Nuitka flags are appended last, so they can override + # Argenta's defaults (e.g. --lto=yes, --jobs=1) and add anything else + # Nuitka supports (--include-package, --include-data-files, --enable-plugin, ...). + if extra_nuitka_args: + args.extend(extra_nuitka_args) + args.append(target) result = subprocess.run(args, check=False) diff --git a/src/argenta/_cli/commands/init.py b/src/argenta/_cli/commands/init.py index 5a95bb6..6554ee9 100644 --- a/src/argenta/_cli/commands/init.py +++ b/src/argenta/_cli/commands/init.py @@ -14,17 +14,17 @@ from ._templates import ( ) -def init_handler(with_arch: Literal["flat", "src"] = "flat") -> None: +def init_handler(arch: Literal["flat", "src"] = "flat") -> None: cwd = Path.cwd() project_name = cwd.name.lower().replace(" ", "_") create_file(cwd / ".gitignore", GITIGNORE_CONTENT) - if with_arch == "flat": + if arch == "flat": create_file(cwd / "main.py", FLAT_MAIN_TEMPLATE) create_file(cwd / "handlers.py", FLAT_HANDLERS_TEMPLATE) - elif with_arch == "src": + elif arch == "src": base_pkg = cwd / "src" / project_name / "application" create_file(base_pkg / "__main__.py", SRC_MAIN_TEMPLATE) diff --git a/src/argenta/_cli/commands/new.py b/src/argenta/_cli/commands/new.py index c8132ee..97fd803 100644 --- a/src/argenta/_cli/commands/new.py +++ b/src/argenta/_cli/commands/new.py @@ -15,7 +15,7 @@ from ._templates import ( ) -def new_handler(project_name: str, with_arch: Literal["flat", "src"] = "flat") -> None: +def new_handler(project_name: str, arch: Literal["flat", "src"] = "flat") -> None: base_dir = Path.cwd() / project_name if base_dir.exists(): @@ -27,11 +27,11 @@ def new_handler(project_name: str, with_arch: Literal["flat", "src"] = "flat") - create_file(base_dir / ".gitignore", GITIGNORE_CONTENT) - if with_arch == "flat": + if arch == "flat": create_file(base_dir / "main.py", FLAT_MAIN_TEMPLATE) create_file(base_dir / "handlers.py", FLAT_HANDLERS_TEMPLATE) - elif with_arch == "src": + elif arch == "src": pkg_name = project_name.lower().replace(" ", "_").replace("-", "_") app_pkg = base_dir / "src" / pkg_name / "application"