def get_correct_indentation_diff(code, filename): """ Generate a diff to make code correctly indented. :param code: a string containing a file's worth of Python code :param filename: the filename being considered (used in diff generation only) :returns: a unified diff to make code correctly indented, or None if code is already correctedly indented """ code_buffer = StringIO(code) output_buffer = StringIO() reindenter = reindent.Reindenter(code_buffer) reindenter.run() reindenter.write(output_buffer) reindent_output = output_buffer.getvalue() output_buffer.close() if code != reindent_output: diff_generator = difflib.unified_diff(code.splitlines(True), reindent_output.splitlines(True), fromfile=filename, tofile=filename + " (reindented)") # work around http://bugs.python.org/issue2142 diff_tuple = map(clean_diff_line_for_python_bug_2142, diff_generator) diff = "".join(diff_tuple) return diff else: return None
class FileChecker(object): """ Picks up a given file and performs various checks, looking after problems and eventually suggesting solutions. """ def __init__(self, path=None, vcs=None, confirm=False): """ Class constructor, sets the path attribute. @param path: Path to the file that will be checked. @param vcs: Version control system being used. @param confirm: Whether to answer yes to all questions asked without prompting the user. """ if path is not None: self.set_path(path=path, vcs=vcs, confirm=confirm) def set_path(self, path, vcs=None, confirm=False): self.path = path self.vcs = vcs self.confirm = confirm self.basename = os.path.basename(self.path) if self.basename.endswith('.py'): self.is_python = True else: self.is_python = False mode = os.stat(self.path)[stat.ST_MODE] self.is_executable = mode & stat.S_IXUSR checked_file = open(self.path, "r") self.first_line = checked_file.readline() checked_file.close() if "python" in self.first_line: self.is_python = True self.corrective_actions = [] self.indent_exceptions = [] version = sys.version_info[0:2] self.check_exceptions = [] if version < (2, 5): self.check_exceptions = [ 'qemu/tests/stepmaker.py', 'virttest/step_editor.py', 'shared/scripts/cb.py' ] if self.is_python: logging.debug("Checking file %s", self.path) if self.is_python and not self.path.endswith(".py"): self.bkp_path = "%s-cp.py" % self.path shutil.copyfile(self.path, self.bkp_path) else: self.bkp_path = None def _get_checked_filename(self): if self.bkp_path is not None: return self.bkp_path else: return self.path def _check_indent(self): """ Verifies the file with the reindent module This tool performs the following checks on python files: * Trailing whitespaces * Tabs * End of line * Incorrect indentation And will automatically correct problems. """ success = True for exc in self.indent_exceptions: if re.search(exc, self.path): return success path = self._get_checked_filename() try: f = open(path) except IOError, msg: logging.error("Error opening %s: %s", path, str(msg)) return False r = reindent.Reindenter(f) f.close() try: if r.run(): success = False logging.info("Reindenting %s", path) f = open(path, "w") r.write(f) f.close() except: pass if not success and path != self.path: shutil.copyfile(path, self.path) return success