diff --git a/_compatibility.py b/_compatibility.py index a7d52d1b..7c7cb699 100644 --- a/_compatibility.py +++ b/_compatibility.py @@ -2,6 +2,8 @@ This is a compatibility module, to make it possible to use jedi also with older python versions. """ +import sys + # next was defined in python 2.6, in python 3 obj.next won't be possible # anymore try: @@ -31,8 +33,6 @@ except ImportError: try: property.setter except AttributeError: - import sys - class property(property): def __init__(self, fget, *args, **kwargs): self.__doc__ = fget.__doc__ @@ -49,3 +49,11 @@ except AttributeError: return cls_ns[propname] else: property = property + +# Borrowed from Ned Batchelder +if sys.hexversion > 0x03000000: + 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')) diff --git a/builtin.py b/builtin.py index 0c6735fd..4931400a 100644 --- a/builtin.py +++ b/builtin.py @@ -5,6 +5,8 @@ import os import debug import parsing +from _compatibility import exec_function + module_find_path = sys.path[1:] @@ -89,7 +91,8 @@ class Parser(CachedModule): temp, sys.path = sys.path, self.sys_path # TODO reenable and check (stackoverflow question - pylab builtins) #print 'sypa', sys.path - exec 'import %s as module' % self.name in self._content + exec_function('import %s as module' % self.name, self._content) + self.sys_path, sys.path = sys.path, temp self.sys_path.pop(0) @@ -171,7 +174,7 @@ class Parser(CachedModule): classes, funcs, stmts, members = get_types(names) # classes - for name, cl in classes.iteritems(): + for name, cl in classes.items(): bases = (c.__name__ for c in cl.__bases__) code += 'class %s(%s):\n' % (name, ','.join(bases)) if depth == 0: @@ -180,7 +183,7 @@ class Parser(CachedModule): code += '\n' # functions - for name, func in funcs.iteritems(): + for name, func in funcs.items(): params, ret = parse_function_doc(func) doc_str = parsing.indent_block('"""\n%s\n"""\n' % func.__doc__) try: @@ -201,7 +204,7 @@ class Parser(CachedModule): code += mixin[:pos] + doc_str + mixin[pos:] # class members (functions) - for name, func in members.iteritems(): + for name, func in members.items(): ret = 'pass' code += '@property\ndef %s(self):\n' % (name) block = '"""\n%s\n"""\n' % func.__doc__ @@ -209,8 +212,8 @@ class Parser(CachedModule): code += parsing.indent_block(block) # variables - for name, value in stmts.iteritems(): - if type(value) == file: + for name, value in stmts.items(): + if type(value).__name__ == 'file': value = 'file' elif type(value).__name__ in ['int', 'bool', 'float', 'dict', 'list', 'tuple']: @@ -290,7 +293,12 @@ def parse_function_doc(func): class _Builtin(object): - _builtins = Parser(name='__builtin__') + # Python 3 compatibility + if sys.hexversion > 0x03000000: + name = 'builtins' + else: + name='__builtin__' + _builtins = Parser(name=name) @property def scope(self): diff --git a/ftest.py b/ftest.py index 4a3b9cd6..1dab12dd 100755 --- a/ftest.py +++ b/ftest.py @@ -3,7 +3,7 @@ import functions functions.debug.debug_function = functions.debug.print_to_stdout -functions.debug.ignored_modules = ['parsing', 'builtin'] +#functions.debug.ignored_modules = ['parsing', 'builtin'] #functions.debug.ignored_modules = ['parsing', 'builtin', 'evaluate', 'modules'] functions.modules.builtin.module_find_path.insert(0, '.') @@ -19,7 +19,7 @@ for i in range(1): #completions = functions.get_definitions(code, 181, 2, path) #completions = functions.complete(code, 42, 200, path) -print '\n', ', '.join(sorted(str(c) for c in completions)) +print('\n', ', '.join(sorted(str(c) for c in completions))) #print [n.name for n in completions] #print [n.name.get_parent_until() for n in completions] -print '#', len(completions) +print('#', len(completions)) diff --git a/modules.py b/modules.py index ebe6f840..57258d28 100644 --- a/modules.py +++ b/modules.py @@ -1,3 +1,4 @@ +from __future__ import with_statement import re import tokenize import imp @@ -60,6 +61,9 @@ class ModuleWithCursor(Module): self._row_temp = None self._relevant_temp = None + # Call the parser already here, because it will be used anyways. + # Also, the position is here important (which will not be used by + # default), therefore fill the cache here. self._parser = parsing.PyFuzzyParser(source, path, row) def get_path_until_cursor(self, column): @@ -192,10 +196,8 @@ def find_module(current_module, point_path): # is a directory module if is_package_directory: path += '/__init__.py' - # python2.5 cannot cope with the `with` statement - #with open(path) as f: - # source = f.read() - source = open(path).read() + with open(path) as f: + source = f.read() else: source = current_namespace[0].read() if path.endswith('.py'): diff --git a/parsetest.py b/parsetest.py index 41817808..7557d015 100644 --- a/parsetest.py +++ b/parsetest.py @@ -132,8 +132,8 @@ class c1(): self.acp = athefirst; self.bcp = 3 def c3(self, daeparam): import os as c4 #from parsing import Scope as c4 - c5 = 1 - c5 = c4( + c5 = 1 + c5 = c4() if 1: print 1 #return c5+'asdf' @@ -178,3 +178,4 @@ a = next(gen_exe) def ret(): r = [] return r. + diff --git a/parsing.py b/parsing.py index af106b1d..5aa3253a 100644 --- a/parsing.py +++ b/parsing.py @@ -34,7 +34,7 @@ TODO check meta classes from _compatibility import next, literal_eval import tokenize -import cStringIO +from io import BytesIO import re import debug @@ -229,7 +229,7 @@ class Module(Scope): The top scope, which is always a module. """ def __init__(self, path, docstr=''): - super(Module, self).__init__(path, docstr) + super(Module, self).__init__(0, 0, docstr) self.path = path self.global_vars = [] @@ -1245,8 +1245,14 @@ class PyFuzzyParser(object): :raises: IndentationError """ - buf = cStringIO.StringIO(self.code) - self.gen = tokenize.generate_tokens(buf.readline) + buf = BytesIO(self.code.encode()) + #print(self.code.encode()) + #print(list(tokenize.tokenize(BytesIO(self.code.encode()).readline))[:9]) + import sys + if sys.hexversion > 0x03000000: + self.gen = tokenize.tokenize(buf.readline) + else: + self.gen = tokenize.generate_tokens(buf.readline) self.currentscope = self.scope extended_flow = ['else', 'elif', 'except', 'finally'] @@ -1270,6 +1276,7 @@ class PyFuzzyParser(object): # check again for unindented stuff. this is true for syntax # errors. only check for names, because thats relevant here. If # some docstrings are not indented, I don't care. + print(self.scope.indent, self.scope) while indent <= self.scope.indent \ and (token_type == tokenize.NAME or tok in ['(', '['])\ and self.scope != self.top: