| Index: third_party/pylint/checkers/imports.py
 | 
| diff --git a/third_party/pylint/checkers/imports.py b/third_party/pylint/checkers/imports.py
 | 
| index 5964a266049103b2f713b6e149191a03f43b0e5f..7e6a4f880c9cc9b4bcb4ae5135df31315b426775 100644
 | 
| --- a/third_party/pylint/checkers/imports.py
 | 
| +++ b/third_party/pylint/checkers/imports.py
 | 
| @@ -1,4 +1,4 @@
 | 
| -# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
 | 
| +# Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE).
 | 
|  # http://www.logilab.fr/ -- mailto:contact@logilab.fr
 | 
|  #
 | 
|  # This program is free software; you can redistribute it and/or modify it under
 | 
| @@ -12,51 +12,55 @@
 | 
|  #
 | 
|  # You should have received a copy of the GNU General Public License along with
 | 
|  # this program; if not, write to the Free Software Foundation, Inc.,
 | 
| -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | 
| +# 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 | 
|  """imports checkers for Python code"""
 | 
|  
 | 
| -import sys
 | 
| -
 | 
|  from logilab.common.graph import get_cycles, DotBackend
 | 
| +from logilab.common.modutils import is_standard_module
 | 
|  from logilab.common.ureports import VerbatimText, Paragraph
 | 
|  
 | 
| -import astroid
 | 
| -from astroid import are_exclusive
 | 
| -from astroid.modutils import get_module_part, is_standard_module
 | 
| +from logilab import astng
 | 
| +from logilab.astng import are_exclusive
 | 
|  
 | 
| -from pylint.interfaces import IAstroidChecker
 | 
| -from pylint.utils import EmptyReport
 | 
| -from pylint.checkers import BaseChecker
 | 
| -from pylint.checkers.utils import check_messages
 | 
| +from pylint.interfaces import IASTNGChecker
 | 
| +from pylint.checkers import BaseChecker, EmptyReport
 | 
|  
 | 
|  
 | 
|  def get_first_import(node, context, name, base, level):
 | 
|      """return the node where [base.]<name> is imported or None if not found
 | 
|      """
 | 
| -    fullname = '%s.%s' % (base, name) if base else name
 | 
| -
 | 
|      first = None
 | 
|      found = False
 | 
| -    for first in context.body:
 | 
| -        if first is node:
 | 
| -            continue
 | 
| -        if first.scope() is node.scope() and first.fromlineno > node.fromlineno:
 | 
| -            continue
 | 
| -        if isinstance(first, astroid.Import):
 | 
| -            if any(fullname == iname[0] for iname in first.names):
 | 
| +    for first in context.values():
 | 
| +        if isinstance(first, astng.Import):
 | 
| +            if name in [iname[0] for iname in first.names]:
 | 
|                  found = True
 | 
|                  break
 | 
| -        elif isinstance(first, astroid.From):
 | 
| -            if level == first.level and any(
 | 
| -                    fullname == '%s.%s' % (first.modname, iname[0])
 | 
| -                    for iname in first.names):
 | 
| +        elif isinstance(first, astng.From):
 | 
| +            if base == first.modname and level == first.level and \
 | 
| +                   name in [iname[0] for iname in first.names]:
 | 
|                  found = True
 | 
|                  break
 | 
| -    if found and not are_exclusive(first, node):
 | 
| +    if found and first is not node and not are_exclusive(first, node):
 | 
|          return first
 | 
|  
 | 
|  # utilities to represents import dependencies as tree and dot graph ###########
 | 
|  
 | 
| +def filter_dependencies_info(dep_info, package_dir, mode='external'):
 | 
| +    """filter external or internal dependencies from dep_info (return a
 | 
| +    new dictionary containing the filtered modules only)
 | 
| +    """
 | 
| +    if mode == 'external':
 | 
| +        filter_func = lambda x: not is_standard_module(x, (package_dir,))
 | 
| +    else:
 | 
| +        assert mode == 'internal'
 | 
| +        filter_func = lambda x: is_standard_module(x, (package_dir,))
 | 
