Metadata-Version: 2.5
Name: chancellery
Version: 0.1.0
Summary: Библиотека русского склонения и генерации документов по шаблонам: ФИО, должности, звания по падежам + рендер docx
Project-URL: Homepage, https://github.com/vlakir/chancellery
Project-URL: Issues, https://github.com/vlakir/chancellery/issues
Project-URL: Source, https://github.com/vlakir/chancellery
Project-URL: Changelog, https://github.com/vlakir/chancellery/blob/main/CHANGELOG.md
Author-email: Vladimir Kirievskiy <vlakir73@yandex.ru>
License-Expression: MIT
License-File: LICENSE
Keywords: declension,documents,docx,morphology,russian,template
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: Russian
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Office/Business
Classifier: Topic :: Text Processing :: Linguistic
Classifier: Typing :: Typed
Requires-Python: >=3.14
Requires-Dist: docxtpl>=0.20.2
Requires-Dist: jinja2>=3.1.6
Requires-Dist: openpyxl>=3.1.5
Requires-Dist: petrovich>=2.0.1
Requires-Dist: pydantic>=2
Requires-Dist: pymorphy3-dicts-ru>=2.4.417150.4580142
Requires-Dist: pymorphy3>=2.0.6
Requires-Dist: python-docx>=1.2.0
Requires-Dist: pyyaml>=6.0.3
Description-Content-Type: text/markdown

# chancellery

**Канцелярия** — библиотека русского склонения и сборки служебных
документов. Склоняет по падежам ФИО, должности и воинские звания (с
автоопределением рода и согласованием слов во фразе) и собирает готовый
`docx` по шаблону с русской разметкой, где падеж задаётся местом
подстановки, а не данными.

Изначальное видение и границы — в [`CONCEPT.md`](CONCEPT.md).

