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():

Reply via email to