Skip to content

Commit 587cacf

Browse files
authored
Merge pull request #176 from python-odin/development
2.11rc3
2 parents 3ebced7 + 49a4d17 commit 587cacf

12 files changed

Lines changed: 131 additions & 113 deletions

File tree

.readthedocs.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
# Required
66
version: 2
77

8+
sphinx:
9+
# Path to your Sphinx configuration file.
10+
configuration: docs/conf.py
11+
812
# Set the version of Python and other tools you might need
913
build:
1014
os: ubuntu-22.04

HISTORY

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
2.11rc3
2+
=======
3+
4+
Changes
5+
-------
6+
7+
- Move the inclusion of the type field (typically `$`) into the resource and not individual codecs.
8+
Ensuring it is defined first.
9+
10+
This could cause a breaking change to any tests that expect existing field order.
11+
12+
113
2.11rc2
214
=======
315

docs/conf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@
6161
# built documents.
6262
#
6363
# The short X.Y version.
64-
version = "1.0"
64+
version = "2.0"
6565
# The full version, including alpha/beta/rc tags.
66-
release = "1.0"
66+
release = "2.0"
6767

6868
# The language for content autogenerated by Sphinx. Refer to documentation
6969
# for a list of supported languages.
@@ -271,4 +271,4 @@
271271
# texinfo_no_detailmenu = False
272272

273273
# Example configuration for intersphinx: refer to the Python standard library.
274-
intersphinx_mapping = {"http://docs.python.org/": None}
274+
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "odin"
7-
version = "2.11rc2"
7+
version = "2.11rc3"
88
description = "Data-structure definition/validation/traversal, mapping and serialisation toolkit for Python"
99
authors = ["Tim Savage <tim@savage.company>"]
1010
license = "BSD-3-Clause"

src/odin/codecs/dict_codec.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from odin import ResourceAdapter, bases, resources
2-
from odin.utils import getmeta
32

43
TYPE_SERIALIZERS = {}
54

@@ -10,12 +9,8 @@ def __init__(self, include_virtual_fields=True, include_type_field=True):
109
self.include_type_field = include_type_field
1110

1211
def default(self, o):
13-
if isinstance(o, (resources.ResourceBase, ResourceAdapter)):
14-
meta = getmeta(o)
15-
obj = o.to_dict(self.include_virtual_fields)
16-
if self.include_type_field:
17-
obj[meta.type_field] = meta.resource_name
18-
return obj
12+
if isinstance(o, resources.ResourceBase | ResourceAdapter):
13+
return o.to_dict(self.include_virtual_fields, self.include_type_field)
1914
elif isinstance(o, bases.ResourceIterable):
2015
return list(o)
2116
elif o.__class__ in TYPE_SERIALIZERS:
@@ -35,9 +30,11 @@ def encode(self, o):
3530
3631
:param d: Dict to load
3732
38-
:param resource: A resource type, resource name or list of resources and names to use as the base for creating a
39-
resource. If a list is supplied the first item will be used if a resource type is not supplied.
40-
:raises ValidationError: During building of the object graph and issues discovered are raised as a ValidationError.
33+
:param resource: A resource type, resource name or list of resources and names to
34+
use as the base for creating a resource. If a list is supplied the first item
35+
will be used if a resource type is not supplied.
36+
:raises ValidationError: During building of the object graph and issues discovered
37+
are raised as a ValidationError.
4138
4239
"""
4340

@@ -46,8 +43,9 @@ def dump(resource, cls=OdinEncoder, **kwargs):
4643
"""
4744
Dump a resource structure into a nested :py:class:`dict`.
4845
49-
While a resource includes a *to_dict* method this method is not recursive. The dict codec recursively iterates
50-
through the resource structure to produce a full dict. This is useful for testing for example.
46+
While a resource includes a *to_dict* method this method is not recursive. The dict
47+
codec recursively iterates through the resource structure to produce a full dict.
48+
This is useful for testing for example.
5149
5250
:param resource: The root resource to dump
5351
:param cls: Encoder class to utilise
@@ -66,13 +64,13 @@ def _encode_dict(dct):
6664
return {k: _encode(o) for k, o in dct.items()}
6765

6866
def _encode(o):
69-
if isinstance(o, (list, tuple)):
67+
if isinstance(o, list | tuple):
7068
return _encode_list(o)
7169
elif isinstance(o, dict):
7270
return _encode_dict(o)
7371
else:
7472
o = _default(o)
75-
if isinstance(o, (list, tuple, dict)):
73+
if isinstance(o, list | tuple | dict):
7674
return _encode(o)
7775
return o
7876

src/odin/codecs/json_codec.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from odin import ResourceAdapter, bases, resources, serializers
77
from odin.exceptions import CodecDecodeError, CodecEncodeError
8-
from odin.utils import getmeta
98

