Skip to content

Commit 75fcdc4

Browse files
committed
[REF] util.views: create new package, move views-related code
Changes: - move `util.views_convert` -> `util.views.convert` - move records-related views helpers into `util.views.records` - move `util.convert_bootstrap` -> `util.views.bootstrap` - move some helpers from `util.records` -> `util.views.records` - add version checks for views/html conversion helpers
1 parent 9aa47bd commit 75fcdc4

File tree

10 files changed

+368
-324
lines changed

10 files changed

+368
-324
lines changed

src/util/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
from .records import *
1717
from .report import *
1818
from .specific import *
19+
from .views import *

src/util/domains.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
from .inherit import for_each_inherit
3232
from .misc import SelfPrintEvalContext
3333
from .pg import column_exists, get_value_or_en_translation, table_exists
34-
from .records import edit_view
34+
from .views import edit_view
3535

3636
# python3 shims
3737
try:

src/util/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@
2525

2626
# avoid namespace clash
2727
from .pg import rename_table as pg_rename_table
28-
from .records import _rm_refs, remove_records, remove_view, replace_record_references_batch
28+
from .records import _rm_refs, remove_records, replace_record_references_batch
2929
from .report import add_to_migration_reports
30+
from .views import remove_view
3031

3132
_logger = logging.getLogger(__name__)
3233

src/util/modules.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
from .models import delete_model
4040
from .orm import env, flush
4141
from .pg import column_exists, table_exists, target_of
42-
from .records import ref, remove_menus, remove_records, remove_view, replace_record_references_batch
42+
from .records import ref, remove_menus, remove_records, replace_record_references_batch
43+
from .views import remove_view
4344

4445
INSTALLED_MODULE_STATES = ("installed", "to install", "to upgrade")
4546
NO_AUTOINSTALL = str2bool(os.getenv("UPG_NO_AUTOINSTALL", "0")) if version_gte("15.0") else False

src/util/records.py

Lines changed: 6 additions & 221 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import logging
33
import os
44
import re
5-
from contextlib import contextmanager
65
from operator import itemgetter
76

87
import lxml
@@ -12,12 +11,12 @@
1211
from odoo import release
1312
from odoo.tools.convert import xml_import
1413
from odoo.tools.misc import file_open
15-
from odoo.tools.translate import xml_translate
1614
except ImportError:
1715
from openerp import release
1816
from openerp.tools.convert import xml_import
1917
from openerp.tools.misc import file_open
2018

19+
from . import views
2120
from .const import NEARLYWARN
2221
from .exceptions import MigrationError
2322
from .helpers import _get_theme_models, _ir_values_value, _validate_model, model_of_table, table_of_model
@@ -41,7 +40,6 @@
4140
table_exists,
4241
target_of,
4342
)
44-
from .report import add_to_migration_reports
4543

4644
_logger = logging.getLogger(__name__)
4745

@@ -52,219 +50,6 @@
5250
basestring = unicode = str
5351

5452

