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 Medi 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(' ')
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:])
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
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 if not lines: return '' lines[-1] = lines[-1][:column] return ''.join(lines)
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
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])
def _get_indentation(node): return split_lines(node.get_first_leaf().prefix)[-1]
def __init__(self, code=None, line=None, column=None, path=None, encoding=None, sys_path=None, environment=None, project=None, source=None, language="python"): 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 self.language = language self.grammar = marso.load_grammar(language=self.language) 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( self.language, 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 = marso.split_lines(code, keepends=True) self._code = code self._pos = line, column cache.clear_time_caches() debug.reset_time()