dataclass-extensions 0.2.4__tar.gz → 0.2.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/PKG-INFO +27 -7
  2. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/README.md +26 -6
  3. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/pyproject.toml +1 -1
  4. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions/decode.py +9 -3
  5. dataclass_extensions-0.2.6/src/dataclass_extensions/version.py +1 -0
  6. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions.egg-info/PKG-INFO +27 -7
  7. dataclass_extensions-0.2.4/src/dataclass_extensions/version.py +0 -1
  8. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/LICENSE +0 -0
  9. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/setup.cfg +0 -0
  10. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions/__init__.py +0 -0
  11. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions/encode.py +0 -0
  12. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions/py.typed +0 -0
  13. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions/registrable.py +0 -0
  14. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions/types.py +0 -0
  15. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions/utils.py +0 -0
  16. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions.egg-info/SOURCES.txt +0 -0
  17. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions.egg-info/dependency_links.txt +0 -0
  18. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions.egg-info/requires.txt +0 -0
  19. {dataclass_extensions-0.2.4 → dataclass_extensions-0.2.6}/src/dataclass_extensions.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataclass-extensions
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Additional functionality for Python dataclasses
5
5
  Author-email: Pete Walsh <epwalsh10@gmail.com>
6
6
  License: Apache License
@@ -231,6 +231,8 @@ Additional functionality for Python dataclasses
231
231
 
232
232
  ## Installation
233
233
 
234
+ Python 3.10 or newer is required. You can install the package from PyPI:
235
+
234
236
  ```fish
235
237
  pip install dataclass-extensions
236
238
  ```
@@ -249,18 +251,39 @@ class Fruit:
249
251
  calories: int
250
252
  price: float
251
253
 
252
-
253
254
  @dataclass
254
255
  class FruitBasket:
255
256
  fruit: Fruit
256
257
  count: int
257
258
 
258
-
259
259
  basket = FruitBasket(fruit=Fruit(calories=200, price=1.0), count=2)
260
260
  assert encode(basket) == {"fruit": {"calories": 200, "price": 1.0}, "count": 2}
261
261
  assert decode(FruitBasket, encode(basket)) == basket
262
262
  ```
263
263
 
264
+ You can also define how to encode/decode non-dataclass types:
265
+
266
+
267
+ ```python
268
+ from dataclasses import dataclass
269
+ from dataclass_extensions import decode, encode
270
+
271
+
272
+ class Foo:
273
+ def __init__(self, x: int):
274
+ self.x = x
275
+
276
+ @dataclass
277
+ class Bar:
278
+ foo: Foo
279
+
280
+ encode.register_encoder(lambda foo: {"x": foo.x}, Foo)
281
+ decode.register_decoder(lambda d: Foo(d["x"]), Foo)
282
+
283
+ encode(Bar(foo=Foo(10))) # {'foo': {'x': 10}}
284
+ decode(Bar, {"foo": {"x": 10}})
285
+ ```
286
+
264
287
  ### Registrable subclasses
265
288
 
266
289
  ```python
@@ -273,28 +296,25 @@ class Fruit(Registrable):
273
296
  calories: int
274
297
  price: float
275
298
 
276
-
277
299
  @Fruit.register("banana")
278
300
  @dataclass
279
301
  class Banana(Fruit):
280
302
  calories: int = 200
281
303
  price: float = 1.25
282
304
 
283
-
284
305
  @Fruit.register("apple")
285
306
  @dataclass
286
307
  class Apple(Fruit):
287
308
  calories: int = 150
288
309
  price: float = 1.50
289
310
 
290
-
291
311
  @dataclass
292
312
  class FruitBasket:
293
313
  fruit: Fruit
294
314
  count: int
295
315
 
296
-
297
316
  basket = FruitBasket(fruit=Apple(), count=2)
317
+ # note the additional "type" field, which corresponds to the registered name of the subclass
298
318
  assert encode(basket) == {"fruit": {"calories": 150, "price": 1.5, "type": "apple"}, "count": 2}
299
319
  assert decode(FruitBasket, encode(basket)) == basket
300
320
  ```
@@ -5,6 +5,8 @@ Additional functionality for Python dataclasses
5
5
 
6
6
  ## Installation
7
7
 
8
+ Python 3.10 or newer is required. You can install the package from PyPI:
9
+
8
10
  ```fish
9
11
  pip install dataclass-extensions
10
12
  ```
@@ -23,18 +25,39 @@ class Fruit:
23
25
  calories: int
24
26
  price: float
25
27
 
26
-
27
28
  @dataclass
28
29
  class FruitBasket:
29
30
  fruit: Fruit
30
31
  count: int
31
32
 
32
-
33
33
  basket = FruitBasket(fruit=Fruit(calories=200, price=1.0), count=2)
34
34
  assert encode(basket) == {"fruit": {"calories": 200, "price": 1.0}, "count": 2}
35
35
  assert decode(FruitBasket, encode(basket)) == basket
36
36
  ```
37
37
 
38
+ You can also define how to encode/decode non-dataclass types:
39
+
40
+
41
+ ```python
42
+ from dataclasses import dataclass
43
+ from dataclass_extensions import decode, encode
44
+
45
+
46
+ class Foo:
47
+ def __init__(self, x: int):
48
+ self.x = x
49
+
50
+ @dataclass
51
+ class Bar:
52
+ foo: Foo
53
+
54
+ encode.register_encoder(lambda foo: {"x": foo.x}, Foo)
55
+ decode.register_decoder(lambda d: Foo(d["x"]), Foo)
56
+
57
+ encode(Bar(foo=Foo(10))) # {'foo': {'x': 10}}
58
+ decode(Bar, {"foo": {"x": 10}})
59
+ ```
60
+
38
61
  ### Registrable subclasses
