Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
879506e
Introduce fully typed clients
vdusek Dec 17, 2025
b845698
Update datamodel-codegen settings
vdusek Jan 5, 2026
e941cc4
Regenerate models
vdusek Jan 9, 2026
401c896
Fix create task
vdusek Jan 13, 2026
4b9fa14
Fix double nesting in get keys of KVS
vdusek Jan 14, 2026
4185ec9
Eliminate Data and Item models
vdusek Jan 14, 2026
701f0d7
Fix get list of Actors
vdusek Jan 14, 2026
8607733
Elimination of lot of ambiguous naming
vdusek Jan 14, 2026
6c2ee78
Prefer generated models rather than apify_shared.consts
vdusek Jan 14, 2026
07bf405
Add WebhookEventType and ActorJobStatus from Open API specs
vdusek Jan 14, 2026
965f5c6
Update models based on the feedback
vdusek Jan 16, 2026
2096769
Update models
vdusek Jan 16, 2026
a13448a
Use datetime fields
vdusek Jan 16, 2026
e79e882
Use integer types for integers
vdusek Jan 16, 2026
7f00b8b
Better request & RQ related types
vdusek Jan 19, 2026
7b53ebd
Add Pydantic; new validation from specs
vdusek Jan 20, 2026
855cfee
Update, use new models
vdusek Jan 21, 2026
1ae96f9
More fixes
vdusek Jan 23, 2026
bd79064
More fixes
vdusek Jan 23, 2026
1057cf1
More tests and updates
vdusek Jan 23, 2026
c0a7ea6
New models
vdusek Jan 23, 2026
e3ca2b6
Increase concurrency
vdusek Jan 23, 2026
268ecc5
Add moooore tests
vdusek Jan 23, 2026
d5883ba
Simplify the inheritance
vdusek Jan 23, 2026
f597f49
Resolve pytest warnings
vdusek Jan 23, 2026
3bab562
Add more integration tests
vdusek Jan 23, 2026
39bcafd
Fix tests
vdusek Jan 23, 2026
d5a537c
Refactor p1
vdusek Jan 27, 2026
494ceb4
rm apify shared
vdusek Jan 27, 2026
891bc2f
Refactor p2
vdusek Jan 27, 2026
d1a59c3
More polishment
vdusek Jan 28, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ jobs:
operating_systems: '["ubuntu-latest"]'
python_version_for_codecov: "3.14"
operating_system_for_codecov: ubuntu-latest
tests_concurrency: "1"
tests_concurrency: "16"
2 changes: 1 addition & 1 deletion docs/01_overview/code/01_usage_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ async def main() -> None:
return

# Fetch results from the Actor run's default dataset.
dataset_client = apify_client.dataset(call_result['defaultDatasetId'])
dataset_client = apify_client.dataset(call_result.default_dataset_id)
list_items_result = await dataset_client.list_items()
print(f'Dataset: {list_items_result}')
2 changes: 1 addition & 1 deletion docs/01_overview/code/01_usage_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ def main() -> None:
return

# Fetch results from the Actor run's default dataset.
dataset_client = apify_client.dataset(call_result['defaultDatasetId'])
dataset_client = apify_client.dataset(call_result.default_dataset_id)
list_items_result = dataset_client.list_items()
print(f'Dataset: {list_items_result}')
2 changes: 1 addition & 1 deletion docs/02_concepts/code/01_async_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ async def main() -> None:

# Start the Actor and get the run ID
run_result = await actor_client.start()
run_client = apify_client.run(run_result['id'])
run_client = apify_client.run(run_result.id)
log_client = run_client.log()

# Stream the logs
Expand Down
12 changes: 6 additions & 6 deletions docs/03_examples/code/02_tasks_async.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import asyncio

from apify_client import ApifyClientAsync
from apify_client.clients.resource_clients import TaskClientAsync
from apify_client._models import Run, Task
from apify_client._resource_clients import TaskClientAsync

TOKEN = 'MY-APIFY-TOKEN'
HASHTAGS = ['zebra', 'lion', 'hippo']


async def run_apify_task(client: TaskClientAsync) -> dict:
result = await client.call()
return result or {}
async def run_apify_task(client: TaskClientAsync) -> Run | None:
return await client.call()


async def main() -> None:
apify_client = ApifyClientAsync(token=TOKEN)

# Create Apify tasks
apify_tasks = list[dict]()
apify_tasks = list[Task]()
apify_tasks_client = apify_client.tasks()

for hashtag in HASHTAGS:
Expand All @@ -34,7 +34,7 @@ async def main() -> None:
apify_task_clients = list[TaskClientAsync]()

for apify_task in apify_tasks:
task_id = apify_task['id']
task_id = apify_task.id
apify_task_client = apify_client.task(task_id)
apify_task_clients.append(apify_task_client)

Expand Down
17 changes: 9 additions & 8 deletions docs/03_examples/code/02_tasks_sync.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
from apify_client import ApifyClient
from apify_client.clients.resource_clients import TaskClient
from apify_client._models import Run, Task
from apify_client._resource_clients import TaskClient

TOKEN = 'MY-APIFY-TOKEN'
HASHTAGS = ['zebra', 'lion', 'hippo']


def run_apify_task(client: TaskClient) -> dict:
result = client.call()
return result or {}
def run_apify_task(client: TaskClient) -> Run | None:
return client.call()


def main() -> None:
apify_client = ApifyClient(token=TOKEN)

# Create Apify tasks
apify_tasks = list[dict]()
apify_tasks = list[Task]()
apify_tasks_client = apify_client.tasks()

