Exemple #1
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)
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)
Exemple #3
0
 def _py__path__(self):
     search_path = self.evaluator.get_sys_path()
     init_path = self.py__file__()
     if os.path.basename(init_path) == '__init__.py':
         with open(init_path, 'rb') as f:
             content = python_bytes_to_unicode(f.read(), errors='replace')
             # these are strings that need to be used for namespace packages,
             # the first one is ``pkgutil``, the second ``pkg_resources``.
             options = ('declare_namespace(__name__)',
                        'extend_path(__path__')
             if options[0] in content or options[1] in content:
                 # It is a namespace, now try to find the rest of the
                 # modules on sys_path or whatever the search_path is.
                 paths = set()
                 for s in search_path:
                     other = os.path.join(s, self.name.string_name)
                     if os.path.isdir(other):
                         paths.add(other)
                 if paths:
                     return list(paths)
                 # TODO I'm not sure if this is how nested namespace
                 # packages work. The tests are not really good enough to
                 # show that.
     # Default to this.
     return [self._get_init_directory()]
Exemple #4
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
Exemple #5
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
Exemple #6
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')
    def parse_and_get_code(self, code=None, path=None, **kwargs):
        if self.allow_different_encoding:
            if code is None:
                with open(path, 'rb') as f:
                    code = f.read()
            code = python_bytes_to_unicode(code, errors='replace')

        return self.grammar.parse(code=code, path=path, **kwargs), code
Exemple #8
0
    def check_fs(path):
        with open(path, 'rb') as f:
            code = python_bytes_to_unicode(f.read(), errors='replace')
            if name in code:
                module = _load_module(evaluator, path, code)

                module_name = sys_path.dotted_path_in_sys_path(evaluator.sys_path, path)
                if module_name is not None:
                    add_module(evaluator, module_name, module)
                return module
Exemple #9
0
 def check_fs(path, base_names):
     try:
         f = open(path, 'rb')
     except FileNotFoundError:
         return None
     with f:
         code = python_bytes_to_unicode(f.read(), errors='replace')
     if name not in code:
         return None
     return _load_module_from_path(evaluator, path, base_names, code)
Exemple #10
0
    def check_fs(path):
        with open(path, 'rb') as f:
            code = python_bytes_to_unicode(f.read(), errors='replace')
            if name in code:
                module = _load_module(evaluator, path, code)

                module_name = sys_path.dotted_path_in_sys_path(
                    evaluator.project.sys_path, path)
                if module_name is not None:
                    add_module(evaluator, module_name, module)
                return module
Exemple #11
0
 def check_fs(path):
     with open(path, 'rb') as f:
         code = python_bytes_to_unicode(f.read(), errors='replace')
         if name in code:
             e_sys_path = evaluator.get_sys_path()
             module_name = sys_path.dotted_path_in_sys_path(e_sys_path, path)
             module = _load_module(
                 evaluator, path, code,
                 sys_path=e_sys_path, module_name=module_name
             )
             return module
Exemple #12
0
 def check_fs(path):
     with open(path, 'rb') as f:
         code = python_bytes_to_unicode(f.read(), errors='replace')
         if name in code:
             e_sys_path = evaluator.get_sys_path()
             module_name = sys_path.dotted_path_in_sys_path(e_sys_path, path)
             module = _load_module(
                 evaluator, path, code,
                 sys_path=e_sys_path, module_name=module_name
             )
             return module
Exemple #13
0
    def parse_and_get_code(self, code=None, path=None, encoding='utf-8',
                           use_latest_grammar=False, file_io=None, **kwargs):
        if self.allow_different_encoding:
            if code is None:
                if file_io is None:
                    file_io = FileIO(path)
                code = file_io.read()
            code = python_bytes_to_unicode(code, encoding=encoding, errors='replace')

        grammar = self.latest_grammar if use_latest_grammar else self.grammar
        return grammar.parse(code=code, path=path, file_io=file_io, **kwargs), code
Exemple #14
0
 def check_fs(file_io, base_names):
     try:
         code = file_io.read()
     except FileNotFoundError:
         return None
     code = python_bytes_to_unicode(code, errors='replace')
     if name not in code:
         return None
     new_file_io = KnownContentFileIO(file_io.path, code)
     m = load_module_from_path(inference_state, new_file_io, base_names)
     if isinstance(m, compiled.CompiledObject):
         return None
     return m.as_context()
Exemple #15
0
def _check_fs(inference_state, file_io, regex):
    try:
        code = file_io.read()
    except FileNotFoundError:
        return None
    code = python_bytes_to_unicode(code, errors='replace')
    if not regex.search(code):
        return None
    new_file_io = KnownContentFileIO(file_io.path, code)
    m = load_module_from_path(inference_state, new_file_io)
    if m.is_compiled():
        return None
    return m.as_context()
Exemple #16
0
    def parse_and_get_code(self, code=None, path=None,
                           use_latest_grammar=False, file_io=None, **kwargs):
        if path is not None:
            path = str(path)
        if code is None:
            if file_io is None:
                file_io = FileIO(path)
            code = file_io.read()
        # We cannot just use parso, because it doesn't use errors='replace'.
        code = parso.python_bytes_to_unicode(code, encoding='utf-8', errors='replace')

        if len(code) > settings._cropped_file_size:
            code = code[:settings._cropped_file_size]

        grammar = self.latest_grammar if use_latest_grammar else self.grammar
        return grammar.parse(code=code, path=path, file_io=file_io, **kwargs), code
Exemple #17
0
 def check_fs(path):
     try:
         f = open(path, 'rb')
     except FileNotFoundError:
         return
     with f:
         code = python_bytes_to_unicode(f.read(), errors='replace')
         if name in code:
             e_sys_path = evaluator.get_sys_path()
             import_names = sys_path.transform_path_to_dotted(e_sys_path, path)
             module = _load_module(
                 evaluator, path, code,
                 sys_path=e_sys_path,
                 import_names=import_names,
             )
             return module
Exemple #18
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)
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')
Exemple #21
0
 def _py__path__(self):
     search_path = self.evaluator.get_sys_path()
     init_path = self.py__file__()
     if os.path.basename(init_path) == '__init__.py':
         with open(init_path, 'rb') as f:
             content = python_bytes_to_unicode(f.read(), errors='replace')
             # these are strings that need to be used for namespace packages,
             # the first one is ``pkgutil``, the second ``pkg_resources``.
             options = ('declare_namespace(__name__)', 'extend_path(__path__')
             if options[0] in content or options[1] in content:
                 # It is a namespace, now try to find the rest of the
                 # modules on sys_path or whatever the search_path is.
                 paths = set()
                 for s in search_path:
                     other = os.path.join(s, self.name.string_name)
                     if os.path.isdir(other):
                         paths.add(other)
                 if paths:
                     return list(paths)
                 # TODO I'm not sure if this is how nested namespace
                 # packages work. The tests are not really good enough to
                 # show that.
     # Default to this.
     return [self._get_init_directory()]