Skip to content

Commit e4b97a1

Browse files
committed
add sub_name support to SimpleDictDocument
1 parent 8c31f54 commit e4b97a1

File tree

3 files changed

+121
-23
lines changed

3 files changed

+121
-23
lines changed

spyne/model/complex.py

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,59 +1057,122 @@ def get_orig(cls):
10571057
return cls.__orig__ or cls
10581058

10591059
@staticmethod
1060-
@memoize
10611060
def get_simple_type_info(cls, hier_delim="."):
10621061
"""Returns a _type_info dict that includes members from all base classes
10631062
and whose types are only primitives. It will prefix field names in
10641063
non-top-level complex objects with field name of its parent.
10651064
1066-
For example, given hier_delim='_'; the following hierarchy: ::
1065+
For example, given hier_delim='.'; the following hierarchy: ::
10671066
10681067
{'some_object': [{'some_string': ['abc']}]}
10691068
10701069
would be transformed to: ::
10711070
1072-
{'some_object_some_string': ['abc']}
1071+
{'some_object.some_string': ['abc']}
10731072
10741073
:param hier_delim: String that will be used as delimiter between field
1075-
names. Default is ``'_'``.
1074+
names. Default is ``'.'``.
10761075
"""
1076+
return ComplexModelBase.get_simple_type_info_with_prot(
1077+
cls, hier_delim=hier_delim)
10771078

1079+
@staticmethod
1080+
@memoize
1081+
def get_simple_type_info_with_prot(cls, prot=None, hier_delim="."):
1082+
"""See :func:ComplexModelBase.get_simple_type_info"""
10781083
fti = cls.get_flat_type_info(cls)
10791084

10801085
retval = TypeInfo()
10811086
tags = set()
1082-
queue = deque([(k, v, (k,), (_is_array(v),), cls)
1083-
for k,v in fti.items()])
1087+
1088+
queue = deque()
1089+
if prot is None:
1090+
for k, v in fti.items():
1091+
sub_name = k
1092+
1093+
queue.append((
1094+
(k,),
1095+
v,
1096+
(sub_name,),
1097+
(_is_array(v),),
1098+
cls,
1099+
))
1100+
1101+
else:
1102+
for k, v in fti.items():
1103+
cls_attrs = prot.get_cls_attrs(v)
1104+
sub_name = cls_attrs.sub_name
1105+
if sub_name is None:
1106+
sub_name = k
1107+
1108+
queue.append((
1109+
(k,),
1110+
v,
1111+
(sub_name,),
1112+
(_is_array(v),),
1113+
cls,
1114+
))
1115+
10841116
tags.add(cls)
10851117

10861118
while len(queue) > 0:
1087-
k, v, prefix, is_array, parent = queue.popleft()
1119+
keys, v, prefix, is_array, parent = queue.popleft()
1120+
k = keys[-1]
10881121
if issubclass(v, Array) and v.Attributes.max_occurs == 1:
10891122
v, = v._type_info.values()
10901123

10911124
key = hier_delim.join(prefix)
10921125
if issubclass(v, ComplexModelBase):
1093-
retval[key] = _SimpleTypeInfoElement(path=tuple(prefix),
1094-
parent=parent, type_=v, is_array=tuple(is_array),
1095-
can_be_empty=True)
1126+
retval[key] = _SimpleTypeInfoElement(
1127+
path=keys,
1128+
parent=parent,
1129+
type_=v,
1130+
is_array=tuple(is_array),
1131+
can_be_empty=True,
1132+
)
10961133

10971134
if not (v in tags):
10981135
tags.add(v)
1099-
queue.extend([
1100-
(k2, v2, prefix + (k2,),
1101-
is_array + (v.Attributes.max_occurs > 1,), v)
1102-
for k2, v2 in v.get_flat_type_info(v).items()])
1136+
if prot is None:
1137+
for k2, v2 in v.get_flat_type_info(v).items():
1138+
sub_name = k2
1139+
queue.append((
1140+
keys + (k2,),
1141+
v2,
1142+
prefix + (sub_name,),
1143+
is_array + (_is_array(v),),
1144+
v
1145+
))
1146+
1147+
else:
1148+
for k2, v2 in v.get_flat_type_info(v).items():
1149+
cls_attrs = prot.get_cls_attrs(v2)
1150+
sub_name = cls_attrs.sub_name
1151+
if sub_name is None:
1152+
sub_name = k2
1153+
1154+
queue.append((
1155+
keys + (k2,),
1156+
v2,
1157+
prefix + (sub_name,),
1158+
is_array + (_is_array(v),),
1159+
v,
1160+
))
1161+
11031162
else:
11041163
value = retval.get(key, None)
11051164

11061165
if value is not None:
11071166
raise ValueError("%r.%s conflicts with %r" %
11081167
(cls, k, value.path))
11091168

