Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
404 changes: 404 additions & 0 deletions .ai/python-guidelines.md

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,13 @@
"Bash(grep -E \"\\\\.json$|\\\\.lock$|todo\\\\.md|action_plan\\\\.md|usability_scorecard\\\\.md\")",
"Bash(echo \"---EXISTS:$?\")",
"Bash(git mv *)",
"Bash(make swagger-lint *)"
"Bash(make swagger-lint *)",
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api branch -a)",
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api log --oneline async..HEAD)",
"Bash(grep -v \":0$\")",
"Bash(grep -E \"\\\\\\\\.py$\")",
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api log --oneline async..main)",
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api log --oneline main..async)"
]
}
}
1 change: 1 addition & 0 deletions CHANGELOG.d/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

12 changes: 12 additions & 0 deletions CHANGELOG.d/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Changelog fragments

Domain async PRs after M1 add one fragment named `<PR-number>-async-<domain>.md`.

Supported format:

```markdown
### Added
- Async-поддержка домена <domain>: Async<X>, Async<Y> (#<PR-number>)
```

M-final aggregates fragments into `CHANGELOG.md` under `## [2.1.0]`.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,26 @@ and this project adheres to Semantic Versioning.
## [Unreleased]

### Added
- Нет изменений.

## [2.1.0] - 2026-05-08

### Added
- Фундамент Async API: `AsyncTransport`, `AsyncAuthProvider`,
`AsyncOperationExecutor`, `AsyncPaginatedList`, `AsyncAvitoClient` без
доменных factory-методов; `RateLimitState` вынесен в shared.
- Async-поддержка домена tariffs: `AsyncTariff` (PoC шаблона).
- Async-поддержка домена accounts: AsyncAccount, AsyncAccountHierarchy.
- Async-поддержка домена ads: AsyncAd, AsyncAdStats, AsyncAdPromotion, AsyncAutoloadProfile, AsyncAutoloadReport, AsyncAutoloadArchive.
- Async-поддержка домена autoteka: AsyncAutotekaVehicle, AsyncAutotekaReport, AsyncAutotekaMonitoring, AsyncAutotekaScoring, AsyncAutotekaValuation.
- Async-поддержка домена cpa: AsyncCallTrackingCall, AsyncCpaArchive, AsyncCpaCall, AsyncCpaChat, AsyncCpaLead.
- Async-поддержка домена jobs: AsyncApplication, AsyncJobDictionary, AsyncJobWebhook, AsyncResume, AsyncVacancy.
- Async-поддержка домена messenger: AsyncChat, AsyncChatMedia, AsyncChatMessage, AsyncChatWebhook, AsyncSpecialOfferCampaign.
- Async-поддержка домена orders: AsyncOrder, AsyncOrderLabel, AsyncDeliveryOrder, AsyncSandboxDelivery, AsyncDeliveryTask, AsyncStock.
- Async-поддержка домена promotion: AsyncPromotionOrder, AsyncBbipPromotion, AsyncTrxPromotion, AsyncCpaAuction, AsyncTargetActionPricing, AsyncAutostrategyCampaign.
- Async-поддержка домена ratings: AsyncRatingProfile, AsyncReview, AsyncReviewAnswer.
- Async-поддержка домена realty: AsyncRealtyAnalyticsReport, AsyncRealtyBooking, AsyncRealtyListing, AsyncRealtyPricing.
- Async convenience methods для `AsyncAvitoClient`: `business_summary`, `account_health`, `listing_health`, `chat_summary`, `order_summary`, `review_summary`, `promotion_summary`, `capabilities`.
- Добавлен `ClientClosedError` для вызовов после `AvitoClient.close()`.

### Deprecated
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ MKDOCS_ENV=DISABLE_MKDOCS_2_WARNING=true NO_MKDOCS_2_WARNING=1

check: test quality

quality: typecheck lint swagger-lint architecture-lint docstring-lint build
quality: typecheck lint swagger-lint architecture-lint async-parity-lint docstring-lint build

build: clean
poetry build
Expand Down Expand Up @@ -41,6 +41,9 @@ swagger-lint:
architecture-lint:
poetry run python scripts/lint_architecture.py

async-parity-lint:
poetry run python scripts/lint_async_parity.py

docstring-lint:
poetry run python scripts/lint_docstrings.py

Expand Down
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ print(ad.title)

По умолчанию настройки читаются из переменных окружения с префиксом `AVITO_`.

`avito-py` — синхронный Python SDK для работы с Avito API через единый объектный фасад `AvitoClient`.
`avito-py` — Python SDK для работы с Avito API через единые sync/async фасады
`AvitoClient` и `AsyncAvitoClient`.

## Установка

Expand Down Expand Up @@ -84,6 +85,19 @@ with AvitoClient(settings) as avito:

Все опциональные параметры конструктора — keyword-only. `AvitoClient` иммутабелен: `base_url`, таймауты, retry-политика и `auth` не меняются у живого клиента — вместо этого создаётся новый клиент.

Async-поверхность использует те же доменные методы и модели, но требует `async with`:

```python
from avito import AsyncAvitoClient

async with AsyncAvitoClient.from_env() as avito:
profile = await avito.account().get_self()
listings = await (await avito.ad(user_id=123).list(limit=20)).materialize()
```

