diff --git a/.gitignore b/.gitignore index c70e9ab..12338f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ site/ api_reference.md +__pycache__/ +*.pyc +site/ diff --git a/WIP.md b/WIP.md index 2e109cb..dee385d 100644 --- a/WIP.md +++ b/WIP.md @@ -43,35 +43,49 @@ ## 📝 Заметки -### Автогенерация документации (2026-03-23 04:28) +### Автогенерация документации (2026-03-23 04:35) -**Инструмент:** pydoc-markdown +**Инструмент:** MkDocs + mkdocstrings + Material theme **Структура:** ``` docs/ -├── api_reference.md # Auto-generated from docstrings +├── index.md # Quick start guide +├── api-reference.md # API overview +├── api/ +│ ├── client.md # KworkClient documentation +│ ├── models.md # Pydantic models +│ └── errors.md # Exception classes +└── examples.md # Usage examples + +site/ # Generated HTML (не коммитим) +├── index.html +├── api-reference/ +└── ... ``` **Конфигурация:** -- `pydoc-markdown.yml` — конфигурация генерации -- Pre-commit hook — автогенерация при коммите +- `mkdocs.yml` — MkDocs конфигурация +- Pre-commit hook — автогенерация HTML при коммите **Покрытие документацией:** -- `KworkClient` — класс, __init__, login(), все API группы -- `CatalogAPI` — get_list(), get_details(), get_details_extra() -- `ProjectsAPI` — get_list(), get_payer_orders(), get_worker_orders() -- `UserAPI` — get_info(), get_reviews(), get_favorite_kworks() -- `ReferenceAPI` — все методы (cities, countries, features, badges...) -- `NotificationsAPI` — все методы (list, fetch, dialogs...) -- `OtherAPI` — все методы (wants, settings, offline...) -- `models.py` — все 20+ моделей -- `errors.py` — все 7 исключений +- `KworkClient` — класс, аутентификация, все методы +- `CatalogAPI` — каталог кворков +- `ProjectsAPI` — биржа проектов +- `UserAPI` — пользовательские данные +- `ReferenceAPI` — справочники +- `NotificationsAPI` — уведомления +- `client.get_*()` — настройки и предпочтения (бывший OtherAPI) +- `models.py` — все модели +- `errors.py` — все исключения **Команды:** ```bash -# Ручная генерация -pydoc-markdown > docs/api_reference.md +# Сборка HTML документации +mkdocs build + +# Локальный просмотр +mkdocs serve ``` ### Аудит эндпоинтов (2026-03-23 03:08) diff --git a/docs/api-reference.md b/docs/api-reference.md new file mode 100644 index 0000000..8aaf2d9 --- /dev/null +++ b/docs/api-reference.md @@ -0,0 +1,9 @@ +# API Reference + +Complete API documentation for Kwork API client. + +## Modules + +- [Client](api/client.md) — Main client class and API groups +- [Models](api/models.md) — Pydantic models for API responses +- [Errors](api/errors.md) — Exception classes diff --git a/docs/api/client.md b/docs/api/client.md new file mode 100644 index 0000000..bee123c --- /dev/null +++ b/docs/api/client.md @@ -0,0 +1,3 @@ +# Client API + +::: kwork_api.client.KworkClient diff --git a/docs/api/errors.md b/docs/api/errors.md new file mode 100644 index 0000000..eef1951 --- /dev/null +++ b/docs/api/errors.md @@ -0,0 +1,5 @@ +# Errors + +Exception classes for API errors. + +::: kwork_api.errors diff --git a/docs/api/models.md b/docs/api/models.md new file mode 100644 index 0000000..44fa61f --- /dev/null +++ b/docs/api/models.md @@ -0,0 +1,5 @@ +# Models + +Pydantic models for API responses. + +::: kwork_api.models diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..8c780aa --- /dev/null +++ b/docs/index.md @@ -0,0 +1,97 @@ +# Kwork API — Python Client + +Unofficial Python client for Kwork.ru API. + +## Installation + +```bash +pip install kwork-api +``` + +Or with UV: + +```bash +uv add kwork-api +``` + +## Quick Start + +### Login with credentials + +```python +from kwork_api import KworkClient + +# Authenticate +client = await KworkClient.login("username", "password") + +# Get catalog +catalog = await client.catalog.get_list(page=1) + +# Get projects +projects = await client.projects.get_list(page=1) + +# Close when done +await client.close() +``` + +### Using context manager + +```python +async with await KworkClient.login("username", "password") as client: + catalog = await client.catalog.get_list(page=1) + # Client automatically closes +``` + +### Restore from token + +```python +# Save token after login +token = client._token + +# Later, restore session +client = KworkClient(token=token) +user_info = await client.user.get_info() +``` + +## API Overview + +### Catalog API + +- `client.catalog.get_list()` — Get kworks catalog +- `client.catalog.get_details(kwork_id)` — Get kwork details + +### Projects API + +- `client.projects.get_list()` — Get freelance projects +- `client.projects.get_payer_orders()` — Your orders as customer +- `client.projects.get_worker_orders()` — Your orders as performer + +### User API + +- `client.user.get_info()` — Get user profile +- `client.user.get_reviews()` — Get user reviews +- `client.user.get_favorite_kworks()` — Get favorite kworks + +### Settings & Preferences + +- `client.get_wants()` — User preferences +- `client.get_kworks_status()` — Kworks status +- `client.update_settings()` — Update settings +- `client.go_offline()` — Set offline status + +See [API Reference](api-reference.md) for full documentation. + +## Error Handling + +```python +from kwork_api import KworkError, KworkAuthError, KworkApiError + +try: + await client.catalog.get_list() +except KworkAuthError: + print("Invalid credentials") +except KworkApiError as e: + print(f"API error: {e.status_code}") +except KworkError as e: + print(f"General error: {e.message}") +``` diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..ec3c29d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,79 @@ +site_name: Kwork API +site_description: Unofficial Python client for Kwork.ru API +site_url: https://github.com/claw/kwork-api + +repo_name: claw/kwork-api +repo_url: https://github.com/claw/kwork-api + +theme: + name: material + features: + - navigation.tabs + - navigation.sections + - toc.integrate + - search.suggest + - search.highlight + palette: + - scheme: default + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + - scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode + +plugins: + - search + - mkdocstrings: + handlers: + python: + paths: [src] + options: + docstring_style: google + show_source: true + show_root_heading: true + show_category_heading: true + merge_init_into_class: true + separate_signature: true + signature_crossrefs: true + filters: + - "!^_" + - "^__init__" + +markdown_extensions: + - admonition + - attr_list + - def_list + - footnotes + - toc: + permalink: true + - pymdownx.arithmatex: + generic: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.caret + - pymdownx.details + - pymdownx.inlinehilite + - pymdownx.keys + - pymdownx.magiclink: + repo_url_shorthand: true + user: claw + repo: kwork-api + - pymdownx.mark + - pymdownx.smartsymbols + - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.tilde + +nav: + - Home: index.md + - API Reference: + - Overview: api-reference.md + - Client: api/client.md + - Models: api/models.md + - Errors: api/errors.md + - Examples: examples.md diff --git a/pyproject.toml b/pyproject.toml index 5adea36..cd79277 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,10 @@ dev = [ "respx>=0.20.0", "ruff>=0.3.0", "pydoc-markdown>=4.8.2", + "mkdocs>=1.6.1", + "mkdocs-material>=9.7.6", + "mkdocstrings>=1.0.3", + "mkdocstrings-python>=2.0.3", ] [tool.pytest.ini_options] diff --git a/src/kwork_api/__pycache__/client.cpython-312.pyc b/src/kwork_api/__pycache__/client.cpython-312.pyc index 88384f2..aba3e05 100644 Binary files a/src/kwork_api/__pycache__/client.cpython-312.pyc and b/src/kwork_api/__pycache__/client.cpython-312.pyc differ diff --git a/src/kwork_api/__pycache__/errors.cpython-312.pyc b/src/kwork_api/__pycache__/errors.cpython-312.pyc index 9da2003..adda591 100644 Binary files a/src/kwork_api/__pycache__/errors.cpython-312.pyc and b/src/kwork_api/__pycache__/errors.cpython-312.pyc differ diff --git a/src/kwork_api/__pycache__/models.cpython-312.pyc b/src/kwork_api/__pycache__/models.cpython-312.pyc index 62350fa..d54b54a 100644 Binary files a/src/kwork_api/__pycache__/models.cpython-312.pyc and b/src/kwork_api/__pycache__/models.cpython-312.pyc differ diff --git a/src/kwork_api/client.py b/src/kwork_api/client.py index 1e245af..2154e8e 100644 --- a/src/kwork_api/client.py +++ b/src/kwork_api/client.py @@ -907,274 +907,214 @@ class KworkClient: data = await self.client._request("POST", "/blockedDialogList") return [Dialog.model_validate(d) for d in data.get("dialogs", [])] - # ========== Other Endpoints ========== + # ========== User Settings & Preferences ========== - class OtherAPI: + async def get_wants(self) -> dict[str, Any]: """ - Прочее API. + Получить пользовательские предпочтения (wants). - Вспомогательные эндпоинты которые не вошли в другие категории: - - Пользовательские настройки и предпочтения (wants) - - Статусы кворков и заказов - - Персональные предложения (offers) - - Настройки профиля - - Статус онлайн/оффлайн + Wants — это настройки интересов пользователя: + - Предпочитаемые категории + - Ключевые слова для мониторинга + - Фильтры для поиска + + Returns: + Словарь с настройками предпочтений. Example: - # Пользовательские предпочтения - wants = await client.other.get_wants() - - # Статус кворков - status = await client.other.get_kworks_status() - - # Установить статус оффлайн - await client.other.go_offline() + wants = await client.get_wants() + print(wants) """ + return await self._request("POST", "/myWants") + + async def get_wants_status(self) -> dict[str, Any]: + """ + Получить статус предпочтений. - def __init__(self, client: "KworkClient"): - self.client = client + Returns: + Статус wants с метаданными. + """ + return await self._request("POST", "/wantsStatusList") + + async def get_kworks_status(self) -> dict[str, Any]: + """ + Получить статусы кворков пользователя. - async def get_wants(self) -> dict[str, Any]: - """ - Получить пользовательские предпочтения (wants). - - Wants — это настройки интересов пользователя: - - Предпочитаемые категории - - Ключевые слова для мониторинга - - Фильтры для поиска - - Returns: - Словарь с настройками предпочтений. - - Example: - wants = await client.other.get_wants() - print(wants) - """ - return await self.client._request("POST", "/myWants") + Возвращает информацию о статусах всех кворков + текущего пользователя (активен, на модерации, и т.д.). - async def get_wants_status(self) -> dict[str, Any]: - """ - Получить статус предпочтений. - - Returns: - Статус wants с метаданными. - """ - return await self.client._request("POST", "/wantsStatusList") + Returns: + Словарь со статусами кворков. - async def get_kworks_status(self) -> dict[str, Any]: - """ - Получить статусы кворков пользователя. - - Возвращает информацию о статусах всех кворков - текущего пользователя (активен, на модерации, и т.д.). - - Returns: - Словарь со статусами кворков. - - Example: - status = await client.other.get_kworks_status() - print(status) - """ - return await self.client._request("POST", "/kworksStatusList") + Example: + status = await client.get_kworks_status() + print(status) + """ + return await self._request("POST", "/kworksStatusList") + + async def get_offers(self) -> dict[str, Any]: + """ + Получить персональные предложения. - async def get_offers(self) -> dict[str, Any]: - """ - Получить персональные предложения. - - Returns: - Список персональных предложений от Kwork. - """ - return await self.client._request("POST", "/offers") + Returns: + Список персональных предложений от Kwork. + """ + return await self._request("POST", "/offers") + + async def get_exchange_info(self) -> dict[str, Any]: + """ + Получить информацию об обмене валюты. - async def get_exchange_info(self) -> dict[str, Any]: - """ - Получить информацию об обмене валюты. - - Returns: - Информация о курсах валют и обмене. - """ - return await self.client._request("POST", "/exchangeInfo") + Returns: + Информация о курсах валют и обмене. + """ + return await self._request("POST", "/exchangeInfo") + + async def get_channel(self) -> dict[str, Any]: + """ + Получить информацию о канале пользователя. - async def get_channel(self) -> dict[str, Any]: - """ - Получить информацию о канале пользователя. - - Returns: - Данные канала (если есть). - """ - return await self.client._request("POST", "/getChannel") + Returns: + Данные канала (если есть). + """ + return await self._request("POST", "/getChannel") + + async def get_in_app_notification(self) -> dict[str, Any]: + """ + Получить внутриприложенное уведомление. - async def get_in_app_notification(self) -> dict[str, Any]: - """ - Получить внутриприложенное уведомление. - - Returns: - Данные in-app уведомления. - """ - return await self.client._request("POST", "/getInAppNotification") + Returns: + Данные in-app уведомления. + """ + return await self._request("POST", "/getInAppNotification") + + async def get_security_user_data(self) -> dict[str, Any]: + """ + Получить данные безопасности пользователя. - async def get_security_user_data(self) -> dict[str, Any]: - """ - Получить данные безопасности пользователя. - - Returns: - Информация о безопасности аккаунта. - """ - return await self.client._request("POST", "/getSecurityUserData") + Returns: + Информация о безопасности аккаунта. + """ + return await self._request("POST", "/getSecurityUserData") + + async def is_dialog_allow(self, user_id: int) -> bool: + """ + Проверить возможность начала диалога с пользователем. - async def is_dialog_allow(self, user_id: int) -> bool: - """ - Проверить возможность начала диалога с пользователем. - - Args: - user_id: ID пользователя для проверки. - - Returns: - True если диалог разрешён, False иначе. - - Example: - allowed = await client.other.is_dialog_allow(12345) - if allowed: - print("Можно написать сообщение") - """ - data = await self.client._request( - "POST", - "/isDialogAllow", - json={"user_id": user_id}, - ) - return data.get("allowed", False) + Args: + user_id: ID пользователя для проверки. - async def get_viewed_kworks(self) -> list[Kwork]: - """ - Получить просмотренные кворки. - - Возвращает список кворков, которые пользователь - просматривал ранее. - - Returns: - Список просмотренных кворков. - - Example: - viewed = await client.other.get_viewed_kworks() - print(f"Просмотрено: {len(viewed)} кворков") - """ - data = await self.client._request("POST", "/viewedCatalogKworks") - return [Kwork.model_validate(k) for k in data.get("kworks", [])] + Returns: + True если диалог разрешён, False иначе. - async def get_favorite_categories(self) -> list[int]: - """ - Получить ID избранных категорий. - - Returns: - Список ID категорий, добавленных в избранное. - - Example: - cats = await client.other.get_favorite_categories() - print(f"Избранные категории: {cats}") - """ - data = await self.client._request("POST", "/favoriteCategories") - return data.get("categories", []) + Example: + allowed = await client.is_dialog_allow(12345) + if allowed: + print("Можно написать сообщение") + """ + data = await self._request( + "POST", + "/isDialogAllow", + json={"user_id": user_id}, + ) + return data.get("allowed", False) + + async def get_viewed_kworks(self) -> list[Kwork]: + """ + Получить просмотренные кворки. - async def update_settings(self, settings: dict[str, Any]) -> dict[str, Any]: - """ - Обновить настройки пользователя. - - Args: - settings: Словарь с настройками для обновления. - Структура зависит от конкретных настроек. - - Returns: - Ответ API с подтверждением обновления. - - Example: - await client.other.update_settings({ - "email_notifications": True, - "language": "ru" - }) - """ - return await self.client._request("POST", "/updateSettings", json=settings) + Возвращает список кворков, которые пользователь + просматривал ранее. - async def go_offline(self) -> dict[str, Any]: - """ - Установить статус пользователя "оффлайн". - - Скрывает онлайн-статус от других пользователей. - - Returns: - Подтверждение изменения статуса. - - Example: - await client.other.go_offline() - """ - return await self.client._request("POST", "/offline") + Returns: + Список просмотренных кворков. - async def get_actor(self) -> dict[str, Any]: - """ - Получить информацию об актёре (текущем пользователе). - - Returns: - Данные актёра/пользователя. - """ - return await self.client._request("POST", "/actor") + Example: + viewed = await client.get_viewed_kworks() + print(f"Просмотрено: {len(viewed)} кворков") + """ + data = await self._request("POST", "/viewedCatalogKworks") + return [Kwork.model_validate(k) for k in data.get("kworks", [])] + + async def get_favorite_categories(self) -> list[int]: + """ + Получить ID избранных категорий. + + Returns: + Список ID категорий, добавленных в избранное. + + Example: + cats = await client.get_favorite_categories() + print(f"Избранные категории: {cats}") + """ + data = await self._request("POST", "/favoriteCategories") + return data.get("categories", []) + + async def update_settings(self, settings: dict[str, Any]) -> dict[str, Any]: + """ + Обновить настройки пользователя. + + Args: + settings: Словарь с настройками для обновления. + Структура зависит от конкретных настроек. + + Returns: + Ответ API с подтверждением обновления. + + Example: + await client.update_settings({ + "email_notifications": True, + "language": "ru" + }) + """ + return await self._request("POST", "/updateSettings", json=settings) + + async def go_offline(self) -> dict[str, Any]: + """ + Установить статус пользователя "оффлайн". + + Скрывает онлайн-статус от других пользователей. + + Returns: + Подтверждение изменения статуса. + + Example: + await client.go_offline() + """ + return await self._request("POST", "/offline") + + async def get_actor(self) -> dict[str, Any]: + """ + Получить информацию об актёре (текущем пользователе). + + Returns: + Данные актёра/пользователя. + """ + return await self._request("POST", "/actor") # ========== API Property Accessors ========== @property def catalog(self) -> CatalogAPI: - """ - API каталога кворков. - - Returns: - CatalogAPI для работы с каталогом. - """ + """API каталога кворков.""" return self.CatalogAPI(self) @property def projects(self) -> ProjectsAPI: - """ - API биржи проектов. - - Returns: - ProjectsAPI для работы с проектами. - """ + """API биржи проектов.""" return self.ProjectsAPI(self) @property def user(self) -> UserAPI: - """ - Пользовательское API. - - Returns: - UserAPI для работы с профилем. - """ + """Пользовательское API.""" return self.UserAPI(self) @property def reference(self) -> ReferenceAPI: - """ - Справочное API. - - Returns: - ReferenceAPI для справочных данных. - """ + """Справочное API.""" return self.ReferenceAPI(self) @property def notifications(self) -> NotificationsAPI: - """ - API уведомлений. - - Returns: - NotificationsAPI для уведомлений и сообщений. - """ + """API уведомлений.""" return self.NotificationsAPI(self) - - @property - def other(self) -> OtherAPI: - """ - Прочее API. - - Returns: - OtherAPI для вспомогательных эндпоинтов. - """ - return self.OtherAPI(self) diff --git a/uv.lock b/uv.lock index a9c0f03..3f1920d 100644 --- a/uv.lock +++ b/uv.lock @@ -25,6 +25,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + [[package]] name = "backports-asyncio-runner" version = "1.2.0" @@ -34,6 +43,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/59/76ab57e3fe74484f48a53f8e337171b4a2349e506eabe136d7e01d059086/backports_asyncio_runner-1.2.0-py3-none-any.whl", hash = "sha256:0da0a936a8aeb554eccb426dc55af3ba63bcdc69fa1a600b5bb305413a4477b5", size = 12313, upload-time = "2025-07-02T02:27:14.263Z" }, ] +[[package]] +name = "backrefs" +version = "6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/a6/e325ec73b638d3ede4421b5445d4a0b8b219481826cc079d510100af356c/backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49", size = 7012303, upload-time = "2026-02-16T19:10:15.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/39/3765df263e08a4df37f4f43cb5aa3c6c17a4bdd42ecfe841e04c26037171/backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8", size = 381075, upload-time = "2026-02-16T19:10:04.322Z" }, + { url = "https://files.pythonhosted.org/packages/0f/f0/35240571e1b67ffb19dafb29ab34150b6f59f93f717b041082cdb1bfceb1/backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be", size = 392874, upload-time = "2026-02-16T19:10:06.314Z" }, + { url = "https://files.pythonhosted.org/packages/e3/63/77e8c9745b4d227cce9f5e0a6f68041278c5f9b18588b35905f5f19c1beb/backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90", size = 398787, upload-time = "2026-02-16T19:10:08.274Z" }, + { url = "https://files.pythonhosted.org/packages/c5/71/c754b1737ad99102e03fa3235acb6cb6d3ac9d6f596cbc3e5f236705abd8/backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b", size = 400747, upload-time = "2026-02-16T19:10:09.791Z" }, + { url = "https://files.pythonhosted.org/packages/af/75/be12ba31a6eb20dccef2320cd8ccb3f7d9013b68ba4c70156259fee9e409/backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7", size = 412602, upload-time = "2026-02-16T19:10:12.317Z" }, + { url = "https://files.pythonhosted.org/packages/21/f8/d02f650c47d05034dcd6f9c8cf94f39598b7a89c00ecda0ecb2911bc27e9/backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7", size = 381077, upload-time = "2026-02-16T19:10:13.74Z" }, +] + [[package]] name = "black" version = "23.12.1" @@ -415,6 +438,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffelib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/51/c936033e16d12b627ea334aaaaf42229c37620d0f15593456ab69ab48161/griffelib-2.0.0-py3-none-any.whl", hash = "sha256:01284878c966508b6d6f1dbff9b6fa607bc062d8261c5c7253cb285b06422a7f", size = 142004, upload-time = "2026-02-09T19:09:40.561Z" }, +] + [[package]] name = "h11" version = "0.16.0" @@ -539,6 +582,10 @@ dev = [ [package.dev-dependencies] dev = [ + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "mkdocstrings" }, + { name = "mkdocstrings-python" }, { name = "pydoc-markdown" }, { name = "pytest" }, { name = "pytest-asyncio" }, @@ -562,6 +609,10 @@ provides-extras = ["dev"] [package.metadata.requires-dev] dev = [ + { name = "mkdocs", specifier = ">=1.6.1" }, + { name = "mkdocs-material", specifier = ">=9.7.6" }, + { name = "mkdocstrings", specifier = ">=1.0.3" }, + { name = "mkdocstrings-python", specifier = ">=2.0.3" }, { name = "pydoc-markdown", specifier = ">=4.8.2" }, { name = "pytest", specifier = ">=8.0.0" }, { name = "pytest-asyncio", specifier = ">=0.23.0" }, @@ -570,6 +621,15 @@ dev = [ { name = "ruff", specifier = ">=0.3.0" }, ] +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -655,6 +715,130 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, ] +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588, upload-time = "2026-02-10T15:23:55.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530, upload-time = "2026-02-10T15:23:53.817Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/25/b3cccb187655b9393572bde9b09261d267c3bf2f2cdabe347673be5976a6/mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1", size = 11047, upload-time = "2026-03-10T02:46:33.632Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650", size = 9555, upload-time = "2026-03-10T02:46:32.256Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.7.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "backrefs" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/29/6d2bcf41ae40802c4beda2432396fff97b8456fb496371d1bc7aad6512ec/mkdocs_material-9.7.6.tar.gz", hash = "sha256:00bdde50574f776d328b1862fe65daeaf581ec309bd150f7bff345a098c64a69", size = 4097959, upload-time = "2026-03-19T15:41:58.161Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/01/bc663630c510822c95c47a66af9fa7a443c295b47d5f041e5e6ae62ef659/mkdocs_material-9.7.6-py3-none-any.whl", hash = "sha256:71b84353921b8ea1ba84fe11c50912cc512da8fe0881038fcc9a0761c0e635ba", size = 9305470, upload-time = "2026-03-19T15:41:55.217Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/46/62/0dfc5719514115bf1781f44b1d7f2a0923fcc01e9c5d7990e48a05c9ae5d/mkdocstrings-1.0.3.tar.gz", hash = "sha256:ab670f55040722b49bb45865b2e93b824450fb4aef638b00d7acb493a9020434", size = 100946, upload-time = "2026-02-07T14:31:40.973Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/41/1cf02e3df279d2dd846a1bf235a928254eba9006dd22b4a14caa71aed0f7/mkdocstrings-1.0.3-py3-none-any.whl", hash = "sha256:0d66d18430c2201dc7fe85134277382baaa15e6b30979f3f3bdbabd6dbdb6046", size = 35523, upload-time = "2026-02-07T14:31:39.27Z" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "2.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffelib" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/33/c225eaf898634bdda489a6766fc35d1683c640bffe0e0acd10646b13536d/mkdocstrings_python-2.0.3.tar.gz", hash = "sha256:c518632751cc869439b31c9d3177678ad2bfa5c21b79b863956ad68fc92c13b8", size = 199083, upload-time = "2026-02-20T10:38:36.368Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/28/79f0f8de97cce916d5ae88a7bee1ad724855e83e6019c0b4d5b3fabc80f3/mkdocstrings_python-2.0.3-py3-none-any.whl", hash = "sha256:0b83513478bdfd803ff05aa43e9b1fca9dd22bcd9471f09ca6257f009bc5ee12", size = 104779, upload-time = "2026-02-20T10:38:34.517Z" }, +] + [[package]] name = "mypy-extensions" version = "1.1.0" @@ -704,6 +888,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, ] +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + [[package]] name = "pathspec" version = "1.0.4" @@ -898,6 +1091,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pymdown-extensions" +version = "10.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/63/06673d1eb6d8f83c0ea1f677d770e12565fb516928b4109c9e2055656a9e/pymdown_extensions-10.21.tar.gz", hash = "sha256:39f4a020f40773f6b2ff31d2cd2546c2c04d0a6498c31d9c688d2be07e1767d5", size = 853363, upload-time = "2026-02-15T20:44:06.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/2c/5b079febdc65e1c3fb2729bf958d18b45be7113828528e8a0b5850dd819a/pymdown_extensions-10.21-py3-none-any.whl", hash = "sha256:91b879f9f864d49794c2d9534372b10150e6141096c3908a455e45ca72ad9d3f", size = 268877, upload-time = "2026-02-15T20:44:05.464Z" }, +] + [[package]] name = "pytest" version = "9.0.2" @@ -944,6 +1150,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, ] +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -1008,6 +1226,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, ] +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + [[package]] name = "requests" version = "2.32.5" @@ -1060,6 +1290,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/e8/726643a3ea68c727da31570bde48c7a10f1aa60eddd628d94078fec586ff/ruff-0.15.7-py3-none-win_arm64.whl", hash = "sha256:18e8d73f1c3fdf27931497972250340f92e8c861722161a9caeb89a58ead6ed2", size = 11023304, upload-time = "2026-03-19T16:26:51.669Z" }, ] +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + [[package]] name = "structlog" version = "25.5.0"