Esempio n. 1
0
    def get_diff(self):
        old_lines = split_lines(self._module_node.get_code(), keepends=True)
        new_lines = split_lines(self.get_new_code(), keepends=True)

        # Add a newline at the end if it's missing. Otherwise the diff will be
        # very weird. A `diff -u file1 file2` would show the string:
        #
        #     \ No newline at end of file
        #
        # This is not necessary IMO, because Jedi does not really play with
        # newlines and the ending newline does not really matter in Python
        # files. ~dave
        if old_lines[-1] != '':
            old_lines[-1] += '\n'
        if new_lines[-1] != '':
            new_lines[-1] += '\n'

        project_path = self._inference_state.project.path
        if self._from_path is None:
            from_p = ''
        else:
            from_p = relpath(self._from_path, project_path)
        if self._to_path is None:
            to_p = ''
        else:
            to_p = relpath(self._to_path, project_path)
        diff = difflib.unified_diff(
            old_lines,
            new_lines,
            fromfile=from_p,
            tofile=to_p,
        )
        # Apparently there's a space at the end of the diff - for whatever
        # reason.
        return ''.join(diff).rstrip(' ')
Esempio n. 2
0
    def get_completions(self, info):
        '''Get Python completions'''
        # https://github.com/davidhalter/jedi/blob/master/jedi/utils.py
        if jedi is None:
            return []

        text = info['code']
        position = (info['line_num'], info['column'])
        interpreter = Interpreter(text, [self.env])

        if jedi.__version__ >= LooseVersion('0.12.0'):
            lines = split_lines(text)
            name = get_on_completion_name(interpreter._module_node, lines,
                                          position)
            before = text[:len(text) - len(name)]
        elif jedi.__version__ >= LooseVersion('0.10.0'):
            lines = split_lines(text)
            name = get_on_completion_name(interpreter._get_module_node(),
                                          lines, position)
            before = text[:len(text) - len(name)]
        else:
            path = UserContext(text, position).get_path_until_cursor()
            path, dot, like = completion_parts(path)
            before = text[:len(text) - len(like)]

        completions = interpreter.completions()
        completions = [before + c.name_with_symbols for c in completions]

        self.kernel.log.error(completions)

        return [c[info['start']:] for c in completions]
Esempio n. 3
0
 def get_diff(self):
     old_lines = split_lines(self._module_node.get_code(), keepends=True)
     new_lines = split_lines(self.get_new_code(), keepends=True)
     project_path = self._inference_state.project._path
     diff = difflib.unified_diff(
         old_lines,
         new_lines,
         fromfile=relpath(self._from_path, project_path),
         tofile=relpath(self._to_path, project_path),
     )
     # Apparently there's a space at the end of the diff - for whatever
     # reason.
     return ''.join(diff).rstrip(' ')
Esempio n. 4
0
    def get_completions(self, info):
        '''Get Python completions'''
        # https://github.com/davidhalter/jedi/blob/master/jedi/utils.py
        if jedi is None:
            return []

        text = info['code']
        position = (info['line_num'], info['column'])
        interpreter = Interpreter(text, [self.env])

        lines = split_lines(text)
        name = get_on_completion_name(
            interpreter._module_node,
            lines,
            position
        )
        before = text[:len(text) - len(name)]

        try:
            completions = interpreter.complete()
        except AttributeError:
            completions = interpreter.completions()

        completions = [before + c.name_with_symbols for c in completions]

        self.kernel.log.error(completions)

        return [c[info['start']:] for c in completions]
def extract(script, new_name):
    """ The `args` / `kwargs` params are the same as in `api.Script`.
    :param operation: The refactoring operation to execute.
    :type operation: str
    :type source: str
    :return: list of changed lines/changed files
    """
    new_lines = split_lines(python_bytes_to_unicode(script.source))
    old_lines = new_lines[:]

    user_stmt = script._parser.user_stmt()

    # TODO care for multiline extracts
    dct = {}
    if user_stmt:
        pos = script._pos
        line_index = pos[0] - 1
        arr, index = helpers.array_for_pos(user_stmt, pos)
        if arr is not None:
            start_pos = arr[index].start_pos
            end_pos = arr[index].end_pos

            # take full line if the start line is different from end line
            e = end_pos[1] if end_pos[0] == start_pos[0] else None
            start_line = new_lines[start_pos[0] - 1]
            text = start_line[start_pos[1]:e]
            for l in range(start_pos[0], end_pos[0] - 1):
                text += '\n' + l
            if e is None:
                end_line = new_lines[end_pos[0] - 1]
                text += '\n' + end_line[:end_pos[1]]

            # remove code from new lines
            t = text.lstrip()
            del_start = start_pos[1] + len(text) - len(t)

            text = t.rstrip()
            del_end = len(t) - len(text)
            if e is None:
                new_lines[end_pos[0] - 1] = end_line[end_pos[1] - del_end:]
                e = len(start_line)
            else:
                e = e - del_end
            start_line = start_line[:del_start] + new_name + start_line[e:]
            new_lines[start_pos[0] - 1] = start_line
            new_lines[start_pos[0]:end_pos[0] - 1] = []

            # add parentheses in multiline case
            open_brackets = ['(', '[', '{']
            close_brackets = [')', ']', '}']
            if '\n' in text and not (text[0] in open_brackets and text[-1] ==
                                     close_brackets[open_brackets.index(text[0])]):
                text = '(%s)' % text

            # add new line before statement
            indent = user_stmt.start_pos[1]
            new = "%s%s = %s" % (' ' * indent, new_name, text)
            new_lines.insert(line_index, new)
    dct[script.path] = script.path, old_lines, new_lines
    return Refactoring(dct)