1110-
retval[key] = _SimpleTypeInfoElement(path=tuple(prefix),
1111-
parent=parent, type_=v, is_array=tuple(is_array),
1112-
can_be_empty=False)
1169+
retval[key] = _SimpleTypeInfoElement(
1170+
path=keys,
1171+
parent=parent,
1172+
type_=v,
1173+
is_array=tuple(is_array),
1174+
can_be_empty=False,
1175+
)
11131176

11141177
return retval
11151178

@@ -1201,7 +1264,7 @@ def customize(cls, **kwargs):
12011264
# during daemon initialization, so it's not really necessary.
12021265
ComplexModelBase.get_subclasses.memo.clear()
12031266
ComplexModelBase.get_flat_type_info.memo.clear()
1204-
ComplexModelBase.get_simple_type_info.memo.clear()
1267+
ComplexModelBase.get_simple_type_info_with_prot.memo.clear()
12051268

12061269
return retval
12071270

@@ -1232,7 +1295,7 @@ def _append_field_impl(cls, field_name, field_type):
12321295
cls._type_info[field_name] = field_type
12331296

12341297
ComplexModelBase.get_flat_type_info.memo.clear()
1235-
ComplexModelBase.get_simple_type_info.memo.clear()
1298+
ComplexModelBase.get_simple_type_info_with_prot.memo.clear()
12361299

12371300
@classmethod
12381301
def _append_to_variants(cls, field_name, field_type):
@@ -1269,7 +1332,7 @@ def _insert_field_impl(cls, index, field_name, field_type):
12691332
cls._type_info.insert(index, (field_name, field_type))
12701333

12711334
ComplexModelBase.get_flat_type_info.memo.clear()
1272-
ComplexModelBase.get_simple_type_info.memo.clear()
1335+
ComplexModelBase.get_simple_type_info_with_prot.memo.clear()
12731336

12741337
@classmethod
12751338
def insert_field(cls, index, field_name, field_type):
@@ -1289,7 +1352,7 @@ def _replace_field_impl(cls, field_name, field_type):
12891352
cls._type_info[field_name] = field_type
12901353

12911354
ComplexModelBase.get_flat_type_info.memo.clear()
1292-
ComplexModelBase.get_simple_type_info.memo.clear()
1355+
ComplexModelBase.get_simple_type_info_with_prot.memo.clear()
12931356

12941357
@classmethod
12951358
def _replace_field(cls, field_name, field_type):

spyne/protocol/dictdoc/simple.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ def simple_dict_to_object(self, ctx, doc, cls, validator=None, req_enc=None):
171171
retval = cls.get_serialization_instance([])
172172
else:
173173
retval = cls.get_deserialization_instance(ctx)
174-
simple_type_info = cls.get_simple_type_info(cls,
174+
175+
simple_type_info = cls.get_simple_type_info_with_prot(cls, self,
175176
hier_delim=self.hier_delim)
176177

177178
logger.debug("Simple type info key: %r", simple_type_info.keys())
@@ -350,7 +351,11 @@ def object_to_simple_dict(self, cls, inst, retval=None,
350351

351352
for k, v in fti.items():
352353
new_prefix = list(prefix)
353-
new_prefix.append(k)
354+
cls_attrs = self.get_cls_attrs(v)
355+
sub_name = cls_attrs.sub_name
356+
if sub_name is None:
357+
sub_name = k
358+
new_prefix.append(sub_name)
354359
subinst = getattr(inst, k, None)
355360

356361
if (issubclass(v, Array) or v.Attributes.max_occurs > 1) and \

spyne/test/model/test_complex.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,36 @@ class CCM(ComplexModel):
536536

537537
assert len(d) == 4
538538

539+
def test_sub_name_ser(self):
540+
class CM(ComplexModel):
541+
integer = Integer(sub_name='i')
542+
string = String(sub_name='s')
543+
544+
val = CM(integer=7, string='b')
545+
546+
d = SimpleDictDocument().object_to_simple_dict(CM, val)
547+
548+
pprint(d)
549+
550+
assert d['i'] == 7
551+
assert d['s'] == 'b'
552+
553+
assert len(d) == 2
554+
555+
def test_sub_name_deser(self):
556+
class CM(ComplexModel):
557+
integer = Integer(sub_name='i')
558+
string = String(sub_name='s')
559+
560+
d = {'i': [7], 's': ['b']}
561+
562+
val = SimpleDictDocument().simple_dict_to_object(None, d, CM)
563+
564+
pprint(d)
565+
566+
assert val.integer == 7
567+
assert val.string == 'b'
568+
539569
def test_array_not_none(self):
540570
class CM(ComplexModel):
541571
i = Integer

0 commit comments

Comments
 (0)