Skip to content

Latest commit

 

History

History
120 lines (88 loc) · 6.76 KB

File metadata and controls

120 lines (88 loc) · 6.76 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

make test          # run all tests
make typecheck     # mypy strict check on avito/
make lint          # ruff check
make swagger-lint  # strict Swagger binding coverage check
make fmt           # ruff format
make check         # test → typecheck → lint → swagger-lint → build (full gate)
make build         # poetry build

# single test
poetry run pytest tests/test_facade.py::test_name

Architecture

Entry point: avito/client.pyAvitoClient is the single public facade. It exposes factory methods (account(), ad(), chat(), etc.) that return domain objects.

Layers (strict separation, no mixing):

Layer Location Responsibility
AvitoClient avito/client.py Public facade, factory methods
SectionClient avito/<domain>/client.py HTTP calls for one API section
Transport avito/core/transport.py httpx, retries, error mapping, token injection
AuthProvider avito/auth/provider.py Token cache, refresh, 401 handling
Mapper avito/<domain>/mappers.py JSON → typed dataclass
Config avito/config.py, avito/auth/settings.py AvitoSettings, AuthSettings

Domain packages follow a uniform structure: __init__.py, domain.py (DomainObject subclass), client.py (SectionClient), models.py (frozen dataclasses), mappers.py, optional enums.py.

Public models are @dataclass(slots=True, frozen=True), inherit SerializableModel (provides to_dict() / model_dump()), and never expose transport fields.

Exceptions live in avito/core/exceptions.py. AvitoError is the base. HTTP codes map to specific types: 401→AuthenticationError, 403→AuthorizationError, 429→RateLimitError, etc. These two are siblings, not parent/child.

Pagination: PaginatedList[T] is lazy. First page loads on creation; subsequent pages load on iteration. materialize() loads all pages.

Testing: tests/fake_transport.py provides FakeTransport — inject it instead of real HTTP. Tests are Arrange/Act/Assert, one scenario per test. Test names describe behavior, not the method under test.

API coverage

docs/avito/api/ contains Swagger/OpenAPI specs (23 documents, 204 operations) — the authoritative source of truth for all API contracts. The canonical SDK coverage map is built from Swagger operation bindings discovered on public domain methods, not from markdown inventory files.

Public SDK methods are documented in docs/site/reference/ and generated by the MkDocs reference builder from the actual package surface. All 204 operations from the specs must be covered. A missing method is a defect.

Swagger binding subsystem

The persistent subsystem context is documented in docs/site/explanations/swagger-binding-subsystem.md.

Core invariant:

each Swagger operation -> exactly one discovered binding
each discovered SDK method -> exactly one Swagger operation

Multiple Swagger bindings on one public SDK method are forbidden. If one public scenario covers different upstream modes, expose separate documented SDK methods and keep compatibility wrappers unbound.

When adding or changing a public method that corresponds to Avito API:

  • consult docs/avito/api/*.json first;
  • add or update the public domain method, section client call, mapper and typed public models;
  • add @swagger_operation(...) on the public domain method;
  • do not put schemas, statuses, content types, request models, response models, error models, path params, or query params into the decorator;
  • add or update class-level Swagger metadata when introducing a domain class;
  • write a reference-ready docstring for the public method: business action, arguments, return model, pagination/dry-run/idempotency behavior when relevant, and common SDK exceptions;
  • update docs/site/how-to/ or docs/site/explanations/ if the method introduces a workflow or a non-obvious contract;
  • update docs/site/explanations/swagger-binding-subsystem.md when changing discovery, linter, JSON report, SwaggerFakeTransport, deprecated/legacy policy, or multi-operation binding policy.

Minimum verification for API-related changes:

make swagger-lint
poetry run pytest tests/core/test_swagger*.py tests/contracts/test_swagger_contracts.py
poetry run pytest tests/domains/<domain>/
poetry run mypy avito
poetry run ruff check .

Before completing an API-surface change, run make check. If generated docs, docs snippets, coverage pages, or reference output changed, also run make docs-strict.

STYLEGUIDE.md — strict compliance is mandatory

STYLEGUIDE.md is a normative document. All code changes must comply with it. When there is a conflict between any consideration and the STYLEGUIDE, the STYLEGUIDE takes priority.

The most critical prohibitions that must never be violated:

  • Mixing layers: transport/auth/parsing/domain logic in one class.
  • Returning dict or Any from public methods.
  • Using resource_id instead of concrete names (item_id, order_id).
  • Annotating list[T] where PaginatedList[T] is returned at runtime.
  • Adding or changing an Avito API public method without a @swagger_operation(...) binding.
  • Adding or changing an Avito API public method without a reference-ready docstring.
  • Duplicating Swagger contract data inside binding decorators.
  • Making AuthenticationError a subclass of AuthorizationError (or vice versa).
  • Writing error messages in mixed languages (Russian only).
  • Injecting methods via setattr/globals() at runtime.
  • Duplicating behavior through two different public methods without deprecation.
  • Leaking internal-layer request-DTOs into public signatures.
  • Adding dead code: unused imports, type aliases, TypeVars.

Key conventions (from STYLEGUIDE.md)

  • All public methods return typed SDK models, never raw dict.
  • Field names are concrete: item_id, user_id — never resource_id.
  • Public method arguments are primitives or domain models — internal request-DTOs must not leak out.
  • Write-operations that accept dry_run: bool = False must build the same payload in both modes; with dry_run=True transport must not be called.
  • Any is forbidden except at JSON boundary layers (with a local comment).
  • Error messages are written in Russian only — no mixed languages.
  • No dynamic method injection (setattr, globals() patching).
  • PaginatedList[T] annotation must match runtime — never annotate as list[T] if you return PaginatedList[T].
  • AuthenticationError (401) and AuthorizationError (403) must not be in an inheritance relation.
  • Dead code (unused imports, aliases, TypeVars) must be removed.
  • Request-objects of the internal layer must not appear in public domain-method signatures.