| +    result = {}
 | 
| +    for importee, importers in dep_info.items():
 | 
| +        if filter_func(importee):
 | 
| +            result[importee] = importers
 | 
| +    return result
 | 
| +
 | 
|  def make_tree_defs(mod_files_list):
 | 
|      """get a list of 2-uple (module, list_of_files_which_import_this_module),
 | 
|      it will return a dictionary to represent this as a tree
 | 
| @@ -82,7 +86,7 @@ def repr_tree_defs(data, indent_str=None):
 | 
|              lines.append('%s %s' % (mod, files))
 | 
|              sub_indent_str = '  '
 | 
|          else:
 | 
| -            lines.append(r'%s\-%s %s' % (indent_str, mod, files))
 | 
| +            lines.append('%s\-%s %s' % (indent_str, mod, files))
 | 
|              if i == len(nodes)-1:
 | 
|                  sub_indent_str = '%s  ' % indent_str
 | 
|              else:
 | 
| @@ -96,16 +100,16 @@ def dependencies_graph(filename, dep_info):
 | 
|      """write dependencies as a dot (graphviz) file
 | 
|      """
 | 
|      done = {}
 | 
| -    printer = DotBackend(filename[:-4], rankdir='LR')
 | 
| +    printer = DotBackend(filename[:-4], rankdir = "LR")
 | 
|      printer.emit('URL="." node[shape="box"]')
 | 
| -    for modname, dependencies in sorted(dep_info.iteritems()):
 | 
| +    for modname, dependencies in dep_info.items():
 | 
|          done[modname] = 1
 | 
|          printer.emit_node(modname)
 | 
|          for modname in dependencies:
 | 
|              if modname not in done:
 | 
|                  done[modname] = 1
 | 
|                  printer.emit_node(modname)
 | 
| -    for depmodname, dependencies in sorted(dep_info.iteritems()):
 | 
| +    for depmodname, dependencies in dep_info.items():
 | 
|          for modname in dependencies:
 | 
|              printer.emit_edge(modname, depmodname)
 | 
|      printer.generate(filename)
 | 
| @@ -124,36 +128,26 @@ def make_graph(filename, dep_info, sect, gtype):
 | 
|  
 | 
|  MSGS = {
 | 
|      'F0401': ('Unable to import %s',
 | 
| -              'import-error',
 | 
|                'Used when pylint has been unable to import a module.'),
 | 
|      'R0401': ('Cyclic import (%s)',
 | 
| -              'cyclic-import',
 | 
|                'Used when a cyclic import between two or more modules is \
 | 
|                detected.'),
 | 
|  
 | 
|      'W0401': ('Wildcard import %s',
 | 
| -              'wildcard-import',
 | 
|                'Used when `from module import *` is detected.'),
 | 
|      'W0402': ('Uses of a deprecated module %r',
 | 
| -              'deprecated-module',
 | 
|                'Used a module marked as deprecated is imported.'),
 | 
|      'W0403': ('Relative import %r, should be %r',
 | 
| -              'relative-import',
 | 
| -              'Used when an import relative to the package directory is '
 | 
| -              'detected.',
 | 
| -              {'maxversion': (3, 0)}),
 | 
| +              'Used when an import relative to the package directory is \
 | 
| +              detected.'),
 | 
|      'W0404': ('Reimport %r (imported line %s)',
 | 
| -              'reimported',
 | 
|                'Used when a module is reimported multiple times.'),
 | 
|      'W0406': ('Module import itself',
 | 
| -              'import-self',
 | 
|                'Used when a module is importing itself.'),
 | 
|  
 | 
|      'W0410': ('__future__ import is not the first non docstring statement',
 | 
| -              'misplaced-future',
 | 
|                'Python 2.5 and greater require __future__ import to be the \
 | 
| -              first non docstring statement in the module.',
 | 
| -              {'maxversion': (3, 0)}),
 | 
| +              first non docstring statement in the module.'),
 | 
|      }
 | 
|  
 | 
|  class ImportsChecker(BaseChecker):
 | 
| @@ -164,45 +158,43 @@ class ImportsChecker(BaseChecker):
 | 
|      * uses of deprecated modules
 | 
|      """
 | 
