From 05db4cee1f2795b112194f5d09f22867be66f79a Mon Sep 17 00:00:00 2001 From: trisdoan Date: Fri, 13 Dec 2024 13:29:45 +0700 Subject: [PATCH] [ADD] prefer-env-translation: Add new check for translation --- src/pylint_odoo/checkers/odoo_addons.py | 22 +++++++++++++++++++ .../test_repo/eighteen_module/README.rst | 1 + .../test_repo/eighteen_module/__init__.py | 2 ++ .../test_repo/eighteen_module/__manifest__.py | 12 ++++++++++ .../test_repo/eighteen_module/models.py | 14 ++++++++++++ .../test_repo/eighteen_module/utils.py | 9 ++++++++ tests/test_main.py | 13 +++++++++++ 7 files changed, 73 insertions(+) create mode 100644 testing/resources/test_repo/eighteen_module/README.rst create mode 100644 testing/resources/test_repo/eighteen_module/__init__.py create mode 100644 testing/resources/test_repo/eighteen_module/__manifest__.py create mode 100644 testing/resources/test_repo/eighteen_module/models.py create mode 100644 testing/resources/test_repo/eighteen_module/utils.py diff --git a/src/pylint_odoo/checkers/odoo_addons.py b/src/pylint_odoo/checkers/odoo_addons.py index e58ddc96..353eb4f4 100644 --- a/src/pylint_odoo/checkers/odoo_addons.py +++ b/src/pylint_odoo/checkers/odoo_addons.py @@ -264,6 +264,11 @@ "deprecated-odoo-model-method", CHECK_DESCRIPTION, ), + "W8161": ( + "Better using self.env._ for getting some performance improvement in some cases. More info at https://github.com/odoo/odoo/pull/174844", + "prefer-env-translation", + CHECK_DESCRIPTION, + ), } DFTL_MANIFEST_REQUIRED_KEYS = ["license"] @@ -832,6 +837,7 @@ def _get_assignation_nodes(self, node): "translation-field", "translation-positional-used", "translation-required", + "prefer-env-translation", ) def visit_call(self, node): if ( @@ -1009,6 +1015,17 @@ def visit_call(self, node): # Check just the following cases "%s %s..." self.add_message("translation-positional-used", node=node, args=(str2translate,)) + # prefer-env-translation: recommend to translate a string (_) with self.env._ + if ( + isinstance(arg, nodes.Const) + and not isinstance( + node.func, nodes.Attribute + ) # ensure it's not already called as attribute, e.g: self.env._() + and "fields" != self.get_func_lib(node.parent.func) + and self._is_instance_method(self.get_enclosing_function(node)) + ): + self.add_message("prefer-env-translation", node=node) + # SQL Injection if self._check_sql_injection_risky(node): self.add_message("sql-injection", node=node) @@ -1044,6 +1061,11 @@ def visit_call(self, node): if infer_node and infer_node.qname() == "itertools.groupby": self.add_message("bad-builtin-groupby", node=node) + @staticmethod + def _is_instance_method(node: FunctionDef) -> bool: + parent = getattr(node, "parent", False) + return isinstance(parent, ClassDef) and ("_name" in parent.locals or "_inherit" in parent.locals) + @utils.only_required_for_messages( "development-status-allowed", "license-allowed", diff --git a/testing/resources/test_repo/eighteen_module/README.rst b/testing/resources/test_repo/eighteen_module/README.rst new file mode 100644 index 00000000..5748659d --- /dev/null +++ b/testing/resources/test_repo/eighteen_module/README.rst @@ -0,0 +1 @@ +# Eighteen module for tests diff --git a/testing/resources/test_repo/eighteen_module/__init__.py b/testing/resources/test_repo/eighteen_module/__init__.py new file mode 100644 index 00000000..af38f37e --- /dev/null +++ b/testing/resources/test_repo/eighteen_module/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import utils diff --git a/testing/resources/test_repo/eighteen_module/__manifest__.py b/testing/resources/test_repo/eighteen_module/__manifest__.py new file mode 100644 index 00000000..bb0b5b8e --- /dev/null +++ b/testing/resources/test_repo/eighteen_module/__manifest__.py @@ -0,0 +1,12 @@ +{ + "name": "Eighteen module for tests", + "license": "AGPL-3", + "author": "Odoo Community Association (OCA)", + "version": "18.0.1.0.0", + "depends": [ + "base", + ], + "data": [ + "security/ir.model.access.csv", + ], +} diff --git a/testing/resources/test_repo/eighteen_module/models.py b/testing/resources/test_repo/eighteen_module/models.py new file mode 100644 index 00000000..a26986d0 --- /dev/null +++ b/testing/resources/test_repo/eighteen_module/models.py @@ -0,0 +1,14 @@ +from odoo import models, _, fields +from odoo.exceptions import UserError + + +class EighteenModel(models.Model): + _name = "eighteen.model" + + name = fields.Char(_("Näme")) + + def my_method7(self): + user_id = 1 + if user_id != 99: + # Method with translation + raise UserError(_("String with translation")) diff --git a/testing/resources/test_repo/eighteen_module/utils.py b/testing/resources/test_repo/eighteen_module/utils.py new file mode 100644 index 00000000..d00d673b --- /dev/null +++ b/testing/resources/test_repo/eighteen_module/utils.py @@ -0,0 +1,9 @@ +from odoo import exceptions, _ + + +def util_method(): + raise exceptions.ValidationError( + _( + "The request to the service timed out. Please contact the author of the app.", + ) + ) diff --git a/tests/test_main.py b/tests/test_main.py index e0cb6080..54bca46f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -472,6 +472,19 @@ def test_build_docstring(self): "The README was updated! Don't panic only failing for CI purposes. Run the same test again.", ) + def test_gettext_env(self): + extra_params = ["--disable=all", "--enable=prefer-env-translation"] + test_repo = os.path.join(self.root_path_modules, "eighteen_module") + + self.assertDictEqual( + self.run_pylint([test_repo], extra_params).linter.stats.by_msg, + {"prefer-env-translation": 1}, + ) + + # This check is only valid for Odoo 18.0 and upwards + extra_params.append("--valid-odoo-versions=18.0") + self.assertTrue(self.run_pylint([test_repo], extra_params).linter.stats.by_msg) + if __name__ == "__main__": unittest.main()