Commit 9781e7f9 authored by Jérome Perrin's avatar Jérome Perrin Committed by Arnaud Fontaine

patchs/pylint: update for python3 support

this works with astroid 3.2.0 and pylint 3.2.0
parent 72ec7d78
...@@ -159,16 +159,12 @@ class ComponentTool(BaseTool): ...@@ -159,16 +159,12 @@ class ComponentTool(BaseTool):
erp5.component.filesystem_import_dict = None erp5.component.filesystem_import_dict = None
erp5.component.ref_manager.gc() erp5.component.ref_manager.gc()
# Clear pylint cache # Clear astroid (pylint) cache
try: from astroid import MANAGER
from astroid.builder import MANAGER astroid_cache = MANAGER.astroid_cache
except ImportError: for k in list(astroid_cache.keys()):
pass if k.startswith('erp5.component.') and k not in component_package_list:
else: del astroid_cache[k]
astroid_cache = MANAGER.astroid_cache
for k in astroid_cache.keys():
if k.startswith('erp5.component.') and k not in component_package_list:
del astroid_cache[k]
if reset_portal_type_at_transaction_boundary: if reset_portal_type_at_transaction_boundary:
portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary() portal.portal_types.resetDynamicDocumentsOnceAtTransactionBoundary()
......
...@@ -419,7 +419,7 @@ def fill_args_from_request(*optional_args): ...@@ -419,7 +419,7 @@ def fill_args_from_request(*optional_args):
return decorator return decorator
_pylint_message_re = re.compile( _pylint_message_re = re.compile(
'^(?P<type>[CRWEF]):\s*(?P<row>\d+),\s*(?P<column>\d+):\s*(?P<message>.*)$') r'^(?P<type>[CRWEF]):\s*(?P<row>\d+),\s*(?P<column>\d+):\s*(?P<message>.*)$')
def checkPythonSourceCode(source_code_str, portal_type=None): def checkPythonSourceCode(source_code_str, portal_type=None):
""" """
...@@ -462,8 +462,11 @@ def checkPythonSourceCode(source_code_str, portal_type=None): ...@@ -462,8 +462,11 @@ def checkPythonSourceCode(source_code_str, portal_type=None):
message_list = [] message_list = []
output_file = StringIO() output_file = StringIO()
try: try:
with tempfile.NamedTemporaryFile(prefix='checkPythonSourceCode', with tempfile.NamedTemporaryFile(
suffix='.py') as input_file: prefix='checkPythonSourceCode',
suffix='.py',
mode='w',
) as input_file:
input_file.write(source_code_str) input_file.write(source_code_str)
input_file.flush() input_file.flush()
...@@ -493,6 +496,8 @@ def checkPythonSourceCode(source_code_str, portal_type=None): ...@@ -493,6 +496,8 @@ def checkPythonSourceCode(source_code_str, portal_type=None):
# TODO-arnau: Enable it properly would require inspection API # TODO-arnau: Enable it properly would require inspection API
# '%s %r has no %r member' # '%s %r has no %r member'
'--disable=E1101,E1103', '--disable=E1101,E1103',
# XXX duplicate-bases causes too many false positives
'--disable=duplicate-bases',
# map and filter should not be considered bad as in some cases # map and filter should not be considered bad as in some cases
# map is faster than its recommended replacement (list # map is faster than its recommended replacement (list
# comprehension) # comprehension)
...@@ -508,7 +513,26 @@ def checkPythonSourceCode(source_code_str, portal_type=None): ...@@ -508,7 +513,26 @@ def checkPythonSourceCode(source_code_str, portal_type=None):
# unused variables # unused variables
'--dummy-variables-rgx=_$|dummy|__traceback_info__|__traceback_supplement__', '--dummy-variables-rgx=_$|dummy|__traceback_info__|__traceback_supplement__',
] ]
if six.PY3:
args.extend(
(
"--msg-template='{C}: {line},{column}: {msg} ({symbol})'",
'--load-plugins=pylint.extensions.bad_builtin',
# BBB until we drop compatibility with PY2
'--disable=redundant-u-string-prefix,raise-missing-from,keyword-arg-before-vararg',
# XXX acceptable to ignore in the context of ERP5
'--disable=unspecified-encoding',
# XXX to many errors for now
'--disable=arguments-differ,arguments-renamed',
'--disable=duplicate-bases,inconsistent-mro',
)
)
else:
args.extend(
(
'--load-plugins=Products.ERP5Type.patches.pylint_compatibility_disable',
)
)
if portal_type == 'Interface Component': if portal_type == 'Interface Component':
# __init__ method from base class %r is not called # __init__ method from base class %r is not called
args.append('--disable=W0231') args.append('--disable=W0231')
...@@ -521,19 +545,15 @@ def checkPythonSourceCode(source_code_str, portal_type=None): ...@@ -521,19 +545,15 @@ def checkPythonSourceCode(source_code_str, portal_type=None):
# Method should have "self" as first argument (no-self-argument) # Method should have "self" as first argument (no-self-argument)
args.append('--disable=E0213') args.append('--disable=E0213')
try:
from pylint.extensions.bad_builtin import __name__ as ext
args.append('--load-plugins=' + ext)
except ImportError:
pass
try: try:
# Note that we don't run pylint as a subprocess, but directly from # Note that we don't run pylint as a subprocess, but directly from
# ERP5 process, so that pylint can access the code from ERP5Type # ERP5 process, so that pylint can access the code from ERP5Type
# dynamic modules from ZODB. # dynamic modules from ZODB.
Run(args, reporter=TextReporter(output_file), exit=False) Run(args, reporter=TextReporter(output_file), exit=False)
finally: finally:
from astroid.builder import MANAGER from astroid import MANAGER
MANAGER.astroid_cache.pop( astroid_cache = MANAGER.astroid_cache
astroid_cache.pop(
os.path.splitext(os.path.basename(input_file.name))[0], os.path.splitext(os.path.basename(input_file.name))[0],
None) None)
......
...@@ -39,8 +39,7 @@ if getZopeVersion()[0] == 2: # BBB Zope2 ...@@ -39,8 +39,7 @@ if getZopeVersion()[0] == 2: # BBB Zope2
else: else:
IS_ZOPE2 = False IS_ZOPE2 = False
import six import six
if six.PY2: from .patches import pylint
from .patches import pylint
from zLOG import LOG, INFO from zLOG import LOG, INFO
DISPLAY_BOOT_PROCESS = False DISPLAY_BOOT_PROCESS = False
......
...@@ -19,9 +19,10 @@ ...@@ -19,9 +19,10 @@
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import absolute_import from __future__ import absolute_import
import six
import sys import sys
import types
import warnings import warnings
import six
from Products.ERP5Type import IS_ZOPE2 from Products.ERP5Type import IS_ZOPE2
# TODO: make sure that trying to use it does not import isort, because the # TODO: make sure that trying to use it does not import isort, because the
...@@ -32,21 +33,21 @@ sys.modules.setdefault('isort', None) ...@@ -32,21 +33,21 @@ sys.modules.setdefault('isort', None)
## All arguments are passed as arguments and this needlessly outputs a 'No ## All arguments are passed as arguments and this needlessly outputs a 'No
## config file found, using default configuration' message on stderr. ## config file found, using default configuration' message on stderr.
try: if six.PY2:
from logilab.common.configuration import OptionsManagerMixIn from logilab.common.configuration import OptionsManagerMixIn
except ImportError: OptionsManagerMixIn.read_config_file = lambda *args, **kw: None
# pylint 2.x (python3)
from pylint.config import OptionsManagerMixIn
OptionsManagerMixIn.read_config_file = lambda *args, **kw: None
## Pylint transforms and plugin to generate AST for ZODB Components ## Pylint transforms and plugin to generate AST for ZODB Components
from astroid.builder import AstroidBuilder from astroid.builder import AstroidBuilder
from astroid.exceptions import AstroidBuildingException if six.PY2:
from astroid import MANAGER, node_classes from astroid.exceptions import AstroidBuildingException as AstroidBuildingError
else:
from astroid.exceptions import AstroidBuildingError
from astroid import node_classes
from astroid import MANAGER
try: if six.PY2:
from astroid.builder import _guess_encoding from astroid.builder import _guess_encoding
except ImportError:
# XXX: With python3, tokenize.detect_encoding() is used instead. This # XXX: With python3, tokenize.detect_encoding() is used instead. This
# should do the same instead of copying/pasting legacy code... # should do the same instead of copying/pasting legacy code...
import re import re
...@@ -61,7 +62,7 @@ except ImportError: ...@@ -61,7 +62,7 @@ except ImportError:
match = _ENCODING_RGX.match(line) match = _ENCODING_RGX.match(line)
if match is not None: if match is not None:
return match.group(1) return match.group(1)
def string_build(self, data, modname='', path=None): def string_build(self, data, modname='', path=None):
""" """
build astroid from source code string and return rebuilded astroid build astroid from source code string and return rebuilded astroid
...@@ -95,11 +96,11 @@ def string_build(self, data, modname='', path=None): ...@@ -95,11 +96,11 @@ def string_build(self, data, modname='', path=None):
LOG("Products.ERP5Type.patches.pylint", WARNING, LOG("Products.ERP5Type.patches.pylint", WARNING,
"%s: Considered as not importable: Wrong encoding? (%r)" % "%s: Considered as not importable: Wrong encoding? (%r)" %
(modname, exc)) (modname, exc))
raise AstroidBuildingException(exc) raise AstroidBuildingError(exc)
module = self._data_build(data, modname, path) module = self._data_build(data, modname, path)
module.file_bytes = data module.file_bytes = data
return self._post_build(module, encoding) return self._post_build(module, encoding)
AstroidBuilder.string_build = string_build AstroidBuilder.string_build = string_build
# patch node_classes.const_factory not to fail on LazyModules that e.g. # patch node_classes.const_factory not to fail on LazyModules that e.g.
# pygolang installs for pytest and ipython into sys.modules dict: # pygolang installs for pytest and ipython into sys.modules dict:
...@@ -154,17 +155,17 @@ def _buildAstroidModuleFromComponentModuleName(modname): ...@@ -154,17 +155,17 @@ def _buildAstroidModuleFromComponentModuleName(modname):
obj = getattr(component_tool, obj = getattr(component_tool,
component_id.replace('_version', '', 1)) component_id.replace('_version', '', 1))
except AttributeError: except AttributeError:
raise AstroidBuildingException() raise AstroidBuildingError()
if obj.getValidationState() in ('modified', 'validated'): if obj.getValidationState() in ('modified', 'validated'):
component_obj = obj component_obj = obj
else: else:
raise AstroidBuildingException() raise AstroidBuildingError()
else: else:
try: try:
package, reference = component_id.split('.', 1) package, reference = component_id.split('.', 1)
except ValueError: except ValueError:
raise AstroidBuildingException() raise AstroidBuildingError()
for version in portal.getVersionPriorityNameList(): for version in portal.getVersionPriorityNameList():
try: try:
obj = getattr(component_tool, obj = getattr(component_tool,
...@@ -183,11 +184,8 @@ def _buildAstroidModuleFromComponentModuleName(modname): ...@@ -183,11 +184,8 @@ def _buildAstroidModuleFromComponentModuleName(modname):
return module return module
if component_obj is None: if component_obj is None:
raise AstroidBuildingException() raise AstroidBuildingError()
# module_build() could also be used but this requires importing
# the ZODB Component and also monkey-patch it to support PEP-302
# for __file__ starting with '<'
module = AstroidBuilder(MANAGER).string_build( module = AstroidBuilder(MANAGER).string_build(
component_obj.getTextContent(validated_only=True), component_obj.getTextContent(validated_only=True),
modname) modname)
...@@ -195,7 +193,7 @@ def _buildAstroidModuleFromComponentModuleName(modname): ...@@ -195,7 +193,7 @@ def _buildAstroidModuleFromComponentModuleName(modname):
def fail_hook_erp5_component(modname): def fail_hook_erp5_component(modname):
if not modname.startswith('erp5.'): if not modname.startswith('erp5.'):
raise AstroidBuildingException() raise AstroidBuildingError()
if (modname in ('erp5.portal_type', if (modname in ('erp5.portal_type',
'erp5.component', 'erp5.component',
...@@ -223,8 +221,11 @@ MANAGER.register_failed_import_hook(fail_hook_erp5_component) ...@@ -223,8 +221,11 @@ MANAGER.register_failed_import_hook(fail_hook_erp5_component)
## transforms but this would require either checking dynamically which ## transforms but this would require either checking dynamically which
## attributes has been added (much more complex than the current approach) ## attributes has been added (much more complex than the current approach)
## or listing them statically (inconvenient). ## or listing them statically (inconvenient).
from astroid.exceptions import NotFoundError from astroid.exceptions import AstroidError, NotFoundError
from astroid.scoped_nodes import Module if six.PY2:
from astroid.scoped_nodes import Module
else:
from astroid.nodes import Module
Module_getattr = Module.getattr Module_getattr = Module.getattr
def _getattr(self, name, *args, **kw): def _getattr(self, name, *args, **kw):
try: try:
...@@ -232,8 +233,22 @@ def _getattr(self, name, *args, **kw): ...@@ -232,8 +233,22 @@ def _getattr(self, name, *args, **kw):
except NotFoundError as e: except NotFoundError as e:
if self.name.startswith('erp5.'): if self.name.startswith('erp5.'):
raise raise
if six.PY3 and (
real_module = __import__(self.name, fromlist=[self.name], level=0) # astroid/pylint on py3 have built-in support for numpy
self.name == 'numpy'
or self.name.startswith('numpy.')
# SOAPPy.Types contains "from SOAPPy.Types import *" which confuses
# this patch
or self.name == 'SOAPpy.Types'
# pysvn also confuses pylint
or self.name == 'pysvn'
# XXX actually maybe we don't need this branch at all on py3
):
raise
real_module = __import__(
self.name,
fromlist=[self.name] if six.PY2 else [name],
level=0)
try: try:
attr = getattr(real_module, name) attr = getattr(real_module, name)
except AttributeError: except AttributeError:
...@@ -249,13 +264,21 @@ def _getattr(self, name, *args, **kw): ...@@ -249,13 +264,21 @@ def _getattr(self, name, *args, **kw):
except AttributeError: except AttributeError:
from astroid import nodes from astroid import nodes
if isinstance(attr, dict): if isinstance(attr, dict):
ast = nodes.Dict(attr) if six.PY2:
ast = nodes.Dict(attr)
else:
ast = nodes.Dict(attr, 0, None, end_lineno=0, end_col_offset=0)
elif isinstance(attr, list): elif isinstance(attr, list):
ast = nodes.List(attr) ast = nodes.List(attr)
elif isinstance(attr, tuple): elif isinstance(attr, tuple):
ast = nodes.Tuple(attr) ast = nodes.Tuple(attr)
elif isinstance(attr, set): elif isinstance(attr, set):
ast = nodes.Set(attr) if six.PY2:
ast = nodes.Set(attr)
else:
ast = nodes.Set(attr, 0, None, end_lineno=0, end_col_offset=0)
elif isinstance(attr, types.ModuleType):
ast = MANAGER.ast_from_module(attr)
else: else:
try: try:
ast = nodes.Const(attr) ast = nodes.Const(attr)
...@@ -266,16 +289,29 @@ def _getattr(self, name, *args, **kw): ...@@ -266,16 +289,29 @@ def _getattr(self, name, *args, **kw):
raise raise
# ast_from_class() actually works for any attribute of a Module # ast_from_class() actually works for any attribute of a Module
# (on py2 at least), but it raises some AssertionError when the class
# is defined dynamically, for example with zope.hookable.hookable,
# which (in version 6.0) is defined as:
#
# if _PURE_PYTHON or _c_hookable is None:
# hookable = _py_hookable
# else: # pragma: no cover
# hookable = _c_hookable
try: try:
ast = MANAGER.ast_from_class(attr) ast = MANAGER.ast_from_class(attr)
except AstroidBuildingException: except (AstroidError, AssertionError):
raise e if six.PY2:
raise e
try:
ast = next(MANAGER.infer_ast_from_something(attr))
except AstroidError:
raise e
self.locals[name] = [ast] self.locals[name] = [ast]
return [ast] return [ast]
Module.getattr = _getattr Module.getattr = _getattr
if sys.version_info < (2, 8): if six.PY2:
from astroid.node_classes import From from astroid.node_classes import From
def _absolute_import_activated(self): def _absolute_import_activated(self):
if (self.name.startswith('checkPythonSourceCode') or if (self.name.startswith('checkPythonSourceCode') or
...@@ -292,25 +328,25 @@ from astroid import register_module_extender ...@@ -292,25 +328,25 @@ from astroid import register_module_extender
def AccessControl_PermissionRole_transform(): def AccessControl_PermissionRole_transform():
return AstroidBuilder(MANAGER).string_build(''' return AstroidBuilder(MANAGER).string_build('''
def rolesForPermissionOn(perm, object, default=_default_roles, n=None): def rolesForPermissionOn(perm, object, default=_default_roles, n=None):
return None return tuple()
class PermissionRole(object): class PermissionRole(object):
def __init__(self, name, default=('Manager',)): def __init__(self, name, default=('Manager',)):
return None return None
def __of__(self, parent): def __of__(self, parent):
return None return imPermissionRole(self)
def rolesForPermissionOn(self, value): def rolesForPermissionOn(self, value):
return None return self.rolesForPermissionOn(None, self)
class imPermissionRole(object): class imPermissionRole(object):
def __of__(self, value): def __of__(self, value):
return None return self.rolesForPermissionOn(None, self)
def rolesForPermissionOn(self, value): def rolesForPermissionOn(self, value):
return None return rolesForPermissionOn(None, self)
def __getitem__(self, i): def __getitem__(self, i):
return None return None
def __len__(self): def __len__(self):
return None return 0
_what_not_even_god_should_do = [] _what_not_even_god_should_do = []
''') ''')
...@@ -338,14 +374,14 @@ def build_stub(parent, identifier_re=r'^[A-Za-z_]\w*$'): ...@@ -338,14 +374,14 @@ def build_stub(parent, identifier_re=r'^[A-Za-z_]\w*$'):
constants = {} constants = {}
methods = {} methods = {}
for name in dir(parent): for name in dir(parent):
if name.startswith("__"): if name in dir(object):
continue continue
# Check if this is a valid name in python # Check if this is a valid name in python
if not re.match(identifier_re, name): if not re.match(identifier_re, name):
continue continue
try: try:
obj = getattr(parent, name) obj = getattr(parent, name)
except: except AttributeError:
continue continue
if inspect.isclass(obj): if inspect.isclass(obj):
classes[name] = obj classes[name] = obj
...@@ -422,7 +458,7 @@ _inspected_modules = {} ...@@ -422,7 +458,7 @@ _inspected_modules = {}
def fail_hook_BTrees(modname): def fail_hook_BTrees(modname):
# Only consider BTrees.OOBTree pattern # Only consider BTrees.OOBTree pattern
if not modname.startswith('BTrees.') or len(modname.split('.')) != 2: if not modname.startswith('BTrees.') or len(modname.split('.')) != 2:
raise AstroidBuildingException() raise AstroidBuildingError()
if modname not in _inspected_modules: if modname not in _inspected_modules:
try: try:
modcode = build_stub( modcode = build_stub(
...@@ -438,7 +474,7 @@ def fail_hook_BTrees(modname): ...@@ -438,7 +474,7 @@ def fail_hook_BTrees(modname):
else: else:
astng = _inspected_modules[modname] astng = _inspected_modules[modname]
if astng is None: if astng is None:
raise AstroidBuildingException('Failed to import module %r' % modname) raise AstroidBuildingError('Failed to import module %r' % modname)
return astng return astng
MANAGER.register_failed_import_hook(fail_hook_BTrees) MANAGER.register_failed_import_hook(fail_hook_BTrees)
...@@ -484,12 +520,20 @@ def register_xpkg(pkgname): ...@@ -484,12 +520,20 @@ def register_xpkg(pkgname):
except ImportError: except ImportError:
pass pass
else: else:
def xpkg_transform(node): if six.PY2:
m = AstroidBuilder(MANAGER).string_build('__path__ = %r' % pkg.__path__) def xpkg_transform(node):
m.package = True m = AstroidBuilder(MANAGER).string_build('__path__ = %r' % pkg.__path__)
m.name = pkgname m.package = True
return m m.name = pkgname
MANAGER.register_transform(Module, xpkg_transform, lambda node: node.name == pkgname) return m
MANAGER.register_transform(Module, xpkg_transform, lambda node: node.name == pkgname)
else:
import importlib
def fail_hook_xpkg(modname):
if modname.split('.')[0] == pkgname:
return MANAGER.ast_from_module(importlib.import_module(modname))
raise AstroidBuildingError()
MANAGER.register_failed_import_hook(fail_hook_xpkg)
register_xpkg('wendelin') register_xpkg('wendelin')
register_xpkg('xlte') register_xpkg('xlte')
......
"""A dummy checker to register messages from pylint3, to be able to
disable the messages on python2 without causing bad-option-value
"""
from __future__ import absolute_import
from pylint import checkers, interfaces
class CompatibilityDisableChecker(checkers.BaseChecker):
name = "compatibility-disable"
msgs = {
"E9999": (
"not-an-iterable",
"not-an-iterable",
"",
),
"E9998": (
"misplaced-bare-raise",
"misplaced-bare-raise",
"",
),
"E9997": (
"unused-private-member",
"unused-private-member",
"",
),
"E9996": (
"using-constant-test",
"using-constant-test",
""
),
"E9995": (
"modified-iterating-list",
"modified-iterating-list",
"",
),
"E9994": (
"unsubscriptable-object",
"unsubscriptable-object",
"",
),
"E9993": (
"invalid-unary-operand-type",
"invalid-unary-operand-type",
"",
),
"E9992": (
"unbalanced-dict-unpacking",
"unbalanced-dict-unpacking",
"",
),
"E9991": (
"self-cls-assignment",
"self-cls-assignment",
"",
),
"E9990": (
"deprecated-class",
"deprecated-class",
"",
),
"E9989": (
"possibly-used-before-assignment",
"possibly-used-before-assignment",
""
)
}
def register(linter):
linter.register_checker(CompatibilityDisableChecker(linter))
...@@ -1899,11 +1899,18 @@ class TestZodbModuleComponent(SecurityTestCase): ...@@ -1899,11 +1899,18 @@ class TestZodbModuleComponent(SecurityTestCase):
component.setTextContent("""import unexistent_module component.setTextContent("""import unexistent_module
""" + valid_code) """ + valid_code)
self.tic() self.tic()
self.assertEqual( if six.PY2:
[m.getMessage().translate() for m in component.checkConsistency()], self.assertEqual(
["Error in Source Code: F: 1, 0: Unable to import 'unexistent_module' (import-error)"]) [m.getMessage().translate() for m in component.checkConsistency()],
self.assertEqual(component.getTextContentErrorMessageList(), ["Error in Source Code: F: 1, 0: Unable to import 'unexistent_module' (import-error)"])
["F: 1, 0: Unable to import 'unexistent_module' (import-error)"]) self.assertEqual(component.getTextContentErrorMessageList(),
["F: 1, 0: Unable to import 'unexistent_module' (import-error)"])
else:
self.assertEqual(
[m.getMessage().translate() for m in component.checkConsistency()],
["Error in Source Code: E: 1, 0: Unable to import 'unexistent_module' (import-error)"])
self.assertEqual(component.getTextContentErrorMessageList(),
["E: 1, 0: Unable to import 'unexistent_module' (import-error)"])
self.assertEqual(component.getTextContentWarningMessageList(), self.assertEqual(component.getTextContentWarningMessageList(),
["W: 1, 0: Unused import unexistent_module (unused-import)"]) ["W: 1, 0: Unused import unexistent_module (unused-import)"])
...@@ -1935,11 +1942,10 @@ class TestZodbModuleComponent(SecurityTestCase): ...@@ -1935,11 +1942,10 @@ class TestZodbModuleComponent(SecurityTestCase):
[ComponentMixin._message_text_content_not_set], [ComponentMixin._message_text_content_not_set],
[], [],
[]), []),
("""def foobar(*args, **kwargs) ("""None()
return 42
""" + valid_code, """ + valid_code,
["Error in Source Code: E: 1, 0: invalid syntax (syntax-error)"], ["Error in Source Code: E: 1, 0: None is not callable (not-callable)"],
["E: 1, 0: invalid syntax (syntax-error)"], ["E: 1, 0: None is not callable (not-callable)"],
[]), []),
# Make sure that foobar NameError is at the end to make sure that after # Make sure that foobar NameError is at the end to make sure that after
# defining foobar function, it is not available at all # defining foobar function, it is not available at all
...@@ -2209,7 +2215,7 @@ def function_foo(*args, **kwargs): ...@@ -2209,7 +2215,7 @@ def function_foo(*args, **kwargs):
def _assertAstroidCacheContent(self, def _assertAstroidCacheContent(self,
must_be_in_cache_set, must_be_in_cache_set,
must_not_be_in_cache_set): must_not_be_in_cache_set):
from astroid.builder import MANAGER from astroid import MANAGER
should_not_be_in_cache_list = [] should_not_be_in_cache_list = []
for modname in MANAGER.astroid_cache: for modname in MANAGER.astroid_cache:
if (modname.startswith('checkPythonSourceCode') or if (modname.startswith('checkPythonSourceCode') or
...@@ -2265,10 +2271,10 @@ def hoge(): ...@@ -2265,10 +2271,10 @@ def hoge():
"""# -*- coding: utf-8 -*- """# -*- coding: utf-8 -*-
# Source code with non-ASCII character should not fail: éàホゲ # Source code with non-ASCII character should not fail: éàホゲ
from %(namespace)s import %(reference1)s from %(namespace)s import %(reference1)s
from %(namespace)s.erp5_version import %(reference1)s from %(namespace)s.erp5_version import %(reference1)s # pylint:disable=reimported
from %(module2)s import hoge from %(module2)s import hoge
from %(module2_with_version)s import hoge from %(module2_with_version)s import hoge # pylint:disable=reimported
import %(module2)s import %(module2)s
import %(module2_with_version)s import %(module2_with_version)s
...@@ -2293,7 +2299,8 @@ from AccessControl.PermissionRole import rolesForPermissionOn, PermissionRole, i ...@@ -2293,7 +2299,8 @@ from AccessControl.PermissionRole import rolesForPermissionOn, PermissionRole, i
# Monkey patch of astroid 1.3.8: it raised 'no-name-in-module' because # Monkey patch of astroid 1.3.8: it raised 'no-name-in-module' because
# Shared.DC was not considered a namespace package # Shared.DC was not considered a namespace package
from Shared.DC.ZRDB.Results import Results # pylint: disable=unused-import from Shared.DC.ZRDB.Results import Results
_ = Results
import lxml.etree import lxml.etree
lxml.etree.Element('test') lxml.etree.Element('test')
...@@ -2340,17 +2347,21 @@ _ = ZBigArray ...@@ -2340,17 +2347,21 @@ _ = ZBigArray
module2_with_version=imported_module2_with_version)) + module2_with_version=imported_module2_with_version)) +
component.getTextContent()) component.getTextContent())
must_be_in_cache_set = set()
if six.PY2:
must_be_in_cache_set.add(namespace)
self._assertAstroidCacheContent( self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace}, must_be_in_cache_set=must_be_in_cache_set,
must_not_be_in_cache_set={'%s.erp5_version' % namespace, must_not_be_in_cache_set={'%s.erp5_version' % namespace,
imported_module1, imported_module1,
imported_module1_with_version, imported_module1_with_version,
imported_module2, imported_module2,
imported_module2_with_version}) imported_module2_with_version})
component.checkSourceCode() component.checkSourceCode()
if six.PY2:
must_be_in_cache_set.add('%s.erp5_version' % namespace)
self._assertAstroidCacheContent( self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace, must_be_in_cache_set=must_be_in_cache_set,
'%s.erp5_version' % namespace},
must_not_be_in_cache_set={imported_module1, must_not_be_in_cache_set={imported_module1,
imported_module1_with_version, imported_module1_with_version,
imported_module2, imported_module2,
...@@ -2358,35 +2369,69 @@ _ = ZBigArray ...@@ -2358,35 +2369,69 @@ _ = ZBigArray
self.tic() self.tic()
self.assertEqual(component.getValidationState(), 'modified') self.assertEqual(component.getValidationState(), 'modified')
self.assertEqual( if six.PY2:
component.getTextContentErrorMessageList(), self.assertEqual(
["E: 3, 0: No name '%s' in module '%s' (no-name-in-module)" % component.getTextContentErrorMessageList(),
(imported_reference1, namespace), [
"E: 4, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" % "E: 3, 0: No name '%s' in module '%s' (no-name-in-module)" %
(imported_reference1, namespace), (imported_reference1, namespace),
# Spurious message but same as filesystem modules: 2 errors raised "E: 4, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" %
# (no-name-in-module and import-error) (imported_reference1, namespace),
"E: 6, 0: No name '%s' in module '%s' (no-name-in-module)" % # Spurious message but same as filesystem modules: 2 errors raised
(imported_reference2, namespace), # (no-name-in-module and import-error)
"F: 6, 0: Unable to import '%s' (import-error)" % "E: 6, 0: No name '%s' in module '%s' (no-name-in-module)" %
imported_module2, (imported_reference2, namespace),
# Spurious message (see above comment) "F: 6, 0: Unable to import '%s' (import-error)" %
"E: 7, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" % imported_module2,
(imported_reference2, namespace), # Spurious message (see above comment)
"F: 7, 0: Unable to import '%s' (import-error)" % "E: 7, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" %
imported_module2_with_version, (imported_reference2, namespace),
# Spurious message (see above comment) "F: 7, 0: Unable to import '%s' (import-error)" %
"E: 9, 0: No name '%s' in module '%s' (no-name-in-module)" % imported_module2_with_version,
(imported_reference2, namespace), # Spurious message (see above comment)
"F: 9, 0: Unable to import '%s' (import-error)" % "E: 9, 0: No name '%s' in module '%s' (no-name-in-module)" %
imported_module2, (imported_reference2, namespace),
# Spurious message (see above comment) "F: 9, 0: Unable to import '%s' (import-error)" %
"E: 10, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" % imported_module2,
(imported_reference2, namespace), # Spurious message (see above comment)
"F: 10, 0: Unable to import '%s' (import-error)" % "E: 10, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" %
imported_module2_with_version]) (imported_reference2, namespace),
"F: 10, 0: Unable to import '%s' (import-error)" %
imported_module2_with_version,
],
)
else:
self.assertEqual(
component.getTextContentErrorMessageList(),
[
"E: 3, 0: No name '%s' in module '%s' (no-name-in-module)" %
(imported_reference1, namespace),
"E: 4, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" %
(imported_reference1, namespace),
"E: 6, 0: Unable to import '%s.%s' (import-error)" %
(namespace, imported_reference2),
# Spurious message but same as filesystem modules: 2 errors raised
# (no-name-in-module and import-error)
"E: 6, 0: No name '%s' in module '%s' (no-name-in-module)" %
(imported_reference2, namespace),
"E: 7, 0: Unable to import '%s' (import-error)" %
imported_module2_with_version,
# Spurious message (see above comment)
"E: 7, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" %
(imported_reference2, namespace),
"E: 9, 0: Unable to import '%s.%s' (import-error)" %
(namespace, imported_reference2),
# Spurious message (see above comment)
"E: 9, 0: No name '%s' in module '%s' (no-name-in-module)" %
(imported_reference2, namespace),
"E: 10, 0: Unable to import '%s' (import-error)" %
imported_module2_with_version,
# Spurious message (see above comment)
"E: 10, 0: No name '%s' in module '%s.erp5_version' (no-name-in-module)" %
(imported_reference2, namespace),
],
)
self.assertEqual(component.getTextContentWarningMessageList(), []) self.assertEqual(component.getTextContentWarningMessageList(), [])
## Simulate user: ## Simulate user:
# 1) First check and validate 'imported' Components # 1) First check and validate 'imported' Components
self.portal.portal_workflow.doActionFor(imported_component1, 'validate_action') self.portal.portal_workflow.doActionFor(imported_component1, 'validate_action')
...@@ -2397,20 +2442,29 @@ _ = ZBigArray ...@@ -2397,20 +2442,29 @@ _ = ZBigArray
message_list = component.checkSourceCode() message_list = component.checkSourceCode()
self.assertEqual(message_list, []) self.assertEqual(message_list, [])
must_be_in_cache_set = {
imported_module1,
imported_module1_with_version,
imported_module2,
imported_module2_with_version,
}
if six.PY2:
must_be_in_cache_set.update({
'%s' % namespace,
'%s.erp5_version' % namespace,
})
self._assertAstroidCacheContent( self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace, must_be_in_cache_set=must_be_in_cache_set,
'%s.erp5_version' % namespace,
imported_module1,
imported_module1_with_version,
imported_module2,
imported_module2_with_version},
must_not_be_in_cache_set=set()) must_not_be_in_cache_set=set())
# 2) Then modify the main one so that it automatically 'validate' # 2) Then modify the main one so that it automatically 'validate'
component.setTextContent(component.getTextContent() + '\n') component.setTextContent(component.getTextContent() + '\n')
self.tic() self.tic()
must_be_in_cache_set = set()
if six.PY2:
must_be_in_cache_set.add(namespace)
self._assertAstroidCacheContent( self._assertAstroidCacheContent(
must_be_in_cache_set={'%s' % namespace}, must_be_in_cache_set=must_be_in_cache_set,
must_not_be_in_cache_set={'%s.erp5_version' % namespace, must_not_be_in_cache_set={'%s.erp5_version' % namespace,
imported_module1, imported_module1,
imported_module1_with_version, imported_module1_with_version,
...@@ -2423,10 +2477,11 @@ _ = ZBigArray ...@@ -2423,10 +2477,11 @@ _ = ZBigArray
component.setTextContent( component.setTextContent(
"""# -*- coding: utf-8 -*- """# -*- coding: utf-8 -*-
from %(module)s import undefined from %(module)s import undefined
from %(module_with_version)s import undefined from %(module_with_version)s import undefined2
# To avoid 'unused-import' warning... # To avoid 'unused-import' warning...
undefined() undefined()
undefined2()
""" % (dict(module=imported_module2, """ % (dict(module=imported_module2,
module_with_version=imported_module2_with_version)) + module_with_version=imported_module2_with_version)) +
...@@ -2437,7 +2492,7 @@ undefined() ...@@ -2437,7 +2492,7 @@ undefined()
component.getTextContentErrorMessageList(), component.getTextContentErrorMessageList(),
["E: 2, 0: No name 'undefined' in module '%s' (no-name-in-module)" % ["E: 2, 0: No name 'undefined' in module '%s' (no-name-in-module)" %
imported_module2_with_version, imported_module2_with_version,
"E: 3, 0: No name 'undefined' in module '%s' (no-name-in-module)" % "E: 3, 0: No name 'undefined2' in module '%s' (no-name-in-module)" %
imported_module2_with_version]) imported_module2_with_version])
self.assertEqual(component.getTextContentWarningMessageList(), []) self.assertEqual(component.getTextContentWarningMessageList(), [])
...@@ -2473,8 +2528,8 @@ def hoge(): ...@@ -2473,8 +2528,8 @@ def hoge():
component = self._newComponent(reference) component = self._newComponent(reference)
component.setTextContent(component.getTextContent() + """ component.setTextContent(component.getTextContent() + """
from %(namespace)s import %(reference)s from %(namespace)s import %(reference)s
from %(namespace)s.bar_version import %(reference)s from %(namespace)s.bar_version import %(reference)s # pylint:disable=reimported
from %(namespace)s.erp5_version import %(reference)s from %(namespace)s.erp5_version import %(reference)s # pylint:disable=reimported
# To avoid 'unused-import' warning... # To avoid 'unused-import' warning...
%(reference)s.hoge() %(reference)s.hoge()
...@@ -2482,7 +2537,7 @@ from %(namespace)s.erp5_version import %(reference)s ...@@ -2482,7 +2537,7 @@ from %(namespace)s.erp5_version import %(reference)s
reference=imported_reference)) reference=imported_reference))
component.checkSourceCode() component.checkSourceCode()
from astroid.builder import MANAGER from astroid import MANAGER
imported_module = self._getComponentFullModuleName(imported_reference) imported_module = self._getComponentFullModuleName(imported_reference)
self.assertEqual( self.assertEqual(
MANAGER.astroid_cache[self._getComponentFullModuleName(imported_reference, version='bar')], MANAGER.astroid_cache[self._getComponentFullModuleName(imported_reference, version='bar')],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment