diff --git a/jedi/api.py b/jedi/api.py index 96ecd0ff..7975e94e 100644 --- a/jedi/api.py +++ b/jedi/api.py @@ -70,9 +70,9 @@ class Script(object): api_classes._clear_caches() debug.reset_time() self.source = modules.source_to_unicode(source, source_encoding) - self.pos = self._line, self._column + self._pos = self._line, self._column self._module = modules.ModuleWithCursor( - path, source=self.source, position=self.pos) + path, source=self.source, position=self._pos) self._source_path = path self.path = None if path is None else os.path.abspath(path) debug.speed('init') @@ -165,7 +165,7 @@ class Script(object): except NotFoundError: scopes = [] scope_generator = evaluate.get_names_of_scope( - self._parser.user_scope, self.pos) + self._parser.user_scope, self._pos) completions = [] for scope, name_list in scope_generator: for c in name_list: @@ -184,7 +184,7 @@ class Script(object): if not current_line.endswith('import import'): continue a = s.import_stmt.alias - if a and a.start_pos <= self.pos <= a.end_pos: + if a and a.start_pos <= self._pos <= a.end_pos: continue names = s.get_defined_names(on_import_stmt=True) else: @@ -230,7 +230,7 @@ class Script(object): return scopes def _get_under_cursor_stmt(self, cursor_txt): - offset = self.pos[0] - 1, self.pos[1] + offset = self._line - 1, self._column r = parsing.Parser(cursor_txt, no_docstr=True, offset=offset) try: stmt = r.module.statements[0] @@ -333,7 +333,7 @@ class Script(object): elif not goto_path: op = self._module.get_operator_under_cursor() if op and op not in lower_priority_operators: - scopes = set([keywords.get_operator(op, self.pos)]) + scopes = set([keywords.get_operator(op, self._pos)]) # Fetch definition of callee if not goto_path: @@ -343,11 +343,11 @@ class Script(object): call = call.next # reset cursor position: (row, col) = call.name.end_pos - self.pos = (row, max(col - 1, 0)) + _pos = (row, max(col - 1, 0)) self._module = modules.ModuleWithCursor( self._source_path, source=self.source, - position=self.pos) + position=_pos) # then try to find the path again goto_path = self._module.get_path_under_cursor() @@ -355,12 +355,12 @@ class Script(object): if goto_path: scopes = set(self._prepare_goto(goto_path)) elif op in lower_priority_operators: - scopes = set([keywords.get_operator(op, self.pos)]) + scopes = set([keywords.get_operator(op, self._pos)]) scopes = resolve_import_paths(scopes) # add keywords - scopes |= keywords.keywords(string=goto_path, pos=self.pos) + scopes |= keywords.keywords(string=goto_path, pos=self._pos) d = set([api_classes.Definition(s) for s in scopes if not isinstance(s, imports.ImportPath._GlobalNamespace)]) @@ -429,7 +429,7 @@ class Script(object): if isinstance(user_stmt, pr.Statement): c = user_stmt.get_commands() if c and not isinstance(c[0], (str, unicode)) and \ - c[0].start_pos > self.pos: + c[0].start_pos > self._pos: # The cursor must be after the start, otherwise the # statement is just an assignee. definitions = [user_stmt] @@ -453,7 +453,7 @@ class Script(object): definitions, search_name = self._goto(add_import_name=True) if isinstance(user_stmt, pr.Statement): c = user_stmt.get_commands()[0] - if not isinstance(c, unicode) and self.pos < c.start_pos: + if not isinstance(c, unicode) and self._pos < c.start_pos: # the search_name might be before `=` definitions = [v for v in user_stmt.set_vars if unicode(v.names[-1]) == search_name] @@ -517,7 +517,7 @@ class Script(object): user_stmt = self._user_stmt() if user_stmt is not None and isinstance(user_stmt, pr.Statement): call, index, _ = helpers.search_function_definition( - user_stmt, self.pos) + user_stmt, self._pos) debug.speed('func_call parsed') return call, index @@ -531,7 +531,7 @@ class Script(object): if user_stmt.alias == i: continue for name_part in i.names: - if name_part.end_pos >= self.pos: + if name_part.end_pos >= self._pos: if not cur_name_part: cur_name_part = name_part kill_count += 1 diff --git a/jedi/parsing_representation.py b/jedi/parsing_representation.py index 1576861f..ddb182a4 100644 --- a/jedi/parsing_representation.py +++ b/jedi/parsing_representation.py @@ -266,7 +266,7 @@ class Scope(Simple, IsScope): :return: True if there are no subscopes, imports and statements. :rtype: bool """ - return not (self.imports or self.subscopes or self.statements) + return not (self.imports or self.subscopes or self.statements or self.returns) @Python3Method def get_statement_for_position(self, pos, include_imports=False): @@ -423,6 +423,8 @@ class Class(Scope): string += ':\n' string += super(Class, self).get_code(True, indention) if self.is_empty(): + if self.docstr: + string += indention string += "pass\n" return string @@ -472,12 +474,11 @@ class Function(Scope): string += "def %s(%s):\n" % (self.name, params) string += super(Function, self).get_code(True, indention) if self.is_empty(): + if self.docstr: + string += indention string += 'pass\n' return string - def is_empty(self): - return super(Function, self).is_empty() and not self.returns - def get_set_vars(self): n = super(Function, self).get_set_vars() for p in self.params: @@ -835,13 +836,6 @@ class Statement(Simple): # first keyword of the first token is global -> must be a global return str(self.token_list[0]) == "global" - def get_command(self, index): - commands = self.get_commands() - try: - return commands[index] - except IndexError: - return None - @property def assignment_details(self): # parse statement which creates the assignment details. diff --git a/jedi/refactoring.py b/jedi/refactoring.py index 172708a2..73018454 100644 --- a/jedi/refactoring.py +++ b/jedi/refactoring.py @@ -112,7 +112,7 @@ def extract(script, new_name): # TODO care for multiline extracts dct = {} if user_stmt: - pos = script.pos + pos = script._pos line_index = pos[0] - 1 arr, index = helpers.array_for_pos(user_stmt, pos) if arr is not None: diff --git a/test/test_debug.py b/test/test_debug.py new file mode 100644 index 00000000..00331072 --- /dev/null +++ b/test/test_debug.py @@ -0,0 +1,9 @@ +import jedi +from jedi import debug + +def test_simple(): + jedi.set_debug_function() + debug.speed('foo') + debug.dbg('bar') + debug.warning('baz') + jedi.set_debug_function(None, False, False, False) diff --git a/test/test_parsing_representation.py b/test/test_parsing_representation.py new file mode 100644 index 00000000..e090d4d4 --- /dev/null +++ b/test/test_parsing_representation.py @@ -0,0 +1,29 @@ +from jedi.parsing import Parser + +def test_get_code(): + """Use the same code that the parser also generates, to compare""" + s = \ +'''"""a docstring""" +class SomeClass(object, mixin): + def __init__(self): + self.xy = 3.0 + 'statement docstr' + def some_method(self): + return 1 + def yield_method(self): + while hasattr(self, 'xy'): + yield True + for x in [1, 2]: + yield x + def empty(self): + pass +class Empty: + pass +class WithDocstring: + """class docstr""" + pass +def method_with_docstring(): + """class docstr""" + pass +''' + assert Parser(s).module.get_code() == s