changeset d8672f4b9e44 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset&node=d8672f4b9e44
description:
Test that all XML view and SVG icon files are used
issue10830
review375751002
diffstat:
CHANGELOG | 1 +
doc/ref/tools/misc.rst | 12 ++++++++++++
trytond/ir/ui/icon.py | 6 ++++--
trytond/tests/test_tools.py | 3 ++-
trytond/tests/test_tryton.py | 21 +++++++++++++++++++--
trytond/tools/__init__.py | 44 +++++++++++++++++++++++++++++++++-----------
trytond/tools/misc.py | 21 ++++++++++++++++-----
7 files changed, 87 insertions(+), 21 deletions(-)
diffs (218 lines):
diff -r 7fe68440fbc7 -r d8672f4b9e44 CHANGELOG
--- a/CHANGELOG Mon Apr 11 23:41:21 2022 +0200
+++ b/CHANGELOG Tue Apr 12 10:35:40 2022 +0200
@@ -1,3 +1,4 @@
+* Test all XML view and SVG icon files are used
* Add notification message
* Add validate_fields to ModelStorage
* Drop support for PyPy and psycopg2cffi
diff -r 7fe68440fbc7 -r d8672f4b9e44 doc/ref/tools/misc.rst
--- a/doc/ref/tools/misc.rst Mon Apr 11 23:41:21 2022 +0200
+++ b/doc/ref/tools/misc.rst Tue Apr 12 10:35:40 2022 +0200
@@ -4,6 +4,18 @@
Miscellaneous
=============
+.. method:: file_open(name[, mode[, subdir[, encoding]]])
+
+ Open the named file in subdir from the root directory.
+
+.. method:: find_path(name[, subdir])
+
+ Return the path of the named file in subdir from root directory.
+
+.. method:: find_dir(name[, subdir])
+
+ Return the path of the named directory in subdir from root directory.
+
.. method:: resolve(name)
Resolve a dotted name to a global object.
diff -r 7fe68440fbc7 -r d8672f4b9e44 trytond/ir/ui/icon.py
--- a/trytond/ir/ui/icon.py Mon Apr 11 23:41:21 2022 +0200
+++ b/trytond/ir/ui/icon.py Tue Apr 12 10:35:40 2022 +0200
@@ -53,6 +53,8 @@
def get_icon(self, name):
path = os.path.join(self.module, self.path.replace('/', os.sep))
- with file_open(path,
- subdir='modules', mode='r', encoding='utf-8') as fp:
+ with file_open(
+ path,
+ subdir='modules' if self.module not in {'ir', 'res'} else '',
+ mode='r', encoding='utf-8') as fp:
return fp.read()
diff -r 7fe68440fbc7 -r d8672f4b9e44 trytond/tests/test_tools.py
--- a/trytond/tests/test_tools.py Mon Apr 11 23:41:21 2022 +0200
+++ b/trytond/tests/test_tools.py Tue Apr 12 10:35:40 2022 +0200
@@ -128,7 +128,8 @@
with file_open('ir/__init__.py') as fp:
self.assertTrue(fp)
- with self.assertRaisesRegex(IOError, "File not found :"):
+ with self.assertRaisesRegex(
+ FileNotFoundError, "No such file or directory:"):
with file_open('ir/noexist'):
pass
diff -r 7fe68440fbc7 -r d8672f4b9e44 trytond/tests/test_tryton.py
--- a/trytond/tests/test_tryton.py Mon Apr 11 23:41:21 2022 +0200
+++ b/trytond/tests/test_tryton.py Tue Apr 12 10:35:40 2022 +0200
@@ -2,6 +2,7 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import doctest
+import glob
import inspect
import operator
import os
@@ -30,7 +31,7 @@
from trytond.model.fields import Function
from trytond.pool import Pool, isregisteredby
from trytond.pyson import PYSONDecoder, PYSONEncoder
-from trytond.tools import file_open, is_instance_method
+from trytond.tools import file_open, find_dir, is_instance_method
from trytond.transaction import Transaction
from trytond.wizard import StateAction, StateView
@@ -273,9 +274,17 @@
View = pool.get('ir.ui.view')
views = View.search([
('module', '=', self.module),
- ('model', '!=', ''),
])
+ directory = find_dir(
+ self.module,
+ subdir='modules' if self.module not in {'ir', 'res'} else '')
+ view_files = set(glob.glob(os.path.join(directory, 'view', '*.xml')))
for view in views:
+ if view.name:
+ view_files.discard(os.path.join(
+ directory, 'view', view.name + '.xml'))
+ if not view.model:
+ continue
with self.subTest(view=view):
if not view.inherit or view.inherit.model == view.model:
self.assertTrue(view.arch,
@@ -314,6 +323,7 @@
self.assertIn(button_name, Model._buttons.keys(),
msg="Button '%s' is not in %s._buttons"
% (button_name, Model.__name__))
+ self.assertFalse(view_files, msg="unused view files")
@with_transaction()
def test_icon(self):
@@ -321,9 +331,16 @@
pool = Pool()
Icon = pool.get('ir.ui.icon')
icons = Icon.search([('module', '=', self.module)])
+ directory = find_dir(
+ self.module,
+ subdir='modules' if self.module not in {'ir', 'res'} else '')
+ icon_files = set(glob.glob(os.path.join(directory, 'icons', '*.svg')))
for icon in icons:
+ icon_files.discard(os.path.join(
+ directory, icon.path.replace('/', os.sep)))
with self.subTest(icon=icon):
self.assertTrue(icon.icon)
+ self.assertFalse(icon_files, msg="unused icon files")
@with_transaction()
def test_rpc_callable(self):
diff -r 7fe68440fbc7 -r d8672f4b9e44 trytond/tools/__init__.py
--- a/trytond/tools/__init__.py Mon Apr 11 23:41:21 2022 +0200
+++ b/trytond/tools/__init__.py Tue Apr 12 10:35:40 2022 +0200
@@ -7,17 +7,11 @@
from .decimal_ import decistmt
from .misc import (
- escape_wildcard, file_open, firstline, get_smtp_server, grouped_slice,
- is_full_text, is_instance_method, lstrip_wildcard, reduce_domain,
- reduce_ids, remove_forbidden_chars, resolve, rstrip_wildcard, slugify,
- sortable_values, sql_pairing, strip_wildcard, unescape_wildcard)
-
-__all__ = ['file_open', 'get_smtp_server', 'reduce_ids',
- 'reduce_domain', 'grouped_slice', 'is_instance_method', 'resolve',
- 'strip_wildcard', 'lstrip_wildcard', 'rstrip_wildcard', 'slugify',
- 'decistmt', 'ClassProperty', 'cursor_dict', 'cached_property',
- 'sortable_values', 'escape_wildcard', 'unescape_wildcard', 'is_full_text',
- 'sql_pairing', 'firstline', 'remove_forbidden_chars']
+ escape_wildcard, file_open, find_dir, find_path, firstline,
+ get_smtp_server, grouped_slice, is_full_text, is_instance_method,
+ lstrip_wildcard, reduce_domain, reduce_ids, remove_forbidden_chars,
+ resolve, rstrip_wildcard, slugify, sortable_values, sql_pairing,
+ strip_wildcard, unescape_wildcard)
class ClassProperty(property):
@@ -33,3 +27,31 @@
break
for row in rows:
yield {d[0]: v for d, v in zip(cursor.description, row)}
+
+
+__all__ = [
+ ClassProperty,
+ cached_property,
+ cursor_dict,
+ decistmt,
+ escape_wildcard,
+ file_open,
+ find_dir,
+ find_path,
+ firstline,
+ get_smtp_server,
+ grouped_slice,
+ is_full_text,
+ is_instance_method,
+ lstrip_wildcard,
+ reduce_domain,
+ reduce_ids,
+ remove_forbidden_chars,
+ resolve,
+ rstrip_wildcard,
+ slugify,
+ sortable_values,
+ sql_pairing,
+ strip_wildcard,
+ unescape_wildcard,
+ ]
diff -r 7fe68440fbc7 -r d8672f4b9e44 trytond/tools/misc.py
--- a/trytond/tools/misc.py Mon Apr 11 23:41:21 2022 +0200
+++ b/trytond/tools/misc.py Tue Apr 12 10:35:40 2022 +0200
@@ -24,7 +24,13 @@
def file_open(name, mode="r", subdir='modules', encoding=None):
- """Open a file from the root dir, using a subdir folder."""
+ "Open a file from the root directory, using subdir folder"
+ path = find_path(name, subdir)
+ return io.open(path, mode, encoding=encoding)
+
+
+def find_path(name, subdir='modules', _test=os.path.isfile):
+ "Return path from the root directory, using subdir folder"
from trytond.modules import EGG_MODULES
root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -71,11 +77,16 @@
else:
name = secure_join(root_path, name)
- for i in (name, egg_name):
- if i and os.path.isfile(i):
- return io.open(i, mode, encoding=encoding)
+ for path in [name, egg_name]:
+ if path and _test(path):
+ return path
+ else:
+ raise FileNotFoundError("No such file or directory: %r" % name)
- raise IOError('File not found : %s ' % name)
+
+def find_dir(name, subdir='modules'):
+ "Return directory from the root directory, using subdir folder"
+ return find_path(name, subdir=subdir, _test=os.path.isdir)
def get_smtp_server():