Reimplemented __hash__ and __eq__ in StrType, 'cause we want the comparison to be based on class name instead of instance's ID. Added a 'folding' feature in order to hide elements based on keys
This commit is contained in:
parent
d1ea1f7317
commit
df78a1ad2e
|
|
@ -1,38 +1,71 @@
|
||||||
from collections import Iterable
|
from collections import Iterable
|
||||||
|
from boltons.iterutils import remap
|
||||||
|
|
||||||
def unique(seq):
|
def unique(seq):
|
||||||
"""Return a new sequence made of unique elements from seq."""
|
"""Return a new sequence made of unique elements from seq.
|
||||||
|
Code borrowed from the Internet.
|
||||||
|
"""
|
||||||
uniques = []
|
uniques = []
|
||||||
[uniques.append(x) for x in seq if not uniques.count(x)]
|
[uniques.append(x) for x in seq if not uniques.count(x)]
|
||||||
return type(seq)(uniques)
|
return type(seq)(uniques)
|
||||||
|
|
||||||
|
|
||||||
class StrType(str):
|
class StrType(str):
|
||||||
"""Helper class to print and compare object types.
|
"""Helper class to print and compare object types (used in function 'get_structure').
|
||||||
Provide the object whose type you want to print.
|
When instanciating this class, provide the object whose type you want to print.
|
||||||
|
__hash__ and __eq__ implemented in order to filter duplicates and yet stay compatible with
|
||||||
|
uniqueness detection (to fit in sets for instance).
|
||||||
"""
|
"""
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
self.value = type(obj).__name__
|
self.value = type(obj).__name__
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return hash(self.value)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, StrType):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return self.value == other.value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"<{self.value}>"
|
return f"<{self.value}>"
|
||||||
|
|
||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
|
|
||||||
|
|
||||||
def get_structure(data):
|
def get_structure(data, folding_keys=[], folding_tag=" (folded)"):
|
||||||
"""Return a kind of map of the could-be nested data.
|
"""Return a kind of map of the could-be nested data.
|
||||||
Duplicates are removed from sequences.
|
Duplicates are removed from sequences.
|
||||||
|
If 'folding_keys' are provided then the corresponding values in the data set will be folded,
|
||||||
|
that is to say replaced by their data type (thus transformed into leaves). The key will be
|
||||||
|
appended with 'folding_tag'.
|
||||||
"""
|
"""
|
||||||
if isinstance(data, dict):
|
if folding_keys:
|
||||||
return {key:get_structure(value) for key, value in data.items()}
|
def visit_fold(path, key, value):
|
||||||
elif (isinstance(data, Iterable)
|
if key in folding_keys:
|
||||||
and not isinstance(data, str)
|
# We only fold iterable types (except for strings and bytes).
|
||||||
and not isinstance(data, bytes)):
|
if (isinstance(data, Iterable)
|
||||||
if data:
|
and not isinstance(data, str)
|
||||||
|
and not isinstance(data, bytes)):
|
||||||
|
return "".join([key, folding_tag]), type(value)()
|
||||||
|
return True
|
||||||
|
|
||||||
|
data = remap(data, visit=visit_fold)
|
||||||
|
|
||||||
|
def extract_structure(data):
|
||||||
|
if data and isinstance(data, dict):
|
||||||
|
return {key:get_structure(value) for key, value in data.items()}
|
||||||
|
elif data and (isinstance(data, Iterable)
|
||||||
|
and not isinstance(data, str)
|
||||||
|
and not isinstance(data, bytes)):
|
||||||
|
# The iterable is not empty, we map each of its elements
|
||||||
return unique(type(data)([get_structure(item) for item in data]))
|
return unique(type(data)([get_structure(item) for item in data]))
|
||||||
return StrType(data)
|
# It's a leaf (or empty iterable),
|
||||||
|
# we return the name of its type
|
||||||
|
return StrType(data)
|
||||||
|
|
||||||
|
return extract_structure(data)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
@ -64,9 +97,11 @@ if __name__ == "__main__":
|
||||||
'2 same dict 1 other': [{'same':3, 'as':b'the other'},
|
'2 same dict 1 other': [{'same':3, 'as':b'the other'},
|
||||||
{'same':3, 'as':b'the other'},
|
{'same':3, 'as':b'the other'},
|
||||||
{'different':'from','the':'other'}],
|
{'different':'from','the':'other'}],
|
||||||
'play me': MaClasse}
|
'play me': MaClasse,
|
||||||
|
'Two folded keys':{'Fold me :)':[1,2,3,4,5],
|
||||||
|
'Fold me too':"folded, can't see me!"}}
|
||||||
|
|
||||||
structure = get_structure(nested)
|
structure = get_structure(nested, ['Fold me :)','Fold me too'], ' [+]')
|
||||||
|
|
||||||
print("The nested data:")
|
print("The nested data:")
|
||||||
pprint(nested)
|
pprint(nested)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue