Skip to content

Commit 763e869

Browse files
committed
Refactor of the serialize and to_serializable function
This commit tries to tackle #268 and rewrite the `serialize` function to handle less class specific cases and move it into the single dispatch function `to_serializable`.
1 parent 0c8f23c commit 763e869

File tree

1 file changed

+42
-20
lines changed

1 file changed

+42
-20
lines changed

pytm/pytm.py

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,7 +1278,6 @@ def get_table(db, klass):
12781278
db.close()
12791279

12801280

1281-
12821281
class Controls:
12831282
"""Controls implemented by/on and Element"""
12841283

@@ -2004,52 +2003,75 @@ def to_serializable(val):
20042003

20052004
@to_serializable.register(TM)
20062005
def ts_tm(obj):
2007-
return serialize(obj, nested=True)
2006+
result = serialize(obj, nested=True, ignore=(
2007+
"_sf", "_duplicate_ignored_attrs", "_threats", "_elements", "assumptions"))
2008+
result["elements"] = [e for e in obj._elements if isinstance(e, (Actor, Asset))]
2009+
result["assumptions"] = list(obj.assumptions)
2010+
return result
20082011

20092012

20102013
@to_serializable.register(Controls)
20112014
@to_serializable.register(Data)
2015+
@to_serializable.register(Finding)
2016+
def _(obj):
2017+
return serialize(obj, nested=False)
2018+
2019+
20122020
@to_serializable.register(Threat)
2013-
@to_serializable.register(Element)
2021+
def _(obj):
2022+
result = serialize(obj, nested=False, ignore=["target"])
2023+
result["target"] = [v.__name__ for v in obj.target]
2024+
return result
2025+
2026+
20142027
@to_serializable.register(Finding)
2028+
def _(obj):
2029+
return serialize(obj, nested=False, ignore=["element"])
2030+
2031+
2032+
@to_serializable.register(Element)
20152033
def ts_element(obj):
2016-
return serialize(obj, nested=False)
2034+
result = serialize(obj, nested=False, ignore=("_is_drawn", "uuid", "levels", "sourceFiles", "assumptions", "findings"))
2035+
result["levels"] = list(obj.levels)
2036+
result["sourceFiles"] = list(obj.sourceFiles)
2037+
result["assumptions"] = list(obj.assumptions)
2038+
result["findings"] = [v.id for v in obj.findings]
2039+
return result
20172040

20182041

2019-
def serialize(obj, nested=False):
2042+
@to_serializable.register(Actor)
2043+
@to_serializable.register(Asset)
2044+
def _(obj):
2045+
# Note that we use the ts_element function defined for the Element class
2046+
result = ts_element(obj)
2047+
result["__class__"] = obj.__class__.__name__
2048+
return result
2049+
2050+
2051+
def serialize(obj, nested=False, ignore=None):
20202052
"""Used if *obj* is an instance of TM, Element, Threat or Finding."""
20212053
klass = obj.__class__
20222054
result = {}
2023-
if isinstance(obj, (Actor, Asset)):
2024-
result["__class__"] = klass.__name__
2055+
if ignore is None:
2056+
ignore = []
2057+
20252058
for i in dir(obj):
20262059
if (
20272060
i.startswith("__")
20282061
or callable(getattr(klass, i, {}))
2029-
or (
2030-
isinstance(obj, TM)
2031-
and i in ("_sf", "_duplicate_ignored_attrs", "_threats")
2032-
)
2033-
or (isinstance(obj, Element) and i in ("_is_drawn", "uuid"))
2034-
or (isinstance(obj, Finding) and i == "element")
2062+
or i in ignore
20352063
):
20362064
continue
20372065
value = getattr(obj, i)
2038-
if isinstance(obj, TM) and i == "_elements":
2039-
value = [e for e in value if isinstance(e, (Actor, Asset))]
20402066
if value is not None:
20412067
if isinstance(value, (Element, Data)):
20422068
value = value.name
2043-
elif isinstance(obj, Threat) and i == "target":
2044-
value = [v.__name__ for v in value]
2045-
elif i in ("levels", "sourceFiles", "assumptions"):
2046-
value = list(value)
20472069
elif (
20482070
not nested
20492071
and not isinstance(value, str)
20502072
and isinstance(value, Iterable)
20512073
):
2052-
value = [v.id if isinstance(v, Finding) else v.name for v in value]
2074+
value = [v.name for v in value]
20532075
result[i.lstrip("_")] = value
20542076
return result
20552077

0 commit comments

Comments
 (0)