Skip to content

Commit 6fe5431

Browse files
authored
More coverage (#503)
1 parent 93d0e9d commit 6fe5431

4 files changed

Lines changed: 113 additions & 62 deletions

File tree

src/cattrs/strategies/_class_methods.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
"""Strategy for using class-specific (un)structuring methods."""
2-
32
from inspect import signature
43
from typing import Any, Callable, Optional, Type, TypeVar
54

6-
from cattrs import BaseConverter
5+
from .. import BaseConverter
76

87
T = TypeVar("T")
98

tests/preconf/test_pyyaml.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""Pyyaml-specific tests."""
2+
from datetime import date, datetime, timezone
3+
4+
from attrs import define
5+
from hypothesis import given
6+
from pytest import raises
7+
8+
from cattrs._compat import FrozenSetSubscriptable
9+
from cattrs.errors import ClassValidationError
10+
from cattrs.preconf.pyyaml import make_converter
11+
12+
from .._compat import is_py38
13+
from ..test_preconf import Everything, everythings, native_unions
14+
15+
16+
@given(everythings())
17+
def test_pyyaml(everything: Everything):
18+
from yaml import safe_dump, safe_load
19+
20+
converter = make_converter()
21+
unstructured = converter.unstructure(everything)
22+
raw = safe_dump(unstructured)
23+
assert converter.structure(safe_load(raw), Everything) == everything
24+
25+
26+
@given(everythings())
27+
def test_pyyaml_converter(everything: Everything):
28+
converter = make_converter()
29+
raw = converter.dumps(everything)
30+
assert converter.loads(raw, Everything) == everything
31+
32+
33+
@given(everythings())
34+
def test_pyyaml_converter_unstruct_collection_overrides(everything: Everything):
35+
converter = make_converter(
36+
unstruct_collection_overrides={FrozenSetSubscriptable: sorted}
37+
)
38+
raw = converter.unstructure(everything)
39+
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])
40+
41+
42+
@given(
43+
union_and_val=native_unions(include_bools=not is_py38), # Literal issues on 3.8
44+
detailed_validation=...,
45+
)
46+
def test_pyyaml_unions(union_and_val: tuple, detailed_validation: bool):
47+
"""Native union passthrough works."""
48+
converter = make_converter(detailed_validation=detailed_validation)
49+
type, val = union_and_val
50+
51+
assert converter.structure(val, type) == val
52+
53+
54+
@given(detailed_validation=...)
55+
def test_pyyaml_dates(detailed_validation: bool):
56+
"""Pyyaml dates work."""
57+
converter = make_converter(detailed_validation=detailed_validation)
58+
59+
@define
60+
class A:
61+
datetime: datetime
62+
date: date
63+
64+
data = """
65+
datetime: 1970-01-01T00:00:00Z
66+
date: 1970-01-01"""
67+
assert converter.loads(data, A) == A(
68+
datetime(1970, 1, 1, tzinfo=timezone.utc), date(1970, 1, 1)
69+
)
70+
71+
bad_data = """
72+
datetime: 1
73+
date: 1
74+
"""
75+
76+
with raises(ClassValidationError if detailed_validation else Exception) as exc_info:
77+
converter.loads(bad_data, A)
78+
79+
if detailed_validation:
80+
assert (
81+
repr(exc_info.value.exceptions[0])
82+
== "Exception('Expected datetime, got 1')"
83+
)
84+
assert (
85+
repr(exc_info.value.exceptions[1]) == "ValueError('Expected date, got 1')"
86+
)

tests/strategies/test_class_methods.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,29 @@ def create(depth: int) -> Union["Nested", None]:
9090
converter = BaseConverter()
9191
use_class_methods(converter, "_structure", "_unstructure")
9292
assert structured == converter.structure(converter.unstructure(structured), Nested)
93+
94+
95+
def test_edge_cases():
96+
"""Test some edge cases, for coverage."""
97+
98+
@define
99+
class Bad:
100+
a: int
101+
102+
@classmethod
103+
def _structure(cls):
104+
"""This has zero args, so can't work."""
105+
106+
@classmethod
107+
def _unstructure(cls):
108+
"""This has zero args, so can't work."""
109+
110+
converter = BaseConverter()
111+
112+
use_class_methods(converter, "_structure", "_unstructure")
113+
114+
# The methods take the wrong number of args, so this should fail.
115+
with pytest.raises(TypeError):
116+
converter.structure({"a": 1}, Bad)
117+
with pytest.raises(TypeError):
118+
converter.unstructure(Bad(1))

tests/test_preconf.py

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
AbstractSet,
3636
Counter,
3737
FrozenSet,
38-
FrozenSetSubscriptable,
3938
Mapping,
4039
MutableMapping,
4140
MutableSequence,
@@ -48,7 +47,6 @@
4847
from cattrs.preconf.cbor2 import make_converter as cbor2_make_converter
4948
from cattrs.preconf.json import make_converter as json_make_converter
5049
from cattrs.preconf.msgpack import make_converter as msgpack_make_converter
51-
from cattrs.preconf.pyyaml import make_converter as pyyaml_make_converter
5250
from cattrs.preconf.tomlkit import make_converter as tomlkit_make_converter
5351
from cattrs.preconf.ujson import make_converter as ujson_make_converter
5452

@@ -581,64 +579,6 @@ def test_bson_unions(union_and_val: tuple, detailed_validation: bool):
581579
assert converter.structure(val, type) == val
582580

583581

584-
@given(everythings())
585-
def test_pyyaml(everything: Everything):
586-
from yaml import safe_dump, safe_load
587-
588-
converter = pyyaml_make_converter()
589-
unstructured = converter.unstructure(everything)
590-
raw = safe_dump(unstructured)
591-
assert converter.structure(safe_load(raw), Everything) == everything
592-
593-
594-
@given(everythings())
595-
def test_pyyaml_converter(everything: Everything):
596-
converter = pyyaml_make_converter()
597-
raw = converter.dumps(everything)
598-
assert converter.loads(raw, Everything) == everything
599-
600-
601-
@given(everythings())
602-
def test_pyyaml_converter_unstruct_collection_overrides(everything: Everything):
603-
converter = pyyaml_make_converter(
604-
unstruct_collection_overrides={FrozenSetSubscriptable: sorted}
605-
)
606-
raw = converter.unstructure(everything)
607-
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])
608-
609-
610-
@given(
611-
union_and_val=native_unions(
612-
include_bools=sys.version_info[:2] != (3, 8) # Literal issues on 3.8
613-
),
614-
detailed_validation=...,
615-
)
616-
def test_pyyaml_unions(union_and_val: tuple, detailed_validation: bool):
617-
"""Native union passthrough works."""
618-
converter = pyyaml_make_converter(detailed_validation=detailed_validation)
619-
type, val = union_and_val
620-
621-
assert converter.structure(val, type) == val
622-
623-
624-
@given(detailed_validation=...)
625-
def test_pyyaml_dates(detailed_validation: bool):
626-
"""Pyyaml dates work."""
627-
converter = pyyaml_make_converter(detailed_validation=detailed_validation)
628-
629-
@define
630-
class A:
631-
datetime: datetime
632-
date: date
633-
634-
data = """
635-
datetime: 1970-01-01T00:00:00Z
636-
date: 1970-01-01"""
637-
assert converter.loads(data, A) == A(
638-
datetime(1970, 1, 1, tzinfo=timezone.utc), date(1970, 1, 1)
639-
)
640-
641-
642582
@given(
643583
everythings(
644584
min_key_length=1,

0 commit comments

Comments
 (0)