Skip to content

Commit 7d2fc82

Browse files
LucasLefevrerrahir
authored andcommitted
[IMP] util/fields: move context utils to their own file
Currently, context related functions are only used in specific fields utils fonction. They are inlined there. In the next commit, adapting and cleaning the context is also required to upgrade spreadsheet files. This commit moves the utility functions to their own file to be able to use them else where.
1 parent 0d7d609 commit 7d2fc82

File tree

2 files changed

+104
-90
lines changed

2 files changed

+104
-90
lines changed

src/util/context.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# python3 shims
4+
try:
5+
basestring # noqa: B018
6+
except NameError:
7+
basestring = str
8+
9+
10+
_CONTEXT_KEYS_TO_CLEAN = (
11+
"group_by",
12+
"pivot_measures",
13+
"pivot_column_groupby",
14+
"pivot_row_groupby",
15+
"graph_groupbys",
16+
"orderedBy",
17+
)
18+
19+
def clean_context(context, fieldname):
20+
"""Remove (in place) all references to the field in the context dictionary."""
21+
22+
def filter_value(key, value):
23+
if key == "orderedBy" and isinstance(value, dict):
24+
res = {k: (filter_value(None, v) if k == "name" else v) for k, v in value.items()}
25+
# return if name didn't match fieldname
26+
return res if "name" not in res or res["name"] is not None else None
27+
if not isinstance(value, basestring):
28+
# if not a string, ignore it
29+
return value
30+
if value.split(":")[0] != fieldname:
31+
# only return if not matching fieldname
32+
return value
33+
return None # value filtered out
34+
35+
if not isinstance(context, dict):
36+
return False
37+
38+
changed = False
39+
for key in _CONTEXT_KEYS_TO_CLEAN:
40+
if context.get(key):
41+
context_part = [filter_value(key, e) for e in context[key]]
42+
changed |= context_part != context[key]
43+
context[key] = [e for e in context_part if e is not None]
44+
45+
for vt in ["pivot", "graph", "cohort"]:
46+
key = "{}_measure".format(vt)
47+
if key in context:
48+
new_value = filter_value(key, context[key])
49+
changed |= context[key] != new_value
50+
context[key] = new_value if new_value is not None else "id"
51+
52+
if vt in context:
53+
changed |= clean_context(context[vt])
54+
55+
return changed
56+
57+
def adapt_context(context, old, new):
58+
"""Replace (in place) all references to field `old` to `new` in the context dictionary."""
59+
60+
# adapt (in place) dictionary values
61+
if not isinstance(context, dict):
62+
return
63+
64+
for key in _CONTEXT_KEYS_TO_CLEAN:
65+
if context.get(key):
66+
context[key] = [_adapt_context_value(key, e, old, new) for e in context[key]]
67+
68+
for vt in ["pivot", "graph", "cohort"]:
69+
key = "{}_measure".format(vt)
70+
if key in context:
71+
context[key] = _adapt_context_value(key, context[key], old, new)
72+
73+
if vt in context:
74+
adapt_context(context[vt], old, new)
75+
76+
def_old = "default_{}".format(old)
77+
def_new = "default_{}".format(new)
78+
79+
if def_old in context:
80+
context[def_new] = context.pop(def_old)
81+
82+
83+
def _adapt_context_value(key, value, old, new):
84+
if key == "orderedBy" and isinstance(value, dict):
85+
# only adapt the "name" key
86+
return {k: (_adapt_context_value(None, v, old, new) if k == "name" else v) for k, v in value.items()}
87+
88+
if not isinstance(value, basestring):
89+
# ignore if not a string
90+
return value
91+
92+
parts = value.split(":", 1)
93+
if parts[0] != old:
94+
# if not match old, leave it
95+
return value
96+
# change to new, and return it
97+
parts[0] = new
98+
return ":".join(parts)

src/util/fields.py

Lines changed: 6 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def make_index_name(table_name, column_name):
3838

3939

4040
from .const import ENVIRON
41+
from .context import adapt_context, clean_context
4142
from .domains import _adapt_one_domain, _replace_path, _valid_path_to, adapt_domains
4243
from .exceptions import SleepyDeveloperError
4344
from .helpers import _dashboard_actions, _validate_model, resolve_model_fields_path, table_of_model
@@ -62,24 +63,14 @@ def make_index_name(table_name, column_name):
6263

6364
# python3 shims
6465
try:
65-
basestring # noqa: B018
66+
unicode # noqa: B018
6667
except NameError:
67-
basestring = unicode = str
68+
unicode = str
6869

6970

7071
_logger = logging.getLogger(__name__)
7172
IMD_FIELD_PATTERN = "field_%s__%s" if version_gte("saas~11.2") else "field_%s_%s"
7273

