Metadata-Version: 2.4
Name: altrepo
Version: 0.3.0
Summary: Async client for ALT Linux repository services (rdb API, packages parser, AppStream, Taskoteka)
License: AGPL-3.0-or-later
Author: Kirill Unitsaev
Author-email: fiersik@altlinux.org
Requires-Python: >=3.13
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: aiohttp (>=3.9.0)
Requires-Dist: beautifulsoup4 (>=4.12.0)
Requires-Dist: lxml (>=5.0.0)
Requires-Dist: pydantic (>=2.0.0)
Project-URL: Bug Tracker, https://gitlab.eterfund.ru/fiersik/python3-module-altrepo/issues
Project-URL: Repository, https://gitlab.eterfund.ru/fiersik/python3-module-altrepo
Description-Content-Type: text/markdown

# altrepo

Асинхронный Python-клиент для работы с сервисами репозитория ALT Linux. Библиотека предоставляет удобный интерфейс для доступа к данным о пакетах, задачах, мейнтейнерах и другой информации из экосистемы ALT Linux.

## Возможности

- **REST API** — полный клиент для [rdb.altlinux.org/api](https://rdb.altlinux.org/api): информация о пакетах, поиск, задачи, мейнтейнеры, баги, ACL, зависимости, эрраты, лицензии и многое другое
- **Парсер новостей** — получение и разбор новостей из рассылки [sisyphus-cybertalk](https://lists.altlinux.org/pipermail/sisyphus-cybertalk/): добавленные, обновлённые и удалённые пакеты, баги
- **Watch** — отслеживание устаревших пакетов через [watch.altlinux.org](https://watch.altlinux.org), как по отдельному мейнтейнеру, так и по всему репозиторию целиком
- **FTBFS** — список пакетов с ошибками пересборки
- **AppStream** — загрузка, кеширование и поиск по AppStream-метаданным пакетов
- **Taskoteka** — клиент для [git.altlinux.org/tasks/api](https://git.altlinux.org/tasks/api): быстрый доступ к задачам girar, фильтрация, полнотекстовый поиск и подписка на изменения через SSE

## Установка

```bash
pip3 install altrepo
```

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

Минимальный пример для начала работы с библиотекой. Создаём клиент, инициализируем сессию и делаем запрос:

```python
import asyncio
from altrepo import ALTRepo
from altrepo.api.types import Branch

async def main():
    async with ALTRepo() as client:
        result = await client.api.package.package_info("firefox", branch=Branch.sisyphus)
        pkg = result.packages[0]
        print(f"{pkg.name} {pkg.version}-{pkg.release}")

asyncio.run(main())
```

## Примеры использования

### Работа с API пакетов

Получение подробной информации о пакете и поиск по имени:

```python
from altrepo.api.types import Branch

# Информация о конкретном пакете
result = await client.api.package.package_info("firefox", branch=Branch.sisyphus)
pkg = result.packages[0]
print(f"{pkg.name} {pkg.version}-{pkg.release} ({pkg.summary})")

# Поиск пакетов по подстроке в имени
found = await client.api.site.find_packages("python3-module-alt", branch=Branch.sisyphus)
for pkg in found.packages[:10]:
    print(f"  {pkg.name}")
```

### Задачи и мейнтейнеры

Поиск задач по мейнтейнеру или по имени пакета:

```python
from altrepo.api.types import Branch

# Задачи мейнтейнера
result = await client.api.task.progress.find_tasks(
    input=["fiersik"], branch=Branch.sisyphus, by_package=False
)
for task in result.tasks[:5]:
    print(f"  #{task.task_id} [{task.task_state}] {task.task_owner}")

# Баги мейнтейнера из Bugzilla
bugs = await client.api.bug.bugzilla_by_maintainer("fiersik")
if bugs:
    for bug in bugs.bugs[:5]:
        print(f"  #{bug.id} {bug.status}: {bug.summary}")
```

### Отслеживание устаревших пакетов

Библиотека поддерживает два режима работы с watch.altlinux.org:

```python
# Устаревшие пакеты конкретного мейнтейнера
watch = await client.parser.packages.watch_by_maintainer("fiersik", "by-acl")
for pkg in watch[:5]:
    print(f"  {pkg.pkg_name}: {pkg.old_version} -> {pkg.new_version}")

# Полный список устаревших пакетов
total = await client.parser.packages.watch_total()
print(f"Всего устаревших пакетов: {len(total)}")
```

### Новости репозитория

Получение свежих новостей о пакетах из рассылки sisyphus-cybertalk:

```python
# Свежие новости Sisyphus за сегодня
news = await client.parser.news.sisyphus()
if news:
    print(f"Добавлено: {len(news.added or [])}")
    print(f"Обновлено: {len(news.updated or [])}")
    print(f"Удалено: {len(news.removed or [])}")

# Агрегированные новости за произвольный период
from datetime import date
news = await client.parser.news.packages_by_range(
    date(2026, 3, 1), date(2026, 3, 10)
)
```

### Taskoteka — задачи girar

Быстрый доступ к данным о задачах через [Taskoteka API](https://git.altlinux.org/tasks/api), без необходимости SSH-доступа:

```python
# Список активных задач
tasks = await client.taskoteka.tasks()
for t in tasks[:5]:
    print(f"  #{t.id} [{t.state}] {t.repo} {t.owner}")

# Фильтрация по состоянию, репозиторию, пользователю
tasks = await client.taskoteka.tasks(state="EPERM", repo="p11")
tasks = await client.taskoteka.tasks(user="rider")

# Полнотекстовый поиск
tasks = await client.taskoteka.tasks(q="rider EPERM php")
for t in tasks:
    print(f"  #{t.id} matches={t.matches}")

# Только ID задач
ids = await client.taskoteka.tasks(state="BUILDING", brief=True)

# Полная информация о задаче
task = await client.taskoteka.tasks(task_id=389466)
print(f"#{task.taskid} [{task.state}] {task.owner}: {task.message}")
for num, sub in task.subtasks.items():
    print(f"  {num}: {sub.pkgname} ({sub.type})")

# Подписка на изменения в реальном времени (SSE)
async for event in client.taskoteka.events():
    print(f"{event.event}: задача #{event.data.id} {event.data.state}")
```

### FTBFS — ошибки пересборки

```python
ftbfs = await client.parser.packages.ftbfs()
print(f"Пакетов с ошибками пересборки: {len(ftbfs)}")
for pkg in ftbfs[:5]:
    print(f"  {pkg.name} {pkg.version} ({pkg.ftbfs_weeks} нед.)")
```

## Конфигурация

Все URL-ы и настройки имеют разумные значения по умолчанию, поэтому для стандартного использования никакая дополнительная конфигурация не требуется. При необходимости любой параметр можно переопределить через `ALTRepoConfig`:

```python
from altrepo import ALTRepo, ALTRepoConfig

config = ALTRepoConfig(
    appstream_dir="/tmp/appstream",
    appstream_branches=["sisyphus", "p11", "p10"],
)
client = ALTRepo(config=config)
```

Если в вашем приложении уже есть `aiohttp.ClientSession`, её можно передать при инициализации:

```python
client = ALTRepo()
await client.init(session=existing_session)
```

## Лицензия

AGPL-3.0-or-later