Подробный контракт async lifecycle, ASGI-рецепты и ограничения описаны в
[async how-to](https://p141592.github.io/avito_python_api/how-to/async/).

### Переменные окружения

| Переменная | Обязательная | Описание |
Expand Down
10 changes: 6 additions & 4 deletions STYLEGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ avito/
ratings/
__init__.py
domain.py
async_domain.py
operations.py
models.py
```
Expand Down Expand Up @@ -96,7 +97,8 @@ Rules:
- Each API section lives in its own package: `ads`, `messenger`, `orders`, `autoload`, etc.
- Only modules belonging to that section are allowed inside each section package.
- `avito/client.py` and `avito/__init__.py` contain only the high-level entry point and public exports.
- `domain.py` contains public `DomainObject` classes, explicit public methods, reference-ready docstrings, `@swagger_operation(...)` bindings, business validation, and construction of internal request models.
- `domain.py` contains public sync `DomainObject` classes, explicit public methods, reference-ready docstrings, `@swagger_operation(..., variant="sync")` bindings, business validation, and construction of internal request models.
- `async_domain.py` is the allowed async companion for ported domains. It contains `AsyncDomainObject` classes named `Async<X>` and mirrors the sync public methods with `async def`, `AsyncPaginatedList[T]` where sync returns `PaginatedList[T]`, and `@swagger_operation(..., variant="async")`.
- `operations.py` or `operations/` contains internal `OperationSpec` definitions: HTTP method, path, operation name, retry policy, path rendering, request model class, response model class, and pagination/binary/multipart strategy when applicable.
- `models.py` or `models/` contains public response dataclasses, internal request/query dataclasses, colocated enum types, `from_payload()`, `to_payload()`, `to_params()`, and normalization logic.
- API domains must not introduce `client.py`, `mappers.py`, or standalone
Expand Down Expand Up @@ -372,8 +374,8 @@ Rules:

Recommendation:

- Build a high-quality sync SDK first.
- The SDK is synchronous — this must be explicitly documented in the README and public API.
- Build a high-quality dual-mode SDK: sync remains the default stable surface, and async is exposed through explicit `Async*` classes.
- The SDK has separate sync and async public surfaces. Async code must not wrap sync network calls; it uses `httpx.AsyncClient`, `AsyncTransport`, `AsyncAuthProvider`, `AsyncOperationExecutor`, and async pagination primitives.

### User-Agent and Client Identification

Expand Down Expand Up @@ -883,7 +885,7 @@ Rules:
- Swagger bindings must not duplicate the API contract. Decorators and binding metadata must not contain request/response schemas, status lists, content types, response models, request models, error models, required fields, path parameter definitions, or query parameter definitions.
- Public domain classes that expose bound methods should declare class-level metadata (`__swagger_domain__`, `__swagger_spec__`, `__sdk_factory__`, and when needed `__sdk_factory_args__`) so discovery can resolve bindings without creating `AvitoClient`, reading required environment variables, or doing network work.
- The canonical coverage map is generated from Swagger registry plus discovered `@swagger_operation` bindings. Markdown inventory files and hand-written coverage tables must not be used as source of truth.
- Each Swagger operation must resolve to exactly one discovered binding in strict mode. One public SDK method must not have more than one Swagger binding. Stacked `@swagger_operation(...)` decorators and `__swagger_bindings__` metadata are forbidden.
- Each Swagger operation must resolve to exactly one discovered binding per surface variant in strict mode: one `sync` binding and, for ported async classes, one `async` binding. One public SDK method must not have more than one Swagger binding. Stacked `@swagger_operation(...)` decorators and `__swagger_bindings__` metadata are forbidden.
- Public method signatures, model field names and types, allowed enum values, and nullable behavior must exactly match the contract in `docs/avito/api/`.
- When there is a discrepancy between code and the specification in `docs/avito/api/`, the specification takes priority.
- If the upstream API adds a new endpoint or changes an existing one, a corresponding SDK change is mandatory.
Expand Down
4 changes: 4 additions & 0 deletions avito/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"""Публичные экспорты пакета SDK для Avito."""

from avito.async_client import AsyncAvitoClient
from avito.auth.settings import AuthSettings
from avito.client import AvitoClient
from avito.config import AvitoSettings
from avito.core.async_pagination import AsyncPaginatedList
from avito.core.exceptions import (
AuthenticationError,
AuthorizationError,
Expand Down Expand Up @@ -34,6 +36,8 @@
__all__ = (
"AccountHealthSummary",
"AuthSettings",
"AsyncAvitoClient",
"AsyncPaginatedList",
"AuthenticationError",
"AuthorizationError",
"AvitoClient",
Expand Down
3 changes: 3 additions & 0 deletions avito/accounts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Пакет accounts."""

from avito.accounts.async_domain import AsyncAccount, AsyncAccountHierarchy
from avito.accounts.domain import Account, AccountHierarchy
from avito.accounts.models import (
AccountActionResult,
Expand All @@ -26,6 +27,8 @@
"AccountHierarchyRole",
"AccountProfile",
"AhUserStatus",
"AsyncAccount",
"AsyncAccountHierarchy",
"CompanyPhone",
"CompanyPhonesResult",
"Employee",
Expand Down
Loading
Loading