Skip to content

Commit 9f83f8c

Browse files
authored
Async (#7)
Async режим работы
1 parent fe2bc35 commit 9f83f8c

95 files changed

Lines changed: 21156 additions & 237 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ai/python-guidelines.md

Lines changed: 404 additions & 0 deletions
Large diffs are not rendered by default.

.claude/settings.local.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,13 @@
5353
"Bash(grep -E \"\\\\.json$|\\\\.lock$|todo\\\\.md|action_plan\\\\.md|usability_scorecard\\\\.md\")",
5454
"Bash(echo \"---EXISTS:$?\")",
5555
"Bash(git mv *)",
56-
"Bash(make swagger-lint *)"
56+
"Bash(make swagger-lint *)",
57+
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api branch -a)",
58+
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api log --oneline async..HEAD)",
59+
"Bash(grep -v \":0$\")",
60+
"Bash(grep -E \"\\\\\\\\.py$\")",
61+
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api log --oneline async..main)",
62+
"Bash(git -C /Users/n.baryshnikov/Projects/avito_python_api log --oneline main..async)"
5763
]
5864
}
5965
}

CHANGELOG.d/.gitkeep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

CHANGELOG.d/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Changelog fragments
2+
3+
Domain async PRs after M1 add one fragment named `<PR-number>-async-<domain>.md`.
4+
5+
Supported format:
6+
7+
```markdown
8+
### Added
9+
- Async-поддержка домена <domain>: Async<X>, Async<Y> (#<PR-number>)
10+
```
11+
12+
M-final aggregates fragments into `CHANGELOG.md` under `## [2.1.0]`.

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,26 @@ and this project adheres to Semantic Versioning.
88
## [Unreleased]
99

1010
### Added
11+
- Нет изменений.
12+
13+
## [2.1.0] - 2026-05-08
14+
15+
### Added
16+
- Фундамент Async API: `AsyncTransport`, `AsyncAuthProvider`,
17+
`AsyncOperationExecutor`, `AsyncPaginatedList`, `AsyncAvitoClient` без
18+
доменных factory-методов; `RateLimitState` вынесен в shared.
19+
- Async-поддержка домена tariffs: `AsyncTariff` (PoC шаблона).
20+
- Async-поддержка домена accounts: AsyncAccount, AsyncAccountHierarchy.
21+
- Async-поддержка домена ads: AsyncAd, AsyncAdStats, AsyncAdPromotion, AsyncAutoloadProfile, AsyncAutoloadReport, AsyncAutoloadArchive.
22+
- Async-поддержка домена autoteka: AsyncAutotekaVehicle, AsyncAutotekaReport, AsyncAutotekaMonitoring, AsyncAutotekaScoring, AsyncAutotekaValuation.
23+
- Async-поддержка домена cpa: AsyncCallTrackingCall, AsyncCpaArchive, AsyncCpaCall, AsyncCpaChat, AsyncCpaLead.
24+
- Async-поддержка домена jobs: AsyncApplication, AsyncJobDictionary, AsyncJobWebhook, AsyncResume, AsyncVacancy.
25+
- Async-поддержка домена messenger: AsyncChat, AsyncChatMedia, AsyncChatMessage, AsyncChatWebhook, AsyncSpecialOfferCampaign.
26+
- Async-поддержка домена orders: AsyncOrder, AsyncOrderLabel, AsyncDeliveryOrder, AsyncSandboxDelivery, AsyncDeliveryTask, AsyncStock.
27+
- Async-поддержка домена promotion: AsyncPromotionOrder, AsyncBbipPromotion, AsyncTrxPromotion, AsyncCpaAuction, AsyncTargetActionPricing, AsyncAutostrategyCampaign.
28+
- Async-поддержка домена ratings: AsyncRatingProfile, AsyncReview, AsyncReviewAnswer.
29+
- Async-поддержка домена realty: AsyncRealtyAnalyticsReport, AsyncRealtyBooking, AsyncRealtyListing, AsyncRealtyPricing.
30+
- Async convenience methods для `AsyncAvitoClient`: `business_summary`, `account_health`, `listing_health`, `chat_summary`, `order_summary`, `review_summary`, `promotion_summary`, `capabilities`.
1131
- Добавлен `ClientClosedError` для вызовов после `AvitoClient.close()`.
1232

1333
### Deprecated

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ MKDOCS_ENV=DISABLE_MKDOCS_2_WARNING=true NO_MKDOCS_2_WARNING=1
66

77
check: test quality
88