73-
_CONTEXT_KEYS_TO_CLEAN = (
74-
"group_by",
75-
"pivot_measures",
76-
"pivot_column_groupby",
77-
"pivot_row_groupby",
78-
"graph_groupbys",
79-
"orderedBy",
80-
)
81-
82-
8374
def ensure_m2o_func_field_data(cr, src_table, column, dst_table):
8475
"""
8576
Fix broken m2o relations.
@@ -123,46 +114,10 @@ def remove_field(cr, model, fieldname, cascade=False, drop_column=True, skip_inh
123114

124115
ENVIRON["__renamed_fields"][model][fieldname] = None
125116

126-
def filter_value(key, value):
127-
if key == "orderedBy" and isinstance(value, dict):
128-
res = {k: (filter_value(None, v) if k == "name" else v) for k, v in value.items()}
129-
# return if name didn't match fieldname
130-
return res if "name" not in res or res["name"] is not None else None
131-
if not isinstance(value, basestring):
132-
# if not a string, ignore it
133-
return value
134-
if value.split(":")[0] != fieldname:
135-
# only return if not matching fieldname
136-
return value
137-
return None # value filtered out
138-
139-
def clean_context(context):
140-
if not isinstance(context, dict):
141-
return False
142-
143-
changed = False
144-
for key in _CONTEXT_KEYS_TO_CLEAN:
145-
if context.get(key):
146-
context_part = [filter_value(key, e) for e in context[key]]
147-
changed |= context_part != context[key]
148-
context[key] = [e for e in context_part if e is not None]
149-
150-
for vt in ["pivot", "graph", "cohort"]:
151-
key = "{}_measure".format(vt)
152-
if key in context:
153-
new_value = filter_value(key, context[key])
154-
changed |= context[key] != new_value
155-
context[key] = new_value if new_value is not None else "id"
156-
157-
if vt in context:
158-
changed |= clean_context(context[vt])
159-
160-
return changed
161-
162117
# clean dashboard's contexts
163118
for id_, action in _dashboard_actions(cr, r"\y{}\y".format(fieldname), model):
164119
context = safe_eval(action.get("context", "{}"), SelfPrintEvalContext(), nocopy=True)
165-
changed = clean_context(context)
120+
changed = clean_context(context, fieldname)
166121
action.set("context", unicode(context))
167122
if changed:
168123
add_to_migration_reports(
@@ -176,7 +131,7 @@ def clean_context(context):
176131
)
177132
for id_, name, context_s in cr.fetchall():
178133
context = safe_eval(context_s or "{}", SelfPrintEvalContext(), nocopy=True)
179-
changed = clean_context(context)
134+
changed = clean_context(context, fieldname)
180135
cr.execute("UPDATE ir_filters SET context = %s WHERE id = %s", [unicode(context), id_])
181136
if changed:
182137
add_to_migration_reports(("ir.filters", id_, name), "Filters/Dashboards")
@@ -1146,50 +1101,11 @@ def _update_field_usage_multi(cr, models, old, new, domain_adapter=None, skip_in
11461101
# ir.ui.view.custom
11471102
# adapt the context. The domain will be done by `adapt_domain`
11481103
eval_context = SelfPrintEvalContext()
1149-
def_old = "default_{}".format(old)
1150-
def_new = "default_{}".format(new)
11511104
match = "{0[old]}|{0[def_old]}".format(p)
11521105

1153-
def adapt_value(key, value):
1154-
if key == "orderedBy" and isinstance(value, dict):
1155-
# only adapt the "name" key
1156-
return {k: (adapt_value(None, v) if k == "name" else v) for k, v in value.items()}
1157-
1158-
if not isinstance(value, basestring):
1159-
# ignore if not a string
1160-
return value
1161-
1162-
parts = value.split(":", 1)
1163-
if parts[0] != old:
1164-
# if not match old, leave it
1165-
return value
1166-
# change to new, and return it
1167-
parts[0] = new
1168-
return ":".join(parts)
1169-
1170-
def adapt_dict(d):
1171-
# adapt (in place) dictionary values
1172-
if not isinstance(d, dict):
1173-
return
1174-
1175-
for key in _CONTEXT_KEYS_TO_CLEAN:
1176-
if d.get(key):
1177-
d[key] = [adapt_value(key, e) for e in d[key]]
1178-
1179-
for vt in ["pivot", "graph", "cohort"]:
1180-
key = "{}_measure".format(vt)
1181-
if key in d:
1182-
d[key] = adapt_value(key, d[key])
1183-
1184-
if vt in d:
1185-
adapt_dict(d[vt])
1186-
11871106
for _, act in _dashboard_actions(cr, match, *only_models or ()):
11881107
context = safe_eval(act.get("context", "{}"), eval_context, nocopy=True)
1189-
adapt_dict(context)
1190-
1191-
if def_old in context:
1192-
context[def_new] = context.pop(def_old)
1108+
adapt_context(context, old, new)
11931109
act.set("context", unicode(context))
11941110

11951111
# domains, related and inhited models

0 commit comments

Comments
 (0)