Skip to content
This repository was archived by the owner on Oct 8, 2021. It is now read-only.

Commit a1a9eeb

Browse files
committed
v2.3.1 quick fix
commit 7244a53 Author: Ben Samuel <[email protected]> Date: Thu Feb 13 11:43:31 2020 -0500 Remove unnecessary comparison of attr.ib's when default not set. - Test that values with nonstandard __eq__ encode if they are required. - Other minor cleanup.
1 parent 745f897 commit a1a9eeb

File tree

6 files changed

+98
-64
lines changed

6 files changed

+98
-64
lines changed

json_syntax/action_v1.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .helpers import ErrorContext, err_ctx
1+
from .errors import ErrorContext, err_ctx
22

33
from datetime import date, datetime, time, timedelta
44
from decimal import InvalidOperation
@@ -184,7 +184,7 @@ def convert_dict_to_attrs(value, pre_hook, inner_map, con):
184184
arg = value[attr.name]
185185
except KeyError:
186186
if attr.is_required:
187-
raise KeyError("Missing key") from None
187+
raise KeyError("Missing key {!r}".format(attr.name)) from None
188188
else:
189189
args[attr.init_name] = attr.inner(arg)
190190
return con(**args)
@@ -198,7 +198,7 @@ def convert_dict_to_dict(value, inner_map, con):
198198
arg = value[attr.name]
199199
except KeyError:
200200
if attr.is_required:
201-
raise KeyError("Missing key") from None
201+
raise KeyError("Missing key {!r}".format(attr.name)) from None
202202
else:
203203
args[attr.name] = attr.inner(arg)
204204
return con(args)
@@ -226,7 +226,7 @@ def convert_attrs_to_dict(value, post_hook, inner_map):
226226
for attr in inner_map:
227227
with ErrorContext("." + attr.name):
228228
field = getattr(value, attr.name)
229-
if field == attr.default:
229+
if not attr.is_required and field == attr.default:
230230
continue
231231
out[attr.name] = attr.inner(field)
232232
if post_hook is not None:

json_syntax/product.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ def __repr__(self):
6767
self.name, "required" if self.is_required else "optional"
6868
)
6969

70+
def long_repr(self):
71+
return "<Attribute {!r} typ={!r} inner={!r} default={!r} is_required={!r}>".format(
72+
self.name, self.typ, self.inner, self.default, self.is_required
73+
)
74+
7075

7176
class AttrsAttribute(Attribute):
7277
@property

json_syntax/std.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
from .helpers import (
2-
has_origin,
3-
get_origin,
4-
issub_safe,
5-
NoneType,
62
JSON2PY,
73
PY2JSON,
84
INSP_JSON,
@@ -12,6 +8,12 @@
128
PY2STR,
139
INSP_STR,
1410
)
11+
from .types import (
12+
has_origin,
13+
get_origin,
14+
issub_safe,
15+
NoneType,
16+
)
1517
from .action_v1 import (
1618
check_collection,
1719
check_float,
@@ -54,7 +56,7 @@
5456

5557

5658
def atoms(verb, typ, ctx):
57-
"Rule to handle atoms on both sides."
59+
"Rule to handle atoms that translate trivially."
5860
if issub_safe(typ, (str, int, NoneType)):
5961
if verb in (JSON2PY, PY2JSON):
6062
if typ is NoneType:

poetry.lock

Lines changed: 51 additions & 54 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "json-syntax"
3-
version = "2.3.0"
3+
version = "2.3.1"
44
description = "Generates functions to convert Python classes to JSON dumpable objects."
55
authors = ["Ben Samuel <[email protected]>"]
66
license = "MIT"

tests/test_attrs.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,33 @@ def test_typed_dict_encoding(dict_type):
396396
assert not inspect("foo")
397397
assert not inspect({})
398398
assert inspect({"a": 3, "b": "foo", "c": True})
399+
400+
401+
@attr.s(eq=False)
402+
class Incomparable:
403+
def __eq__(self, other):
404+
raise RuntimeError("Can't compare this class")
405+
406+
def __ne__(self, other):
407+
raise RuntimeError("Can't compare this class")
408+
409+
410+
@attr.s
411+
class IncomparableContainer:
412+
field1 = attr.ib(type=Incomparable)
413+
field2 = attr.ib(type=int, default=3)
414+
415+
416+
def test_encode_incomparable():
417+
"Test that encoding doesn't fail if a field's __eq__ method throws."
418+
419+
rules = Rules(at.attrs_classes, std.atoms, std.lists)
420+
421+
encoder = at.attrs_classes(verb=PY2JSON, typ=IncomparableContainer, ctx=rules)
422+
assert encoder(IncomparableContainer(Incomparable())) == {"field1": {}}
423+
assert encoder(IncomparableContainer(Incomparable(), 4)) == {"field1": {}, "field2": 4}
424+
425+
decoder = at.attrs_classes(verb=JSON2PY, typ=IncomparableContainer, ctx=rules)
426+
actual = decoder({"field1": {}})
427+
assert isinstance(actual.field1, Incomparable)
428+
assert actual.field2 == 3

0 commit comments

Comments
 (0)