9-
quality: typecheck lint swagger-lint architecture-lint docstring-lint build
9+
quality: typecheck lint swagger-lint architecture-lint async-parity-lint docstring-lint build
1010

1111
build: clean
1212
poetry build
@@ -41,6 +41,9 @@ swagger-lint:
4141
architecture-lint:
4242
poetry run python scripts/lint_architecture.py
4343

44+
async-parity-lint:
45+
poetry run python scripts/lint_async_parity.py
46+
4447
docstring-lint:
4548
poetry run python scripts/lint_docstrings.py
4649

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ print(ad.title)
2424

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

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

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

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

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

88+
Async-поверхность использует те же доменные методы и модели, но требует `async with`:
89+
90+
```python
91+
from avito import AsyncAvitoClient
92+
93+
async with AsyncAvitoClient.from_env() as avito:
94+
profile = await avito.account().get_self()
95+
listings = await (await avito.ad(user_id=123).list(limit=20)).materialize()
96+
```
97+
98+
Подробный контракт async lifecycle, ASGI-рецепты и ограничения описаны в
99+
[async how-to](https://p141592.github.io/avito_python_api/how-to/async/).
100+
87101
### Переменные окружения
88102

89103
| Переменная | Обязательная | Описание |

STYLEGUIDE.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ avito/
6565
ratings/
6666
__init__.py
6767
domain.py
68+
async_domain.py
6869
operations.py
6970
models.py
7071
```
@@ -96,7 +97,8 @@ Rules:
9697
- Each API section lives in its own package: `ads`, `messenger`, `orders`, `autoload`, etc.
9798
- Only modules belonging to that section are allowed inside each section package.
9899
- `avito/client.py` and `avito/__init__.py` contain only the high-level entry point and public exports.
99-
- `domain.py` contains public `DomainObject` classes, explicit public methods, reference-ready docstrings, `@swagger_operation(...)` bindings, business validation, and construction of internal request models.
100+
- `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.
101+
- `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")`.
100102
- `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.
101103
- `models.py` or `models/` contains public response dataclasses, internal request/query dataclasses, colocated enum types, `from_payload()`, `to_payload()`, `to_params()`, and normalization logic.
102104
- API domains must not introduce `client.py`, `mappers.py`, or standalone
@@ -372,8 +374,8 @@ Rules:
372374

373375
Recommendation:
374376

375-
- Build a high-quality sync SDK first.
376-
- The SDK is synchronous — this must be explicitly documented in the README and public API.
377+
- Build a high-quality dual-mode SDK: sync remains the default stable surface, and async is exposed through explicit `Async*` classes.
378+
- 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.
377379

378380
### User-Agent and Client Identification
379381

@@ -883,7 +885,7 @@ Rules:
883885
- 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.
884886
- 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.
885887
- 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.
886-
- 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.
888+
- 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.
887889
- Public method signatures, model field names and types, allowed enum values, and nullable behavior must exactly match the contract in `docs/avito/api/`.
888890
- When there is a discrepancy between code and the specification in `docs/avito/api/`, the specification takes priority.
889891
- If the upstream API adds a new endpoint or changes an existing one, a corresponding SDK change is mandatory.

avito/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Публичные экспорты пакета SDK для Avito."""
22

3+
from avito.async_client import AsyncAvitoClient
34
from avito.auth.settings import AuthSettings
45
from avito.client import AvitoClient
56
from avito.config import AvitoSettings
7+
from avito.core.async_pagination import AsyncPaginatedList
68
from avito.core.exceptions import (
79
AuthenticationError,
810
AuthorizationError,
@@ -34,6 +36,8 @@
3436
__all__ = (
3537
"AccountHealthSummary",
3638
"AuthSettings",
39+
"AsyncAvitoClient",
40+
"AsyncPaginatedList",
3741
"AuthenticationError",
3842
"AuthorizationError",
3943
"AvitoClient",

avito/accounts/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Пакет accounts."""
22

3+
from avito.accounts.async_domain import AsyncAccount, AsyncAccountHierarchy
34
from avito.accounts.domain import Account, AccountHierarchy
45
from avito.accounts.models import (
56
AccountActionResult,
@@ -26,6 +27,8 @@
2627
"AccountHierarchyRole",
2728
"AccountProfile",
2829
"AhUserStatus",
30+
"AsyncAccount",
31+
"AsyncAccountHierarchy",
2932
"CompanyPhone",
3033
"CompanyPhonesResult",
3134
"Employee",

0 commit comments

Comments
 (0)