55-
def remove_view(cr, xml_id=None, view_id=None, silent=False, key=None):
56-
"""
57-
Recursively delete the given view and its inherited views, as long as they
58-
are part of a module. Will crash as soon as a custom view exists anywhere
59-
in the hierarchy.
60-
61-
Also handle multi-website COWed views.
62-
"""
63-
assert bool(xml_id) ^ bool(view_id)
64-
if xml_id:
65-
view_id = ref(cr, xml_id)
66-
if view_id:
67-
module, _, name = xml_id.partition(".")
68-
cr.execute("SELECT model FROM ir_model_data WHERE module=%s AND name=%s", [module, name])
69-
70-
[model] = cr.fetchone()
71-
if model != "ir.ui.view":
72-
raise ValueError("%r should point to a 'ir.ui.view', not a %r" % (xml_id, model))
73-
else:
74-
# search matching xmlid for logging or renaming of custom views
75-
xml_id = "?"
76-
if not key:
77-
cr.execute("SELECT module, name FROM ir_model_data WHERE model='ir.ui.view' AND res_id=%s", [view_id])
78-
if cr.rowcount:
79-
xml_id = "%s.%s" % cr.fetchone()
80-
81-
# From given or determined xml_id, the views duplicated in a multi-website
82-
# context are to be found and removed.
83-
if xml_id != "?" and column_exists(cr, "ir_ui_view", "key"):
84-
cr.execute("SELECT id FROM ir_ui_view WHERE key = %s AND id != %s", [xml_id, view_id])
85-
for [v_id] in cr.fetchall():
86-
remove_view(cr, view_id=v_id, silent=silent, key=xml_id)
87-
88-
if not view_id:
89-
return
90-
91-
cr.execute(
92-
"""
93-
SELECT v.id, x.module || '.' || x.name, v.name
94-
FROM ir_ui_view v LEFT JOIN
95-
ir_model_data x ON (v.id = x.res_id AND x.model = 'ir.ui.view' AND x.module !~ '^_')
96-
WHERE v.inherit_id = %s;
97-
""",
98-
[view_id],
99-
)
100-
for child_id, child_xml_id, child_name in cr.fetchall():
101-
if child_xml_id:
102-
if not silent:
103-
_logger.info(
104-
"remove deprecated built-in view %s (ID %s) as parent view %s (ID %s) is going to be removed",
105-
child_xml_id,
106-
child_id,
107-
xml_id,
108-
view_id,
109-
)
110-
remove_view(cr, child_xml_id, silent=True)
111-
else:
112-
if not silent:
113-
_logger.warning(
114-
"deactivate deprecated custom view with ID %s as parent view %s (ID %s) is going to be removed",
115-
child_id,
116-
xml_id,
117-
view_id,
118-
)
119-
disable_view_query = """
120-
UPDATE ir_ui_view
121-
SET name = (name || ' - old view, inherited from ' || %%s),
122-
inherit_id = NULL
123-
%s
124-
WHERE id = %%s
125-
"""
126-
# In 8.0, disabling requires setting mode to 'primary'
127-
extra_set_sql = ""
128-
if column_exists(cr, "ir_ui_view", "mode"):
129-
extra_set_sql = ", mode = 'primary' "
130-
131-
# Column was not present in v7 and it's older version
132-
if column_exists(cr, "ir_ui_view", "active"):
133-
extra_set_sql += ", active = false "
134-
135-
disable_view_query = disable_view_query % extra_set_sql
136-
cr.execute(disable_view_query, (key or xml_id, child_id))
137-
add_to_migration_reports(
138-
{"id": child_id, "name": child_name},
139-
"Disabled views",
140-
)
141-
if not silent:
142-
_logger.info("remove deprecated %s view %s (ID %s)", key and "COWed" or "built-in", key or xml_id, view_id)
143-
144-
remove_records(cr, "ir.ui.view", [view_id])
145-
146-
147-
@contextmanager
148-
def edit_view(cr, xmlid=None, view_id=None, skip_if_not_noupdate=True, active=True):
149-
"""Contextmanager that may yield etree arch of a view.
150-
As it may not yield, you must use `skippable_cm`
151-
152-
with util.skippable_cm(), util.edit_view(cr, 'xml.id') as arch:
153-
arch.attrib['string'] = 'My Form'
154-
155-
When view_id is passed to identify a view, view's arch will always yield to be edited because
156-
we assume that xmlid for such view does not exist to check its noupdate flag.
157-
158-
If view's noupdate=false then the arch will not be yielded for edit unless skip_if_not_noupdate=False,
159-
because when noupdate=False we assume it is a standard view that will be updated by the ORM later on anyways.
160-
161-
If view's noupdate=True, the view will be yielded for edit.
162-
163-
If the `active` argument is not None, the view will be (de)activated accordingly.
164-
165-
For more details, see discussion in: https://github.com/odoo/upgrade-specific/pull/4216
166-
"""
167-
assert bool(xmlid) ^ bool(view_id), "You Must specify either xmlid or view_id"
168-
noupdate = True
169-
if xmlid:
170-
if "." not in xmlid:
171-
raise ValueError("Please use fully qualified name <module>.<name>")
172-
173-
module, _, name = xmlid.partition(".")
174-
cr.execute(
175-
"""
176-
SELECT res_id, noupdate
177-
FROM ir_model_data
178-
WHERE module = %s
179-
AND name = %s
180-
""",
181-
[module, name],
182-
)
183-
data = cr.fetchone()
184-
if data:
185-
view_id, noupdate = data
186-
187-
if view_id and not (skip_if_not_noupdate and not noupdate):
188-
arch_col = "arch_db" if column_exists(cr, "ir_ui_view", "arch_db") else "arch"
189-
jsonb_column = column_type(cr, "ir_ui_view", arch_col) == "jsonb"
190-
cr.execute(
191-
"""
192-
SELECT {arch}
193-
FROM ir_ui_view
194-
WHERE id=%s
195-
""".format(
196-
arch=arch_col,
197-
),
198-
[view_id],
199-
)
200-
[arch] = cr.fetchone() or [None]
201-
if arch:
202-
203-
def parse(arch):
204-
arch = arch.encode("utf-8") if isinstance(arch, unicode) else arch
205-
return lxml.etree.fromstring(arch.replace(b"&#13;\n", b"\n"))
206-
207-
if jsonb_column:
208-
209-
def get_trans_terms(value):
210-
terms = []
211-
xml_translate(terms.append, value)
212-
return terms
213-
214-
translation_terms = {lang: get_trans_terms(value) for lang, value in arch.items()}
215-
arch_etree = parse(arch["en_US"])
216-
yield arch_etree
217-
new_arch = lxml.etree.tostring(arch_etree, encoding="unicode")
218-
terms_en = translation_terms["en_US"]
219-
arch_column_value = Json(
220-
{
221-
lang: xml_translate(dict(zip(terms_en, terms)).get, new_arch)
222-
for lang, terms in translation_terms.items()
223-
}
224-
)
225-
else:
226-
arch_etree = parse(arch)
227-
yield arch_etree
228-
arch_column_value = lxml.etree.tostring(arch_etree, encoding="unicode")
229-
230-
set_active = ", active={}".format(bool(active)) if active is not None else ""
231-
cr.execute(
232-
"UPDATE ir_ui_view SET {arch}=%s{set_active} WHERE id=%s".format(arch=arch_col, set_active=set_active),
233-
[arch_column_value, view_id],
234-
)
235-
236-
237-
def add_view(cr, name, model, view_type, arch_db, inherit_xml_id=None, priority=16):
238-
inherit_id = None
239-
if inherit_xml_id:
240-
inherit_id = ref(cr, inherit_xml_id)
241-
if not inherit_id:
242-
raise ValueError(
243-
"Unable to add view '%s' because its inherited view '%s' cannot be found!" % (name, inherit_xml_id)
244-
)
245-
arch_col = "arch_db" if column_exists(cr, "ir_ui_view", "arch_db") else "arch"
246-
jsonb_column = column_type(cr, "ir_ui_view", arch_col) == "jsonb"
247-
arch_column_value = Json({"en_US": arch_db}) if jsonb_column else arch_db
248-
cr.execute(
249-
"""
250-
INSERT INTO ir_ui_view(name, "type", model, inherit_id, mode, active, priority, %s)
251-
VALUES(%%(name)s, %%(view_type)s, %%(model)s, %%(inherit_id)s, %%(mode)s, 't', %%(priority)s, %%(arch_db)s)
252-
RETURNING id
253-
"""
254-
% arch_col,
255-
{
256-
"name": name,
257-
"view_type": view_type,
258-
"model": model,
259-
"inherit_id": inherit_id,
260-
"mode": "extension" if inherit_id else "primary",
261-
"priority": priority,
262-
"arch_db": arch_column_value,
263-
},
264-
)
265-
return cr.fetchone()[0]
266-
267-
26853
# fmt:off
26954
if version_gte("saas~14.3"):
27055
def remove_asset(cr, name):
@@ -273,7 +58,7 @@ def remove_asset(cr, name):
27358
remove_records(cr, "ir.asset", [aid for aid, in cr.fetchall()])
27459
else:
27560
def remove_asset(cr, name):
276-
remove_view(cr, name, silent=True)
61+
views.remove_view(cr, name, silent=True)
27762
# fmt:on
27863

27964

@@ -304,7 +89,7 @@ def remove_record(cr, name):
30489
# deleguate to the right method
30590
if model == "ir.ui.view":
30691
_logger.log(NEARLYWARN, "Removing view %r", name)
307-
return remove_view(cr, view_id=res_id)
92+
return views.remove_view(cr, view_id=res_id)
30893

30994
if model == "ir.ui.menu":
31095
_logger.log(NEARLYWARN, "Removing menu %r", name)
@@ -332,7 +117,7 @@ def remove_records(cr, model, ids):
332117
)
333118
if theme_copy_model == "ir.ui.view":
334119
for (view_id,) in cr.fetchall():
335-
remove_view(cr, view_id=view_id)
120+
views.remove_view(cr, view_id=view_id)
336121
else:
337122
remove_records(cr, theme_copy_model, [rid for rid, in cr.fetchall()])
338123

@@ -347,7 +132,7 @@ def remove_records(cr, model, ids):
347132
remove_menus(cr, [menu_id for menu_id, in cr.fetchall()])
348133
elif inh.model == "ir.ui.view":
349134
for (view_id,) in cr.fetchall():
350-
remove_view(cr, view_id=view_id)
135+
views.remove_view(cr, view_id=view_id)
351136
else:
352137
remove_records(cr, inh.model, [rid for rid, in cr.fetchall()])
353138

@@ -399,7 +184,7 @@ def _rm_refs(cr, model, ids=None):
399184
if ref_model == "ir.ui.view":
400185
cr.execute("SELECT id" + query_tail, [needle])
401186
for (view_id,) in cr.fetchall():
402-
remove_view(cr, view_id=view_id, silent=True)
187+
views.remove_view(cr, view_id=view_id, silent=True)
403188
elif ref_model == "ir.ui.menu":
404189
cr.execute("SELECT id" + query_tail, [needle])
405190
menu_ids = tuple(m[0] for m in cr.fetchall())

src/util/views/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .records import *

src/util/convert_bootstrap.py renamed to src/util/views/bootstrap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
except ImportError:
1212
from distutils.version import StrictVersion as Version # N.B. deprecated, will be removed in py3.12
1313

14-
from .views_convert import (
14+
from .convert import (
1515
ALL,
1616
BE,
1717
BS,

0 commit comments

Comments
 (0)