diff options
-rw-r--r-- | .hgtags | 2 | ||||
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | __pkginfo__.py | 9 | ||||
-rw-r--r-- | brain/py2mechanize.py | 20 | ||||
-rw-r--r-- | brain/py2qt4.py | 25 | ||||
-rw-r--r-- | brain/py2stdlib.py | 55 | ||||
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | inspector.py | 2 | ||||
-rw-r--r-- | rebuilder.py | 2 | ||||
-rw-r--r-- | scoped_nodes.py | 8 | ||||
-rw-r--r-- | setup.py | 21 | ||||
-rw-r--r-- | test/data/absimport.py | 3 | ||||
-rw-r--r-- | test/data/email.py | 1 | ||||
-rw-r--r-- | test/unittest_manager.py | 5 | ||||
-rw-r--r-- | test/unittest_nodes.py | 13 | ||||
-rw-r--r-- | test/unittest_scoped_nodes.py | 18 |
16 files changed, 181 insertions, 18 deletions
@@ -37,3 +37,5 @@ fd80e67a98016c455479ac80bb387c08970aae57 logilab-astng-version-0.23.0 abf75e6ca8ae4e48084ed1ee72a6cfa571c5db85 logilab-astng-debian-version-0.23.1-1 e2ba7d936faf27fe8d680572265a99345f47faed logilab-astng-version-0.24.0 d517d5a9bac963fac4777eecc34f09c1263c076c logilab-astng-debian-version-0.24.0-1 +604235790acecbc65ddffc0b32fbdda63b836b54 logilab-astng-version-0.24.1 +185d76f61c9c5436c0d8b4400d73468fd1e13ef0 logilab-astng-debian-version-0.24.1-1 @@ -1,6 +1,15 @@ Change log for the astng package ================================ + -- + * #106191: fix __future__ absolute import w/ From node + * #50395: fix function fromlineno when some decorator is splited on + multiple lines (patch by Mark Gius) + * #92362: fix pyreverse crash on relative import + * #104041: fix crash 'module object has no file_encoding attribute' + * #4294 (pylint-brain): bad inference on mechanize.Browser.open + * #46273 (pylint-brain): bad inference subprocess.Popen.communicate + 2012-07-18 -- 0.24.0 * include pylint brain extension, describing some stuff not properly understood until then. (#100013, #53049, #23986, #72355) diff --git a/__pkginfo__.py b/__pkginfo__.py index c21926d9..214973fb 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -24,7 +24,7 @@ distname = 'logilab-astng' modname = 'astng' subpackage_of = 'logilab' -numversion = (0, 24, 0) +numversion = (0, 24, 1) version = '.'.join([str(num) for num in numversion]) install_requires = ['logilab-common >= 0.53.0'] @@ -43,3 +43,10 @@ from os.path import join include_dirs = ['brain', join('test', 'regrtest_data'), join('test', 'data'), join('test', 'data2')] + +classifiers = ["Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Quality Assurance", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 3", + ] diff --git a/brain/py2mechanize.py b/brain/py2mechanize.py new file mode 100644 index 00000000..50f718e7 --- /dev/null +++ b/brain/py2mechanize.py @@ -0,0 +1,20 @@ +from logilab.astng import MANAGER +from logilab.astng.builder import ASTNGBuilder + +def mechanize_transform(module): + fake = ASTNGBuilder(MANAGER).string_build(''' + +class Browser(object): + def open(self, url, data=None, timeout=None): + return None + def open_novisit(self, url, data=None, timeout=None): + return None + def open_local_file(self, filename): + return None + +''') + module.locals['Browser'] = fake.locals['Browser'] + +import py2stdlib +py2stdlib.MODULE_TRANSFORMS['mechanize'] = mechanize_transform + diff --git a/brain/py2qt4.py b/brain/py2qt4.py new file mode 100644 index 00000000..f3d8c3bf --- /dev/null +++ b/brain/py2qt4.py @@ -0,0 +1,25 @@ +"""ASTNG hooks for the Python 2 qt4 module. + +Currently help understanding of : + +* PyQT4.QtCore +""" + +from logilab.astng import MANAGER +from logilab.astng.builder import ASTNGBuilder + + +def pyqt4_qtcore_transform(module): + fake = ASTNGBuilder(MANAGER).string_build(''' + +def SIGNAL(signal_name): pass + +class QObject(object): + def emit(self, signal): pass +''') + for klass in ('QObject',): + module.locals[klass] = fake.locals[klass] + + +import py2stdlib +py2stdlib.MODULE_TRANSFORMS['PyQt4.QtCore'] = pyqt4_qtcore_transform diff --git a/brain/py2stdlib.py b/brain/py2stdlib.py index 4c1c3b7e..c16ad4c4 100644 --- a/brain/py2stdlib.py +++ b/brain/py2stdlib.py @@ -95,16 +95,59 @@ def cleanup_resources(force=False): for func_name, func in fake.locals.items(): module.locals[func_name] = func - # for func in ('resource_exists', 'resource_isdir', 'resource_filename', - # 'resource_stream', 'resource_string', 'resource_listdir', - # 'extraction_error', 'get_cache_path', 'postprocess', - # 'set_extraction_path', 'cleanup_resources'): - # module.locals[func] = fake.locals[func] +def urlparse_transform(module): + fake = ASTNGBuilder(MANAGER).string_build(''' + +def urlparse(urlstring, default_scheme='', allow_fragments=True): + return ParseResult() + +class ParseResult(object): + def __init__(self): + self.scheme = '' + self.netloc = '' + self.path = '' + self.params = '' + self.query = '' + self.fragment = '' + self.username = None + self.password = None + self.hostname = None + self.port = None + + def geturl(self): + return '' +''') + + for func_name, func in fake.locals.items(): + module.locals[func_name] = func + +def subprocess_transform(module): + fake = ASTNGBuilder(MANAGER).string_build(''' + +class Popen(object): + + def __init__(self, args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0): + pass + + def communicate(self, input=None): + return ('string', 'string') + ''') + + for func_name, func in fake.locals.items(): + module.locals[func_name] = func + + MODULE_TRANSFORMS['hashlib'] = hashlib_transform MODULE_TRANSFORMS['collections'] = collections_transform MODULE_TRANSFORMS['pkg_resources'] = pkg_resources_transform +MODULE_TRANSFORMS['urlparse'] = urlparse_transform +MODULE_TRANSFORMS['subprocess'] = subprocess_transform def transform(module): @@ -117,3 +160,5 @@ def transform(module): from logilab.astng import MANAGER MANAGER.register_transformer(transform) + + diff --git a/debian/changelog b/debian/changelog index f62287ae..fd6d66e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +logilab-astng (0.24.1-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault <sylvain.thenault@logilab.fr> Fri, 05 Oct 2012 12:52:08 +0200 + logilab-astng (0.24.0-1) unstable; urgency=low * new upstream release diff --git a/inspector.py b/inspector.py index a4abd1f2..e6672a48 100644 --- a/inspector.py +++ b/inspector.py @@ -254,7 +254,7 @@ class Linker(IdGeneratorMixIn, LocalsVisitor): if fullname.find('.') > -1: try: # XXX: don't use get_module_part, missing package precedence - fullname = get_module_part(fullname) + fullname = get_module_part(fullname, context_file) except ImportError: continue if fullname != basename: diff --git a/rebuilder.py b/rebuilder.py index bac7a095..216708a8 100644 --- a/rebuilder.py +++ b/rebuilder.py @@ -457,7 +457,7 @@ class TreeRebuilder(object): def visit_from(self, node, parent): """visit a From node by returning a fresh instance of it""" names = [(alias.name, alias.asname) for alias in node.names] - newnode = new.From(node.module or '', names, node.level) + newnode = new.From(node.module or '', names, node.level or None) _set_infos(node, newnode, parent) # store From names to add them to locals after building self._from_nodes.append(newnode) diff --git a/scoped_nodes.py b/scoped_nodes.py index 1a1242c5..9c23ebfa 100644 --- a/scoped_nodes.py +++ b/scoped_nodes.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # copyright 2003-2010 Sylvain Thenault, all rights reserved. # contact mailto:thenault@gmail.com @@ -220,6 +220,9 @@ class Module(LocalsDictNodeNG): # the file from which as been extracted the astng representation. It may # be None if the representation has been built from a built-in module file = None + # encoding of python source file, so we can get unicode out of it (python2 + # only) + file_encoding = None # the module name name = None # boolean for astng built from source (i.e. ast) @@ -540,7 +543,8 @@ class Function(Statement, Lambda): self.fromlineno = self.lineno # lineno is the line number of the first decorator, we want the def statement lineno if self.decorators is not None: - self.fromlineno += len(self.decorators.nodes) + self.fromlineno += sum(node.tolineno - node.lineno + 1 + for node in self.decorators.nodes) self.tolineno = lastchild.tolineno self.blockstart_tolineno = self.args.tolineno @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # pylint: disable=W0404,W0622,W0704,W0613 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-astng. @@ -60,6 +60,7 @@ include_dirs = getattr(__pkginfo__, 'include_dirs', []) ext_modules = getattr(__pkginfo__, 'ext_modules', None) install_requires = getattr(__pkginfo__, 'install_requires', None) dependency_links = getattr(__pkginfo__, 'dependency_links', []) +classifiers = getattr(__pkginfo__, 'classifiers', []) STD_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build') @@ -104,8 +105,7 @@ except ImportError: ''' class MyInstallLib(install_lib.install_lib): - """extend install_lib command to handle package __init__.py and - include_dirs variable if necessary + """extend install_lib command to handle package __init__.py if necessary """ def run(self): """overridden from install_lib class""" @@ -118,17 +118,27 @@ class MyInstallLib(install_lib.install_lib): stream = open(product_init, 'w') stream.write(EMPTY_FILE) stream.close() + + +class MyBuildPy(build_py): + """extend build_by command to handle include_dirs variable if necessary + """ + def run(self): + """overridden from install_lib class""" + build_py.run(self) # manually install included directories if any if include_dirs: if subpackage_of: base = join(subpackage_of, modname) else: base = modname + basedir = os.path.join(self.build_lib, base) for directory in include_dirs: - dest = join(self.install_dir, base, directory) + dest = join(basedir, directory) shutil.rmtree(dest, ignore_errors=True) shutil.copytree(directory, dest) + def install(**kwargs): """setup entry point""" if USE_SETUPTOOLS: @@ -155,6 +165,7 @@ def install(**kwargs): license = license, description = description, long_description = long_description, + classifiers = classifiers, author = author, author_email = author_email, url = web, @@ -162,7 +173,7 @@ def install(**kwargs): data_files = data_files, ext_modules = ext_modules, cmdclass = {'install_lib': MyInstallLib, - 'build_py': build_py}, + 'build_py': MyBuildPy}, **kwargs ) diff --git a/test/data/absimport.py b/test/data/absimport.py new file mode 100644 index 00000000..f98effa6 --- /dev/null +++ b/test/data/absimport.py @@ -0,0 +1,3 @@ +from __future__ import absolute_import +import email +from email import message diff --git a/test/data/email.py b/test/data/email.py new file mode 100644 index 00000000..dc593564 --- /dev/null +++ b/test/data/email.py @@ -0,0 +1 @@ +"""fake email module to test absolute import doesn't grab this one""" diff --git a/test/unittest_manager.py b/test/unittest_manager.py index 9206ded8..d87967f7 100644 --- a/test/unittest_manager.py +++ b/test/unittest_manager.py @@ -83,8 +83,9 @@ class ASTNGManagerTC(TestCase): obj = self.manager.project_from_files([DATA], _silent_no_wrap, 'data') expected = set(['SSL1', '__init__', 'all', 'appl', 'format', 'module', 'module2', 'noendingnewline', 'nonregr', 'notall']) - expected = ['data', 'data.SSL1', 'data.SSL1.Connection1', 'data.all', - 'data.appl', 'data.appl.myConnection', 'data.format', + expected = ['data', 'data.SSL1', 'data.SSL1.Connection1', + 'data.absimport', 'data.all', + 'data.appl', 'data.appl.myConnection', 'data.email', 'data.format', 'data.module', 'data.module2', 'data.noendingnewline', 'data.nonregr', 'data.notall'] self.assertListEqual(sorted(k for k in obj.keys()), expected) diff --git a/test/unittest_nodes.py b/test/unittest_nodes.py index e3e359a8..7eb9099c 100644 --- a/test/unittest_nodes.py +++ b/test/unittest_nodes.py @@ -35,7 +35,7 @@ import sys from logilab.common import testlib from logilab.astng.node_classes import unpack_infer -from logilab.astng.bases import YES +from logilab.astng.bases import YES, InferenceContext from logilab.astng.exceptions import ASTNGBuildingException, NotFoundError from logilab.astng import BUILTINS_MODULE, builder, nodes from logilab.astng.as_string import as_string @@ -306,6 +306,17 @@ except PickleError: excs = list(unpack_infer(handler_type)) + def test_absolute_import(self): + astng = abuilder.file_build(self.datapath('absimport.py')) + ctx = InferenceContext() + ctx.lookupname = 'message' + # will fail if absolute import failed + astng['message'].infer(ctx).next() + ctx.lookupname = 'email' + m = astng['email'].infer(ctx).next() + self.assertFalse(m.file.startswith(self.datapath('email.py'))) + + class CmpNodeTC(testlib.TestCase): def test_as_string(self): ast = abuilder.string_build("a == 2").body[0] diff --git a/test/unittest_scoped_nodes.py b/test/unittest_scoped_nodes.py index 89e42833..6e647566 100644 --- a/test/unittest_scoped_nodes.py +++ b/test/unittest_scoped_nodes.py @@ -617,6 +617,24 @@ class Past(Present): self.assertIsInstance(attr1, nodes.AssName) self.assertEqual(attr1.name, 'attr') + def test_function_with_decorator_lineno(self): + data = ''' +@f(a=2, + b=3) +def g1(x): + print x + +@f(a=2, + b=3) +def g2(): + pass +''' + astng = abuilder.string_build(data) + self.assertEqual(astng['g1'].fromlineno, 4) + self.assertEqual(astng['g1'].tolineno, 5) + self.assertEqual(astng['g2'].fromlineno, 9) + self.assertEqual(astng['g2'].tolineno, 10) + __all__ = ('ModuleNodeTC', 'ImportNodeTC', 'FunctionNodeTC', 'ClassNodeTC') |