109
LIST_TYPES = (bases.ResourceIterable, typing.ValuesView, typing.KeysView)
1110
JSON_TYPES = {
@@ -18,9 +17,7 @@
1817

1918

2019
class OdinEncoder(json.JSONEncoder):
21-
"""
22-
Encoder for Odin resources.
23-
"""
20+
"""Encoder for Odin resources."""
2421

2522
def __init__(
2623
self, include_virtual_fields=True, include_type_field=True, *args, **kwargs
@@ -30,12 +27,8 @@ def __init__(
3027
self.include_type_field = include_type_field
3128

3229
def default(self, o):
33-
if isinstance(o, (resources.ResourceBase, ResourceAdapter)):
34-
meta = getmeta(o)
35-
obj = o.to_dict(self.include_virtual_fields)
36-
if self.include_type_field:
37-
obj[meta.type_field] = meta.resource_name
38-
return obj
30+
if isinstance(o, resources.ResourceBase | ResourceAdapter):
31+
return o.to_dict(self.include_virtual_fields, self.include_type_field)
3932

4033
elif isinstance(o, LIST_TYPES):
4134
return list(o)
@@ -53,11 +46,12 @@ def load(fp, resource=None, full_clean=True, default_to_not_supplied=False):
5346
See :py:meth:`loads` for more details of the loading operation.
5447
5548
:param fp: a file pointer to read JSON data from.
56-
:param resource: A resource type, resource name or list of resources and names to use as the base for creating a
57-
resource. If a list is supplied the first item will be used if a resource type is not supplied.
49+
:param resource: A resource type, resource name or list of resources and names to
50+
use as the base for creating a resource. If a list is supplied the first item
51+
will be used if a resource type is not supplied.
5852
:param full_clean: Do a full clean of the object as part of the loading process.
59-
:param default_to_not_supplied: Used for loading partial resources. Any fields not supplied are replaced with
60-
NOT_SUPPLIED.
53+
:param default_to_not_supplied: Used for loading partial resources. Any fields not
54+
supplied are replaced with NOT_SUPPLIED.
6155
:returns: A resource object or object graph of resources loaded from file.
6256
6357
"""
@@ -68,18 +62,21 @@ def loads(s, resource=None, full_clean=True, default_to_not_supplied=False):
6862
"""
6963
Load from a JSON encoded string.
7064
71-
If a ``resource`` value is supplied it is used as the base resource for the supplied JSON. I one is not supplied a
72-
resource type field ``$`` is used to obtain the type represented by the dictionary. A ``ValidationError`` will be
73-
raised if either of these values are supplied and not compatible. It is valid for a type to be supplied in the file
74-
to be a child object from within the inheritance tree.
65+
If a ``resource`` value is supplied it is used as the base resource for the
66+
supplied JSON. I one is not supplied a resource type field ``$`` is used to obtain
67+
the type represented by the dictionary. A ``ValidationError`` will be raised if
68+
either of these values are supplied and not compatible. It is valid for a type to
69+
be supplied in the file to be a child object from within the inheritance tree.
7570
7671
:param s: String to load and parse.
77-
:param resource: A resource type, resource name or list of resources and names to use as the base for creating a
78-
resource. If a list is supplied the first item will be used if a resource type is not supplied.
72+
:param resource: A resource type, resource name or list of resources and names to
73+
use as the base for creating a resource. If a list is supplied the first item
74+
will be used if a resource type is not supplied.
7975
:param full_clean: Do a full clean of the object as part of the loading process.
80-
:param default_to_not_supplied: Used for loading partial resources. Any fields not supplied are replaced with
81-
NOT_SUPPLIED.
82-
:returns: A resource object or object graph of resources parsed from supplied string.
76+
:param default_to_not_supplied: Used for loading partial resources. Any fields not
77+
supplied are replaced with NOT_SUPPLIED.
78+
:returns: A resource object or object graph of resources parsed from supplied
79+
string.
8380
8481
"""
8582
try:
@@ -95,7 +92,8 @@ def dump(resource, fp, cls=OdinEncoder, **kwargs):
9592
Dump to a JSON encoded file.
9693
9794
:param resource: The root resource to dump to a JSON encoded file.
98-
:param cls: Encoder to use serializing to a string; default is the :py:class:`OdinEncoder`.
95+
:param cls: Encoder to use serializing to a string; default is the
96+
:py:class:`OdinEncoder`.
9997
:param fp: The file pointer that represents the output file.
10098
10199
"""
@@ -110,7 +108,8 @@ def dumps(resource, cls=OdinEncoder, **kwargs):
110108
Dump to a JSON encoded string.
111109
112110
:param resource: The root resource to dump to a JSON encoded file.
113-
:param cls: Encoder to use serializing to a string; default is the :py:class:`OdinEncoder`.
111+
:param cls: Encoder to use serializing to a string; default is the
112+
:py:class:`OdinEncoder`.
114113
:returns: JSON encoded string.
115114
116115
"""

src/odin/codecs/msgpack_codec.py

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Codec to load/save Message Pack (msgpack) documents."""
2+
23
import datetime
34
import uuid
45
from typing import TextIO
@@ -11,7 +12,6 @@
1112
) from None # noqa
1213

1314
from odin import ResourceAdapter, bases, resources, serializers
14-
from odin.utils import getmeta
1515

1616
TYPE_SERIALIZERS = {
1717
datetime.date: serializers.date_iso_format,
@@ -31,11 +31,8 @@ def __init__(self, include_virtual_fields: bool = True, *args, **kwargs):
3131
self.include_virtual_fields = include_virtual_fields
3232

3333
def default(self, o):
34-
if isinstance(o, (resources.ResourceBase, ResourceAdapter)):
35-
meta = getmeta(o)
36-
obj = o.to_dict(self.include_virtual_fields)
37-
obj[meta.type_field] = meta.resource_name
38-
return obj
34+
if isinstance(o, resources.ResourceBase | ResourceAdapter):
35+
return o.to_dict(self.include_virtual_fields, True)
3936

4037
elif isinstance(o, bases.ResourceIterable):
4138
return list(o)
@@ -55,7 +52,8 @@ def load(
5552
See :py:meth:`loads` for more details of the loading operation.
5653
5754
:param fp: a file pointer to read MessagePack data from.
58-
:param resource: A resource instance or a resource name to use as the base for creating a resource.
55+
:param resource: A resource instance or a resource name to use as the base for
56+
creating a resource.
5957
:param full_clean: Do a full clean of the object as part of the loading process.
6058
:param default_to_not_supplied:
6159
:returns: A resource object or object graph of resources loaded from file.
@@ -73,16 +71,20 @@ def loads(
7371
):
7472
"""Load from a MessagePack encoded string/bytes.
7573
76-
If a ``resource`` value is supplied it is used as the base resource for the supplied MessagePack data. I one is not
77-
supplied a resource type field ``$`` is used to obtain the type represented by the dictionary. A ``ValidationError``
78-
will be raised if either of these values are supplied and not compatible. It is valid for a type to be supplied in
79-
the file to be a child object from within the inheritance tree.
74+
If a ``resource`` value is supplied it is used as the base resource for the
75+
supplied MessagePack data. I one is not supplied a resource type field ``$`` is
76+
used to obtain the type represented by the dictionary. A ``ValidationError``
77+
will be raised if either of these values are supplied and not compatible. It is
78+
valid for a type to be supplied in the file to be a child object from within the
79+
inheritance tree.
8080
8181
:param s: String to load and parse.
82-
:param resource: A resource instance or a resource name to use as the base for creating a resource.
82+
:param resource: A resource instance or a resource name to use as the base for
83+
creating a resource.
8384
:param full_clean: Do a full clean of the object as part of the loading process.
8485
:param default_to_not_supplied:
85-
:returns: A resource object or object graph of resources parsed from supplied string.
86+
:returns: A resource object or object graph of resources parsed from supplied
87+
string.
8688
"""
8789
return resources.build_object_graph(
8890
msgpack.loads(s), resource, full_clean, False, default_to_not_supplied
@@ -94,13 +96,14 @@ def dump(
9496
fp: TextIO,
9597
cls=OdinPacker,
9698
include_virtual_fields: bool = True,
97-
**kwargs
99+
**kwargs,
98100
):
99101
"""Dump to a MessagePack encoded file.
100102
101103
:param include_virtual_fields:
102104
:param resource: The root resource to dump to a MessagePack encoded file.
103-
:param cls: Encoder to use serializing to a string; default is the :py:class:`OdinEncoder`.
105+
:param cls: Encoder to use serializing to a string; default is the
106+
:py:class:`OdinEncoder`.
104107
:param fp: The file pointer that represents the output file.
105108
"""
106109
fp.write(cls(include_virtual_fields, **kwargs).pack(resource))
@@ -110,13 +113,14 @@ def dumps(
110113
resource: resources.ResourceBase,
111114
cls=OdinPacker,
112115
include_virtual_fields: bool = True,
113-
**kwargs
116+
**kwargs,
114117
):
115118
"""Dump to a MessagePack encoded string.
116119
117120
:param include_virtual_fields:
118121
:param resource: The root resource to dump to a MessagePack encoded file.
119-
:param cls: Encoder to use serializing to a string; default is the :py:class:`OdinEncoder`.
122+
:param cls: Encoder to use serializing to a string; default is the
123+
:py:class:`OdinEncoder`.
120124
:returns: MessagePack encoded string.
121125
"""
122126
return cls(include_virtual_fields, **kwargs).pack(resource)

0 commit comments

Comments
 (0)