summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2015-03-30 21:46:38 +0300
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2015-03-30 21:46:38 +0300
commit489781ea3eae1e6b169f4ebc35ec0cf7bd3e269b (patch)
tree905991526bea989fe37561696d340ecebb5a9363
parent4409770f227d0641e6f85c2ee89b044f5d3f9998 (diff)
downloadastroid-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--ChangeLog6
-rw-r--r--astroid/builder.py4
-rw-r--r--astroid/modutils.py24
-rw-r--r--astroid/raw_building.py38
-rw-r--r--astroid/tests/resources.py2
-rw-r--r--astroid/tests/unittest_brain.py3
-rw-r--r--astroid/tests/unittest_builder.py9
-rw-r--r--astroid/tests/unittest_inference.py14
-rw-r--r--astroid/tests/unittest_manager.py19
-rw-r--r--astroid/tests/unittest_modutils.py12
-rw-r--r--astroid/tests/unittest_regrtest.py1
11 files changed, 93 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog
index de5df60..d291623 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 = {}