for hashtag in HASHTAGS:
Expand All @@ -32,18 +32,19 @@ def main() -> None:
apify_task_clients = list[TaskClient]()

for apify_task in apify_tasks:
task_id = apify_task['id']
task_id = apify_task.id
apify_task_client = apify_client.task(task_id)
apify_task_clients.append(apify_task_client)

print('Task clients created:', apify_task_clients)

# Execute Apify tasks
task_run_results = list[dict]()
task_run_results = list[Run]()

for client in apify_task_clients:
result = run_apify_task(client)
task_run_results.append(result)
if result is not None:
task_run_results.append(result)

print('Task results:', task_run_results)

Expand Down
4 changes: 2 additions & 2 deletions docs/03_examples/code/03_retrieve_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ async def main() -> None:

for dataset_item in actor_datasets.items:
# Dataset items can be handled here. Dataset items can be paginated
dataset_client = apify_client.dataset(dataset_item['id'])
dataset_client = apify_client.dataset(dataset_item.id)
dataset_items = await dataset_client.list_items(limit=1000)

# Items can be pushed to single dataset
merging_dataset_client = apify_client.dataset(merging_dataset['id'])
merging_dataset_client = apify_client.dataset(merging_dataset.id)
await merging_dataset_client.push_items(dataset_items.items)

# ...
Expand Down
4 changes: 2 additions & 2 deletions docs/03_examples/code/03_retrieve_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ def main() -> None:

for dataset_item in actor_datasets.items:
# Dataset items can be handled here. Dataset items can be paginated
dataset_client = apify_client.dataset(dataset_item['id'])
dataset_client = apify_client.dataset(dataset_item.id)
dataset_items = dataset_client.list_items(limit=1000)

# Items can be pushed to single dataset
merging_dataset_client = apify_client.dataset(merging_dataset['id'])
merging_dataset_client = apify_client.dataset(merging_dataset.id)
merging_dataset_client.push_items(dataset_items.items)

# ...
Expand Down
33 changes: 28 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ classifiers = [
]
keywords = ["apify", "api", "client", "automation", "crawling", "scraping"]
dependencies = [
"apify-shared>=2.1.0,<3.0.0",
"colorama>=0.4.0",
"impit>=0.9.2",
"more_itertools>=10.0.0",
"pydantic[email]>=2.11.0",
]

[project.urls]
Expand Down Expand Up @@ -64,6 +64,7 @@ dev = [
"ty~=0.0.0",
"types-colorama<0.5.0",
"werkzeug<4.0.0", # Werkzeug is used by pytest-httpserver
"datamodel-code-generator[http,ruff]<1.0.0",
]

[tool.hatch.build.targets.wheel]
Expand Down Expand Up @@ -144,6 +145,12 @@ indent-style = "space"
"N999", # Invalid module name
"T201", # print found
]
"src/apify_client/_models.py" = [
"D", # Everything from the pydocstyle
"E501", # Line too long
"ERA001", # Commented-out code
"TC003", # Move standard library import into a type-checking block
]

[tool.ruff.lint.flake8-quotes]
docstring-quotes = "double"
Expand Down Expand Up @@ -171,10 +178,7 @@ python-version = "3.10"
include = ["src", "tests", "scripts", "docs", "website"]

[[tool.ty.overrides]]
include = [
"docs/**/*.py",
"website/**/*.py",
]
include = ["docs/**/*.py", "website/**/*.py"]

[tool.ty.overrides.rules]
unresolved-import = "ignore"
Expand Down Expand Up @@ -220,3 +224,22 @@ cwd = "website"
[tool.poe.tasks.run-docs]
shell = "./build_api_reference.sh && corepack enable && yarn && uv run yarn start"
cwd = "website"

# https://koxudaxi.github.io/datamodel-code-generator/
[tool.datamodel-codegen]
# url = "https://docs.apify.com/api/openapi.json"
input = "../apify-docs/static/api/openapi.json"
input_file_type = "openapi"
output = "src/apify_client/_models.py"
target_python_version = "3.10"
output_model_type = "pydantic_v2.BaseModel"
use_schema_description = true
use_field_description = true
use_union_operator = true
capitalise_enum_members = true
collapse_root_models = true
set_default_enum_member = true
use_annotated = true
wrap_string_literal = true
snake_case_field = true
formatters = ["ruff-check", "ruff-format"]
6 changes: 3 additions & 3 deletions scripts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def get_current_package_version() -> str:
# It replaces the version number on the line with the format `version = "1.2.3"`
def set_current_package_version(version: str) -> None:
with open(PYPROJECT_TOML_FILE_PATH, 'r+', encoding='utf-8') as pyproject_toml_file:
updated_pyproject_toml_file_lines = []
updated_pyproject_toml_file_lines = list[str]()
version_string_found = False
for line in pyproject_toml_file:
line_processed = line
Expand Down Expand Up @@ -59,8 +59,8 @@ def get_published_package_versions() -> list:
package_data = json.load(urlopen(package_info_url)) # noqa: S310
published_versions = list(package_data['releases'].keys())
# If the URL returns 404, it means the package has no releases yet (which is okay in our case)
except HTTPError as e:
if e.code != 404:
except HTTPError as exc:
if exc.code != 404:
raise
published_versions = []
return published_versions
2 changes: 1 addition & 1 deletion src/apify_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from importlib import metadata

from .client import ApifyClient, ApifyClientAsync
from ._apify_client import ApifyClient, ApifyClientAsync

__version__ = metadata.version('apify-client')

Expand Down
Loading