Skip to content

Commit b0b9efc

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 d5e7f79 commit b0b9efc

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
@@ -36,7 +36,7 @@
3636
from .inherit import for_each_inherit
3737
from .misc import SelfPrintEvalContext
3838
from .pg import column_exists, get_value_or_en_translation, table_exists
39-
from .records import edit_view
39+
from .views import edit_view
4040

4141
# python3 shims
4242
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
@@ -42,7 +41,6 @@
4241
table_exists,
4342
target_of,
4443
)
45-
from .report import add_to_migration_reports
4644

4745
_logger = logging.getLogger(__name__)
4846

@@ -53,219 +51,6 @@
5351
basestring = unicode = str
5452

5553

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

28065

@@ -305,7 +90,7 @@ def remove_record(cr, name):
30590
# deleguate to the right method
30691
if model == "ir.ui.view":
30792
_logger.log(NEARLYWARN, "Removing view %r", name)
308-
return remove_view(cr, view_id=res_id)
93+
return views.remove_view(cr, view_id=res_id)
30994

31095
if model == "ir.ui.menu":
31196
_logger.log(NEARLYWARN, "Removing menu %r", name)
@@ -333,7 +118,7 @@ def remove_records(cr, model, ids):
333118
)
334119
if theme_copy_model == "ir.ui.view":
335120
for (view_id,) in cr.fetchall():
336-
remove_view(cr, view_id=view_id)
121+
views.remove_view(cr, view_id=view_id)
337122
else:
338123
remove_records(cr, theme_copy_model, [rid for (rid,) in cr.fetchall()])
339124

@@ -348,7 +133,7 @@ def remove_records(cr, model, ids):
348133
remove_menus(cr, [menu_id for (menu_id,) in cr.fetchall()])
349134
elif inh.model == "ir.ui.view":
350135
for (view_id,) in cr.fetchall():
351-
remove_view(cr, view_id=view_id)
136+
views.remove_view(cr, view_id=view_id)
352137
else:
353138
remove_records(cr, inh.model, [rid for (rid,) in cr.fetchall()])
354139

@@ -400,7 +185,7 @@ def _rm_refs(cr, model, ids=None):
400185
if ref_model == "ir.ui.view":
401186
cr.execute("SELECT id" + query_tail, [needle])
402187
for (view_id,) in cr.fetchall():
403-
remove_view(cr, view_id=view_id, silent=True)
188+
views.remove_view(cr, view_id=view_id, silent=True)
404189
elif ref_model == "ir.ui.menu":
405190
cr.execute("SELECT id" + query_tail, [needle])
406191
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
@@ -12,7 +12,7 @@
1212
except ImportError:
1313
from distutils.version import StrictVersion as Version # N.B. deprecated, will be removed in py3.12
1414

15-
from .views_convert import (
15+
from .convert import (
1616
ALL,
1717
BE,
1818
BS,

0 commit comments

Comments
 (0)