diff --git a/frappe/__init__.py b/frappe/__init__.py index 37c282f04a..10c8afbf23 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -55,29 +55,23 @@ controllers = {} class _dict(dict): """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): 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""" - super(_dict, self).update(d) + + super().update(*args, **kwargs) return self def copy(self): - return _dict(dict(self).copy()) + return _dict(self) def _(msg, lang=None, context=None): diff --git a/frappe/model/meta.py b/frappe/model/meta.py index c363e63f4f..407f7d0811 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -134,24 +134,22 @@ class Meta(Document): def as_dict(self, no_nulls=False): def serialize(doc): out = {} - for key in doc.__dict__: - value = doc.__dict__.get(key) - + for key, value in doc.__dict__.items(): 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 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 # set empty lists for unset 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] = [] return out