diff --git a/README.md b/README.md index 2dd9abf3..bbe37415 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ no-wizard-in-models | No wizard class for model directory. See the complete stru no-write-in-compute | Compute method calling `write`. Use `update` instead. | E8135 odoo-addons-relative-import | Same Odoo module absolute import. You should use relative import with "." instead of "odoo.addons.%s" | W8150 odoo-exception-warning | `odoo.exceptions.Warning` is a deprecated alias to `odoo.exceptions.UserError` use `from odoo.exceptions import UserError` | R8101 +prefer-env-translation | Better using self.env._ More info at https://github.com/odoo/odoo/pull/174844 | W8161 print-used | Print used. Use `logger` instead. | W8116 prohibited-method-override | Prohibited override of "%s" method. | W8107 renamed-field-parameter | Field parameter "%s" is no longer supported. Use "%s" instead. | W8111 @@ -122,6 +123,10 @@ To know what version of odoo are you running pylint needs the parameter with particular odoo version e.g. `"16.0"` +Check valid only for odoo >= 18.0 + + prefer-env-translation + Checks valid only for odoo >= 14.0 translation-format-interpolation @@ -144,20 +149,20 @@ Checks valid only for odoo <= 13.0 * attribute-deprecated - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L105 attribute "_columns" deprecated - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L106 attribute "_defaults" deprecated - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L107 attribute "length" deprecated + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L108 attribute "_columns" deprecated + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L109 attribute "_defaults" deprecated + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L110 attribute "length" deprecated * attribute-string-redundant - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L161 The attribute string is redundant. String parameter equal to name of variable - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L209 The attribute string is redundant. String parameter equal to name of variable - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L219 The attribute string is redundant. String parameter equal to name of variable + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L164 The attribute string is redundant. String parameter equal to name of variable + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L212 The attribute string is redundant. String parameter equal to name of variable + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L222 The attribute string is redundant. String parameter equal to name of variable * bad-builtin-groupby - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L110 Used builtin function `itertools.groupby`. Prefer `odoo.tools.groupby` instead. More info about https://github.com/odoo/odoo/issues/105376 - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L111 Used builtin function `itertools.groupby`. Prefer `odoo.tools.groupby` instead. More info about https://github.com/odoo/odoo/issues/105376 + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L113 Used builtin function `itertools.groupby`. Prefer `odoo.tools.groupby` instead. More info about https://github.com/odoo/odoo/issues/105376 + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L114 Used builtin function `itertools.groupby`. Prefer `odoo.tools.groupby` instead. More info about https://github.com/odoo/odoo/issues/105376 * consider-merging-classes-inherited @@ -166,13 +171,13 @@ Checks valid only for odoo <= 13.0 * context-overridden - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L192 Context overridden using dict. Better using kwargs `with_context(**{'overwrite_context': True})` or `with_context(key=value)` - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L194 Context overridden using dict. Better using kwargs `with_context(**ctx)` or `with_context(key=value)` - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L196 Context overridden using dict. Better using kwargs `with_context(**ctx2)` or `with_context(key=value)` + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L195 Context overridden using dict. Better using kwargs `with_context(**{'overwrite_context': True})` or `with_context(key=value)` + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L197 Context overridden using dict. Better using kwargs `with_context(**ctx)` or `with_context(key=value)` + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L199 Context overridden using dict. Better using kwargs `with_context(**ctx2)` or `with_context(key=value)` * deprecated-odoo-model-method - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L91 fields_view_get has been deprecated by Odoo. Please look for alternatives. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L94 fields_view_get has been deprecated by Odoo. Please look for alternatives. - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/eleven_module/models.py#L17 fields_view_get has been deprecated by Odoo. Please look for alternatives. * development-status-allowed @@ -187,15 +192,15 @@ Checks valid only for odoo <= 13.0 * external-request-timeout - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L690 Use of external request method `requests.delete` without timeout. It could wait for a long time - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L691 Use of external request method `requests.get` without timeout. It could wait for a long time - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L692 Use of external request method `requests.head` without timeout. It could wait for a long time + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L1001 Use of external request method `odoo.addons.iap.models.iap.jsonrpc` without timeout. It could wait for a long time + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L1002 Use of external request method `odoo.addons.iap.models.iap.jsonrpc` without timeout. It could wait for a long time + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L1003 Use of external request method `odoo.addons.iap.models.iap.jsonrpc` without timeout. It could wait for a long time * invalid-commit - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L409 Use of cr.commit() directly - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#never-commit-the-transaction - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L410 Use of cr.commit() directly - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#never-commit-the-transaction - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L411 Use of cr.commit() directly - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#never-commit-the-transaction + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L540 Use of cr.commit() directly - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#never-commit-the-transaction + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L541 Use of cr.commit() directly - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#never-commit-the-transaction + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L542 Use of cr.commit() directly - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#never-commit-the-transaction * license-allowed @@ -239,11 +244,11 @@ Checks valid only for odoo <= 13.0 * method-compute - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L155 Name of compute method should start with "_compute_" + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L158 Name of compute method should start with "_compute_" * method-inverse - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L157 Name of inverse method should start with "_inverse_" + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L160 Name of inverse method should start with "_inverse_" * method-required-super @@ -253,7 +258,7 @@ Checks valid only for odoo <= 13.0 * method-search - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L156 Name of search method should start with "_search_" + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L159 Name of search method should start with "_search_" * missing-readme @@ -270,19 +275,19 @@ Checks valid only for odoo <= 13.0 * no-wizard-in-models - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L829 No wizard class for model directory. See the complete structure https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#complete-structure + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L1024 No wizard class for model directory. See the complete structure https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#complete-structure * no-write-in-compute - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L114 Compute method calling `write`. Use `update` instead. - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L116 Compute method calling `write`. Use `update` instead. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L117 Compute method calling `write`. Use `update` instead. - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L119 Compute method calling `write`. Use `update` instead. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L122 Compute method calling `write`. Use `update` instead. * odoo-addons-relative-import - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L49 Same Odoo module absolute import. You should use relative import with "." instead of "odoo.addons.broken_module" - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L50 Same Odoo module absolute import. You should use relative import with "." instead of "odoo.addons.broken_module" - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L51 Same Odoo module absolute import. You should use relative import with "." instead of "odoo.addons.broken_module" + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L52 Same Odoo module absolute import. You should use relative import with "." instead of "odoo.addons.broken_module" + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L53 Same Odoo module absolute import. You should use relative import with "." instead of "odoo.addons.broken_module" * odoo-exception-warning @@ -290,14 +295,20 @@ Checks valid only for odoo <= 13.0 - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/pylint_oca_broken.py#L11 `odoo.exceptions.Warning` is a deprecated alias to `odoo.exceptions.UserError` use `from odoo.exceptions import UserError` - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/pylint_oca_broken.py#L8 `odoo.exceptions.Warning` is a deprecated alias to `odoo.exceptions.UserError` use `from odoo.exceptions import UserError` + * prefer-env-translation + + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L146 Better using self.env._ More info at https://github.com/odoo/odoo/pull/174844 + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L156 Better using self.env._ More info at https://github.com/odoo/odoo/pull/174844 + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L322 Better using self.env._ More info at https://github.com/odoo/odoo/pull/174844 + * print-used - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/test_module/except_pass.py#L20 Print used. Use `logger` instead. * renamed-field-parameter - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L209 Field parameter "digits_compute" is no longer supported. Use "digits" instead. - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L209 Field parameter "select" is no longer supported. Use "index" instead. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L212 Field parameter "digits_compute" is no longer supported. Use "digits" instead. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L212 Field parameter "select" is no longer supported. Use "index" instead. * resource-not-exist @@ -307,9 +318,9 @@ Checks valid only for odoo <= 13.0 * sql-injection - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L576 SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L578 SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L580 SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L771 SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L773 SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L775 SQL injection risk. Use parameters if you can. - More info https://github.com/OCA/odoo-community.org/blob/master/website/Contribution/CONTRIBUTING.rst#no-sql-injection * test-folder-imported @@ -319,58 +330,63 @@ Checks valid only for odoo <= 13.0 * translation-contains-variable - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L371 Translatable term in "'Variable not translatable: %s' % variable1" contains variables. Use _('Variable not translatable: %s') % variable1 instead - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L372 Translatable term in "'Variables not translatable: %s, %s' % (variable1, variable2)" contains variables. Use _('Variables not translatable: %s, %s') % (variable1, variable2) instead - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L374 Translatable term in "'Variable not translatable: %s' % variable1" contains variables. Use _('Variable not translatable: %s') % variable1 instead + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L375 Translatable term in "'Variables not translatable: %s, %s' % (variable1, variable2)" contains variables. Use _('Variables not translatable: %s, %s') % (variable1, variable2) instead + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L377 Translatable term in "'Variable not translatable: %s' % variable1" contains variables. Use _('Variable not translatable: %s') % variable1 instead * translation-field - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L143 Translation method _("string") in fields is not necessary. - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L153 Translation method _("string") in fields is not necessary. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L146 Translation method _("string") in fields is not necessary. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L156 Translation method _("string") in fields is not necessary. * translation-format-interpolation - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L380 Use lazy % or .format() or % formatting in odoo._ functions - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L381 Use lazy % or .format() or % formatting in odoo._ functions - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L473 Use lazy % or .format() or % formatting in odoo._ functions + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L383 Use lazy % or .format() or % formatting in odoo._ functions + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L384 Use lazy % or .format() or % formatting in odoo._ functions + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L447 Use lazy % or .format() or % formatting in odoo._ functions * translation-format-truncated - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L484 Logging format string ends in middle of conversion specifier + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L649 Logging format string ends in middle of conversion specifier + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L664 Logging format string ends in middle of conversion specifier * translation-fstring-interpolation - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L482 Use lazy % or .format() or % formatting in odoo._ functions + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L647 Use lazy % or .format() or % formatting in odoo._ functions + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L662 Use lazy % or .format() or % formatting in odoo._ functions * translation-not-lazy - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L345 Use lazy % or .format() or % formatting in odoo._ functions - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L346 Use lazy % or .format() or % formatting in odoo._ functions - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L348 Use lazy % or .format() or % formatting in odoo._ functions + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L349 Use lazy % or .format() or % formatting in odoo._ functions + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L351 Use lazy % or .format() or % formatting in odoo._ functions * translation-positional-used - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L372 Translation method _('Variables not translatable: %s, %s' % (variable1, variable2)) is using positional string printf formatting with multiple arguments. Use named placeholder `_("%(placeholder)s")` instead. - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L375 Translation method _('Variables not translatable: %s %s' % (variable1, variable2)) is using positional string printf formatting with multiple arguments. Use named placeholder `_("%(placeholder)s")` instead. - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L378 Translation method _('Variables not translatable: %s, %s' % (variable1, variable2)) is using positional string printf formatting with multiple arguments. Use named placeholder `_("%(placeholder)s")` instead. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L375 Translation method _('Variables not translatable: %s, %s' % (variable1, variable2)) is using positional string printf formatting with multiple arguments. Use named placeholder `_("%(placeholder)s")` instead. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L378 Translation method _('Variables not translatable: %s %s' % (variable1, variable2)) is using positional string printf formatting with multiple arguments. Use named placeholder `_("%(placeholder)s")` instead. + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L381 Translation method _('Variables not translatable: %s, %s' % (variable1, variable2)) is using positional string printf formatting with multiple arguments. Use named placeholder `_("%(placeholder)s")` instead. * translation-required - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L322 String parameter on "message_post" requires translation. Use body=_('Body not translatable %s') - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L322 String parameter on "message_post" requires translation. Use subject=_('Subject not translatable') - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L324 String parameter on "message_post" requires translation. Use body=_('Body not translatable {}') + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L325 String parameter on "message_post" requires translation. Use body=_('Body not translatable %s') + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L325 String parameter on "message_post" requires translation. Use subject=_('Subject not translatable') + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L327 String parameter on "message_post" requires translation. Use body=_('Body not translatable {}') * translation-too-few-args - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L480 Not enough arguments for odoo._ format string + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L645 Not enough arguments for odoo._ format string + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L660 Not enough arguments for odoo._ format string * translation-too-many-args - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L485 Too many arguments for odoo._ format string + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L650 Too many arguments for odoo._ format string + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L665 Too many arguments for odoo._ format string * translation-unsupported-format - - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L483 Unsupported odoo._ format character 'y' (0x79) at index 30 + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L648 Unsupported odoo._ format character 'y' (0x79) at index 30 + - https://github.com/OCA/pylint-odoo/blob/v9.3.0/testing/resources/test_repo/broken_module/models/broken_model.py#L663 Unsupported odoo._ format character 'y' (0x79) at index 30 * use-vim-comment diff --git a/src/pylint_odoo/checkers/custom_logging.py b/src/pylint_odoo/checkers/custom_logging.py index 9eb32350..02f82b48 100644 --- a/src/pylint_odoo/checkers/custom_logging.py +++ b/src/pylint_odoo/checkers/custom_logging.py @@ -5,6 +5,7 @@ from astroid import builder, exceptions as astroid_exceptions, nodes from pylint.checkers import logging +from .. import misc from .odoo_addons import OdooAddons from .odoo_base_checker import OdooBaseChecker @@ -67,9 +68,9 @@ def add_message(self, msgid, *args, **kwargs): return super().add_message(msgid, *args, **kwargs) def visit_call(self, node): - if not isinstance(node.func, nodes.Name): + name = OdooAddons.get_func_name(node.func) + if name not in misc.TRANSLATION_METHODS: return - name = node.func.name with config_logging_modules(self.linter, ("odoo",)): self._check_log_method(node, name) diff --git a/src/pylint_odoo/checkers/odoo_addons.py b/src/pylint_odoo/checkers/odoo_addons.py index 0d69ce13..367ffd8a 100644 --- a/src/pylint_odoo/checkers/odoo_addons.py +++ b/src/pylint_odoo/checkers/odoo_addons.py @@ -265,6 +265,11 @@ "deprecated-odoo-model-method", CHECK_DESCRIPTION, ), + "W8161": ( + "Better using self.env._ More info at https://github.com/odoo/odoo/pull/174844", + "prefer-env-translation", + CHECK_DESCRIPTION, + ), } DFTL_MANIFEST_REQUIRED_KEYS = ["license"] @@ -569,6 +574,7 @@ class OdooAddons(OdooBaseChecker, BaseChecker): "odoo_maxversion": "13.0", }, "no-raise-unlink": {"odoo_minversion": "15.0"}, + "prefer-env-translation": {"odoo_minversion": "18.0"}, } def __init__(self, linter: PyLinter): @@ -789,6 +795,7 @@ def _get_assignation_nodes(self, node): "method-inverse", "method-search", "no-write-in-compute", + "prefer-env-translation", "print-used", "renamed-field-parameter", "sql-injection", @@ -870,8 +877,7 @@ def visit_call(self, node): self.odoo_computes.add(method_name) if ( isinstance(argument_aux, nodes.Call) - and isinstance(argument_aux.func, nodes.Name) - and argument_aux.func.name == "_" + and self.get_func_name(argument_aux.func) in misc.TRANSLATION_METHODS ): self.add_message("translation-field", node=argument_aux) index += 1 @@ -942,7 +948,12 @@ def visit_call(self, node): self.add_message("translation-required", node=node, args=("message_post", keyword, as_string)) # Call _(...) with variables into the term to be translated - if isinstance(node.func, nodes.Name) and node.func.name == "_" and node.args: + if self.get_func_name(node.func) in misc.TRANSLATION_METHODS and node.args: + # "_" -> isinstance(node.func, nodes.Name) + # "self.env._" -> isinstance(node.func, nodes.Attribute) + if isinstance(node.func, nodes.Name) and node.func.as_string() in misc.TRANSLATION_METHODS: + self.add_message("prefer-env-translation", node=node) + wrong = "" right = "" arg = node.args[0] diff --git a/src/pylint_odoo/misc.py b/src/pylint_odoo/misc.py index 78a803c6..35d0a7c0 100644 --- a/src/pylint_odoo/misc.py +++ b/src/pylint_odoo/misc.py @@ -35,6 +35,7 @@ "18.0", ] DFTL_MANIFEST_VERSION_FORMAT = r"({valid_odoo_versions})\.\d+\.\d+\.\d+$" +TRANSLATION_METHODS = ("_", "_lt") class StringParseError(TypeError): diff --git a/testing/resources/test_repo/broken_module/models/broken_model.py b/testing/resources/test_repo/broken_module/models/broken_model.py index c781ab15..a62a9485 100644 --- a/testing/resources/test_repo/broken_module/models/broken_model.py +++ b/testing/resources/test_repo/broken_module/models/broken_model.py @@ -44,6 +44,8 @@ from odoo import fields, models, _ from odoo.exceptions import UserError from odoo import exceptions +from odoo.tools.translate import LazyTranslate + # Relatives import for odoo addons from odoo.addons.broken_module import broken_model as broken_model1 @@ -61,6 +63,7 @@ import itertools from itertools import groupby +_lt = LazyTranslate(__name__) other_field = fields.Char() @@ -402,6 +405,134 @@ def my_method1(self, variable1): self.message_post(_('Double method _ and lstrtip %s').lstrip() % (variable1,)) # TODO: Emit message for this case return error_msg + def my_method11(self, variable1): + # Shouldn't show error of field-argument-translate + self.my_method2(self.env._('hello world')) + + # Message post with new translation function + self.message_post(subject=self.env._('Subject translatable'), + body=self.env._('Body translatable')) + self.message_post(self.env._('Body translatable'), + self.env._('Subject translatable')) + self.message_post(self.env._('Body translatable'), + subject=self.env._('Subject translatable')) + self.message_post(self.env._('A CDR has been recovered for %s') % (variable1,)) + self.message_post(self.env._('A CDR has been recovered for %s') % variable1) + self.message_post(self.env._('Var {a}').format(a=variable1)) + self.message_post(self.env._('Var %(variable)s') % {'variable': variable1}) + self.message_post(subject=self.env._('Subject translatable'), + body=self.env._('Body translatable %s') % variable1) + self.message_post(subject=self.env._('Subject translatable %(variable)s') % + {'variable': variable1}, + message_type='notification') + self.message_post(self.env._('Body translatable'), + self.env._('Subject translatable {a}').format(a=variable1)) + self.message_post(self.env._('Body translatable %s') % variable1, + self.env._('Subject translatable %(variable)s') % + {'variable': variable1}) + self.message_post('

