Metadata-Version: 2.4
Name: repo-switch-hub
Version: 0.1.0
Summary: Toggle Huggingface Hub and Cloud.ru Repo
License-Expression: MIT
License-File: LICENSE
Author: Nikita Yakovlev
Requires-Python: >=3.12
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Requires-Dist: datasets (>=5.0.0,<6.0.0)
Requires-Dist: huggingface-hub (>=1.16.4,<2.0.0)
Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
Project-URL: Issues, https://github.com/cloud-ru/evo-repo-switch-hub/issues
Project-URL: Repository, https://github.com/cloud-ru/evo-repo-switch-hub
Description-Content-Type: text/markdown

# Switch Hub
Switch hub — это утилита для переключения между разными источниками моделей и
датасетов: Hugging Face Hub и Cloud.ru Repo. Она позволяет прозрачно работать с моделями и датасетами в разных
экосистемах, не меняя привычный интерфейс `huggingface_hub`/`datasets`/`transformers`.

### Основные возможности

- Лёгкое переключение между хранилищами: Hugging Face Hub, Cloud.ru Repo.
- Минимальные изменения в коде — привычный интерфейс `transformers`, `datasets`, `huggingface_hub` работает как
  обычно, меняется только эндпоинт "под капотом".
- Безопасный откат состояния: `reset()` и контекстный менеджер `context()` гарантируют, что окружение вернётся к
  исходному виду.
- Гибкость для CI/CD, исследований и продакшена.

### Установка

```bash
pip install repo-switch-hub
```

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

Минимальный пример, показывающий саму идею: интерфейс `huggingface_hub`/`datasets` остаётся привычным, меняется
только то, куда фактически идут запросы.

```python
from switch_hub import HubSwitcher

switcher = HubSwitcher(hf_token="hf_xxx", rh_token="rh_yyy")

switcher.switch_to_hf()  # все операции huggingface_hub/datasets идут на Hugging Face Hub
# ... работа с моделями/датасетами как обычно ...

switcher.switch_to_rh()  # переключились на Cloud.ru Repo, интерфейс не изменился
# ... работа с моделями/датасетами как обычно ...

switcher.reset()  # вернуть исходные HF_ENDPOINT, токены и внутренние настройки
```

### Пример из практики

Более полный пример — перенос модели из Hugging Face Hub в Cloud.ru Repo целиком, файл в файл (1:1), чтобы потом
использовать её в сервисе без потерь. Для этого лучше не полагаться на `push_to_hub` конкретного класса модели
(`AutoModel` и подобные пушат только то, что относится к самой модели — например, без файлов токенайзера), а
работать напрямую через `huggingface_hub.snapshot_download`/`upload_folder`, которые копируют репозиторий целиком,
независимо от того, что из него понимает конкретный ML-фреймворк.

```python
import os

from dotenv import load_dotenv
from huggingface_hub import snapshot_download, upload_folder
from switch_hub.main import HubSwitcher

load_dotenv()

HF_TOKEN = os.getenv("HF_TOKEN")
CLOUD_TOKEN = os.getenv("CLOUD_TOKEN")

switcher = HubSwitcher(
    hf_token=HF_TOKEN,
    rh_token=CLOUD_TOKEN,
)

# Переключаемся на Hugging Face Hub
switcher.switch_to_hf()

# Скачиваем репозиторий модели целиком (все файлы) в локальный кэш
local_path = snapshot_download("google-bert/bert-base-uncased")

# Переключаемся на Cloud.ru Repo и заливаем модель туда 1:1
switcher.switch_to_rh()
upload_folder(
    repo_id="981f9634-37e4-41ce-84cb-786a8da52dba/switch-hub-test",
    folder_path=local_path,
)

# Дальше при необходимости — любые операции с моделью

# Скачиваем модель целиком из Cloud.ru Repo
# local_path_rh = snapshot_download("user_id/model_repository_name")

# Переключаемся на Hugging Face Hub и заливаем обновлённую модель обратно
# switcher.switch_to_hf()
# upload_folder(repo_id="some_user/some_model", folder_path=local_path_rh)
```

---

## Работа с аутентификацией и токенами

Для работы с приватными и большинством публичных репозиториев потребуется токен доступа:

- **Hugging Face Hub:** одна из переменных `HF_TOKEN`, `HUGGING_FACE_HUB_TOKEN`, `HF_API_TOKEN` (проверяются именно в
  этом порядке — используется первая найденная).
