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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ jobs:
- uses: hynek/setup-cached-uv@757bedc3f972eb7227a1aa657651f15a8527c817

- name: "Build package"
run: "uvx pdm build"
run: "uv build"
- name: "List result"
run: "ls -l dist"
- name: "Check wheel contents"
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,3 @@ settings.json
.editorconfig
.mypy_cache
.pytest_cache
.pdm-python
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Our backwards-compatibility policy can be found [here](https://github.com/python
([#728](https://github.com/python-attrs/cattrs/pull/728))
- Fix the `detailed_validation` parameter being passed under the wrong name in {func}`namedtuple_dict_structure_factory <cattrs.cols.namedtuple_dict_structure_factory>`, causing it to be silently ignored.
([#723](https://github.com/python-attrs/cattrs/pull/723))
- _cattrs_ is now autoformatted using Ruff.
([#732](https://github.com/python-attrs/cattrs/pull/732))

## 26.1.0 (2026-02-18)

Expand Down
2 changes: 1 addition & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ sync version="":

lint:
uv run -p python3.14 --group lint ruff check src/ tests bench
uv run -p python3.14 --group lint black --check src tests docs/conf.py
uv run -p python3.14 --group lint ruff format --check src tests docs/conf.py

test *args="-x --ff -n auto tests":
uv run {{ if python != '' { '-p ' + python } else { '' } }} --all-extras --group test --group lint pytest {{args}}
Expand Down
13 changes: 7 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
[tool.black]
skip-magic-trailing-comma = true

[dependency-groups]
lint = [
"black>=25.1.0",
"ruff>=0.12.2",
]
test = [
Expand Down Expand Up @@ -148,7 +144,7 @@ select = [
"I", # isort
]
ignore = [
"E501", # line length is handled by black
"E501", # line length is handled by the formatter
"RUF001", # leave my smart characters alone
"S101", # assert
"S307", # hands off my eval
Expand All @@ -161,14 +157,19 @@ ignore = [
"UP006", # We support old typing constructs at runtime
"UP007", # We support old typing constructs at runtime
"UP035", # We support old typing constructs at runtime
"UP038", # Dubious rule
"UP045", # We support old typing constructs at runtime
]

[tool.ruff.lint.pyupgrade]
# Preserve types, even if a file imports `from __future__ import annotations`.
keep-runtime-typing = true

[tool.ruff.lint.isort]
split-on-trailing-comma = false

[tool.ruff.format]
skip-magic-trailing-comma = true

[tool.hatch.version]
source = "vcs"
raw-options = { local_scheme = "no-local-version" }
Expand Down
1 change: 0 additions & 1 deletion src/cattrs/cols.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ def structure_tuple(obj: Iterable[T], _: type = type) -> tuple[T, ...]:
handler = converter.structure

if converter.detailed_validation:

# We have to structure into a list first anyway.
list_structure = list_structure_factory(type, converter)

Expand Down
1 change: 0 additions & 1 deletion tests/preconf/test_pyyaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

@given(everythings())
def test_pyyaml(everything: Everything):

converter = make_converter()
unstructured = converter.unstructure(everything)
raw = safe_dump(unstructured)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_disambiguators.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class A:
def test_disambiguation(cl_and_vals_a, cl_and_vals_b):
"""Disambiguation should work when there are unique required fields."""
cl_a, vals_a, kwargs_a = cl_and_vals_a
cl_b, vals_b, kwargs_b = cl_and_vals_b
cl_b, _, _ = cl_and_vals_b
c = Converter()

req_a = {a.name for a in fields(cl_a)}
Expand Down
3 changes: 1 addition & 2 deletions tests/test_generics.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def test_raises_if_no_generic_params_supplied(

with pytest.raises(
StructureHandlerNotFoundError,
match="Unsupported type: ~T. Register a structure hook for it.|Missing type for generic argument T, specify it when structuring.",
match=r"Unsupported type: ~T. Register a structure hook for it.|Missing type for generic argument T, specify it when structuring.",
) as exc:
converter.structure(asdict(data), TClass)

Expand Down Expand Up @@ -320,7 +320,6 @@ class Outer(Generic[T]):

@pytest.mark.skipif(not is_py311_plus, reason="3.11+ only")
def test_generate_typeddict_mapping() -> None:

T = TypeVar("T")
U = TypeVar("U")

Expand Down
1 change: 0 additions & 1 deletion tests/test_preconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,6 @@ class A:
booleans(),
)
def test_tomllib_converter(everything: Everything, detailed_validation: bool):

converter = tomllib_make_converter(detailed_validation=detailed_validation)
raw = converter.dumps(everything)

Expand Down
4 changes: 2 additions & 2 deletions tests/test_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def test_structuring_dicts_opts(dict_and_type, data):
@given(dicts_of_primitives)
def test_stringifying_dicts(dict_and_type):
converter = BaseConverter()
d, t = dict_and_type
d, _ = dict_and_type

converted = converter.structure(d, Dict[str, str])

Expand Down Expand Up @@ -267,7 +267,7 @@ def test_structuring_lists_of_opt(list_and_type, detailed_validation: bool) -> N
def test_stringifying_lists_of_opt(list_and_type):
"""Test structuring Optional primitive types into strings."""
converter = BaseConverter()
lst, t = list_and_type
lst, _ = list_and_type

lst.append(None)

Expand Down
4 changes: 2 additions & 2 deletions tests/test_structure_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def test_structure_union(cl_and_vals_a, cl_and_vals_b):
"""Structuring of automatically-disambiguable unions works."""
converter = BaseConverter()
cl_a, vals_a, kwargs_a = cl_and_vals_a
cl_b, vals_b, kwargs_b = cl_and_vals_b
cl_b, _, _ = cl_and_vals_b
a_field_names = {a.name for a in fields(cl_a)}
b_field_names = {a.name for a in fields(cl_b)}
assume(a_field_names)
Expand Down Expand Up @@ -126,7 +126,7 @@ def test_structure_union_explicit(cl_and_vals_a, cl_and_vals_b):
"""Structuring of manually-disambiguable unions works."""
converter = BaseConverter()
cl_a, vals_a, kwargs_a = cl_and_vals_a
cl_b, vals_b, kwargs_b = cl_and_vals_b
cl_b, _, _ = cl_and_vals_b

def dis(obj, _):
return converter.structure(obj, cl_a)
Expand Down
2 changes: 1 addition & 1 deletion tests/typeddicts.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def generic_typeddicts(draw: DrawFn, total: bool = True) -> tuple[TypedDictType,
actual_types = []
for ix, (attr_name, attr_type) in enumerate(list(attrs_dict.items())):
if ix in generic_attrs:
typevar = TypeVar(f"T{ix+1}")
typevar = TypeVar(f"T{ix + 1}")
generics.append(typevar)
if total and draw(booleans()):
# We might decide to make these NotRequired
Expand Down
Loading
Loading