refactor!: improved `frappe._dict`version-14
@@ -55,29 +55,23 @@ controllers = {} | |||||
class _dict(dict): | class _dict(dict): | ||||
"""dict like object that exposes keys as attributes""" | """dict like object that exposes keys as attributes""" | ||||
def __getattr__(self, key): | |||||
ret = self.get(key) | |||||
# "__deepcopy__" exception added to fix frappe#14833 via DFP | |||||
if not ret and key.startswith("__") and key != "__deepcopy__": | |||||
raise AttributeError() | |||||
return ret | |||||
def __setattr__(self, key, value): | |||||
self[key] = value | |||||
__slots__ = () | |||||
__getattr__ = dict.get | |||||
__setattr__ = dict.__setitem__ | |||||
__delattr__ = dict.__delitem__ | |||||
__setstate__ = dict.update | |||||
def __getstate__(self): | def __getstate__(self): | ||||
return self | return self | ||||
def __setstate__(self, d): | |||||
self.update(d) | |||||
def update(self, d): | |||||
def update(self, *args, **kwargs): | |||||
"""update and return self -- the missing dict feature in python""" | """update and return self -- the missing dict feature in python""" | ||||
super(_dict, self).update(d) | |||||
super().update(*args, **kwargs) | |||||
return self | return self | ||||
def copy(self): | def copy(self): | ||||
return _dict(dict(self).copy()) | |||||
return _dict(self) | |||||
def _(msg, lang=None, context=None): | def _(msg, lang=None, context=None): | ||||
@@ -134,24 +134,22 @@ class Meta(Document): | |||||
def as_dict(self, no_nulls=False): | def as_dict(self, no_nulls=False): | ||||
def serialize(doc): | def serialize(doc): | ||||
out = {} | out = {} | ||||
for key in doc.__dict__: | |||||
value = doc.__dict__.get(key) | |||||
for key, value in doc.__dict__.items(): | |||||
if isinstance(value, (list, tuple)): | if isinstance(value, (list, tuple)): | ||||
if len(value) > 0 and hasattr(value[0], "__dict__"): | |||||
value = [serialize(d) for d in value] | |||||
else: | |||||
if not value or not isinstance(value[0], BaseDocument): | |||||
# non standard list object, skip | # non standard list object, skip | ||||
continue | continue | ||||
if isinstance(value, (str, int, float, datetime, list, tuple)) or ( | |||||
not no_nulls and value is None | |||||
value = [serialize(d) for d in value] | |||||
if (not no_nulls and value is None) or isinstance( | |||||
value, (str, int, float, datetime, list, tuple) | |||||
): | ): | ||||
out[key] = value | out[key] = value | ||||
# set empty lists for unset table fields | # set empty lists for unset table fields | ||||
for table_field in DOCTYPE_TABLE_FIELDS: | for table_field in DOCTYPE_TABLE_FIELDS: | ||||
if not out.get(table_field.fieldname): | |||||
if out.get(table_field.fieldname) is None: | |||||
out[table_field.fieldname] = [] | out[table_field.fieldname] = [] | ||||
return out | return out | ||||