56 lines
1.8 KiB
Python
56 lines
1.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import ast
|
|
import itertools
|
|
import os
|
|
|
|
from . import lint_case
|
|
from odoo.tools.misc import file_open
|
|
|
|
class L10nChecker(lint_case.NodeVisitor):
|
|
def matches_tagged(self, node):
|
|
if isinstance(node, ast.Call):
|
|
if isinstance(node.func, ast.Attribute):
|
|
return node.func.attr == 'tagged'
|
|
if isinstance(node.func, ast.Name):
|
|
return node.func.id == 'tagged'
|
|
return False
|
|
|
|
def visit_ClassDef(self, node):
|
|
tags = {
|
|
arg.value
|
|
for deco in node.decorator_list
|
|
for arg in deco.args
|
|
if self.matches_tagged(deco)
|
|
}
|
|
if (
|
|
(len({'post_install_l10n', 'external_l10n'} & tags) != 1)
|
|
or ('post_install_l10n' in tags and 'post_install' not in tags)
|
|
# or ('post_install_l10n' not in tags and 'post_install' in tags)
|
|
or (('external_l10n' in tags) ^ ('external' in tags))
|
|
):
|
|
if any(
|
|
stmt.name.startswith('test_')
|
|
for stmt in node.body
|
|
if isinstance(stmt, ast.FunctionDef)
|
|
):
|
|
return [node]
|
|
return []
|
|
|
|
|
|
class L10nLinter(lint_case.LintCase):
|
|
def test_l10n_test_tags(self):
|
|
checker = L10nChecker()
|
|
rs = []
|
|
for path in self.iter_module_files('**/l10n_*/tests/*.py'):
|
|
with file_open(path, 'rb') as f:
|
|
t = ast.parse(f.read(), path)
|
|
rs.extend(zip(itertools.repeat(os.path.relpath(path)), checker.visit(t)))
|
|
|
|
rs.sort(key=lambda t: t[0])
|
|
assert not rs, "missing `post_install_l10n` tag at\n" + '\n'.join(
|
|
"- %s:%d" % (path, node.lineno)
|
|
for path, node in rs
|
|
)
|