170 lines
4.5 KiB
Python
170 lines
4.5 KiB
Python
|
"""
|
||
|
This is a compatibility module, to make it possible to use jedi also with older
|
||
|
python versions.
|
||
|
"""
|
||
|
import sys
|
||
|
|
||
|
is_py3k = sys.hexversion >= 0x03000000
|
||
|
|
||
|
is_py25 = sys.hexversion < 0x02060000
|
||
|
|
||
|
# next was defined in python 2.6, in python 3 obj.next won't be possible
|
||
|
# anymore
|
||
|
try:
|
||
|
next = next
|
||
|
except NameError:
|
||
|
_raiseStopIteration = object()
|
||
|
|
||
|
def next(iterator, default=_raiseStopIteration):
|
||
|
if not hasattr(iterator, 'next'):
|
||
|
raise TypeError("not an iterator")
|
||
|
try:
|
||
|
return iterator.next()
|
||
|
except StopIteration:
|
||
|
if default is _raiseStopIteration:
|
||
|
raise
|
||
|
else:
|
||
|
return default
|
||
|
|
||
|
# ast module was defined in python 2.6
|
||
|
try:
|
||
|
from ast import literal_eval
|
||
|
except ImportError:
|
||
|
literal_eval = eval
|
||
|
|
||
|
|
||
|
# properties in 2.5
|
||
|
try:
|
||
|
property.setter
|
||
|
except AttributeError:
|
||
|
class property(property):
|
||
|
def __init__(self, fget, *args, **kwargs):
|
||
|
self.__doc__ = fget.__doc__
|
||
|
super(property, self).__init__(fget, *args, **kwargs)
|
||
|
|
||
|
def setter(self, fset):
|
||
|
cls_ns = sys._getframe(1).f_locals
|
||
|
for k, v in cls_ns.iteritems():
|
||
|
if v == self:
|
||
|
propname = k
|
||
|
break
|
||
|
cls_ns[propname] = property(self.fget, fset,
|
||
|
self.fdel, self.__doc__)
|
||
|
return cls_ns[propname]
|
||
|
else:
|
||
|
property = property
|
||
|
|
||
|
# unicode function
|
||
|
try:
|
||
|
unicode = unicode
|
||
|
except NameError:
|
||
|
unicode = str
|
||
|
|
||
|
if is_py3k:
|
||
|
utf8 = lambda s: s
|
||
|
else:
|
||
|
utf8 = lambda s: s.decode('utf-8')
|
||
|
|
||
|
utf8.__doc__ = """
|
||
|
Decode a raw string into unicode object. Do nothing in Python 3.
|
||
|
"""
|
||
|
|
||
|
# exec function
|
||
|
if is_py3k:
|
||
|
def exec_function(source, global_map):
|
||
|
exec(source, global_map)
|
||
|
else:
|
||
|
eval(compile("""def exec_function(source, global_map):
|
||
|
exec source in global_map """, 'blub', 'exec'))
|
||
|
|
||
|
# StringIO (Python 2.5 has no io module), so use io only for py3k
|
||
|
try:
|
||
|
from StringIO import StringIO
|
||
|
except ImportError:
|
||
|
from io import StringIO
|
||
|
|
||
|
# hasattr function used because python
|
||
|
if is_py3k:
|
||
|
hasattr = hasattr
|
||
|
else:
|
||
|
def hasattr(obj, name):
|
||
|
try:
|
||
|
getattr(obj, name)
|
||
|
return True
|
||
|
except AttributeError:
|
||
|
return False
|
||
|
|
||
|
|
||
|
class Python3Method(object):
|
||
|
def __init__(self, func):
|
||
|
self.func = func
|
||
|
|
||
|
def __get__(self, obj, objtype):
|
||
|
if obj is None:
|
||
|
return lambda *args, **kwargs: self.func(*args, **kwargs)
|
||
|
else:
|
||
|
return lambda *args, **kwargs: self.func(obj, *args, **kwargs)
|
||
|
|
||
|
try:
|
||
|
# the python3 way
|
||
|
from functools import reduce
|
||
|
except ImportError:
|
||
|
reduce = reduce
|
||
|
|
||
|
|
||
|
def use_metaclass(meta, *bases):
|
||
|
""" Create a class with a metaclass. """
|
||
|
if not bases:
|
||
|
bases = (object,)
|
||
|
return meta("HackClass", bases, {})
|
||
|
|
||
|
try:
|
||
|
from inspect import cleandoc
|
||
|
except ImportError:
|
||
|
# python 2.5 doesn't have this method
|
||
|
import string
|
||
|
|
||
|
def cleandoc(doc):
|
||
|
"""Clean up indentation from docstrings.
|
||
|
|
||
|
Any whitespace that can be uniformly removed from the second line
|
||
|
onwards is removed."""
|
||
|
try:
|
||
|
lines = string.split(string.expandtabs(doc), '\n')
|
||
|
except UnicodeError:
|
||
|
return None
|
||
|
else:
|
||
|
# Find minimum indentation of any non-blank lines after first line.
|
||
|
margin = sys.maxint
|
||
|
for line in lines[1:]:
|
||
|
content = len(string.lstrip(line))
|
||
|
if content:
|
||
|
indent = len(line) - content
|
||
|
margin = min(margin, indent)
|
||
|
# Remove indentation.
|
||
|
if lines:
|
||
|
lines[0] = lines[0].lstrip()
|
||
|
if margin < sys.maxint:
|
||
|
for i in range(1, len(lines)):
|
||
|
lines[i] = lines[i][margin:]
|
||
|
# Remove any trailing or leading blank lines.
|
||
|
while lines and not lines[-1]:
|
||
|
lines.pop()
|
||
|
while lines and not lines[0]:
|
||
|
lines.pop(0)
|
||
|
return string.join(lines, '\n')
|
||
|
|
||
|
if is_py25:
|
||
|
# adds the `itertools.chain.from_iterable` constructor
|
||
|
import itertools
|
||
|
|
||
|
class chain(itertools.chain):
|
||
|
@staticmethod
|
||
|
def from_iterable(iterables):
|
||
|
# chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
|
||
|
for it in iterables:
|
||
|
for element in it:
|
||
|
yield element
|
||
|
itertools.chain = chain
|
||
|
del chain
|