Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 12 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ lint = [
test = [
"hypothesis>=6.135.26",
"pytest>=8.4.1",
"pytest-typing; python_version == '3.14' and implementation_name == 'cpython'",
"mypy; python_version == '3.14' and implementation_name == 'cpython'",
"pytest-benchmark>=5.1.0",
"immutables>=0.21",
"coverage>=7.9.2",
Expand All @@ -29,6 +31,16 @@ build-backend = "hatchling.build"
[tool.mypy]
strict = true

[tool.pytest]
addopts = [
"-l",
"--benchmark-sort=fullname",
"--benchmark-warmup=true",
"--benchmark-warmup-iterations=5",
"--benchmark-group-by=fullname",
]
typing_checkers = ["mypy"]

[project]
name = "cattrs"
description = "Composable complex class support for attrs and dataclasses."
Expand Down Expand Up @@ -96,9 +108,6 @@ tomllib = [
"tomli-w>=1.1.0",
]

[tool.pytest.ini_options]
addopts = "-l --benchmark-sort=fullname --benchmark-warmup=true --benchmark-warmup-iterations=5 --benchmark-group-by=fullname"

[tool.coverage.run]
parallel = true
source_pkgs = ["cattrs", "tests"]
Expand Down
104 changes: 104 additions & 0 deletions tests/test_typing_structure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Structuring Types

These tests exercise the static return types for the structuring APIs.

## Global structure returns attrs instances

```python
from attrs import define

from cattrs import structure


@define
class User:
id: int
name: str


user = structure({"id": 1, "name": "Ada"}, User)
reveal_type(user) # revealed: test_snippet.User

name: str = user.name
```

## Converter structure returns dataclass instances

```python
from dataclasses import dataclass

from cattrs import Converter


@dataclass
class Point:
x: int
y: int


converter = Converter()
point = converter.structure({"x": 1, "y": 2}, Point)
reveal_type(point) # revealed: test_snippet.Point

x: int = point.x
```

## Converter structure returns TypedDicts

```python
from typing import TypedDict

from cattrs import Converter


class Movie(TypedDict):
title: str
year: int


converter = Converter()
movie = converter.structure({"title": "Alien", "year": 1979}, Movie)
reveal_type(movie) # revealed: TypedDict(test_snippet.Movie, {"title": str, "year": int})

title: str = movie["title"]
```

## Converter structure returns homogeneous tuples

```python
from cattrs import Converter


converter = Converter()
numbers = converter.structure([1, 2, 3], tuple[int, ...])
reveal_type(numbers) # revealed: tuple[int, ...]

first: int = numbers[0]
```

## Converter structure returns heterogeneous tuples

```python
from cattrs import Converter


converter = Converter()
row = converter.structure(["Ada", 37, True], tuple[str, int, bool])
reveal_type(row) # revealed: tuple[str, int, bool]

name: str = row[0]
age: int = row[1]
active: bool = row[2]
```

## Structure result participates in type checking

```python
from cattrs import Converter


converter = Converter()

value: int = converter.structure("1", int)
bad: str = converter.structure("1", int) # mypy-error: [assignment]
```
Loading
Loading