This file provides guidance to programming agents when working with code in this repository.
Python client for the Apify API. Provides ApifyClient (sync) and ApifyClientAsync (async) classes to interact with the Apify platform. Published on PyPI as apify-client.
Uses uv for project management and Poe the Poet as task runner. Requires Python 3.11+.
uv run poe install-dev # Install dev deps + git hooks
uv run poe check-code # Run all checks (lint, type-check, unit-tests, docstring check)
uv run poe lint # Ruff format check + ruff check
uv run poe format # Auto-fix lint issues and format
uv run poe type-check # Run ty type checker
uv run poe unit-tests # Run unit tests
uv run poe check-async-docstrings # Verify async docstrings match sync
uv run poe fix-async-docstrings # Auto-fix async docstrings
# Run a single test
uv run pytest tests/unit/test_file.py
uv run pytest tests/unit/test_file.py::test_nameIntegration tests require APIFY_TEST_USER_API_TOKEN and APIFY_TEST_USER_2_API_TOKEN env vars.
ApifyClient/ApifyClientAsync are the entry points. They provide methods that return resource sub-clients:
ApifyClient
├── .actor(id) → ActorClient (single resource operations)
├── .actors() → ActorCollectionClient (list/create)
├── .dataset(id) → DatasetClient
├── .datasets() → DatasetCollectionClient
├── .run(id) → RunClient
├── .runs() → RunCollectionClient
└── ... (schedules, tasks, webhooks, key-value stores, request queues, etc.)
Each resource client can create child clients (e.g., ActorClient.builds() → BuildCollectionClient).
Every resource client has both sync and async variants in the same file. For example, actor.py contains both ActorClient and ActorClientAsync. Both share the same interface — async versions use async/await.
Docstrings are written on sync clients and automatically copied to async clients via scripts/check_async_docstrings.py. When modifying docstrings, edit only the sync client and run uv run poe fix-async-docstrings.
ClientRegistry/ClientRegistryAsync (in _client_registry.py) holds references to all resource client classes and is passed to each client. This avoids circular imports and lets resource clients create child clients without directly importing them.
HttpClient/HttpClientAsync— abstract base classes in_http_clients/_base.pyImpitHttpClient/ImpitHttpClientAsync— default implementation (Rust-based Impit)HttpResponse— Protocol (not a concrete class) for response objects- Users can plug in custom HTTP clients via
ApifyClient.with_custom_http_client()
ResourceClientBase— shared URL building, parameter handling, metaclass-based loggingResourceClient/ResourceClientAsync— sync/async base classes with HTTP call methodsWithLogDetailsClientmetaclass — auto-wraps public methods for structured logging
_models.py is auto-generated from the OpenAPI spec using datamodel-code-generator. Do not edit manually; regenerate with uv run poe generate-models. Contains Pydantic v2 BaseModel classes for all API responses.
- Line length: 120 characters
- Linting/formatting: Ruff with nearly all rules enabled (see
pyproject.toml) - Type checking: ty (Astral's type checker)
- Docstrings: Google style format, single backticks for inline code references (
`ApifyClient`not``ApifyClient``) - Imports:
from __future__ import annotationsused throughout - Commits: Conventional Commits format (feat, fix, refactor, etc.)
- Unit tests (
tests/unit/): Usepytest-httpserverto mock HTTP. No network required. - Integration tests (
tests/integration/): Hit the live Apify API. - Async:
asyncio_mode = "auto"— async tests run automatically without markers. - Parallelism: Tests run in parallel via
pytest-xdist.
Unit test pattern:
def test_example(httpserver: HTTPServer) -> None:
httpserver.expect_request('/v2/endpoint').respond_with_json({'data': ...})
client = ApifyClient(token='test', api_url=httpserver.url_for('/').removesuffix('/'))
# assert client behavior