Odoo18-Base/odoo/addons/test_lint/tests/test_manifests.py
2025-01-06 10:57:38 +07:00

124 lines
5.3 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from ast import literal_eval
from os.path import join as opj
from odoo.modules import get_modules
from odoo.modules.module import _DEFAULT_MANIFEST, module_manifest, get_module_path
from odoo.tests import BaseCase
from odoo.tools.misc import file_open, file_path
_logger = logging.getLogger(__name__)
MANIFEST_KEYS = {
'name', 'icon', 'addons_path', 'license', # mandatory keys
*_DEFAULT_MANIFEST, # optional keys
'contributors', 'maintainer', 'url', # unused "informative" keys
}
class ManifestLinter(BaseCase):
def _load_manifest(self, module):
"""Do not rely on odoo/modules/module -> load_manifest
as we want to check manifests content, independently of the
values from _DEFAULT_MANIFEST added automatically by load_manifest
"""
mod_path = get_module_path(module, downloaded=True)
manifest_file = module_manifest(mod_path)
manifest_data = {}
with file_open(manifest_file, mode='r') as f:
manifest_data.update(literal_eval(f.read()))
return manifest_data
def test_manifests(self):
for module in get_modules():
with self.subTest(module=module):
manifest_data = self._load_manifest(module)
self._test_manifest_keys(module, manifest_data)
self._test_manifest_values(module, manifest_data)
def _test_manifest_keys(self, module, manifest_data):
manifest_keys = manifest_data.keys()
unknown_keys = manifest_keys - MANIFEST_KEYS
self.assertEqual(unknown_keys, set(), f"Unknown manifest keys in module {module!r}. Either there are typos or they must be white listed.")
def _test_manifest_values(self, module, manifest_data):
verified_keys = [
'application', 'auto_install',
'summary', 'description', 'author',
'demo', 'data', 'test',
# todo installable ?
]
if len(manifest_data.get('countries', [])) == 1 and 'l10n' not in module:
_logger.warning(
"Module %r specific to one single country %r should contain `l10n` in their name.",
module, manifest_data['countries'][0])
for key in manifest_data:
value = manifest_data[key]
if key in _DEFAULT_MANIFEST:
if key in verified_keys:
self.assertNotEqual(
value,
_DEFAULT_MANIFEST[key],
f"Setting manifest key {key} to the default manifest value for module {module!r}. "
"You can remove this key from the dict to reduce noise/inconsistencies between manifests specifications"
" and ease understanding of manifest content."
)
expected_type = type(_DEFAULT_MANIFEST[key])
if not isinstance(value, expected_type):
if key != 'auto_install':
_logger.warning(
"Wrong type for manifest value %s in module %s, expected %s",
key, module, expected_type)
elif not isinstance(value, list):
_logger.warning(
"Wrong type for manifest value %s in module %s, expected bool or list",
key, module)
else:
if key == 'countries':
self._test_manifest_countries_value(module, value)
elif key == 'icon':
self._test_manifest_icon_value(module, value)
def _test_manifest_icon_value(self, module, value):
self.assertTrue(
isinstance(value, str),
f"Wrong type for manifest value icon in module {module!r}, expected string",
)
self.assertNotEqual(
value,
f"/{module}/static/description/icon.png",
f"Setting manifest key icon to the default manifest value for module {module!r}. "
"You can remove this key from the dict to reduce noise/inconsistencies between manifests specifications"
" and ease understanding of manifest content."
)
if not value:
_logger.warning(
"Empty value specified as icon in manifest of module %r."
" Please specify a correct value or remove this key from the manifest.",
module)
else:
path_parts = value.split('/')
try:
file_path(opj(*path_parts[1:]))
except FileNotFoundError:
_logger.warning(
"Icon value specified in manifest of module %s wasn't found in given path."
" Please specify a correct value or remove this key from the manifest.",
module)
def _test_manifest_countries_value(self, module, values):
for value in values:
if value and len(value) != 2:
_logger.warning(
"Country value %s specified for the icon in manifest of module %s doesn't look like a country code"
"Please specify a correct value or remove this key from the manifest.",
value, module)