Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
serializer_utils
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Container Registry
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Rolf H. B. van Kleef
serializer_utils
Commits
00e99d9c
Verified
Commit
00e99d9c
authored
Nov 08, 2018
by
Rolf H. B. van Kleef
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixed defaulting
parent
5d9c0d96
Pipeline
#1260
canceled with stages
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
131 additions
and
15 deletions
+131
-15
dict_deserializer/deserializer.py
dict_deserializer/deserializer.py
+28
-15
test_DirectoryExample.py
test_DirectoryExample.py
+103
-0
No files found.
dict_deserializer/deserializer.py
View file @
00e99d9c
...
...
@@ -86,22 +86,28 @@ class Deserializable(metaclass=BaseMeta):
return
fields
def
get_deserialization_class
(
t
,
d
,
try_all
=
False
):
def
get_deserialization_classes
(
t
,
d
,
try_all
=
True
)
->
List
[
type
]:
candidates
=
[]
for
sc
in
t
.
__subclasses__
():
if
hasattr
(
sc
,
'_discriminators'
):
for
discriminator
in
sc
.
_discriminators
:
if
not
discriminator
.
check
(
d
):
# Invalid
break
else
:
# All were valid
try
:
return
get_deserialization_class
(
sc
,
t
,
try_all
)
candidates
.
extend
(
get_deserialization_classes
(
sc
,
t
,
try_all
)
)
except
TypeError
as
e
:
if
not
try_all
:
raise
e
return
t
if
not
getattr
(
t
,
'_abstract'
,
True
):
candidates
.
append
(
t
)
return
candidates
def
deserialize
(
rule
:
Rule
,
data
,
try_all
=
False
,
key
=
None
):
def
deserialize
(
rule
:
Rule
,
data
,
try_all
=
True
,
key
=
'$'
):
# In case of primitive types, attempt to assign.
try
:
return
rule
.
validate
(
key
,
data
)
...
...
@@ -111,7 +117,10 @@ def deserialize(rule: Rule, data, try_all=False, key=None):
if
type
(
rule
.
type
)
is
type
(
Union
):
for
arg
in
rule
.
type
.
__args__
:
try
:
return
deserialize
(
Rule
(
arg
),
data
,
try_all
,
key
)
v
=
deserialize
(
Rule
(
arg
),
data
,
try_all
,
key
)
if
v
is
None
:
v
=
rule
.
default
return
v
except
TypeError
:
pass
raise
TypeError
(
'{} did not match any of {} for key {}.'
.
format
(
type
(
data
),
rule
.
type
.
__args__
,
key
))
...
...
@@ -126,23 +135,27 @@ def deserialize(rule: Rule, data, try_all=False, key=None):
t
=
rule
.
type
.
__args__
[
0
]
result
=
[]
for
i
,
v
in
enumerate
(
data
):
result
.
append
(
deserialize
(
Rule
(
t
),
v
,
try_all
,
i
))
result
.
append
(
deserialize
(
Rule
(
t
),
v
,
try_all
,
'{}.{}'
.
format
(
key
,
i
)
))
return
result
if
issubclass
(
rule
.
type
,
Deserializable
):
if
not
isinstance
(
data
,
dict
):
raise
TypeError
(
'Cannot deserialize non-dict into class.'
)
cl
s
=
get_deserialization_clas
s
(
rule
.
type
,
data
,
try_all
)
cl
asses
=
get_deserialization_classe
s
(
rule
.
type
,
data
,
try_all
)
if
hasattr
(
cls
,
'_abstract'
)
and
cls
.
_abstract
:
raise
TypeError
(
'Cannot deserialize into {}: is abstract.'
.
format
(
cls
.
__name__
))
for
cls
in
classes
:
try
:
instance
=
cls
()
for
k
,
r
in
cls
.
get_attrs
()
.
items
():
v
=
deserialize
(
r
,
data
[
k
]
if
k
in
data
else
r
.
default
,
try_all
,
key
=
'{}.{}'
.
format
(
key
,
k
))
setattr
(
instance
,
k
,
v
)
instance
=
cls
()
for
k
,
r
in
cls
.
get_attrs
()
.
items
()
:
v
=
deserialize
(
r
,
data
[
k
]
if
k
in
data
else
r
.
default
,
try_all
,
key
=
k
)
setattr
(
instance
,
k
,
v
)
return
instance
except
TypeError
as
e
:
if
not
try_all
:
raise
e
r
eturn
instance
r
aise
TypeError
(
'Unable to find matching non-abstract (sub)type of {} with key {}.'
.
format
(
rule
.
type
,
key
))
raise
TypeError
(
'Unable to find a deserialization candidate for {} in {}.'
.
format
(
data
,
rule
))
\ No newline at end of file
raise
TypeError
(
'Unable to find a deserialization candidate for {} with key {}.'
.
format
(
rule
,
key
))
\ No newline at end of file
test_DirectoryExample.py
0 → 100644
View file @
00e99d9c
import
unittest
from
typing
import
List
,
Optional
from
dict_deserializer.annotations
import
abstract
from
dict_deserializer.deserializer
import
Deserializable
,
deserialize
,
Rule
@
abstract
class
Object
(
Deserializable
):
def
__init__
(
self
,
name
=
None
):
self
.
name
=
name
name
:
str
def
__repr__
(
self
):
return
'Object(name="{}")'
.
format
(
self
.
name
)
def
__eq__
(
self
,
other
):
return
isinstance
(
other
,
Object
)
and
other
.
name
==
self
.
name
class
User
(
Object
):
def
__init__
(
self
,
full_name
=
None
,
calling_name
=
None
,
*
args
,
**
kwargs
):
super
(
User
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
full_name
=
full_name
self
.
calling_name
=
calling_name
full_name
:
str
calling_name
:
Optional
[
str
]
=
'Unknown'
def
__repr__
(
self
):
if
self
.
calling_name
is
None
:
return
'User(super={}, full_name="{}")'
\
.
format
(
super
(
User
,
self
)
.
__repr__
(),
self
.
full_name
)
return
'User(super={}, full_name="{}", calling_name="{}")'
\
.
format
(
super
(
User
,
self
)
.
__repr__
(),
self
.
full_name
,
self
.
calling_name
)
def
__eq__
(
self
,
other
):
return
isinstance
(
other
,
User
)
and
super
(
User
,
self
)
.
__eq__
(
other
)
and
\
other
.
full_name
==
self
.
full_name
and
\
other
.
calling_name
==
self
.
calling_name
class
Group
(
Object
):
def
__init__
(
self
,
members
=
None
,
*
args
,
**
kwargs
):
super
(
Group
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
members
=
members
members
:
List
[
Object
]
def
__repr__
(
self
):
return
'Group(super={}, members=[{}])'
\
.
format
(
super
(
Group
,
self
)
.
__repr__
(),
','
.
join
([
m
.
__repr__
()
for
m
in
self
.
members
]))
def
__eq__
(
self
,
other
):
return
isinstance
(
other
,
Group
)
and
super
(
Group
,
self
)
.
__eq__
(
other
)
\
and
other
.
members
==
self
.
members
class
TestLists
(
unittest
.
TestCase
):
def
test_CorrectDeserializationForNestedWithTypeUnionsAndLists
(
self
):
self
.
assertEqual
(
Group
(
name
=
'IAPC'
,
members
=
[
User
(
name
=
'Rolf'
,
full_name
=
'Rolf van Kleef'
,
calling_name
=
'Unknown'
),
Group
(
name
=
'Syscom'
,
members
=
[
User
(
name
=
'Kevin'
,
full_name
=
'Kevin Alberts'
,
calling_name
=
'Kevin'
),
]),
],
),
deserialize
(
Rule
(
Object
),
{
'name'
:
'IAPC'
,
'members'
:
[
{
'name'
:
'Rolf'
,
'full_name'
:
'Rolf van Kleef'
},
{
'name'
:
'Syscom'
,
'members'
:
[
{
'name'
:
'Kevin'
,
'full_name'
:
'Kevin Alberts'
,
'calling_name'
:
'Kevin'
},
]},
],
})
)
def
test_FailDeserializeWithInvalidTypes
(
self
):
with
self
.
assertRaises
(
TypeError
):
deserialize
(
Rule
(
Object
),
{
'name'
:
'Karel'
,
'full_name'
:
0.0
,
})
with
self
.
assertRaises
(
TypeError
):
deserialize
(
Rule
(
Object
),
{
'name'
:
'Rolf'
,
'full_name'
:
'Rolf van Kleef'
,
'calling_name'
:
False
,
})
def
test_DeserializeIntoAbstract
(
self
):
with
self
.
assertRaises
(
TypeError
)
as
ctx
:
deserialize
(
Rule
(
Object
),
{
'name'
:
'Test'
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment