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: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
([#81](https://github.com/python-attrs/cattrs/issues/81))
- Add `cbor2` serialization library to the `cattr.preconf` package.
- Add optional dependencies for `cattrs.preconf` third-party libraries. ([#337](https://github.com/python-attrs/cattrs/pull/337))
- All preconf converters now allow overriding the default `unstruct_collection_overrides` in `make_converter`.
([#350](https://github.com/python-attrs/cattrs/issues/350) [#353](https://github.com/python-attrs/cattrs/pull/353))

## 22.2.0 (2022-10-03)

Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/bson.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ def gen_structure_mapping(cl: Any):

def make_converter(*args, **kwargs) -> BsonConverter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
AbstractSet: list,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = BsonConverter(*args, **kwargs)
configure_converter(res)
Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/cbor2.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ def configure_converter(converter: BaseConverter):

def make_converter(*args, **kwargs) -> Cbor2Converter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
AbstractSet: list,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = Cbor2Converter(*args, **kwargs)
configure_converter(res)
Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def configure_converter(converter: BaseConverter):

def make_converter(*args, **kwargs) -> JsonConverter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
AbstractSet: list,
Counter: dict,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = JsonConverter(*args, **kwargs)
configure_converter(res)
Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/msgpack.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ def configure_converter(converter: BaseConverter):

def make_converter(*args, **kwargs) -> MsgpackConverter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
AbstractSet: list,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = MsgpackConverter(*args, **kwargs)
configure_converter(res)
Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/orjson.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ def key_handler(v):

def make_converter(*args, **kwargs) -> OrjsonConverter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
AbstractSet: list,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = OrjsonConverter(*args, **kwargs)
configure_converter(res)
Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/pyyaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def configure_converter(converter: BaseConverter):

def make_converter(*args, **kwargs) -> PyyamlConverter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
FrozenSetSubscriptable: list,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = PyyamlConverter(*args, **kwargs)
configure_converter(res)
Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/tomlkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ def key_handler(k: bytes):

def make_converter(*args, **kwargs) -> TomlkitConverter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
AbstractSet: list,
tuple: list,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = TomlkitConverter(*args, **kwargs)
configure_converter(res)
Expand Down
2 changes: 1 addition & 1 deletion src/cattrs/preconf/ujson.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def configure_converter(converter: BaseConverter):

def make_converter(*args, **kwargs) -> UjsonConverter:
kwargs["unstruct_collection_overrides"] = {
**kwargs.get("unstruct_collection_overrides", {}),
AbstractSet: list,
**kwargs.get("unstruct_collection_overrides", {}),
}
res = UjsonConverter(*args, **kwargs)
configure_converter(res)
Expand Down
109 changes: 109 additions & 0 deletions tests/test_preconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
)

from cattrs._compat import (
AbstractSet,
Counter,
FrozenSet,
FrozenSetSubscriptable,
Mapping,
MutableMapping,
MutableSequence,
Expand Down Expand Up @@ -173,6 +175,15 @@ def test_stdlib_json_converter(everything: Everything):
assert converter.loads(converter.dumps(everything), Everything) == everything


@given(everythings())
def test_stdlib_json_converter_unstruct_collection_overrides(everything: Everything):
converter = json_make_converter(unstruct_collection_overrides={AbstractSet: sorted})
raw = converter.unstructure(everything)
assert raw["a_set"] == sorted(raw["a_set"])
assert raw["a_mutable_set"] == sorted(raw["a_mutable_set"])
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])


@given(
everythings(
min_int=-9223372036854775808, max_int=9223372036854775807, allow_inf=False
Expand All @@ -198,6 +209,21 @@ def test_ujson_converter(everything: Everything):
assert converter.loads(raw, Everything) == everything


@given(
everythings(
min_int=-9223372036854775808, max_int=9223372036854775807, allow_inf=False
)
)
def test_ujson_converter_unstruct_collection_overrides(everything: Everything):
converter = ujson_make_converter(
unstruct_collection_overrides={AbstractSet: sorted}
)
raw = converter.unstructure(everything)
assert raw["a_set"] == sorted(raw["a_set"])
assert raw["a_mutable_set"] == sorted(raw["a_mutable_set"])
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])


@pytest.mark.skipif(python_implementation() == "PyPy", reason="no orjson on PyPy")
@given(
everythings(
Expand Down Expand Up @@ -231,6 +257,24 @@ def test_orjson_converter(everything: Everything, detailed_validation: bool):
assert converter.loads(raw, Everything) == everything


@pytest.mark.skipif(python_implementation() == "PyPy", reason="no orjson on PyPy")
@given(
everythings(
min_int=-9223372036854775808, max_int=9223372036854775807, allow_inf=False
)
)
def test_orjson_converter_unstruct_collection_overrides(everything: Everything):
from cattrs.preconf.orjson import make_converter as orjson_make_converter

converter = orjson_make_converter(
unstruct_collection_overrides={AbstractSet: sorted}
)
raw = converter.unstructure(everything)
assert raw["a_set"] == sorted(raw["a_set"])
assert raw["a_mutable_set"] == sorted(raw["a_mutable_set"])
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])


@given(everythings(min_int=-9223372036854775808, max_int=18446744073709551615))
def test_msgpack(everything: Everything):
from msgpack import dumps as msgpack_dumps
Expand All @@ -251,6 +295,17 @@ def test_msgpack_converter(everything: Everything):
assert converter.loads(raw, Everything, strict_map_key=False) == everything


@given(everythings(min_int=-9223372036854775808, max_int=18446744073709551615))
def test_msgpack_converter_unstruct_collection_overrides(everything: Everything):
converter = msgpack_make_converter(
unstruct_collection_overrides={AbstractSet: sorted}
)
raw = converter.unstructure(everything)
assert raw["a_set"] == sorted(raw["a_set"])
assert raw["a_mutable_set"] == sorted(raw["a_mutable_set"])
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])


@given(
everythings(
min_int=-9223372036854775808,
Expand Down Expand Up @@ -294,6 +349,22 @@ def test_bson_converter(everything: Everything, detailed_validation: bool):
)


@given(
everythings(
min_int=-9223372036854775808,
max_int=9223372036854775807,
allow_null_bytes_in_keys=False,
allow_datetime_microseconds=False,
)
)
def test_bson_converter_unstruct_collection_overrides(everything: Everything):
converter = bson_make_converter(unstruct_collection_overrides={AbstractSet: sorted})
raw = converter.unstructure(everything)
assert raw["a_set"] == sorted(raw["a_set"])
assert raw["a_mutable_set"] == sorted(raw["a_mutable_set"])
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])


@given(everythings())
def test_pyyaml(everything: Everything):
from yaml import safe_dump, safe_load
Expand All @@ -311,6 +382,15 @@ def test_pyyaml_converter(everything: Everything):
assert converter.loads(raw, Everything) == everything


@given(everythings())
def test_pyyaml_converter_unstruct_collection_overrides(everything: Everything):
converter = pyyaml_make_converter(
unstruct_collection_overrides={FrozenSetSubscriptable: sorted}
)
raw = converter.unstructure(everything)
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])


