summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgtags2
-rw-r--r--ChangeLog9
-rw-r--r--__pkginfo__.py9
-rw-r--r--brain/py2mechanize.py20
-rw-r--r--brain/py2qt4.py25
-rw-r--r--brain/py2stdlib.py55
-rw-r--r--debian/changelog6
-rw-r--r--inspector.py2
-rw-r--r--rebuilder.py2
-rw-r--r--scoped_nodes.py8
-rw-r--r--setup.py21
-rw-r--r--test/data/absimport.py3
-rw-r--r--test/data/email.py1
-rw-r--r--test/unittest_manager.py5
-rw-r--r--test/unittest_nodes.py13
-rw-r--r--test/unittest_scoped_nodes.py18
16 files changed, 181 insertions, 18 deletions
diff --git a/.hgtags b/.hgtags
index fb9af264..ab0d0591 100644
--- a/.hgtags
+++ b/.hgtags
@@ -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
diff --git a/ChangeLog b/ChangeLog
index 2a36ef9a..58e6ed67 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/setup.py b/setup.py
index 4889da26..b8e600ef 100644
--- a/setup.py
+++ b/setup.py
@@ -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')