Esempio n. 6
0
    def _complete_in_string(self, start_leaf, string):
        """
        To make it possible for people to have completions in doctests or
        generally in "Python" code in docstrings, we use the following
        heuristic:

        - Having an indented block of code
        - Having some doctest code that starts with `>>>`
        - Having backticks that doesn't have whitespace inside it
        """
        def iter_relevant_lines(lines):
            include_next_line = False
            for l in code_lines:
                if include_next_line or l.startswith('>>>') or l.startswith(
                        ' '):
                    yield re.sub(r'^( *>>> ?| +)', '', l)
                else:
                    yield None

                include_next_line = bool(re.match(' *>>>', l))

        string = dedent(string)
        code_lines = split_lines(string, keepends=True)
        relevant_code_lines = list(iter_relevant_lines(code_lines))
        if relevant_code_lines[-1] is not None:
            # Some code lines might be None, therefore get rid of that.
            relevant_code_lines = [c or '\n' for c in relevant_code_lines]
            return self._complete_code_lines(relevant_code_lines)
        match = re.search(r'`([^`\s]+)', code_lines[-1])
        if match:
            return self._complete_code_lines([match.group(1)])
        return []
Esempio n. 7
0
def _replace(nodes, expression_replacement, extracted, pos,
             insert_before_leaf=None, remaining_prefix=None):
    # Now try to replace the nodes found with a variable and move the code
    # before the current statement.
    definition = _get_parent_definition(nodes[0])
    if insert_before_leaf is None:
        insert_before_leaf = definition.get_first_leaf()
    first_node_leaf = nodes[0].get_first_leaf()

    lines = split_lines(insert_before_leaf.prefix, keepends=True)
    if first_node_leaf is insert_before_leaf:
        if remaining_prefix is not None:
            # The remaining prefix has already been calculated.
            lines[:-1] = remaining_prefix
    lines[-1:-1] = [indent_block(extracted, lines[-1]) + '\n']
    extracted_prefix = ''.join(lines)

    replacement_dct = {}
    if first_node_leaf is insert_before_leaf:
        replacement_dct[nodes[0]] = extracted_prefix + expression_replacement
    else:
        if remaining_prefix is None:
            p = first_node_leaf.prefix
        else:
            p = remaining_prefix + _get_indentation(nodes[0])
        replacement_dct[nodes[0]] = p + expression_replacement
        replacement_dct[insert_before_leaf] = extracted_prefix + insert_before_leaf.value

    for node in nodes[1:]:
        replacement_dct[node] = ''
    return replacement_dct
Esempio n. 8
0
def _rename(names, replace_str):
    """ For both rename and inline. """
    order = sorted(names, key=lambda x: (x.module_path, x.line, x.column),
                   reverse=True)

    def process(path, old_lines, new_lines):
        if new_lines is not None:  # goto next file, save last
            dct[path] = path, old_lines, new_lines

    dct = {}
    current_path = object()
    new_lines = old_lines = None
    for name in order:
        if name.in_builtin_module():
            continue
        if current_path != name.module_path:
            current_path = name.module_path

            process(current_path, old_lines, new_lines)
            if current_path is not None:
                # None means take the source that is a normal param.
                with open(current_path) as f:
                    source = f.read()

            new_lines = split_lines(python_bytes_to_unicode(source))
            old_lines = new_lines[:]

        nr, indent = name.line, name.column
        line = new_lines[nr - 1]
        new_lines[nr - 1] = line[:indent] + replace_str + \
            line[indent + len(name.name):]
    process(current_path, old_lines, new_lines)
    return dct
