From 5f064a2a0a277840d29e93e86c174224c99d8dba Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 31 Jul 2016 20:37:48 +0200 Subject: [PATCH] Add a way to get the line in a BaseDefinition. Fixes #518. --- CHANGELOG.rst | 1 + jedi/api/classes.py | 22 ++++++++++++++++++++++ jedi/parser/__init__.py | 1 + jedi/parser/fast.py | 1 + test/test_api/test_api.py | 19 +++++++++++++++++++ 5 files changed, 44 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6adf8d72..4d000d8e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,7 @@ Changelog - Actual semantic completions for the complete Python syntax. - Basic type inference for ``yield from`` PEP 380. - PEP 484 support (most of the important features of it). Thanks Claude! (@reinhrst) +- Added ``get_line_code`` to ``Definition`` and ``Completion`` objects. - Again a lot of internal changes. 0.9.0 (2015-04-10) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 9a2c9655..aa4bc320 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -11,6 +11,7 @@ from jedi._compatibility import unicode, use_metaclass from jedi import settings from jedi import common from jedi.parser import tree +from jedi.parser.utils import load_parser from jedi.evaluate.cache import memoize_default, CachedMetaClass from jedi.evaluate import representation as er from jedi.evaluate import iterable @@ -360,6 +361,27 @@ class BaseDefinition(object): def __repr__(self): return "<%s %s>" % (type(self).__name__, self.description) + def get_line_code(self, before=0, after=0): + """ + Returns the line of code where this object was defined. + + :param before: Add n lines before the current line to the output. + :param after: Add n lines after the current line to the output. + + :return str: Returns the line(s) of code or an empty string if it's a + builtin. + """ + if self.in_builtin_module(): + return '' + + path = self._definition.get_parent_until().path + parser = load_parser(path) + lines = common.splitlines(parser.source) + + line_nr = self._name.start_pos[0] + start_line_nr = line_nr - before + return '\n'.join(lines[start_line_nr:line_nr + after + 1]) + class Completion(BaseDefinition): """ diff --git a/jedi/parser/__init__.py b/jedi/parser/__init__.py index 87e38ae9..22f38605 100644 --- a/jedi/parser/__init__.py +++ b/jedi/parser/__init__.py @@ -113,6 +113,7 @@ class Parser(object): source += '\n' self._added_newline = True + self.source = source self._start_symbol = start_symbol self._grammar = grammar diff --git a/jedi/parser/fast.py b/jedi/parser/fast.py index 5c244402..9c471fd4 100644 --- a/jedi/parser/fast.py +++ b/jedi/parser/fast.py @@ -282,6 +282,7 @@ class FastParser(use_metaclass(CachedFastParser)): self.number_of_splits = 0 self.number_of_misses = 0 self.module.reset_caches() + self.source = source try: self._parse(source) except: diff --git a/test/test_api/test_api.py b/test/test_api/test_api.py index 5658540f..a4665f78 100644 --- a/test/test_api/test_api.py +++ b/test/test_api/test_api.py @@ -145,3 +145,22 @@ def test_goto_definition_not_multiple(): def test_usage_description(): descs = [u.description for u in api.Script("foo = ''; foo").usages()] assert set(descs) == set(["foo = ''", 'foo']) + + +def test_get_line_code(): + def get_line_code(source, line=None, **kwargs): + return api.Script(source, line=line).completions()[0].get_line_code(**kwargs) + + # On builtin + assert get_line_code('') == '' + + # On custom code + line = ' foo' + assert get_line_code('def foo():\n%s' % line) == line + + # With before/after + line = ' foo' + source = 'def foo():\n%s\nother_line' % line + assert get_line_code(source, line=2) == line + assert get_line_code(source, line=2, after=1) == line + '\nother_line' + assert get_line_code(source, line=2, after=1, before=1) == source