From 594e653347e3edef07d5074b7a4eb98ab48f1f37 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 30 Mar 2022 10:15:34 +0530 Subject: [PATCH 1/5] refactor: improved `frappe._dict` --- frappe/__init__.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 37c282f04a..e2c8fc5413 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -55,15 +55,9 @@ 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 + __getattr__ = dict.get + __setattr__ = dict.__setitem__ + __delattr__ = dict.__delitem__ def __getstate__(self): return self @@ -73,11 +67,12 @@ class _dict(dict): def update(self, d): """update and return self -- the missing dict feature in python""" - super(_dict, self).update(d) + + super().update(d) return self def copy(self): - return _dict(dict(self).copy()) + return _dict(self) def _(msg, lang=None, context=None): From d2dfc8c3357682a1ad0366d5bbf85e5ce4c225f1 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 4 Apr 2022 10:16:09 +0530 Subject: [PATCH 2/5] fix: define `__slots__` to avoid `__dict__` creation --- frappe/__init__.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index e2c8fc5413..10c8afbf23 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -55,20 +55,19 @@ controllers = {} class _dict(dict): """dict like object that exposes keys as attributes""" + __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().update(d) + super().update(*args, **kwargs) return self def copy(self): From 93051389b1cdf06fb379ff9d9bc70291fbbeca30 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Fri, 8 Apr 2022 01:54:40 +0530 Subject: [PATCH 3/5] fix: use `isinstance` instead of looping over `__dict__` --- frappe/model/meta.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/frappe/model/meta.py b/frappe/model/meta.py index c363e63f4f..5031f7f901 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -134,24 +134,23 @@ 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 ( + isinstance(value, (str, int, float, datetime, list, tuple)) + or (not no_nulls and value is None) ): 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 From 38959637e75c9f1ed29de7fc79bf5d4e98a73e6c Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 13 Apr 2022 11:40:35 +0530 Subject: [PATCH 4/5] perf: move less expensive condition first Co-authored-by: gavin --- frappe/model/meta.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 5031f7f901..760182ac39 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -143,8 +143,8 @@ class Meta(Document): value = [serialize(d) for d in value] if ( - isinstance(value, (str, int, float, datetime, list, tuple)) - or (not no_nulls and value is None) + (not no_nulls and value is None) + or isinstance(value, (str, int, float, datetime, list, tuple)) ): out[key] = value From 77879933ce113006dddf27e459972aff2dc9f5e8 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 13 Apr 2022 13:21:01 +0530 Subject: [PATCH 5/5] style: make changes as per linter --- frappe/model/meta.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/model/meta.py b/frappe/model/meta.py index 760182ac39..407f7d0811 100644 --- a/frappe/model/meta.py +++ b/frappe/model/meta.py @@ -142,9 +142,8 @@ class Meta(Document): value = [serialize(d) for d in value] - if ( - (not no_nulls and value is None) - or isinstance(value, (str, int, float, datetime, list, tuple)) + if (not no_nulls and value is None) or isinstance( + value, (str, int, float, datetime, list, tuple) ): out[key] = value