39
62
 
40
63
  ```python
@@ -47,28 +70,25 @@ class Fruit(Registrable):
47
70
  calories: int
48
71
  price: float
49
72
 
50
-
51
73
  @Fruit.register("banana")
52
74
  @dataclass
53
75
  class Banana(Fruit):
54
76
  calories: int = 200
55
77
  price: float = 1.25
56
78
 
57
-
58
79
  @Fruit.register("apple")
59
80
  @dataclass
60
81
  class Apple(Fruit):
61
82
  calories: int = 150
62
83
  price: float = 1.50
63
84
 
64
-
65
85
  @dataclass
66
86
  class FruitBasket:
67
87
  fruit: Fruit
68
88
  count: int
69
89
 
70
-
71
90
  basket = FruitBasket(fruit=Apple(), count=2)
91
+ # note the additional "type" field, which corresponds to the registered name of the subclass
72
92
  assert encode(basket) == {"fruit": {"calories": 150, "price": 1.5, "type": "apple"}, "count": 2}
73
93
  assert decode(FruitBasket, encode(basket)) == basket
74
94
  ```
@@ -107,7 +107,7 @@ ignore_missing_imports = true
107
107
  no_site_packages = true
108
108
  check_untyped_defs = true
109
109
  no_namespace_packages = true
110
- disable_error_code = ["has-type", "import-untyped"]
110
+ disable_error_code = ["has-type"]
111
111
  exclude = [
112
112
  "^src/test/_type_alias\\.py$",
113
113
  ]
@@ -90,7 +90,7 @@ def _coerce(
90
90
  if _safe_issubclass(allowed_type, Enum):
91
91
  try:
92
92
  return allowed_type(value)
93
- except TypeError:
93
+ except (TypeError, ValueError):
94
94
  pass
95
95
 
96
96
  # e.g. typing.NamedTuple
@@ -106,8 +106,14 @@ def _coerce(
106
106
  except TypeError:
107
107
  pass
108
108
 
109
- if allowed_type is float and _safe_isinstance(value, (float, int)):
110
- return float(value)
109
+ if allowed_type is float:
110
+ if _safe_isinstance(value, (float, int)):
111
+ return float(value)
112
+ elif _safe_isinstance(value, str): # need this to handle scientific notation
113
+ try:
114
+ return float(value)
115
+ except ValueError:
116
+ pass
111
117
 
112
118
  origin = getattr(allowed_type, "__origin__", None)
113
119
  args = getattr(allowed_type, "__args__", None)
@@ -0,0 +1 @@
1
+ VERSION = "0.2.6"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataclass-extensions
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Additional functionality for Python dataclasses
5
5
  Author-email: Pete Walsh <epwalsh10@gmail.com>
6
6
  License: Apache License
@@ -231,6 +231,8 @@ Additional functionality for Python dataclasses
231
231
 
232
232
  ## Installation
233
233
 
234
+ Python 3.10 or newer is required. You can install the package from PyPI:
235
+
234
236
  ```fish
235
237
  pip install dataclass-extensions
236
238
  ```
@@ -249,18 +251,39 @@ class Fruit:
249
251
  calories: int
250
252
  price: float
251
253
 
252
-
253
254
  @dataclass
254
255
  class FruitBasket:
255
256
  fruit: Fruit
256
257
  count: int
257
258
 
258
-
259
259
  basket = FruitBasket(fruit=Fruit(calories=200, price=1.0), count=2)
260
260
  assert encode(basket) == {"fruit": {"calories": 200, "price": 1.0}, "count": 2}
261
261
  assert decode(FruitBasket, encode(basket)) == basket
262
262
  ```
263
263
 
264
+ You can also define how to encode/decode non-dataclass types:
265
+
266
+
267
+ ```python
268
+ from dataclasses import dataclass
269
+ from dataclass_extensions import decode, encode
270
+
271
+
272
+ class Foo:
273
+ def __init__(self, x: int):
274
+ self.x = x
275
+
276
+ @dataclass
277
+ class Bar:
278
+ foo: Foo
279
+
280
+ encode.register_encoder(lambda foo: {"x": foo.x}, Foo)
281
+ decode.register_decoder(lambda d: Foo(d["x"]), Foo)
282
+
283
+ encode(Bar(foo=Foo(10))) # {'foo': {'x': 10}}
284
+ decode(Bar, {"foo": {"x": 10}})
285
+ ```
286
+
264
287
  ### Registrable subclasses
265
288
 
266
289
  ```python
@@ -273,28 +296,25 @@ class Fruit(Registrable):
273
296
  calories: int
274
297
  price: float
275
298
 
276
-
277
299
  @Fruit.register("banana")
278
300
  @dataclass
279
301
  class Banana(Fruit):
280
302
  calories: int = 200
281
303
  price: float = 1.25
282
304
 
283
-
284
305
  @Fruit.register("apple")
285
306
  @dataclass
286
307
  class Apple(Fruit):
287
308
  calories: int = 150
288
309
  price: float = 1.50
289
310
 
290
-
291
311
  @dataclass
292
312
  class FruitBasket:
293
313
  fruit: Fruit
294
314
  count: int
295
315
 
296
-
297
316
  basket = FruitBasket(fruit=Apple(), count=2)
317
+ # note the additional "type" field, which corresponds to the registered name of the subclass
298
318
  assert encode(basket) == {"fruit": {"calories": 150, "price": 1.5, "type": "apple"}, "count": 2}
299
319
  assert decode(FruitBasket, encode(basket)) == basket
300
320
  ```
@@ -1 +0,0 @@
1
- VERSION = "0.2.4"