Skip to content

Commit bd52c61

Browse files
committed
docs: renumber Pydantic guide to 11
1 parent a27cf5a commit bd52c61

6 files changed

Lines changed: 65 additions & 78 deletions

File tree

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
---
22
id: input-validation
3-
title: Validate Actor input with Pydantic
3+
title: Input validation with Pydantic
44
description: Parse, validate, and type your Actor's input with Pydantic models instead of reaching into a raw dictionary.
55
---
66

77
import CodeBlock from '@theme/CodeBlock';
88
import RunnableCodeBlock from '@site/src/components/RunnableCodeBlock';
99
import ApiLink from '@theme/ApiLink';
1010

11-
import RawInputExample from '!!raw-loader!roa-loader!./code/10_raw_input.py';
12-
import PydanticExample from '!!raw-loader!roa-loader!./code/10_pydantic.py';
13-
import HttpUrlExample from '!!raw-loader!./code/10_http_url.py';
14-
import ModelValidatorExample from '!!raw-loader!./code/10_model_validator.py';
11+
import RawInputExample from '!!raw-loader!roa-loader!./code/11_raw_input.py';
12+
import PydanticExample from '!!raw-loader!roa-loader!./code/11_pydantic.py';
13+
import HttpUrlExample from '!!raw-loader!./code/11_http_url.py';
14+
import ModelValidatorExample from '!!raw-loader!./code/11_model_validator.py';
1515

1616
In this guide, you'll learn how to validate your Apify Actor's input with [Pydantic](https://docs.pydantic.dev/), so that your code works with a typed, guaranteed-valid object instead of a raw dictionary.
1717

docs/03_guides/code/10_pydantic.py

Lines changed: 0 additions & 72 deletions
This file was deleted.

docs/03_guides/code/11_pydantic.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import asyncio
2+
from typing import Literal
3+
4+
from pydantic import BaseModel, ConfigDict, Field, ValidationError, field_validator
5+
6+
from apify import Actor
7+
8+
9+
class ActorInput(BaseModel):
10+
"""Typed and validated representation of the Actor input."""
11+
12+
# Accept both snake_case and the input schema's camelCase; ignore extras.
13+
model_config = ConfigDict(populate_by_name=True, extra='ignore')
14+
15+
# Required: non-empty list of search terms (normalized below).
16+
search_terms: list[str] = Field(alias='searchTerms', min_length=1)
17+
18+
# Optional: 1-100, defaults to 10.
19+
max_results: int = Field(alias='maxResults', default=10, ge=1, le=100)
20+
21+
# Optional: restricted to a fixed set of choices.
22+
output_format: Literal['json', 'csv'] = Field(alias='outputFormat', default='json')
23+
24+
@field_validator('search_terms')
25+
@classmethod
26+
def _normalize_terms(cls, value: list[str]) -> list[str]:
27+
# Trim whitespace and drop empty terms.
28+
cleaned = [term.strip() for term in value if term.strip()]
29+
if not cleaned:
30+
raise ValueError('searchTerms must contain at least one non-empty term')
31+
return cleaned
32+
33+
34+
async def main() -> None:
35+
async with Actor:
36+
# Read the raw input (a plain dict, not yet validated).
37+
raw_input = await Actor.get_input() or {}
38+
39+
# Validate the raw input against the model.
40+
try:
41+
actor_input = ActorInput.model_validate(raw_input)
42+
except ValidationError as exc:
43+
# Log a per-field summary, then re-raise to fail the run.
44+
Actor.log.error('The Actor input is invalid:\n%s', exc)
45+
raise
46+
47+
# Work with typed attributes from here on.
48+
Actor.log.info('Input passed validation: %s', actor_input.model_dump())
49+
50+
max_results = actor_input.max_results
51+
for term in actor_input.search_terms:
52+
Actor.log.info('Processing %r (max %d results)', term, max_results)
53+
54+
# Store the normalized input as output.
55+
await Actor.set_value('OUTPUT', actor_input.model_dump())
56+
57+
58+
if __name__ == '__main__':
59+
asyncio.run(main())
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
async def main() -> None:
77
# Enter the context of the Actor.
88
async with Actor:
9-
# Read the input and reach into the raw dictionary for each value.
9+
# Read the input and reach into the raw dict.
1010
actor_input = await Actor.get_input() or {}
1111
search_terms = actor_input.get('searchTerms', [])
1212
max_results = actor_input.get('maxResults', 10)

0 commit comments

Comments
 (0)