steosmorphy 1.0.1
Высокопроизводительный морфологический анализатор для Python
Requires Python: >=3.7

# steosmorphy: Руководство пользователя

**steosmorphy** — это высокопроизводительный морфологический анализатор для русского языка, предоставляющий Python-интерфейс к ядру, написанному на Go.

### Исходный код:
- [SteosMorphy-py](https://github.com/SteosOfficial/SteosMorphy-py)

### Ключевые особенности

*   **Знакомый API:** Интерфейс и возможности во многом вдохновлены `pymorphy2`.
*   **Полный функционал:** Включает разбор, лемматизацию, генерацию всех словоформ и предсказание несловарных слов.
*   **Корректная обработка супплетивизма:** Правильно генерирует все формы для слов вроде `хороший -> лучший`.
*   **Высокая производительность:** Скорость анализа составляет **~100 микросекунд** на слово (~10 000 слов/сек на одном ядре CPU).
*   При использовании пакетной обработки слов скорость достигает до **~20 микросекунд** за одно слово

### Оглавление

- [steosmorphy: Руководство пользователя](#steosmorphy-руководство-пользователя)
    - [Исходный код:](#исходный-код)
    - [Ключевые особенности](#ключевые-особенности)
    - [Оглавление](#оглавление)
  - [1. Установка](#1-установка)
  - [2. Быстрый старт](#2-быстрый-старт)
  - [3. API и объекты результата](#3-api-и-объекты-результата)
    - [3.1. Метод `analyze`](#31-метод-analyze)
    - [3.2. Метод (`parse_list`)](#32-метод-parse_list)
    - [3.3. Метод (`inflect_list`)](#33-метод-inflect_list)
    - [3.4. Объект `AnalysisResult`](#34-объект-analysisresult)
    - [3.5. Объект `Parsed`](#35-объект-parsed)
  - [4. Примеры использования](#4-примеры-использования)
    - [4.1. Разбор неоднозначности](#41-разбор-неоднозначности)
    - [4.2. Генерация словоформ и супплетивизм](#42-генерация-словоформ-и-супплетивизм)
    - [4.3. Работа с несловарными словами](#43-работа-с-несловарными-словами)
  - [5. Производительность](#5-производительность)
      - [Юнит- и интеграционные тесты](#юнит--и-интеграционные-тесты)
      - [Нагрузочные тесты и бенчмарки](#нагрузочные-тесты-и-бенчмарки)
  - [7. Зависимости и окружение](#7-зависимости-и-окружение)
      - [Для работы библиотеки (Runtime)](#для-работы-библиотеки-runtime)
      - [Для разработки и тестирования (Development)](#для-разработки-и-тестирования-development)
  - [8. Справочник по граммемам](#8-справочник-по-граммемам)
    - [Основные поля](#основные-поля)
    - [Грамматические категории](#грамматические-категории)

---

## 1. Установка

Библиотека устанавливается из PyPI стандартной командой:

```bash
pip install steosmorphy
```

Пакет содержит уже скомпилированные бинарные файлы для операционных систем (Windows, Linux, macOS), поэтому установка Go не требуется.

---

## 2. Быстрый старт

Использовать библиотеку очень просто.

```python
from steosmorphy import MorphAnalyzer

# 1. Инициализируем анализатор.
# Словарь загружается автоматически при первом создании объекта.
analyzer = MorphAnalyzer()

# 2. Анализируем слово
word = "стали"
result = analyzer.analyze(word)

# 3. Работаем с результатом
print(f"Варианты разбора для слова '{word}':")

# `result.parses` - это список всех возможных разборов
for p in result.parses:
    print(f"  - Лемма: {p.lemma:<10} Часть речи: {p.part_of_speech:<15} Падеж: {p.case}")

# `result.forms` - это список всех словоформ (лексема)
print(f"\nПримеры словоформ для '{word}':")
for p in result.forms[:5]: # Ограничим вывод
    print(f"  - {p.word}")
```

---


## 3. API и объекты результата

### 3.1. Метод `analyze`

Он принимает на вход слово и возвращает объект `AnalysisResult`, содержащий полный анализ. Если слово не найдено в словаре и не может быть предсказано, метод вернет `None`.

`analyzer.analyze(word: str) -> AnalysisResult | None`

### 3.2. Метод (`parse_list`)

Для достижения максимальной производительности при обработке большого количества слов используйте метод `parse_list`.

**`analyzer.parse_list(words: list[str]) -> list[Parsed]`**

Этот метод принимает на вход список слов, передает его целиком в ядро на Go, где он обрабатывается в многопоточном
режиме, и возвращает единый список всех возможных разборов.

**Почему это важно?**
Каждый вызов `analyze` из Python несет в себе накладные расходы на "пересечение границы" между Python и Go. Метод
`parse_list` пересекает эту границу **всего один раз** для всего списка, что приводит к **многократному (в 5-10 раз)
ускорению** по сравнению с вызовом `analyze` в цикле.

**Пример использования:**

```python
words = ["мама", "мыла", "раму", "стали", "программистка", "хороший"]

# Вызываем пакетную обработку
all_parses = analyzer.parse_list(words)

# `all_parses` - это плоский список всех разборов
# (для "стали" будет два объекта, итого 7)
for p in all_parses:
    print(f"Слово: {p.word:<15} Лемма: {p.lemma:<15} ЧР: {p.part_of_speech}")

```

**Рекомендация:**
**Всегда используйте `parse_list`, если вам нужно обработать более одного слова.** Вызов `analyze` в цикле следует
применять только для анализа единичных, интерактивно вводимых слов.

`ОСТОРОЖНО`
Передача на вход метода слишком большого числа слов может потребовать большого объема оперативной памяти во время работы
метода.
Например, использование списка из `1 000 000` может использовать свыше `5ГБ` ОЗУ!

### 3.3. Метод (`inflect_list`) 

Работает аналогичным образом с методом `parse_list`, но возвращает список всех словоформ для каждого слова из входного списка.

**`analyzer.inflect_list(words: list[str]) -> list[Parsed]`**

### 3.4. Объект `AnalysisResult`

Это контейнер для всего результата анализа.

*   **`.parses` (`list[Parsed]`)**
    Список объектов `Parsed`, представляющих все возможные варианты разбора для исходного слова.

*   **`.forms` (`list[Parsed]`)**
    Список объектов `Parsed`, представляющих все словоформы (полную лексему) для исходного слова.

*   **`.first` (`Parsed | None`)**
    Удобный доступ к **первому (самому вероятному)** варианту разбора из списка `.parses`. Эквивалентно `result.parses[0]`.

### 3.5. Объект `Parsed`

Каждый `*Parsed` — это объект, содержащий полный разбор одной словоформы с доступом к полям через точку.

*   `.word` (`str`): Сама словоформа.
*   `.lemma` (`str`): Нормальная (словарная) форма.
*   `.tags` (`str`): "Сырая" строка тегов для отладки.
*   `.part_of_speech` (`str`): Часть речи.
*   `.animacy` (`str`): Одушевленность.
*   `.aspect` (`str`): Вид глагола.
*   `.case` (`str`): Падеж.
*   `.gender` (`str`): Род.
*   `.mood` (`str`): Наклонение.
*   `.number` (`str`): Число.
*   `.person` (`str`): Лицо.
*   `.tense` (`str`): Время.
*   `.transitivity` (`str`): Переходность.
*   `.voice` (`str`): Залог.
*   `.other_tags` (`set[str]`): Множество прочих тегов.

---

## 4. Примеры использования

### 4.1. Разбор неоднозначности

Многие слова в русском языке неоднозначны. `analyze` вернет все варианты в списке `.parses`.

```python
result = analyzer.analyze("стекла")

for p in result.parses:
    if p.part_of_speech == "Глагол":
        print(f"Это глагол '{p.lemma}' в форме {p.gender} рода, {p.tense} времени.")
        # -> Это глагол 'стечь' в форме Средний рода, Прошедшее времени.
    elif p.part_of_speech == "Существительное":
        print(f"Это существительное '{p.lemma}' в {p.case} падеже.")
        # -> Это существительное 'стекло' в Родительный падеже.
```

### 4.2. Генерация словоформ и супплетивизм

Список `.forms` содержит полную лексему слова, включая формы, образованные от разных корней.

```python
result = analyzer.analyze("хорошая")

# `result.forms` будет содержать *полную* лексему
all_forms = {p.word for p in result.forms}

print("лучший" in all_forms)  # -> True
print("хорошую" in all_forms) # -> True
```

### 4.3. Работа с несловарными словами

Если слово не найдено в словаре, анализатор автоматически пытается его предсказать.

```python
result = analyzer.analyze("нейросеть")
p = result.first

print(p.lemma)          # -> нейросеть
print(p.part_of_speech) # -> Существительное
print(p.gender)         # -> Женский

# Будут также сгенерированы все предсказанные словоформы
forms = {f.word for f in result.forms}
print("нейросетей" in forms) # -> True
```

---

## 5. Производительность

`steosmorphy` спроектирован для высокой производительности.

*   **Скорость (одно слово):** Среднее время анализа одного слова через `analyze()` составляет около **~100 микросекунд**.
*   **Память:** Потребление оперативной памяти остается стабильно низким (**~100-150 МБ**).
*   **Пакетная обработка:** При использовании методов `parse_list()` / `inflect_list()` среднее время на слово приближается к нативным **~20 микросекундам**, что позволяет обрабатывать **до 50 000 слов в секунду** на одном ядре CPU.
```

---

## 6. Тестирование

#### Требования для тестов Python

Перед запуском убедитесь, что вы установили все необходимые зависимости для разработки:
```bash
pip install pytest pytest-benchmark
```
Также убедитесь, что ваш пакет `steosmorphy` установлен, желательно в режиме редактирования:
```bash
pip install -e .
```

#### Юнит- и интеграционные тесты

Файл `tests/test_analyzer.py` содержит тесты, которые проверяют корректность разбора и генерации словоформ.

**Как запустить:**
Находясь в корне проекта, выполните команду:
```bash
pytest
```
`pytest` автоматически найдет и запустит все тесты. Для подробного вывода используйте флаги `-v` (verbose) и `-s` (чтобы видеть вывод `print`).

#### Нагрузочные тесты и бенчмарки

*   **Микро-бенчмарки (`tests/test_benchmark.py`):** Измеряют точное время выполнения одного вызова `analyze` для разных типов слов. Запускаются с помощью плагина `pytest-benchmark`.

    **Как запустить:**
    ```bash
    pytest --benchmark-only
    ```
    Вы увидите подробную статистическую таблицу со средним, медианным, минимальным и максимальным временем выполнения.

*   **Нагрузочные тесты (`tests/test_load.py`):** Эмулируют реальную нагрузку, прогоняя через анализатор сотни тысяч и миллионы случайных слов. Эти тесты измеряют общую "пропускную способность" (слов в секунду) и помогают выявить утечки памяти или деградацию производительности под нагрузкой.

    **Как запустить:**
    ```bash
    pytest -v -s tests/test_load.py
    ```
Наличие такой всеобъемлющей тестовой системы позволяет гарантировать высокое качество и надежность библиотеки `steosmorphy`.

---

## 7. Зависимости и окружение

#### Для работы библиотеки (Runtime)

Конечный пользователь, устанавливающий ваш пакет через `pip`, не нуждается ни в каких внешних зависимостях, так как все
необходимое встроено в Python.

* **Python:** Требуется версия **Python 3.7** или новее.
* **Используемые стандартные библиотеки:**
  * `ctypes`: Для взаимодействия со скомпилированной Go-библиотекой (`.dll`/`.so`).
  * `json`: Для десериализации результатов, полученных от Go.
  * `platform`: Для определения операционной системы и выбора правильного файла библиотеки.
  * `importlib.resources`: Для надежного поиска файлов (`.dll`, `.dawg`) внутри установленного пакета.

#### Для разработки и тестирования (Development)

Если вы хотите вносить изменения или запускать тесты, вам понадобятся следующие инструменты:

* **`pytest`:** Мощный фреймворк для написания и запуска юнит-тестов и интеграционных тестов.
* **`pytest-benchmark`:** Плагин для `pytest` для проведения тестов производительности (микро-бенчмарков).

Установить их можно командой:

```bash
pip install pytest pytest-benchmark
```

---

## 8. Справочник по граммемам

Каждый успешный разбор слова возвращается в виде объекта `Parsed`. Этот раздел подробно описывает каждое поле этого
объекта и возможные значения, которые оно может принимать.

### Основные поля

* **`word` (`str`)**
  Исходная словоформа, которая была передана на анализ или сгенерирована.
  *Пример: "коту", "стали", "хорошая".*

* **`lemma` (`str`)**
  Нормальная форма слова. Для существительных — именительный падеж, единственное число. Для глаголов — инфинитив. Для
  прилагательных — именительный падеж, единственное число, мужской род.
  *Пример: "кот", "стать", "хороший".*

* **`tags` (`string`)**
  Все грамматические теги в виде строки, разделенных запятой. Полезна для отладки или для случаев, когда требуется
  полный набор граммем в одной строке.
  *Пример: `"Существительное,Одушевленное,Мужской,Единственное число,Дательный"`.*

### Грамматические категории

* **`part_of_speech` (`str`)**
  **Часть речи.** Это основная категория слова.
    * `Существительное`
    * `Прилагательное`
    * `Глагол`
    * `Наречие`
    * `Причастие`
    * `Деепричастие`
    * `Местоимение`
    * `Числительное`
    * `Предлог`
    * `Частица`
    * `Союз`
    * `Междометие`
    * `Вводное слово`

* **`animacy` (`str`)**
  **Одушевленность.** Категория, присущая существительным и согласующимся с ними частям речи.
    * `Одушевленное`
    * `Неодушевленное`

* **`aspect` (`str`)**
  **Вид.** Характеристика глаголов, причастий и деепричастий.
    * `Совершенный`
    * `Несовершенный`
    * `Двувидовой`

* **`case` (`str`)**
  **Падеж.** Одна из ключевых характеристик для склоняемых частей речи.
    * `Именительный`
    * `Родительный`
    * `Дательный`
    * `Винительный`
    * `Творительный`
    * `Предложный`
    * `Звательный` (для обращений, напр., "боже")
    * `Местный` (напр., "в лесу")
    * `Счетный` (напр., "два часа")
    * `Партитивный` (напр., "чашка чаю")
    * `Ждательный` (специфический падеж, напр., "ждать письма")
    * `Несклоняемый` (для несклоняемых слов, напр., "пальто")

* **`gender` (`str`)**
  **Род.**
    * `Мужской`
    * `Женский`
    * `Средний`
    * `Общий` (напр., "сирота", "умница")
    * `Парный` (используется для обозначения парных предметов, но редко встречается)

* **`mood` (`str`)**
  **Наклонение.** Характеристика глагола.
    * `Повелительное` (indc - изъявительное - обычно опускается)

* **`number` (`str`)**
  **Число.**
    * `Единственное число`
    * `Множественное число`

* **`person` (`str`)**
  **Лицо.** Характеристика глаголов в настоящем/будущем времени и личных местоимений.
    * `1-е лицо` (я, мы)
    * `2-е лицо` (ты, вы)
    * `3-е лицо` (он, она, оно, они)
    * `нет лица` (для безличных глаголов)

* **`tense` (`str`)**
  **Время.** Характеристика глагола.
    * `Прошедшее`
    * `Настоящее`
    * `Будущее`

* **`transitivity` (`str`)**
  **Переходность.** Способность глагола сочетаться с дополнением в винительном падеже без предлога.
    * `Переходный`
    * `Непереходный`
    * `Лабильный` (может быть и переходным, и непереходным)

* **`voice` (`str`)**
  **Залог.** Характеристика причастий.
    * `Действительный`
    * `Страдательный`

* **`other_tags` (`set[str]`)**
  Множество для всех остальных граммем, которые не попали в основные поля. Это позволяет сохранить всю информацию из
  исходного словаря.
  *Примеры: "Краткая форма", "Сравнительная степень", "Имя собственное", "Фамилия", "Сокращение", "Разговорное" и т.д.*