@given(
everythings(
min_key_length=1,
Expand Down Expand Up @@ -345,6 +425,24 @@ def test_tomlkit_converter(everything: Everything, detailed_validation: bool):
assert converter.loads(raw, Everything) == everything


@given(
everythings(
min_key_length=1,
allow_null_bytes_in_keys=False,
key_blacklist_characters=['"', "\\"],
allow_control_characters_in_values=False,
)
)
def test_tomlkit_converter_unstruct_collection_overrides(everything: Everything):
converter = tomlkit_make_converter(
unstruct_collection_overrides={AbstractSet: sorted}
)
raw = converter.unstructure(everything)
assert raw["a_set"] == sorted(raw["a_set"])
assert raw["a_mutable_set"] == sorted(raw["a_mutable_set"])
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])


def test_bson_objectid():
"""BSON ObjectIds are supported by default."""
converter = bson_make_converter()
Expand All @@ -368,3 +466,14 @@ def test_cbor2_converter(everything: Everything):
converter = cbor2_make_converter()
raw = converter.dumps(everything)
assert converter.loads(raw, Everything) == everything


@given(everythings(min_int=-9223372036854775808, max_int=18446744073709551615))
def test_cbor2_converter_unstruct_collection_overrides(everything: Everything):
converter = cbor2_make_converter(
unstruct_collection_overrides={AbstractSet: sorted}
)
raw = converter.unstructure(everything)
assert raw["a_set"] == sorted(raw["a_set"])
assert raw["a_mutable_set"] == sorted(raw["a_mutable_set"])
assert raw["a_frozenset"] == sorted(raw["a_frozenset"])