Esempio n. 9
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', sys_path=None, environment=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        # Load the Python grammar of the current interpreter.
        project = get_default_project(
            os.path.dirname(self.path)if path else os.getcwd()
        )
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
        self._evaluator = Evaluator(
            project, environment=environment, script_path=self.path
        )
        debug.speed('init')
        self._module_node, source = self._evaluator.parse_and_get_code(
            code=source,
            path=self.path,
            encoding=encoding,
            cache=False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(source, keepends=True)
        self._code = source
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_string = self._code_lines[line - 1]
        line_len = len(line_string)
        if line_string.endswith('\r\n'):
            line_len -= 1
        if line_string.endswith('\n'):
            line_len -= 1

        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter (%d) is not in a valid range '
                             '(0-%d) for line %d (%r).' % (
                                 column, line_len, line, line_string))
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
Esempio n. 10
0
def collections_namedtuple(obj, arguments, callback):
    """
    Implementation of the namedtuple function.

    This has to be done by processing the namedtuple class template and
    evaluating the result.

    """
    evaluator = obj.evaluator

    # Process arguments
    name = u'jedi_unknown_namedtuple'
    for c in _follow_param(evaluator, arguments, 0):
        x = get_str_or_none(c)
        if x is not None:
            name = force_unicode(x)
            break

    # TODO here we only use one of the types, we should use all.
    param_contexts = _follow_param(evaluator, arguments, 1)
    if not param_contexts:
        return NO_CONTEXTS
    _fields = list(param_contexts)[0]
    string = get_str_or_none(_fields)
    if string is not None:
        fields = force_unicode(string).replace(',', ' ').split()
    elif isinstance(_fields, iterable.Sequence):
        fields = [
            force_unicode(get_str_or_none(v))
            for lazy_context in _fields.py__iter__()
            for v in lazy_context.infer()
        ]
        fields = [f for f in fields if f is not None]
    else:
        return NO_CONTEXTS

    # Build source code
    code = _NAMEDTUPLE_CLASS_TEMPLATE.format(
        typename=name,
        field_names=tuple(fields),
        num_fields=len(fields),
        arg_list=repr(tuple(fields)).replace("u'", "").replace("'", "")[1:-1],
        repr_fmt='',
        field_defs='\n'.join(
            _NAMEDTUPLE_FIELD_TEMPLATE.format(index=index, name=name)
            for index, name in enumerate(fields)))

    # Parse source code
    module = evaluator.grammar.parse(code)
    generated_class = next(module.iter_classdefs())
    parent_context = ModuleContext(
        evaluator,
        module,
        file_io=None,
        string_names=None,
        code_lines=parso.split_lines(code, keepends=True),
    )

    return ContextSet(
        [ClassContext(evaluator, parent_context, generated_class)])