**Статус: 0.1.0.** Движок переехал из
[«Дьяка»](https://github.com/vlakir/dyak) 0.3.3, где обкатан на настоящих
кадровых документах; поведение сверено с эталоном донора поабзацно.
План переноса — в
[`specs/T001-engine-extraction/spec.md`](specs/T001-engine-extraction/spec.md).

Потребители: «Дьяк» (кадровые документы пачкой из таблицы) и
«Летопись» (приказы из кадровой базы).

## Быстрый старт

```bash
uv add chancellery
```

Сценарий целиком — таблица со строками данных плюс размеченный шаблон
`docx` дают папку готовых документов, по одному на строку:

```python
from chancellery import generate_documents

written = generate_documents(
    table='employees.xlsx',
    template='order_template.docx',
    out='out',
    filename='{{ Фамилия }}.docx',  # необязательно: по умолчанию — по ФИО
)
```

Если сценарий не подходит (источник данных не таблица, свой цикл, своя
обработка ошибок) — те же слои доступны по отдельности: `read_table`,
`build_context`, `render_document`, `check_table`. А если документы не
нужны вовсе, а нужно только склонение:

```python
from chancellery import Case, Person, PetrovichInflector, PhraseInflector, build_context

context = build_context(
    Person(
        cells={
            'Фамилия': 'Иванов',
            'Имя': 'Пётр',
            'Отчество': 'Семёнович',
            'Должность': 'старший механик-водитель',
        }
    ),
    roles={
        'surname': 'Фамилия',
        'name': 'Имя',
        'patronymic': 'Отчество',
        'position': 'Должность',
    },
    inflector=PetrovichInflector(),
    position_inflector=PhraseInflector(),
)
context['ФИО'].inflect(Case.DATV)  # Иванову Петру Семёновичу
context['Должность'].inflect(Case.DATV)  # старшему механику-водителю
```

## Разметка шаблона

Падеж задаётся **местом подстановки**, а не данными: один и тот же
человек в шапке стоит в именительном, а в теле приказа — в дательном,
и шаблон говорит об этом фильтром.

**Падежные фильтры:**

```jinja
{{ ФИО | ип }}   именительный    Иванов Пётр Семёнович
{{ ФИО | рд }}   родительный     Иванова Петра Семёновича
{{ ФИО | дт }}   дательный       Иванову Петру Семёновичу
{{ ФИО | вн }}   винительный     Иванова Петра Семёновича
{{ ФИО | тв }}   творительный    Ивановым Петром Семёновичем
{{ ФИО | пр }}   предложный      Иванове Петре Семёновиче
```

Тег без фильтра даёт именительный. Фильтр применим к любому склоняемому
значению — ФИО, части имени, должности, званию, произвольной колонке.

**Согласование по полу** — фильтр `согл`, мужская форма первой; пол
берётся из ФИО (определяется автоматически по имени и отчеству):

```jinja
{{ ФИО | согл('ознакомлен', 'ознакомлена') }}
```

**Теги ФИО.** Колонка «ФИО» разбирается на части, а части собираются
обратно, поэтому доступны сразу все формы:

```jinja
{{ ФИО }}                 Иванов Пётр Семёнович
{{ Фамилия }}             Иванов          {{ Имя }}, {{ Отчество }} — так же
{{ Инициалы }}            Иванов П. С.
{{ Инициалы_впереди }}    П. С. Иванов
{{ Инициалы_слитно }}     Иванов П.С.
{{ Имя_инициал }}         П.              одна буква с точкой
```

Инициалы тоже склоняются: `{{ Инициалы | рд }}` → «Иванова П. С.».
Пустое отчество не роняет рендер — форма просто становится короче.

**Остальные колонки** доступны по своему заголовку: `{{ Должность | дт }}`,
`{{ Номер приказа }}`. Заголовок нормализуется (пробелы → подчёркивания,
спецсимволы вычищаются), поэтому «л/н» в таблице пишется в шаблоне как
`{{ л_н }}`.

Неизвестная переменная — **ошибка**, а не пустое место в готовом приказе:
шаблон рендерится в строгом режиме. Пустое значение, наоборот, убирается
вместе с осиротевшей пунктуацией.

## Разработка

Менеджер зависимостей и окружения: **`uv`**.

```bash
uv sync                       # поставить зависимости
uv run pytest                 # прогнать тесты
```

## Зависимости

```bash
uv add <pkg>                  # runtime
uv add --dev <pkg>            # dev
```

## Выпуск версии

```bash
scripts/publish.sh --test    # репетиция на TestPyPI (нужен PYPI_TEST_TOKEN)
scripts/publish.sh           # боевой PyPI
```

Скрипт сам гоняет четыре гейта, собирает колесо и архив исходников,
проверяет артефакты `twine` и выкладывает. Токен читается из `.secrets`
(под git-ignore, образец — `.secrets.example`) и машину не покидает.
Порядок: закрыть версию в `CHANGELOG.md`, поднять `version` в
`pyproject.toml`, слить, поставить git-тег вида `0.1.0`, выложить.

## Проверки перед push

```bash
uv run ruff check .
uv run ruff format --check .
uv run mypy src
scripts/pytest-guard.sh --cov=src --cov-report=term-missing --cov-fail-under=80
```

Все четыре должны проходить с 0 ошибок. Обходные манёвры (`# noqa`,
`# type: ignore`, расширение `ignore`-секции) — только по согласованию.

## Структура проекта

- `src/` — корень исходников.
- `CONCEPT.md` — изначальное видение проекта (immutable).
- `DECISIONS.md` — архитектурные решения с обоснованиями (ADR-Lite).
- `BOARD.md` — рабочая Kanban-доска (To Do / Doing / Done).
- `BACKLOG.md` — парковка идей и побочных находок.
- `CHANGELOG.md` — журнал заметных изменений.
- `specs/` — спецификации крупных фич.
- `CLAUDE.md` — проектные правила для Claude (Claude Code).

## Методика работы

Проект создан из шаблона
[vlakir/dreamteam](https://github.com/vlakir/dreamteam). Подробное
описание методики (scope discipline, ритуал spec/clarify/analyze для
крупных фич, pre-push контроль) — см. репозиторий шаблона.

<!-- Ниже добавляются проект-специфичные разделы: API, развёртывание,
     схемы БД, документация модулей, контакты и т.п. -->
