diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-03-30 21:46:38 +0300 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-03-30 21:46:38 +0300 |
commit | 489781ea3eae1e6b169f4ebc35ec0cf7bd3e269b (patch) | |
tree | 905991526bea989fe37561696d340ecebb5a9363 | |
parent | 4409770f227d0641e6f85c2ee89b044f5d3f9998 (diff) | |
download | astroid-489781ea3eae1e6b169f4ebc35ec0cf7bd3e269b.tar.gz |
Add some fixes which enhances the Jython support.
The fix mostly includes updates to modutils, which is
modified in order to properly lookup paths from live objects,
which ends in $py.class, not pyc as for Python 2,
Closes issue #83.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | astroid/builder.py | 4 | ||||
-rw-r--r-- | astroid/modutils.py | 24 | ||||
-rw-r--r-- | astroid/raw_building.py | 38 | ||||
-rw-r--r-- | astroid/tests/resources.py | 2 | ||||
-rw-r--r-- | astroid/tests/unittest_brain.py | 3 | ||||
-rw-r--r-- | astroid/tests/unittest_builder.py | 9 | ||||
-rw-r--r-- | astroid/tests/unittest_inference.py | 14 | ||||
-rw-r--r-- | astroid/tests/unittest_manager.py | 19 | ||||
-rw-r--r-- | astroid/tests/unittest_modutils.py | 12 | ||||
-rw-r--r-- | astroid/tests/unittest_regrtest.py | 1 |
11 files changed, 93 insertions, 39 deletions
@@ -11,6 +11,12 @@ Change log for the astroid package (used to be astng) multiprocessing.managers.SyncManager. + * Add some fixes which enhances the Jython support. + The fix mostly includes updates to modutils, which is + modified in order to properly lookup paths from live objects, + which ends in $py.class, not pyc as for Python 2, + Closes issue #83. + 2015-03-14 -- 1.3.6 * Class.slots raises NotImplementedError for old style classes. diff --git a/astroid/builder.py b/astroid/builder.py index 671d75c..5aaab5c 100644 --- a/astroid/builder.py +++ b/astroid/builder.py @@ -32,7 +32,7 @@ from astroid.raw_building import InspectBuilder from astroid.rebuilder import TreeRebuilder from astroid.manager import AstroidManager from astroid.bases import YES, Instance -from astroid.modutils import modpath_from_file +from astroid.modutils import modpath_from_file, _path_from_filename from _ast import PyCF_ONLY_AST def parse(string): @@ -94,7 +94,7 @@ class AstroidBuilder(InspectBuilder): node = None path = getattr(module, '__file__', None) if path is not None: - path_, ext = splitext(module.__file__) + path_, ext = splitext(_path_from_filename(path)) if ext in ('.py', '.pyc', '.pyo') and exists(path_ + '.py'): node = self.file_build(path_ + '.py', modname) if node is None: diff --git a/astroid/modutils.py b/astroid/modutils.py index 5ea6330..5241f58 100644 --- a/astroid/modutils.py +++ b/astroid/modutils.py @@ -32,6 +32,7 @@ __docformat__ = "restructuredtext en" import imp import os +import platform import sys from distutils.sysconfig import get_python_lib from distutils.errors import DistutilsPlatformError @@ -83,7 +84,7 @@ except DistutilsPlatformError: STD_LIB_DIRS = set() EXT_LIB_DIR = get_python_lib() - +IS_JYTHON = platform.python_implementation() == 'Jython' BUILTIN_MODULES = dict(zip(sys.builtin_module_names, [1]*len(sys.builtin_module_names))) @@ -97,6 +98,20 @@ def _normalize_path(path): return os.path.normcase(os.path.abspath(path)) +def _path_from_filename(filename, is_jython=IS_JYTHON): + if not is_jython: + if sys.version_info > (3, 0): + return filename + else: + if filename.endswith(".pyc"): + return filename[:-1] + return filename + head, has_pyclass, _ = filename.partition("$py.class") + if has_pyclass: + return head + ".py" + return filename + + _NORM_PATH_CACHE = {} def _cache_normalize_path(path): @@ -246,7 +261,9 @@ def modpath_from_file(filename, extrapath=None): :rtype: list(str) :return: the corresponding splitted module's name """ - base = os.path.splitext(os.path.abspath(filename))[0] + filename = _path_from_filename(filename) + filename = os.path.abspath(filename) + base = os.path.splitext(filename)[0] if extrapath is not None: for path_ in extrapath: path = os.path.abspath(path_) @@ -419,7 +436,8 @@ def get_source_file(filename, include_no_ext=False): :rtype: str :return: the absolute path of the source file if it exists """ - base, orig_ext = os.path.splitext(os.path.abspath(filename)) + filename = os.path.abspath(_path_from_filename(filename)) + base, orig_ext = os.path.splitext(filename) for ext in PY_SOURCE_EXTS: source_path = '%s.%s' % (base, ext) if os.path.exists(source_path): diff --git a/astroid/raw_building.py b/astroid/raw_building.py index 99a026a..abfe254 100644 --- a/astroid/raw_building.py +++ b/astroid/raw_building.py @@ -24,7 +24,8 @@ __docformat__ = "restructuredtext en" import sys from os.path import abspath from inspect import (getargspec, isdatadescriptor, isfunction, ismethod, - ismethoddescriptor, isclass, isbuiltin, ismodule) + ismethoddescriptor, isclass, isbuiltin, ismodule, + isroutine) import six from astroid.node_classes import CONST_CLS @@ -200,6 +201,22 @@ def _base_class_object_build(node, member, basenames, name=None, localname=None) return klass +def _build_from_function(node, name, member, module): + # verify this is not an imported function + try: + code = six.get_function_code(member) + except AttributeError: + # Some implementations don't provide the code object, + # such as Jython. + code = None + filename = getattr(code, 'co_filename', None) + if filename is None: + assert isinstance(member, object) + object_build_methoddescriptor(node, member, name) + elif filename != getattr(module, '__file__', None): + attach_dummy_node(node, name, member) + else: + object_build_function(node, member, name) class InspectBuilder(object): @@ -253,20 +270,11 @@ class InspectBuilder(object): if ismethod(member): member = six.get_method_function(member) if isfunction(member): - # verify this is not an imported function - filename = getattr(six.get_function_code(member), - 'co_filename', None) - if filename is None: - assert isinstance(member, object) - object_build_methoddescriptor(node, member, name) - elif filename != getattr(self._module, '__file__', None): - attach_dummy_node(node, name, member) - else: - object_build_function(node, member, name) - elif isbuiltin(member): + _build_from_function(node, name, member, self._module) + elif isbuiltin(member): if (not _io_discrepancy(member) and self.imported_member(node, member, name)): - continue + continue object_build_methoddescriptor(node, member, name) elif isclass(member): if self.imported_member(node, member, name): @@ -289,6 +297,10 @@ class InspectBuilder(object): object_build_datadescriptor(node, member, name) elif type(member) in _CONSTANTS: attach_const_node(node, name, member) + elif isroutine(member): + # This should be called for Jython, where some builtin + # methods aren't catched by isbuiltin branch. + _build_from_function(node, name, member, self._module) else: # create an empty node so that the name is actually defined attach_dummy_node(node, name, member) diff --git a/astroid/tests/resources.py b/astroid/tests/resources.py index 03d4562..7988d05 100644 --- a/astroid/tests/resources.py +++ b/astroid/tests/resources.py @@ -33,7 +33,7 @@ def find(name): def build_file(path, modname=None): - return builder.AstroidBuilder().file_build(find(path), modname) + return builder.AstroidBuilder().file_build(find(path), modname) class SysPathSetup(object): diff --git a/astroid/tests/unittest_brain.py b/astroid/tests/unittest_brain.py index 79bb3c6..540d8e6 100644 --- a/astroid/tests/unittest_brain.py +++ b/astroid/tests/unittest_brain.py @@ -15,6 +15,7 @@ # You should have received a copy of the GNU Lesser General Public License along # with logilab-astng. If not, see <http://www.gnu.org/licenses/>. """Tests for basic functionality in astroid.brain.""" +import os import sys import unittest from textwrap import dedent @@ -140,6 +141,8 @@ class NoseBrainTest(unittest.TestCase): class MultiprocessingBrainTest(unittest.TestCase): + @unittest.skipIf(os.name == 'java', + 'multiprocesing is not available on Jython') def test_multiprocessing_manager(self): # Test that we have the proper attributes # for a multiprocessing.managers.SyncManager diff --git a/astroid/tests/unittest_builder.py b/astroid/tests/unittest_builder.py index 4db0ae3..3df9d36 100644 --- a/astroid/tests/unittest_builder.py +++ b/astroid/tests/unittest_builder.py @@ -306,6 +306,9 @@ class BuilderTest(unittest.TestCase): self.assertTrue(time_ast) self.assertEqual(time_ast['time'].args.defaults, []) + if os.name == 'java': + test_inspect_build1 = unittest.expectedFailure(test_inspect_build1) + def test_inspect_build2(self): """test astroid tree build from a living object""" try: @@ -449,6 +452,11 @@ class BuilderTest(unittest.TestCase): with self.assertRaises(InferenceError): next(astroid['global_no_effect'].ilookup('CSTE2')) + @unittest.skipIf(os.name == 'java', + 'This test is skipped on Jython, because the ' + 'socket object is patched later on with the ' + 'methods we are looking for. Since we do not ' + 'understand setattr in for loops yet, we skip this') def test_socket_build(self): import socket astroid = self.builder.module_build(socket) @@ -456,7 +464,6 @@ class BuilderTest(unittest.TestCase): # the socket module) but the last one as those attributes dynamically # set and astroid is missing this. for fclass in astroid.igetattr('socket'): - #print fclass.root().name, fclass.name, fclass.lineno self.assertIn('connect', fclass) self.assertIn('send', fclass) self.assertIn('close', fclass) diff --git a/astroid/tests/unittest_inference.py b/astroid/tests/unittest_inference.py index fad7351..135681c 100644 --- a/astroid/tests/unittest_inference.py +++ b/astroid/tests/unittest_inference.py @@ -17,6 +17,7 @@ # with astroid. If not, see <http://www.gnu.org/licenses/>. """tests for the astroid inference capabilities """ +import os import sys from functools import partial import unittest @@ -736,6 +737,9 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): self.assertIsInstance(infered[0], nodes.Function) self.assertEqual(infered[0].name, 'open') + if os.name == 'java': + test_builtin_open = unittest.expectedFailure(test_builtin_open) + def test_callfunc_context_func(self): code = ''' def mirror(arg=None): @@ -791,9 +795,6 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): from os.path import exists as e assert e(__file__) - - from new import code as make_code - print (make_code) ''' ast = test_utils.build_module(code, __name__) infered = list(ast.igetattr('osp')) @@ -804,13 +805,6 @@ class InferenceTest(resources.SysPathSetup, unittest.TestCase): self.assertEqual(len(infered), 1) self.assertIsInstance(infered[0], nodes.Function) self.assertEqual(infered[0].name, 'exists') - if sys.version_info >= (3, 0): - self.skipTest('<new> module has been removed') - infered = list(ast.igetattr('make_code')) - self.assertEqual(len(infered), 1) - self.assertIsInstance(infered[0], Instance) - self.assertEqual(str(infered[0]), - 'Instance of %s.type' % BUILTINS) def _test_const_infered(self, node, value): infered = list(node.infer()) diff --git a/astroid/tests/unittest_manager.py b/astroid/tests/unittest_manager.py index b960d23..07b2588 100644 --- a/astroid/tests/unittest_manager.py +++ b/astroid/tests/unittest_manager.py @@ -16,6 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License along # with astroid. If not, see <http://www.gnu.org/licenses/>. import os +import platform import sys import unittest @@ -25,6 +26,15 @@ from astroid.exceptions import AstroidBuildingException from astroid.tests import resources +def _get_file_from_object(obj): + if platform.python_implementation() == 'Jython': + return obj.__file__.split("$py.class")[0] + ".py" + if sys.version_info > (3, 0): + return obj.__file__ + else: + return obj.__file__[:-1] + + class AstroidManagerTest(resources.SysPathSetup, resources.AstroidCacheSetupMixin, unittest.TestCase): @@ -134,12 +144,9 @@ class AstroidManagerTest(resources.SysPathSetup, def test_file_from_module(self): """check if the unittest filepath is equals to the result of the method""" - if sys.version_info > (3, 0): - unittest_file = unittest.__file__ - else: - unittest_file = unittest.__file__[:-1] - self.assertEqual(unittest_file, - self.manager.file_from_module_name('unittest', None)[0]) + self.assertEqual( + _get_file_from_object(unittest), + self.manager.file_from_module_name('unittest', None)[0]) def test_file_from_module_name_astro_building_exception(self): """check if the method launch a exception with a wrong module name""" diff --git a/astroid/tests/unittest_modutils.py b/astroid/tests/unittest_modutils.py index 61391a5..e62ffe6 100644 --- a/astroid/tests/unittest_modutils.py +++ b/astroid/tests/unittest_modutils.py @@ -27,6 +27,10 @@ from astroid import modutils from astroid.tests import resources +def _get_file_from_object(obj): + return modutils._path_from_filename(obj.__file__) + + class ModuleFileTest(unittest.TestCase): package = "mypypa" @@ -122,8 +126,9 @@ class FileFromModPathTest(resources.SysPathSetup, unittest.TestCase): if it exists""" def test_site_packages(self): - self.assertEqual(os.path.realpath(modutils.file_from_modpath(['astroid', 'modutils'])), - os.path.realpath(modutils.__file__.replace('.pyc', '.py'))) + filename = _get_file_from_object(modutils) + result = modutils.file_from_modpath(['astroid', 'modutils']) + self.assertEqual(os.path.realpath(result), filename) def test_std_lib(self): from os import path @@ -157,8 +162,9 @@ class FileFromModPathTest(resources.SysPathSetup, unittest.TestCase): class GetSourceFileTest(unittest.TestCase): def test(self): + filename = _get_file_from_object(os.path) self.assertEqual(modutils.get_source_file(os.path.__file__), - os.path.normpath(os.path.__file__.replace('.pyc', '.py'))) + os.path.normpath(filename)) def test_raise(self): self.assertRaises(modutils.NoSourceFile, modutils.get_source_file, 'whatever') diff --git a/astroid/tests/unittest_regrtest.py b/astroid/tests/unittest_regrtest.py index 056e77f..7db372c 100644 --- a/astroid/tests/unittest_regrtest.py +++ b/astroid/tests/unittest_regrtest.py @@ -50,6 +50,7 @@ class NonRegressionTests(resources.AstroidCacheSetupMixin, # avoid caching into the AstroidManager borg since we get problems # with other tests : manager.__dict__ = {} + manager._failed_import_hooks = [] manager.astroid_cache = {} manager._mod_file_cache = {} manager.transforms = {} |