|  
 | 
| -    __implements__ = IAstroidChecker
 | 
| +    __implements__ = IASTNGChecker
 | 
|  
 | 
|      name = 'imports'
 | 
|      msgs = MSGS
 | 
|      priority = -2
 | 
|  
 | 
| -    if sys.version_info < (3,):
 | 
| -        deprecated_modules = ('regsub', 'TERMIOS', 'Bastion', 'rexec')
 | 
| -    else:
 | 
| -        deprecated_modules = ('stringprep', 'optparse')
 | 
|      options = (('deprecated-modules',
 | 
| -                {'default' : deprecated_modules,
 | 
| +                {'default' : ('regsub', 'string', 'TERMIOS',
 | 
| +                              'Bastion', 'rexec'),
 | 
|                   'type' : 'csv',
 | 
|                   'metavar' : '<modules>',
 | 
|                   'help' : 'Deprecated modules which should not be used, \
 | 
|  separated by a comma'}
 | 
| -               ),
 | 
| +                ),
 | 
|                 ('import-graph',
 | 
|                  {'default' : '',
 | 
|                   'type' : 'string',
 | 
|                   'metavar' : '<file.dot>',
 | 
|                   'help' : 'Create a graph of every (i.e. internal and \
 | 
|  external) dependencies in the given file (report RP0402 must not be disabled)'}
 | 
| -               ),
 | 
| +                ),
 | 
|                 ('ext-import-graph',
 | 
|                  {'default' : '',
 | 
|                   'type' : 'string',
 | 
|                   'metavar' : '<file.dot>',
 | 
|                   'help' : 'Create a graph of external dependencies in the \
 | 
|  given file (report RP0402 must not be disabled)'}
 | 
| -               ),
 | 
| +                ),
 | 
|                 ('int-import-graph',
 | 
|                  {'default' : '',
 | 
|                   'type' : 'string',
 | 
|                   'metavar' : '<file.dot>',
 | 
|                   'help' : 'Create a graph of internal dependencies in the \
 | 
|  given file (report RP0402 must not be disabled)'}
 | 
| -               ),
 | 
| -              )
 | 
| +                ),
 | 
| +
 | 
| +               )
 | 
|  
 | 
|      def __init__(self, linter=None):
 | 
|          BaseChecker.__init__(self, linter)
 | 
| @@ -213,7 +205,7 @@ given file (report RP0402 must not be disabled)'}
 | 
|                           self.report_external_dependencies),
 | 
|                          ('RP0402', 'Modules dependencies graph',
 | 
|                           self.report_dependencies_graph),
 | 
| -                       )
 | 
| +                        )
 | 
|  
 | 
|      def open(self):
 | 
|          """called before visiting project (i.e set of modules)"""
 | 
| @@ -225,9 +217,9 @@ given file (report RP0402 must not be disabled)'}
 | 
|      def close(self):
 | 
|          """called before visiting project (i.e set of modules)"""
 | 
|          # don't try to compute cycles if the associated message is disabled
 | 
| -        if self.linter.is_message_enabled('cyclic-import'):
 | 
| +        if self.linter.is_message_enabled('R0401'):
 | 
|              for cycle in get_cycles(self.import_graph):
 | 
| -                self.add_message('cyclic-import', args=' -> '.join(cycle))
 | 
| +                self.add_message('R0401', args=' -> '.join(cycle))
 | 
|  
 | 
|      def visit_import(self, node):
 | 
|          """triggered when an import statement is seen"""
 | 
| @@ -241,9 +233,7 @@ given file (report RP0402 must not be disabled)'}
 | 
|              self._check_deprecated_module(node, name)
 | 
|              self._check_reimport(node, name)
 | 
|  
 | 
| -    # TODO This appears to be the list of all messages of the checker...
 | 
| -    # @check_messages('W0410', 'W0401', 'W0403', 'W0402', 'W0404', 'W0406', 'F0401')
 | 