%s

' % self.env._('Body translatable')) + self.message_post(body='

%s

' % self.env._('Body translatable')) + + # translation new function with variables in the term + variable2 = variable1 + self.message_post(self.env._('Variable not translatable: %s' % variable1)) + self.message_post(self.env._('Variables not translatable: %s, %s' % ( + variable1, variable2))) + self.message_post(body=self.env._('Variable not translatable: %s' % variable1)) + self.message_post(body=self.env._('Variables not translatable: %s %s' % ( + variable1, variable2))) + error_msg = self.env._('Variable not translatable: %s' % variable1) + error_msg = self.env._('Variables not translatable: %s, %s' % ( + variable1, variable2)) + error_msg = self.env._('Variable not translatable: {}'.format(variable1)) + error_msg = self.env._('Variables not translatable: {}, {variable2}'.format( + variable1, variable2=variable2)) + + # string with parameters without name + # so you can't change the order in the translation + self.env._('%s %d') % ('hello', 3) + self.env._('%s %s') % ('hello', 'world') + self.env._('{} {}').format('hello', 3) + self.env._('{} {}').format('hello', 'world') + + # Valid cases + self.env._('%(strname)s') % {'strname': 'hello'} + self.env._('%(strname)s %(intname)d') % {'strname': 'hello', 'intname': 3} + self.env._('%s') % 'hello' + self.env._('%d') % 3 + self.env._('{}').format('hello') + self.env._('{}').format(3) + + # It raised exception but it was already fixed + msg = "Invalid not _ method %s".lstrip() % "value" + # It should emit message but binop.left is showing "lstrip" only instead of "_" + self.message_post(self.env._('Double method _ and lstrtip %s').lstrip() % (variable1,)) # TODO: Emit message for this case + return error_msg + + def my_method111(self, variable1): + # Shouldn't show error of field-argument-translate + self.my_method2(_lt('hello world')) + + # Message post with new translation function + self.message_post(subject=_lt('Subject translatable'), + body=_lt('Body translatable')) + self.message_post(_lt('Body translatable'), + _lt('Subject translatable')) + self.message_post(_lt('Body translatable'), + subject=_lt('Subject translatable')) + self.message_post(_lt('A CDR has been recovered for %s') % (variable1,)) + self.message_post(_lt('A CDR has been recovered for %s') % variable1) + self.message_post(_lt('Var {a}').format(a=variable1)) + self.message_post(_lt('Var %(variable)s') % {'variable': variable1}) + self.message_post(subject=_lt('Subject translatable'), + body=_lt('Body translatable %s') % variable1) + self.message_post(subject=_lt('Subject translatable %(variable)s') % + {'variable': variable1}, + message_type='notification') + self.message_post(_lt('Body translatable'), + _lt('Subject translatable {a}').format(a=variable1)) + self.message_post(_lt('Body translatable %s') % variable1, + _lt('Subject translatable %(variable)s') % + {'variable': variable1}) + self.message_post('

%s

' % _lt('Body translatable')) + self.message_post(body='

%s

' % _lt('Body translatable')) + + # translation new function with variables in the term + variable2 = variable1 + self.message_post(_lt('Variable not translatable: %s' % variable1)) + self.message_post(_lt('Variables not translatable: %s, %s' % ( + variable1, variable2))) + self.message_post(body=_lt('Variable not translatable: %s' % variable1)) + self.message_post(body=_lt('Variables not translatable: %s %s' % ( + variable1, variable2))) + error_msg = _lt('Variable not translatable: %s' % variable1) + error_msg = _lt('Variables not translatable: %s, %s' % ( + variable1, variable2)) + error_msg = _lt('Variable not translatable: {}'.format(variable1)) + error_msg = _lt('Variables not translatable: {}, {variable2}'.format( + variable1, variable2=variable2)) + + # string with parameters without name + # so you can't change the order in the translation + _lt('%s %d') % ('hello', 3) + _lt('%s %s') % ('hello', 'world') + _lt('{} {}').format('hello', 3) + _lt('{} {}').format('hello', 'world') + + # Valid cases + _lt('%(strname)s') % {'strname': 'hello'} + _lt('%(strname)s %(intname)d') % {'strname': 'hello', 'intname': 3} + _lt('%s') % 'hello' + _lt('%d') % 3 + _lt('{}').format('hello') + _lt('{}').format(3) + + # It raised exception but it was already fixed + msg = "Invalid not _ method %s".lstrip() % "value" + # It should emit message but binop.left is showing "lstrip" only instead of "_" + self.message_post(_lt('Double method _ and lstrtip %s').lstrip() % (variable1,)) # TODO: Emit message for this case + return error_msg + def my_method2(self, variable2): return variable2 @@ -432,6 +563,18 @@ def my_method7(self): # Method with translation raise UserError(_('String with translation')) + def my_method71(self): + user_id = 1 + if user_id != 99: + # Method with translation + raise UserError(self.env._('String with translation')) + + def my_method72(self): + user_id = 1 + if user_id != 99: + # Method with translation + raise UserError(_lt('String with translation')) + def my_method8(self): user_id = 1 if user_id != 99: @@ -476,6 +619,28 @@ def my_method13(self): raise exceptions.Warning(_( 'String with params format %(p1)s' % {'p1': 'v1'})) + def my_method131(self): + # Shouldn't show error + raise exceptions.Warning(self.env._( + 'String with params format {p1}').format(p1='v1')) + raise exceptions.Warning(self.env._( + 'String with params format {p1}'.format(p1='v1'))) + raise exceptions.Warning(self.env._( + 'String with params format %(p1)s') % {'p1': 'v1'}) + raise exceptions.Warning(self.env._( + 'String with params format %(p1)s' % {'p1': 'v1'})) + + def my_method132(self): + # Shouldn't show error + raise exceptions.Warning(_lt( + 'String with params format {p1}').format(p1='v1')) + raise exceptions.Warning(_lt( + 'String with params format {p1}'.format(p1='v1'))) + raise exceptions.Warning(_lt( + 'String with params format %(p1)s') % {'p1': 'v1'}) + raise exceptions.Warning(_lt( + 'String with params format %(p1)s' % {'p1': 'v1'})) + def my_method14(self): _("String with missing args %s %s", "param1") _("String with missing kwargs %(param1)s", param2="hola") @@ -491,6 +656,36 @@ def my_method14(self): _("String with correct args %s", "param1") _("String with correct kwargs %(param1)s", param1="hola") + def my_method141(self): + self.env._("String with missing args %s %s", "param1") + self.env._("String with missing kwargs %(param1)s", param2="hola") + self.env._(f"String with f-interpolation {self.param1}") + self.env._("String unsupported character %y", "param1") + self.env._("format truncated %s%", 'param1') + self.env._("too many args %s", 'param1', 'param2') + + self.env._("multi-positional args without placeholders %s %s", 'param1', 'param2') + + self.env._("multi-positional args without placeholders {} {}".format('param1', 'param2')) + + self.env._("String with correct args %s", "param1") + self.env._("String with correct kwargs %(param1)s", param1="hola") + + def my_method142(self): + _lt("String with missing args %s %s", "param1") + _lt("String with missing kwargs %(param1)s", param2="hola") + _lt(f"String with f-interpolation {self.param1}") + _lt("String unsupported character %y", "param1") + _lt("format truncated %s%", 'param1') + _lt("too many args %s", 'param1', 'param2') + + _lt("multi-positional args without placeholders %s %s", 'param1', 'param2') + + _lt("multi-positional args without placeholders {} {}".format('param1', 'param2')) + + _lt("String with correct args %s", "param1") + _lt("String with correct kwargs %(param1)s", param1="hola") + def old_api_method_alias(self, cursor, user, ids, context=None): # old api pass diff --git a/tests/test_main.py b/tests/test_main.py index 438f9ef7..8a84ca2f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -47,22 +47,23 @@ "no-write-in-compute": 16, "odoo-addons-relative-import": 4, "odoo-exception-warning": 4, + "prefer-env-translation": 111, "print-used": 1, "renamed-field-parameter": 2, "resource-not-exist": 4, "sql-injection": 21, "test-folder-imported": 3, - "translation-contains-variable": 11, + "translation-contains-variable": 33, "translation-field": 2, - "translation-format-interpolation": 4, - "translation-format-truncated": 1, - "translation-fstring-interpolation": 1, - "translation-not-lazy": 21, - "translation-positional-used": 10, + "translation-format-interpolation": 8, + "translation-format-truncated": 2, + "translation-fstring-interpolation": 2, + "translation-not-lazy": 42, + "translation-positional-used": 30, "translation-required": 15, - "translation-too-few-args": 1, - "translation-too-many-args": 1, - "translation-unsupported-format": 1, + "translation-too-few-args": 2, + "translation-too-many-args": 2, + "translation-unsupported-format": 2, "use-vim-comment": 1, "website-manifest-key-not-valid-uri": 1, "no-raise-unlink": 2, @@ -150,6 +151,9 @@ def test_20_expected_errors(self): def test_25_checks_excluding_by_odoo_version(self): """All odoolint errors vs found but excluding based on Odoo version""" excluded_msgs = { + "deprecated-odoo-model-method", + "no-raise-unlink", + "prefer-env-translation", "translation-format-interpolation", "translation-format-truncated", "translation-fstring-interpolation", @@ -157,8 +161,6 @@ def test_25_checks_excluding_by_odoo_version(self): "translation-too-few-args", "translation-too-many-args", "translation-unsupported-format", - "no-raise-unlink", - "deprecated-odoo-model-method", } self.default_extra_params += ["--valid-odoo-versions=13.0"] pylint_res = self.run_pylint(self.paths_modules) @@ -176,7 +178,12 @@ def test_35_checks_emiting_by_odoo_version(self): real_errors = pylint_res.linter.stats.by_msg expected_errors = self.expected_errors.copy() expected_errors.update({"manifest-version-format": 6}) - excluded_msgs = {"no-raise-unlink", "translation-contains-variable", "deprecated-odoo-model-method"} + excluded_msgs = { + "deprecated-odoo-model-method", + "no-raise-unlink", + "prefer-env-translation", + "translation-contains-variable", + } for excluded_msg in excluded_msgs: expected_errors.pop(excluded_msg) self.assertEqual(expected_errors, real_errors) @@ -322,6 +329,22 @@ def test_140_check_migrations_is_not_odoo_module(self): expected_errors = {} self.assertDictEqual(real_errors, expected_errors) + def test_gettext_env(self): + """prefer-env-translation is only valid for odoo v18.0+ but not for older odoo versions""" + pylint_res = self.run_pylint( + self.paths_modules, ["--valid-odoo-versions=18.0", "--disable=all", "--enable=prefer-env-translation"] + ) + real_errors = pylint_res.linter.stats.by_msg + expected_errors = {"prefer-env-translation": self.expected_errors.get("prefer-env-translation")} + self.assertEqual(expected_errors, real_errors) + + pylint_res = self.run_pylint( + self.paths_modules, ["--valid-odoo-versions=17.0", "--disable=all", "--enable=prefer-env-translation"] + ) + real_errors = pylint_res.linter.stats.by_msg + expected_errors = {} + self.assertEqual(expected_errors, real_errors) + @unittest.skipUnless(not sys.platform.startswith("win"), "TOOD: Fix with windows") # TODO: Fix it def test_145_check_fstring_sqli(self): """Verify the linter is capable of finding SQL Injection vulnerabilities