Esempio n. 11
0
    def __init__(self, source=None, line=None, column=None, path=None,
                 encoding='utf-8', sys_path=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # TODO do we really want that?
        self._source = python_bytes_to_unicode(source, encoding, errors='replace')
        self._code_lines = split_lines(self._source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()
        project = Project(sys_path=sys_path)
        self._evaluator = Evaluator(self._grammar, project)
        project.add_script_path(self.path)
        debug.speed('init')
Esempio n. 12
0
def _rename(names, replace_str):
    """ For both rename and inline. """
    order = sorted(names,
                   key=lambda x: (x.module_path, x.line, x.column),
                   reverse=True)

    def process(path, old_lines, new_lines):
        if new_lines is not None:  # goto next file, save last
            dct[path] = path, old_lines, new_lines

    dct = {}
    current_path = object()
    new_lines = old_lines = None
    for name in order:
        if name.in_builtin_module():
            continue
        if current_path != name.module_path:
            current_path = name.module_path

            process(current_path, old_lines, new_lines)
            if current_path is not None:
                # None means take the source that is a normal param.
                with open(current_path) as f:
                    source = f.read()

            new_lines = split_lines(python_bytes_to_unicode(source))
            old_lines = new_lines[:]

        nr, indent = name.line, name.column
        line = new_lines[nr - 1]
        new_lines[nr - 1] = line[:indent] + replace_str + \
            line[indent + len(name.name):]
    process(current_path, old_lines, new_lines)
    return dct
Esempio n. 13
0
    def __init__(self, code=None, *, path=None, environment=None, project=None):
        self._orig_path = path
        if isinstance(path, str):
            path = Path(path)

        self.path = path.absolute() if path else None

        if code is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                code = f.read()

        if project is None:
            # Load the Python grammar of the current interpreter.
            project = get_default_project(None if self.path is None else self.path.parent)

        self._inference_state = InferenceState(
            project, environment=environment, script_path=self.path
        )
        debug.speed('init')
        self._module_node, code = self._inference_state.parse_and_get_code(
            code=code,
            path=self.path,
            use_latest_grammar=path and path.suffix == '.pyi',
            cache=False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(code, keepends=True)
        self._code = code

        cache.clear_time_caches()
        debug.reset_time()
Esempio n. 14
0
def extract(script, new_name):
    """ The `args` / `kwargs` params are the same as in `api.Script`.
    :param operation: The refactoring operation to execute.
    :type operation: str
    :type source: str
    :return: list of changed lines/changed files
    """
    new_lines = split_lines(python_bytes_to_unicode(script.source))
    old_lines = new_lines[:]

    user_stmt = script._parser.user_stmt()

    # TODO care for multiline extracts
    dct = {}
    if user_stmt:
        pos = script._pos
        line_index = pos[0] - 1
        arr, index = helpers.array_for_pos(user_stmt, pos)
        if arr is not None:
            start_pos = arr[index].start_pos
            end_pos = arr[index].end_pos

            # take full line if the start line is different from end line
            e = end_pos[1] if end_pos[0] == start_pos[0] else None
            start_line = new_lines[start_pos[0] - 1]
            text = start_line[start_pos[1]:e]
            for l in range(start_pos[0], end_pos[0] - 1):
                text += '\n' + l
            if e is None:
                end_line = new_lines[end_pos[0] - 1]
                text += '\n' + end_line[:end_pos[1]]

            # remove code from new lines
            t = text.lstrip()
            del_start = start_pos[1] + len(text) - len(t)

            text = t.rstrip()
            del_end = len(t) - len(text)
            if e is None:
                new_lines[end_pos[0] - 1] = end_line[end_pos[1] - del_end:]
                e = len(start_line)
            else:
                e = e - del_end
            start_line = start_line[:del_start] + new_name + start_line[e:]
            new_lines[start_pos[0] - 1] = start_line
            new_lines[start_pos[0]:end_pos[0] - 1] = []

            # add parentheses in multiline case
            open_brackets = ['(', '[', '{']
            close_brackets = [')', ']', '}']
            if '\n' in text and not (text[0] in open_brackets and text[-1] ==
                                     close_brackets[open_brackets.index(text[0])]):
                text = '(%s)' % text

            # add new line before statement
            indent = user_stmt.start_pos[1]
            new = "%s%s = %s" % (' ' * indent, new_name, text)
            new_lines.insert(line_index, new)
    dct[script.path] = script.path, old_lines, new_lines
    return Refactoring(dct)
Esempio n. 15
0
def collections_namedtuple(evaluator, obj, arguments):
    """
    Implementation of the namedtuple function.

    This has to be done by processing the namedtuple class template and
    evaluating the result.

    """
    collections_context = obj.parent_context
    _class_template_set = collections_context.py__getattribute__(
        u'_class_template')
    if not _class_template_set:
        # Namedtuples are not supported on Python 2.6, early 2.7, because the
        # _class_template variable is not defined, there.
        return NO_CONTEXTS

    # Process arguments
    # TODO here we only use one of the types, we should use all.
    # TODO this is buggy, doesn't need to be a string
    name = list(_follow_param(evaluator, arguments, 0))[0].get_safe_value()
    _fields = list(_follow_param(evaluator, arguments, 1))[0]
    if isinstance(_fields, compiled.CompiledObject):
        fields = _fields.get_safe_value().replace(',', ' ').split()
    elif isinstance(_fields, iterable.Sequence):
        fields = [
            v.get_safe_value() for lazy_context in _fields.py__iter__()
            for v in lazy_context.infer() if is_string(v)
        ]
    else:
        return NO_CONTEXTS

    def get_var(name):
        x, = collections_context.py__getattribute__(name)
        return x.get_safe_value()

    base = next(iter(_class_template_set)).get_safe_value()
    base += _NAMEDTUPLE_INIT
    # Build source code
    code = base.format(
        typename=name,
        field_names=tuple(fields),
        num_fields=len(fields),
        arg_list=repr(tuple(fields)).replace("u'", "").replace("'", "")[1:-1],
        repr_fmt=', '.join(
            get_var(u'_repr_template').format(name=name) for name in fields),
        field_defs='\n'.join(
            get_var(u'_field_template').format(index=index, name=name)
            for index, name in enumerate(fields)))

    # Parse source code
    module = evaluator.grammar.parse(code)
    generated_class = next(module.iter_classdefs())
    parent_context = ModuleContext(
        evaluator,
        module,
        None,
        code_lines=parso.split_lines(code, keepends=True),
    )
    return ContextSet(ClassContext(evaluator, parent_context, generated_class))
Esempio n. 16
0
def collections_namedtuple(value, arguments, callback):
    """
    Implementation of the namedtuple function.

    This has to be done by processing the namedtuple class template and
    inferring the result.

    """
    inference_state = value.inference_state

    # Process arguments
    name = 'jedi_unknown_namedtuple'
    for c in _follow_param(inference_state, arguments, 0):
        x = get_str_or_none(c)
        if x is not None:
            name = x
            break

    # TODO here we only use one of the types, we should use all.
    param_values = _follow_param(inference_state, arguments, 1)
    if not param_values:
        return NO_VALUES
    _fields = list(param_values)[0]
    string = get_str_or_none(_fields)
    if string is not None:
        fields = string.replace(',', ' ').split()
    elif isinstance(_fields, iterable.Sequence):
        fields = [
            get_str_or_none(v) for lazy_value in _fields.py__iter__()
            for v in lazy_value.infer()
        ]
        fields = [f for f in fields if f is not None]
    else:
        return NO_VALUES

    # Build source code
    code = _NAMEDTUPLE_CLASS_TEMPLATE.format(
        typename=name,
        field_names=tuple(fields),
        num_fields=len(fields),
        arg_list=repr(tuple(fields)).replace("'", "")[1:-1],
        repr_fmt='',
        field_defs='\n'.join(
            _NAMEDTUPLE_FIELD_TEMPLATE.format(index=index, name=name)
            for index, name in enumerate(fields)))

    # Parse source code
    module = inference_state.grammar.parse(code)
    generated_class = next(module.iter_classdefs())
    parent_context = ModuleValue(
        inference_state,
        module,
        code_lines=parso.split_lines(code, keepends=True),
    ).as_context()

    return ValueSet(
        [ClassValue(inference_state, parent_context, generated_class)])
Esempio n. 17
0
def _split_prefix_at(leaf, until_line):
    """
    Returns a tuple of the leaf's prefix, split at the until_line
    position.
    """
    # second means the second returned part
    second_line_count = leaf.start_pos[0] - until_line
    lines = split_lines(leaf.prefix, keepends=True)
    return ''.join(lines[:-second_line_count]), ''.join(lines[-second_line_count:])
Esempio n. 18
0
def collections_namedtuple(evaluator, obj, arguments):
    """
    Implementation of the namedtuple function.

    This has to be done by processing the namedtuple class template and
    evaluating the result.

    """
    collections_context = obj.parent_context
    _class_template_set = collections_context.py__getattribute__(u'_class_template')
    if not _class_template_set:
        # Namedtuples are not supported on Python 2.6, early 2.7, because the
        # _class_template variable is not defined, there.
        return NO_CONTEXTS

    # Process arguments
    # TODO here we only use one of the types, we should use all.
    # TODO this is buggy, doesn't need to be a string
    name = list(_follow_param(evaluator, arguments, 0))[0].get_safe_value()
    _fields = list(_follow_param(evaluator, arguments, 1))[0]
    if isinstance(_fields, compiled.CompiledObject):
        fields = _fields.get_safe_value().replace(',', ' ').split()
    elif isinstance(_fields, iterable.Sequence):
        fields = [
            v.get_safe_value()
            for lazy_context in _fields.py__iter__()
            for v in lazy_context.infer() if is_string(v)
        ]
    else:
        return NO_CONTEXTS

    def get_var(name):
        x, = collections_context.py__getattribute__(name)
        return x.get_safe_value()

    base = next(iter(_class_template_set)).get_safe_value()
    base += _NAMEDTUPLE_INIT
    # Build source code
    code = base.format(
        typename=name,
        field_names=tuple(fields),
        num_fields=len(fields),
        arg_list=repr(tuple(fields)).replace("u'", "").replace("'", "")[1:-1],
        repr_fmt=', '.join(get_var(u'_repr_template').format(name=name) for name in fields),
        field_defs='\n'.join(get_var(u'_field_template').format(index=index, name=name)
                             for index, name in enumerate(fields))
    )

    # Parse source code
    module = evaluator.grammar.parse(code)
    generated_class = next(module.iter_classdefs())
    parent_context = ModuleContext(
        evaluator, module, None,
        code_lines=parso.split_lines(code, keepends=True),
    )
    return ContextSet(ClassContext(evaluator, parent_context, generated_class))
def cut_value_at_position(leaf, position):
    """
    Cuts of the value of the leaf at position
    """
    lines = split_lines(leaf.value, keepends=True)[:position[0] - leaf.line + 1]
    column = position[1]
    if leaf.line == position[0]:
        column -= leaf.column
    lines[-1] = lines[-1][:column]
    return ''.join(lines)
Esempio n. 20
0
    def get_desired_result(self):

        if platform.system().lower() == 'windows' and self.type == 'diff':
            # Windows uses backslashes to separate paths.
            lines = split_lines(self._desired_result, keepends=True)
            for i, line in enumerate(lines):
                if re.search(' import_tree/', line):
                    lines[i] = line.replace('/', '\\')
            return ''.join(lines)
        return self._desired_result
Esempio n. 21
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None,
                 environment=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        # Load the Python grammar of the current interpreter.
        project = get_default_project(self.path or os.getcwd())
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
        self._evaluator = Evaluator(project,
                                    environment=environment,
                                    script_path=self.path)
        self._project = project
        debug.speed('init')
        self._module_node, source = self._evaluator.parse_and_get_code(
            code=source,
            path=self.path,
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=True,
            cache_path=settings.cache_directory)
        debug.speed('parsed')
        self._code_lines = parso.split_lines(source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
Esempio n. 22
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None,
                 environment=None,
                 _project=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        project = _project
        if project is None:
            # Load the Python grammar of the current interpreter.
            project = get_default_project(
                os.path.dirname(self.path) if path else os.getcwd())
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
        self._inference_state = InferenceState(project,
                                               environment=environment,
                                               script_path=self.path)
        debug.speed('init')
        self._module_node, source = self._inference_state.parse_and_get_code(
            code=source,
            path=self.path,
            encoding=encoding,
            use_latest_grammar=path and path.endswith('.pyi'),
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(source, keepends=True)
        self._code = source
        self._pos = line, column

        cache.clear_time_caches()
        debug.reset_time()
Esempio n. 23
0
def _is_on_comment(leaf, position):
    comment_lines = split_lines(leaf.prefix)
    difference = leaf.start_pos[0] - position[0]
    prefix_start_pos = leaf.get_start_pos_of_prefix()
    if difference == 0:
        indent = leaf.start_pos[1]
    elif position[0] == prefix_start_pos[0]:
        indent = prefix_start_pos[1]
    else:
        indent = 0
    line = comment_lines[-difference - 1][:position[1] - indent]
    return '#' in line
Esempio n. 24
0
def _is_on_comment(leaf, position):
    comment_lines = split_lines(leaf.prefix)
    difference = leaf.start_pos[0] - position[0]
    prefix_start_pos = leaf.get_start_pos_of_prefix()
    if difference == 0:
        indent = leaf.start_pos[1]
    elif position[0] == prefix_start_pos[0]:
        indent = prefix_start_pos[1]
    else:
        indent = 0
    line = comment_lines[-difference - 1][:position[1] - indent]
    return '#' in line
Esempio n. 25
0
def _get_text_edits(changes: ChangedFile) -> List[types.TextEdit]:
    result = []
    old_lines = split_lines(changes._module_node.get_code(), keepends=True)
    new_lines = split_lines(changes.get_new_code(), keepends=True)
    line_number = 0
    start = None
    replace_lines = False
    lines: List[str] = []

    def _append():
        if replace_lines:
            end = types.Position(line_number)
        else:
            end = start
        result.append(types.TextEdit(types.Range(start, end), ''.join(lines)))

    for line in differ.compare(old_lines, new_lines):
        kind = line[0]
        if kind == '?':
            continue
        if kind == '-':
            if not start:
                start = types.Position(line_number)
            replace_lines = True
            line_number += 1
            continue
        if kind == '+':
            if not start:
                start = types.Position(line_number)
            lines.append(line[2:])
            continue
        if start:
            _append()
            start = None
            replace_lines = False
            lines = []
        line_number += 1
    if start:
        _append()
    return result
Esempio n. 26
0
    def get_completions(self, info):
        self._create_context()

        text = info["code"]
        lines = split_lines(text)
        position = (info["line_num"], info["column"])
        code = COMPLETION_TEMPLATE % (text, str(lines), str(position))

        response = self.command.execute(code)
        result = self._strip_out(response[1])
        before, _, completions = eval(result)
        completions = [before + c for c in completions]
        return [c[info["start"]:] for c in completions]
Esempio n. 27
0
def _get_typing_replacement_module(grammar):
    """
    The idea is to return our jedi replacement for the PEP-0484 typing module
    as discussed at https://github.com/davidhalter/jedi/issues/663
    """
    global _typing_module, _typing_module_code_lines
    if _typing_module is None:
        typing_path = \
            os.path.abspath(os.path.join(__file__, "../jedi_typing.py"))
        with open(typing_path) as f:
            code = unicode(f.read())
        _typing_module = grammar.parse(code)
        _typing_module_code_lines = split_lines(code, keepends=True)
    return _typing_module, _typing_module_code_lines
Esempio n. 28
0
def _get_typing_replacement_module(grammar):
    """
    The idea is to return our jedi replacement for the PEP-0484 typing module
    as discussed at https://github.com/davidhalter/jedi/issues/663
    """
    global _typing_module, _typing_module_code_lines
    if _typing_module is None:
        typing_path = \
            os.path.abspath(os.path.join(__file__, "../jedi_typing.py"))
        with open(typing_path) as f:
            code = unicode(f.read())
        _typing_module = grammar.parse(code)
        _typing_module_code_lines = split_lines(code, keepends=True)
    return _typing_module, _typing_module_code_lines
Esempio n. 29
0
    def get_completions(self, info):
        '''Get Python completions'''
        # https://github.com/davidhalter/jedi/blob/master/jedi/utils.py
        if jedi is None:
            return []

        text = info['code']
        position = (info['line_num'], info['column'])
        interpreter = Interpreter(text, [self.env])

        if jedi.__version__ >= LooseVersion('0.12.0'):
            lines = split_lines(text)
            name = get_on_completion_name(
                interpreter._module_node,
                lines,
                position
            )
            before = text[:len(text) - len(name)]
        elif jedi.__version__ >= LooseVersion('0.10.0'):
            lines = split_lines(text)
            name = get_on_completion_name(
                interpreter._get_module_node(),
                lines,
                position
            )
            before = text[:len(text) - len(name)]
        else:
            path = UserContext(text, position).get_path_until_cursor()
            path, dot, like = completion_parts(path)
            before = text[:len(text) - len(like)]

        completions = interpreter.completions()
        completions = [before + c.name_with_symbols for c in completions]

        self.kernel.log.error(completions)

        return [c[info['start']:] for c in completions]
Esempio n. 30
0
def inline(script):
    """
    :type script: api.Script
    """
    new_lines = split_lines(python_bytes_to_unicode(script.source))

    dct = {}

    definitions = script.goto_assignments()
    assert len(definitions) == 1
    stmt = definitions[0]._definition
    usages = script.usages()
    inlines = [
        r for r in usages
        if not stmt.start_pos <= (r.line, r.column) <= stmt.end_pos
    ]
    inlines = sorted(inlines,
                     key=lambda x: (x.module_path, x.line, x.column),
                     reverse=True)
    expression_list = stmt.expression_list()
    # don't allow multi-line refactorings for now.
    assert stmt.start_pos[0] == stmt.end_pos[0]
    index = stmt.start_pos[0] - 1

    line = new_lines[index]
    replace_str = line[expression_list[0].start_pos[1]:stmt.end_pos[1] + 1]
    replace_str = replace_str.strip()
    # tuples need parentheses
    if expression_list and isinstance(expression_list[0], pr.Array):
        arr = expression_list[0]
        if replace_str[0] not in ['(', '[', '{'] and len(arr) > 1:
            replace_str = '(%s)' % replace_str

    # if it's the only assignment, remove the statement
    if len(stmt.get_defined_names()) == 1:
        line = line[:stmt.start_pos[1]] + line[stmt.end_pos[1]:]

    dct = _rename(inlines, replace_str)
    # remove the empty line
    new_lines = dct[script.path][2]
    if line.strip():
        new_lines[index] = line
    else:
        new_lines.pop(index)

    return Refactoring(dct)
Esempio n. 31
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()
        project = Project(sys_path=sys_path)
        self._evaluator = Evaluator(self._grammar, project)
        self._module_node, source = self._evaluator.parse_and_get_code(
            code=source,
            path=self.path,
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=True,
            cache_path=settings.cache_directory)
        self._code_lines = split_lines(source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()

        project.add_script_path(self.path)
        debug.speed('init')
Esempio n. 32
0
def inline(script):
    """
    :type script: api.Script
    """
    new_lines = split_lines(python_bytes_to_unicode(script.source))

    dct = {}

    definitions = script.goto_assignments()
    with common.ignored(AssertionError):
        assert len(definitions) == 1
        stmt = definitions[0]._definition
        usages = script.usages()
        inlines = [r for r in usages
                   if not stmt.start_pos <= (r.line, r.column) <= stmt.end_pos]
        inlines = sorted(inlines, key=lambda x: (x.module_path, x.line, x.column),
                         reverse=True)
        expression_list = stmt.expression_list()
        # don't allow multiline refactorings for now.
        assert stmt.start_pos[0] == stmt.end_pos[0]
        index = stmt.start_pos[0] - 1

        line = new_lines[index]
        replace_str = line[expression_list[0].start_pos[1]:stmt.end_pos[1] + 1]
        replace_str = replace_str.strip()
        # tuples need parentheses
        if expression_list and isinstance(expression_list[0], pr.Array):
            arr = expression_list[0]
            if replace_str[0] not in ['(', '[', '{'] and len(arr) > 1:
                replace_str = '(%s)' % replace_str

        # if it's the only assignment, remove the statement
        if len(stmt.get_defined_names()) == 1:
            line = line[:stmt.start_pos[1]] + line[stmt.end_pos[1]:]

        dct = _rename(inlines, replace_str)
        # remove the empty line
        new_lines = dct[script.path][2]
        if line.strip():
            new_lines[index] = line
        else:
            new_lines.pop(index)

    return Refactoring(dct)
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # TODO do we really want that?
        self._source = python_bytes_to_unicode(source,
                                               encoding,
                                               errors='replace')
        self._code_lines = split_lines(self._source)
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_len = len(self._code_lines[line - 1])
        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter is not in a valid range.')
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()
        if sys_path is None:
            venv = os.getenv('VIRTUAL_ENV')
            if venv:
                sys_path = list(get_venv_path(venv))
        self._evaluator = Evaluator(self._grammar, sys_path=sys_path)
        debug.speed('init')
Esempio n. 34
0
File: utils.py Progetto: grf123/jedi
        def complete(self, text, state):
            """
            This complete stuff is pretty weird, a generator would make
            a lot more sense, but probably due to backwards compatibility
            this is still the way how it works.

            The only important part is stuff in the ``state == 0`` flow,
            everything else has been copied from the ``rlcompleter`` std.
            library module.
            """
            if state == 0:
                sys.path.insert(0, os.getcwd())
                # Calling python doesn't have a path, so add to sys.path.
                try:
                    logging.debug("Start REPL completion: " + repr(text))
                    interpreter = Interpreter(text,
                                              [namespace_module.__dict__])

                    lines = split_lines(text)
                    position = (len(lines), len(lines[-1]))
                    name = get_on_completion_name(interpreter._module_node,
                                                  lines, position)
                    before = text[:len(text) - len(name)]
                    completions = interpreter.completions()
                    logging.debug("REPL completions: %s", completions)
                except:
                    logging.error("REPL Completion error:\n" +
                                  traceback.format_exc())
                    raise
                finally:
                    sys.path.pop(0)

                self.matches = [
                    before + c.name_with_symbols for c in completions
                ]
            try:
                return self.matches[state]
            except IndexError:
                return None
Esempio n. 35
0
        def complete(self, text, state):
            """
            This complete stuff is pretty weird, a generator would make
            a lot more sense, but probably due to backwards compatibility
            this is still the way how it works.

            The only important part is stuff in the ``state == 0`` flow,
            everything else has been copied from the ``rlcompleter`` std.
            library module.
            """
            if state == 0:
                sys.path.insert(0, os.getcwd())
                # Calling python doesn't have a path, so add to sys.path.
                try:
                    logging.debug("Start REPL completion: " + repr(text))
                    interpreter = Interpreter(text, [namespace_module.__dict__])

                    lines = split_lines(text)
                    position = (len(lines), len(lines[-1]))
                    name = get_on_completion_name(
                        interpreter._module_node,
                        lines,
                        position
                    )
                    before = text[:len(text) - len(name)]
                    completions = interpreter.completions()
                    logging.debug("REPL completions: %s", completions)
                except:
                    logging.error("REPL Completion error:\n" + traceback.format_exc())
                    raise
                finally:
                    sys.path.pop(0)

                self.matches = [before + c.name_with_symbols for c in completions]
            try:
                return self.matches[state]
            except IndexError:
                return None
Esempio n. 36
0
    def __init__(self,
                 code=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding=None,
                 sys_path=None,
                 environment=None,
                 project=None,
                 source=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if encoding is None:
            encoding = 'utf-8'
        else:
            warnings.warn(
                "Deprecated since version 0.17.0. You should cast to valid "
                "unicode yourself, especially if you are not using utf-8.",
                DeprecationWarning,
                stacklevel=2)
        if line is not None:
            warnings.warn(
                "Providing the line is now done in the functions themselves "
                "like `Script(...).complete(line, column)`",
                DeprecationWarning,
                stacklevel=2)
        if column is not None:
            warnings.warn(
                "Providing the column is now done in the functions themselves "
                "like `Script(...).complete(line, column)`",
                DeprecationWarning,
                stacklevel=2)
        if source is not None:
            code = source
            warnings.warn("Use the code keyword argument instead.",
                          DeprecationWarning,
                          stacklevel=2)
        if code is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                code = f.read()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        if project is None:
            # Load the Python grammar of the current interpreter.
            project = get_default_project(
                os.path.dirname(self.path) if path else None)
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
            warnings.warn(
                "Deprecated since version 0.17.0. Use the project API instead, "
                "which means Script(project=Project(dir, sys_path=sys_path)) instead.",
                DeprecationWarning,
                stacklevel=2)

        self._inference_state = InferenceState(project,
                                               environment=environment,
                                               script_path=self.path)
        debug.speed('init')
        self._module_node, code = self._inference_state.parse_and_get_code(
            code=code,
            path=self.path,
            encoding=encoding,
            use_latest_grammar=path and path.endswith('.pyi'),
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(code, keepends=True)
        self._code = code
        self._pos = line, column

        cache.clear_time_caches()
        debug.reset_time()
Esempio n. 37
0
    def __init__(self,
                 source=None,
                 line=None,
                 column=None,
                 path=None,
                 encoding='utf-8',
                 sys_path=None,
                 environment=None):
        self._orig_path = path
        # An empty path (also empty string) should always result in no path.
        self.path = os.path.abspath(path) if path else None

        if source is None:
            # TODO add a better warning than the traceback!
            with open(path, 'rb') as f:
                source = f.read()

        # Load the Python grammar of the current interpreter.
        self._grammar = parso.load_grammar()

        if sys_path is not None and not is_py3:
            sys_path = list(map(force_unicode, sys_path))

        # Load the Python grammar of the current interpreter.
        project = get_default_project(
            # iOS: getcwd() creates problems. We force it to ~/Documents
            #            os.path.dirname(self.path)if path else os.getcwd()
            os.path.dirname(self.path) if path else os.path.
            join(os.getenv("HOME"), 'Library/lib/python3.7/'))
        # TODO deprecate and remove sys_path from the Script API.
        if sys_path is not None:
            project._sys_path = sys_path
        self._evaluator = Evaluator(project,
                                    environment=environment,
                                    script_path=self.path)
        self._project = project
        debug.speed('init')
        self._module_node, source = self._evaluator.parse_and_get_code(
            code=source,
            path=self.path,
            encoding=encoding,
            cache=
            False,  # No disk cache, because the current script often changes.
            diff_cache=settings.fast_parser,
            cache_path=settings.cache_directory,
        )
        debug.speed('parsed')
        self._code_lines = parso.split_lines(source, keepends=True)
        self._code = source
        line = max(len(self._code_lines), 1) if line is None else line
        if not (0 < line <= len(self._code_lines)):
            raise ValueError('`line` parameter is not in a valid range.')

        line_string = self._code_lines[line - 1]
        line_len = len(line_string)
        if line_string.endswith('\r\n'):
            line_len -= 1
        if line_string.endswith('\n'):
            line_len -= 1

        column = line_len if column is None else column
        if not (0 <= column <= line_len):
            raise ValueError('`column` parameter (%d) is not in a valid range '
                             '(0-%d) for line %d (%r).' %
                             (column, line_len, line, line_string))
        self._pos = line, column
        self._path = path

        cache.clear_time_caches()
        debug.reset_time()
Esempio n. 38
0
def _remove_indent_of_prefix(prefix):
    r"""
    Removes the last indentation of a prefix, e.g. " \n \n " becomes " \n \n".
    """
    return ''.join(split_lines(prefix, keepends=True)[:-1])
Esempio n. 39
0
def _get_indentation(node):
    return split_lines(node.get_first_leaf().prefix)[-1]