8000 Add pipeline API by adriangb · Pull Request #9459 · pydantic/pydantic · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
e7eb43c
Add pipeline API
adriangb May 20, 2024
7d78407
port to python 3.10
adriangb May 20, 2024
6a1622d
port to python 3.10
adriangb May 20, 2024
947e920
fix syntax
adriangb May 20, 2024
b3fe1c4
handle slots
8000 adriangb May 20, 2024
a6d56cc
Remove match
adriangb May 21, 2024
42505df
Remove match
adriangb May 21, 2024
b2855d0
ignore warning
adriangb May 21, 2024
aafb856
fix import
adriangb May 21, 2024
0bd8b39
fix union
adriangb May 21, 2024
697833f
fix union
adriangb May 21, 2024
d767731
sort imports
adriangb May 21, 2024
8abb6e4
move
adriangb May 21, 2024
217b11d
move
adriangb May 21, 2024
89c46a1
add missing file
adriangb May 21, 2024
6e91a32
namespace
adriangb May 23, 2024
8e4d535
initial tests
sydney-runkle May 29, 2024
ada5853
add more operators
adriangb May 30, 2024
8742e9e
Add json schema tests, add section mapping existing validators
adriangb May 31, 2024
f55b6e1
move things around for expeirmental pattern
sydney-runkle May 31, 2024
7132bae
fix docs tests
sydney-runkle May 31, 2024
0444fc9
maybe fix 3.9 test
sydney-runkle May 31, 2024
1a8e505
use typing Pattern
sydney-runkle May 31, 2024
d979841
add PydanticExperimentalWarning
sydney-runkle May 31, 2024
fadf3bb
ignore warnings, for some reason pytestmark wasn't working
sydney-runkle May 31, 2024
1699f35
3.8 friendly removesuffix
sydney-runkle May 31, 2024
d0a9372
Apply docs suggestions from code review
sydney-runkle Jun 4, 2024
bed0752
add __all__
adriangb Jun 4, 2024
eb61549
rename class to pipeline
adriangb Jun 4, 2024
a18a4df
get rid of on_lambda_err
adriangb Jun 4, 2024
34663fe
pr feedback
adriangb Jun 4, 2024
dff9ad9
make transform use the field type instead of any
adriangb Jun 4, 2024
479ab3c
add import
adriangb Jun 4, 2024
7b49219
rename parse() -> validate_as()
adriangb Jun 4, 2024
51bcad6
rename internal classes
adriangb Jun 4, 2024
13b1721
make Pipeline _Pipeline
adriangb Jun 4, 2024
b8573b5
Remove namespaces
adriangb Jun 4, 2024
888c4ed
more test
adriangb Jun 4, 2024
141c8b6
use ellipsis
sydney-runkle Jun 4, 2024
9d4194b
updating imports from internal test
sydney-runkle Jun 4, 2024
128d4ea
maybe fixing zoneinfo tests, switching up validate_as annotation again
sydney-runkle Jun 4, 2024
1c7302d
docs and linting
sydney-runkle Jun 4, 2024
88dcb75
removing tzinfo stuff :(
sydney-runkle Jun 5, 2024
19a3ee6
a bit more explanation
sydney-runkle Jun 5, 2024
0652472
api docs update
sydney-runkle Jun 5, 2024
4ccf4e5
Additional Test Cases for Experimental Pipeline API (#9566)
dAIsySHEng1 Jun 5, 2024
bad0a1a
fix common predicates + add tests
sydney-runkle Jun 5, 2024
a9d1099
remove unnee 8000 ded line
sydney-runkle Jun 5, 2024
14e9944
update to version policy docs
sydney-runkle Jun 5, 2024
42a2708
skip linting
sydney-runkle Jun 5, 2024
021604f
fix type hint for _Pipeline.then
adriangb Jun 5, 2024
38a2730
Apply suggestions from code review
sydney-runkle Jun 5, 2024
0c36b7c
Update pydantic/experimental/pipeline.py
sydney-runkle Jun 5, 2024
8d46b21
add public todo
sydney-runkle Jun 5, 2024
a46c2e3
move predicate up
sydney-runkle Jun 5, 2024
7386d69
new idea for overload
sydney-runkle Jun 5, 2024
dc07b50
test fixes
sydney-runkle Jun 5, 2024
cbb216b
update test cases with comments
sydney-runkle Jun 5, 2024
581cbe8
no freeze notes
sydney-runkle Jun 5, 2024
c3a008f
suggested frozen change
sydney-runkle Jun 5, 2024
26c5325
add test
adriangb Jun 5, 2024
166df3d
add more assertions
adriangb Jun 5, 2024
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
Prev Previous commit
Next Next commit
move things around for expeirmental pattern
  • Loading branch information
sydney-runkle committed May 31, 2024
commit f55b6e1263c91c0045ae038343b119ba90a0bb88
65 changes: 65 additions & 0 deletions docs/concepts/experimental.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Experimental Features

In this section you will find documentation for new, experimental features in Pydantic. These features are subject to change or removal, and we are looking for feedback and suggestions before making them a permanent part of Pydantic.

<!-- TODO: (@sydney-runkle) add link to versioning policy for experimental features -->

## Pipeline API

Pydantic v2.8.0 introduced an experimental pipeline API that allows composing parsing, constraints and transformations in a more type-safe manner than existing APIs. This API is subject to change or removal, we are looking for feedback and suggestions before making it a permanent part of Pydantic.

```python
from __future__ import annotations

from datetime import datetime

from typing_extensions import Annotated

from pydantic import BaseModel
from pydantic.experimental.pipeline import parse, parse_defer


class User(BaseModel):
name: Annotated[str, parse(str).str.lower()] # (1)!
age: Annotated[int, parse(int).gt(0)] # (2)!
username: Annotated[str, parse(str).str.pattern(r'[a-z]+')] # (3)!
password: Annotated[
str,
parse(str).transform(str.lower).predicate(lambda x: x != 'password')] # (4)!
favorite_number: Annotated[ # (5)!
int,
(parse(int) | parse(str).str.strip().parse(int)).gt(0),
]
friends: Annotated[list[User], parse().len(0, 100)] # (6)!
family: Annotated[ # (7)!
list[User],
parse_defer(lambda: list[User]).transform(lambda x: x[1:]),
]
bio: Annotated[datetime, parse(int).transform(lambda x: x / 1_000_000).parse()] # (8)!
```

1. Lowercase a string.
2. Constrain an integer to be greater than zero.
3. Constrain a string to match a regex pattern.
4. You can also use the lower level transform, constrain and predicate methods.
5. Use the `|` or `&` operators to combine steps (like a logical OR or AND).
6. Calling `parse()` with no arguments implies `parse(<field type>)`. Use `parse(Any)` to accept any type.
7. For recursive types you can use `parse_defer` to reference the type itself before it's defined.
8. You can call `parse()` before or after other steps to do pre or post processing.

### Mapping from `BeforeValidator`, `AfterValidator` and `WrapValidator`

The `parse` method is a more type-safe way to define `BeforeValidator`, `AfterValidator` and `WrapValidator`:

```python
# BeforeValidator
Annotated[int, parse(str).str.strip().parse()] # (1)!
# AfterValidator
Annotated[int, parse().transform(lambda x: x * 2)] # (2)!
# WrapValidator
Annotated[int, parse(str).str.strip().parse().transform(lambda x: x * 2)] # (3)!
```

1. Strip whitespace from a string before parsing it as an integer.
2. Multiply an integer by 2 after parsing it.
3. Strip whitespace from a string, parse it as an integer, then multiply it by 2.
60 changes: 0 additions & 60 deletions docs/concepts/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,66 +122,6 @@ except ValidationError as exc:
"""
```

#### Experimental pipeline API

Pydantic v2.8.0 introduced an experimental pipeline API that allows composing parsing, constraints and transformations in a more type-safe manner than existing APIs. This API is subject to change or removal, we are looking for feedback and suggestions before making it a permanent part of Pydantic.

```python
from __future__ import annotations

from datetime import datetime

from typing_extensions import Annotated

from pydantic import BaseModel
from pydantic.transform_experimental import parse, parse_defer


class User(BaseModel):
name: Annotated[str, parse(str).str.lower()] # (1)!
age: Annotated[int, parse(int).gt(0)] # (2)!
username: Annotated[str, parse(str).str.pattern(r'[a-z]+')] # (3)!
password: Annotated[
str,
parse(str).transform(str.lower).predicate(lambda x: x != 'password')] # (4)!
favorite_number: Annotated[ # (5)!
int,
(parse(int) | parse(str).str.strip().parse(int)).gt(0),
]
friends: Annotated[list[User], parse().len(0, 100)] # (6)!
family: Annotated[ # (7)!
list[User],
parse_defer(lambda: list[User]).transform(lambda x: x[1:]),
]
bio: Annotated[datetime, parse(int).transform(lambda x: x / 1_000_000).parse()] # (8)!
```

1. Lowercase a string.
2. Constrain an integer to be greater than zero.
3. Constrain a string to match a regex pattern.
4. You can also use the lower level transform, constrain and predicate methods.
5. Use the `|` or `&` operators to combine steps (like a logical OR or AND).
6. Calling `parse()` with no arguments implies `parse(<field type>)`. Use `parse(Any)` to accept any type.
7. For recursive types you can use `parse_defer` to reference the type itself before it's defined.
8. You can call `parse()` before or after other steps to do pre or post processing.

##### Mapping from `BeforeValidator`, `AfterValidator` and `WrapValidator`

The `parse` method is a more type-safe way to define `BeforeValidator`, `AfterValidator` and `WrapValidator`:

```python
# BeforeValidator
Annotated[int, parse(str).str.strip().parse()] # (1)!
# AfterValidator
Annotated[int, parse().transform(lambda x: x * 2)] # (2)!
# WrapValidator
Annotated[int, parse(str).str.strip().parse().transform(lambda x: x * 2)] # (3)!
```

1. Strip whitespace from a string before parsing it as an integer.
2. Multiply an integer by 2 after parsing it.
3. Strip whitespace from a string, parse it as an integer, then multiply it by 2.

#### Adding validation and serialization

You can add or override validation, serialization, and JSON schemas to an arbitrary type using the markers that
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ nav:
- Settings Management: concepts/pydantic_settings.md
- Performance: concepts/performance.md
- Pydantic Plugins: concepts/plugins.md
- Experimental: concepts/experimental.md
- API Documentation:
- Pydantic:
- BaseModel: api/base_model.md
Expand All @@ -124,6 +125,7 @@ nav:
- Version Information: api/version.md
- Pydantic Plugins: api/plugin.md
- Annotated Handlers: api/annotated_handlers.md
- Experimental: api/experimental.md
- Pydantic Core:
- pydantic_core: api/pydantic_core.md
- pydantic_core.core_schema: api/pydantic_core_schema.md
Expand Down
1 change: 1 addition & 0 deletions pydantic/experimental/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""__init__.py for the experimental submodule of pydantic."""
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
from dataclasses import dataclass
from decimal import Decimal
from functools import cached_property, partial
from typing import TYPE_CHECKING, Annotated, Any, Callable, Generic, Protocol, TypeVar, Union, overload
from typing import TYPE_CHECKING, Any, Callable, Generic, Protocol, TypeVar, Union, overload

import annotated_types
from typing_extensions import Annotated

if TYPE_CHECKING:
from pydantic_core import core_schema as cs
Expand Down
2 changes: 1 addition & 1 deletion tests/test_transform.py → tests/test_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing_extensions import Annotated

from pydantic import TypeAdapter, ValidationError
from pydantic.transform_experimental import parse
from pydantic.experimental.pipeline import parse


@pytest.mark.parametrize('potato_variation', ['potato', ' potato ', ' potato', 'potato ', ' POTATO ', ' PoTatO '])
Expand Down
Empty file added text.txt
Empty file.
0