- **Cloud.ru Repo:** `RH_TOKEN` — **обязателен для `switch_to_rh()`/`context('rh')`**, без него будет выброшено
  исключение `RepoTokenMissingError`.

#### Как передавать токены

**1. Через переменные окружения или `.env` файл**
Рекомендуется для локальной разработки и CI/CD. `HubSwitcher` сам подхватывает `.env` из корня проекта при импорте
пакета:

```dotenv
HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
RH_TOKEN=rh_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
RH_ENDPOINT=https://mr-repo.cloud.ru
```

**2. Явно в конструктор `HubSwitcher`**

```python
from switch_hub import HubSwitcher

switcher = HubSwitcher(
    hf_token="hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    rh_token="rh_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
    rh_endpoint="https://mr-repo.cloud.ru",  # опционально, есть значение по умолчанию
)
```

Приоритет для всех параметров одинаковый: **явно переданное значение → переменная окружения → значение по
умолчанию** (значение по умолчанию есть только у `rh_endpoint`: `https://mr-repo.cloud.ru`).

#### Важно:

- **`RH_TOKEN` обязателен только в момент переключения на Repo** (`switch_to_rh()` / `context('rh')`) — при его
  отсутствии конструктор `HubSwitcher()` создаётся без ошибок, но переключение упадёт с `RepoTokenMissingError`.
- **`HF_TOKEN` не обязателен**, но рекомендуется указывать всегда, чтобы избежать лимитов и быть готовым к работе с
  приватным контентом Hugging Face.
- Никогда не публикуйте свои токены в открытых источниках — используйте секреты сборки и переменные окружения.

---

### Описание ключевых методов

**switch_to_hf() / switch_to_rh()**
Переключают текущий процесс на Hugging Face Hub или Cloud.ru Repo соответственно: подменяют `HF_ENDPOINT` и
внутренние настройки `huggingface_hub`/`datasets`, а также выставляют нужные токены авторизации. Изменения
действуют глобально на процесс, пока не будет вызван `reset()` (или пока не выйдете из блока `context()`).

```python
switcher.switch_to_rh()
# ... работа с приватным Repo ...
switcher.switch_to_hf()
```

**reset()**
Восстанавливает все переменные окружения и внутренние настройки, которые были изменены при переключении между
хабами. Используйте этот метод, если нужно вручную откатить все изменения состояния, внесённые switcher'ом,
например после завершения операций с приватным registry.

```python
switcher.switch_to_rh()
# ... работа с приватным хабом ...
switcher.reset()  # Возвращение к исходным параметрам окружения
```

**context(mode)**
Контекстный менеджер для временного переключения хаба.
После выхода из блока `with` окружение автоматически восстанавливается к исходному — даже если внутри блока
произошло исключение.

```python
from switch_hub import HubSwitcher

switcher = HubSwitcher()

with switcher.context('rh'):
    # В этом блоке все операции проходят через Cloud.ru Repo
    ...

# После выхода из блока — автоматически восстановлен Hugging Face/прежний хаб
# mode: может быть 'hf' (Hugging Face Hub) или 'rh' (Cloud.ru Repo)
```

---

### Обработка ошибок

**`RepoTokenMissingError`** (`switch_hub.exceptions.RepoTokenMissingError`) — выбрасывается при попытке
переключиться на Repo (`switch_to_rh()` / `context('rh')`) без установленного `RH_TOKEN`:

```python
from switch_hub.exceptions import RepoTokenMissingError

try:
    switcher.switch_to_rh()
except RepoTokenMissingError:
    ...  # RH_TOKEN не задан — переключение не выполнено, окружение не изменилось
```

---

### Кейсы использования

- **Исследование новых моделей:** переключайтесь между публичными репозиториями и приватным registry.
- **Экспорт и импорт моделей между Cloud.ru и Hugging Face.**
- **Автоматизация CI/CD пайплайнов для MLOps.**

---

**P.S.** Эти способы аутентификации работают для моделей, датасетов и других библиотек, использующих
`huggingface_hub`/`datasets` под капотом.
_Рекомендуется всегда указывать `RH_TOKEN` и `HF_TOKEN` через переменные окружения или секреты инфраструктуры для
максимальной гибкости и безопасности._