| -    @check_messages(*(MSGS.keys()))
 | 
| +
 | 
|      def visit_from(self, node):
 | 
|          """triggered when a from statement is seen"""
 | 
|          basename = node.modname
 | 
| @@ -252,13 +242,10 @@ given file (report RP0402 must not be disabled)'}
 | 
|              prev = node.previous_sibling()
 | 
|              if prev:
 | 
|                  # consecutive future statements are possible
 | 
| -                if not (isinstance(prev, astroid.From)
 | 
| -                        and prev.modname == '__future__'):
 | 
| -                    self.add_message('misplaced-future', node=node)
 | 
| +                if not (isinstance(prev, astng.From)
 | 
| +                       and prev.modname == '__future__'):
 | 
| +                    self.add_message('W0410', node=node)
 | 
|              return
 | 
| -        for name, _ in node.names:
 | 
| -            if name == '*':
 | 
| -                self.add_message('wildcard-import', args=basename, node=node)
 | 
|          modnode = node.root()
 | 
|          importedmodnode = self.get_imported_module(modnode, node, basename)
 | 
|          if importedmodnode is None:
 | 
| @@ -266,26 +253,28 @@ given file (report RP0402 must not be disabled)'}
 | 
|          self._check_relative_import(modnode, node, importedmodnode, basename)
 | 
|          self._check_deprecated_module(node, basename)
 | 
|          for name, _ in node.names:
 | 
| -            if name != '*':
 | 
| -                self._add_imported_module(node, '%s.%s' % (importedmodnode.name, name))
 | 
| -                self._check_reimport(node, name, basename, node.level)
 | 
| +            if name == '*':
 | 
| +                self.add_message('W0401', args=basename, node=node)
 | 
| +                continue
 | 
| +            self._add_imported_module(node, '%s.%s' % (importedmodnode.name, name))
 | 
| +            self._check_reimport(node, name, basename, node.level)
 | 
|  
 | 
|      def get_imported_module(self, modnode, importnode, modname):
 | 
|          try:
 | 
|              return importnode.do_import_module(modname)
 | 
| -        except astroid.InferenceError, ex:
 | 
| +        except astng.InferenceError, ex:
 | 
|              if str(ex) != modname:
 | 
|                  args = '%r (%s)' % (modname, ex)
 | 
|              else:
 | 
|                  args = repr(modname)
 | 
| -            self.add_message("import-error", args=args, node=importnode)
 | 
| +            self.add_message("F0401", args=args, node=importnode)
 | 
|  
 | 
|      def _check_relative_import(self, modnode, importnode, importedmodnode,
 | 
|                                 importedasname):
 | 
|          """check relative import. node is either an Import or From node, modname
 | 
|          the imported module name.
 | 
|          """
 | 
| -        if not self.linter.is_message_enabled('relative-import'):
 | 
| +        if 'W0403' not in self.active_msgs:
 | 
|              return
 | 
|          if importedmodnode.file is None:
 | 
|              return False # built-in module
 | 
| @@ -295,55 +284,52 @@ given file (report RP0402 must not be disabled)'}
 | 
|              return False
 | 
|          if importedmodnode.name != importedasname:
 | 
|              # this must be a relative import...
 | 
| -            self.add_message('relative-import', args=(importedasname, importedmodnode.name),
 | 
| +            self.add_message('W0403', args=(importedasname, importedmodnode.name),
 | 
|                               node=importnode)
 | 
|  
 | 
|      def _add_imported_module(self, node, importedmodname):
 | 
|          """notify an imported module, used to analyze dependencies"""
 | 
| -        try:
 | 
| -            importedmodname = get_module_part(importedmodname)
 | 
| -        except ImportError:
 | 
| -            pass
 | 
|          context_name = node.root().name
 | 
|          if context_name == importedmodname:
 | 
|              # module importing itself !
 | 
| -            self.add_message('import-self', node=node)
 | 
| +            self.add_message('W0406', node=node)
 | 
|          elif not is_standard_module(importedmodname):
 | 
|              # handle dependencies
 | 
|              importedmodnames = self.stats['dependencies'].setdefault(
 | 
|                  importedmodname, set())
 | 
|              if not context_name in importedmodnames:
 | 
|                  importedmodnames.add(context_name)
 | 
| -            # update import graph
 | 
| -            mgraph = self.import_graph.setdefault(context_name, set())
 | 
| -            if not importedmodname in mgraph:
 | 
| -                mgraph.add(importedmodname)
 | 
| +            if is_standard_module( importedmodname, (self.package_dir(),) ):
 | 
| +                # update import graph
 | 
| +                mgraph = self.import_graph.setdefault(context_name, set())
 | 
| +                if not importedmodname in mgraph:
 | 
| +                    mgraph.add(importedmodname)
 | 
|  
 | 
|      def _check_deprecated_module(self, node, mod_path):
 | 
|          """check if the module is deprecated"""
 | 
|          for mod_name in self.config.deprecated_modules:
 | 
|              if mod_path == mod_name or mod_path.startswith(mod_name + '.'):
 | 
| -                self.add_message('deprecated-module', node=node, args=mod_path)
 | 
| +                self.add_message('W0402', node=node, args=mod_path)
 | 
|  
 | 
| -    def _check_reimport(self, node, name, basename=None, level=None):
 | 
| +    def _check_reimport(self, node, name, basename=None, level=0):
 | 
|          """check if the import is necessary (i.e. not already done)"""
 | 
| -        if not self.linter.is_message_enabled('reimported'):
 | 
| +        if 'W0404' not in self.active_msgs:
 | 
|              return
 | 
|          frame = node.frame()
 | 
|          root = node.root()
 | 
|          contexts = [(frame, level)]
 | 
|          if root is not frame:
 | 
| -            contexts.append((root, None))
 | 
| +            contexts.append((root, 0))
 | 
|          for context, level in contexts:
 | 
|              first = get_first_import(node, context, name, basename, level)
 | 
|              if first is not None:
 | 
| -                self.add_message('reimported', node=node,
 | 
| +                self.add_message('W0404', node=node,
 | 
|                                   args=(name, first.fromlineno))
 | 
|  
 | 
|  
 | 
|      def report_external_dependencies(self, sect, _, dummy):
 | 
|          """return a verbatim layout for displaying dependencies"""
 | 
| -        dep_info = make_tree_defs(self._external_dependencies_info().iteritems())
 | 
| +        dep_info = make_tree_defs(self._external_dependencies_info().items())
 | 
|          if not dep_info:
 | 
|              raise EmptyReport()
 | 
|          tree_str = repr_tree_defs(dep_info)
 | 
| @@ -373,11 +359,8 @@ given file (report RP0402 must not be disabled)'}
 | 
|          cache them
 | 
|          """
 | 
|          if self.__ext_dep_info is None:
 | 
| -            package = self.linter.current_name
 | 
| -            self.__ext_dep_info = result = {}
 | 
| -            for importee, importers in self.stats['dependencies'].iteritems():
 | 
| -                if not importee.startswith(package):
 | 
| -                    result[importee] = importers
 | 
| +            self.__ext_dep_info = filter_dependencies_info(
 | 
| +                self.stats['dependencies'], self.package_dir(), 'external')
 | 
|          return self.__ext_dep_info
 | 
|  
 | 
|      def _internal_dependencies_info(self):
 | 
| @@ -385,11 +368,8 @@ given file (report RP0402 must not be disabled)'}
 | 
|          cache them
 | 
|          """
 | 
|          if self.__int_dep_info is None:
 | 
| -            package = self.linter.current_name
 | 
| -            self.__int_dep_info = result = {}
 | 
| -            for importee, importers in self.stats['dependencies'].iteritems():
 | 
| -                if importee.startswith(package):
 | 
| -                    result[importee] = importers
 | 
| +            self.__int_dep_info = filter_dependencies_info(
 | 
| +                self.stats['dependencies'], self.package_dir(), 'internal')
 | 
|          return self.__int_dep_info
 | 
|  
 | 
|  
 | 
| 
 |