def get_stats(self, config, args): """Run tests using Pylint. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # get Pylint version command = ['pylint', '--version', '--rcfile=%s' % self.rcfile] version_info = ''.join( run_command(command, verbose=False)[0].split('\n')[:2]) print 'USING :', version_info # Collect python files not present in packages py_extra = get_source_filenames(config, 'py', unpackaged_only=True) # call Pylint command = ['pylint'] + config['py_packages'] \ + py_extra \ + ['--rcfile=%s' % self.rcfile, '--ignore=%s' % ( ','.join(config['py_exclude'])), '-j 2', ] output = run_command(command, has_failed=has_failed)[0] # parse the output of Pylint into standard return values lines = output.split('\n')[:-1] score = lines[-2].split()[6] print 'SCORE :', score counter = Counter() messages = set([]) for line in lines: # skip lines that don't contain error messages if '.py:' not in line: continue if line.startswith('Report'): break # extract error information msg_id, _keyword, location, msg = line.split(' ', 3) counter[msg_id] += 1 filename, pos = location.split(':') lineno, charno = pos.split(',') lineno = int(lineno) charno = int(charno) if charno == 0: charno = None messages.add( Message(filename, lineno, charno, '%s %s' % (msg_id, msg))) return counter, messages
def get_stats(self, config, args): """Run tests using Pylint. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # get Pylint version command = ['pylint', '--version', '--rcfile=%s' % self.rcfile] version_info = ''.join(run_command(command, verbose=False)[0].split('\n')[:2]) print 'USING :', version_info # Collect python files not present in packages py_extra = get_source_filenames(config, 'py', unpackaged_only=True) # call Pylint command = ['pylint'] + config['py_packages'] \ + py_extra \ + ['--rcfile=%s' % self.rcfile, '--ignore=%s' % ( ','.join(config['py_exclude'])), '-j 2', ] output = run_command(command, has_failed=has_failed)[0] # parse the output of Pylint into standard return values lines = output.split('\n')[:-1] score = lines[-2].split()[6] print 'SCORE :', score counter = Counter() messages = set([]) for line in lines: # skip lines that don't contain error messages if '.py:' not in line: continue if line.startswith('Report'): break # extract error information msg_id, _keyword, location, msg = line.split(' ', 3) counter[msg_id] += 1 filename, pos = location.split(':') lineno, charno = pos.split(',') lineno = int(lineno) charno = int(charno) if charno == 0: charno = None messages.add(Message(filename, lineno, charno, '%s %s' % (msg_id, msg))) return counter, messages
def get_stats(self, config, args): """Run tests using Cppcheck. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Look for custom cppcheck build fns_cppcheck = sorted( glob('%s/cached/cppcheck-*/cppcheck' % self.qaworkdir)) if len(fns_cppcheck) > 0: binary = os.path.abspath(fns_cppcheck[-1]) else: binary = 'cppcheck' print 'USING BINARY :', binary # Get version command = [binary, '--version'] print 'USING VERSION :', run_command(command, verbose=False)[0].strip() # Call Cppcheck command = [binary] + get_source_filenames(config, 'cpp') + \ ['-q', '--enable=all', '--std=c++11', '--xml', '--suppress=missingIncludeSystem', '--suppress=unusedFunction'] xml_str = run_command(command)[1] etree = ElementTree.fromstring(xml_str) # Parse the output of Cppcheck into standard return values counter = Counter() messages = set([]) for error in etree: if 'file' not in error.attrib: continue key = '%15s %40s %30s' % ( error.attrib['severity'], error.attrib['file'].ljust(40), error.attrib['id'].ljust(30), ) counter[key] += 1 text = '%s %s %s' % (error.attrib['severity'], error.attrib['id'], error.attrib['msg']) messages.add( Message(error.attrib['file'], int(error.attrib['line']), None, text)) return counter, messages
def get_stats(self, config, args): """Run tests using pydocstyle. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ['pydocstyle', '--version'] version = run_command(command, verbose=False)[0].strip() print 'USING : pydocstyle', version # Call pydocstyle in the directories containing Python code. All files will be # checked, including test files. Missing docstrings are ignored because they are # detected by PyLint in a better way. command = ['pydocstyle', '--match=.*\\.py', '--add-ignore=D100,D101,D102,D103,D104,D105'] + \ config['py_packages'] + \ get_source_filenames(config, 'py', unpackaged_only=True) output = run_command(command, has_failed=has_failed)[1] # Parse the standard output of pydocstyle counter = Counter() messages = set([]) lines = output.split('\n')[:-1] while len(lines) > 0: if 'WARNING: ' in lines[0]: lines.pop(0) else: words = lines.pop(0).split() filename, lineno = words[0].split(':') code, description = lines.pop(0).split(':', 1) code = code.strip() description = description.strip() key = '%s %s' % (code, filename) message = Message(filename, int(lineno), None, '%s %s' % (code, description)) counter[key] += 1 messages.add(message) return counter, messages
def get_stats(self, config, args): """Run tests using Cppcheck. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Look for custom cppcheck build fns_cppcheck = sorted(glob('%s/cached/cppcheck-*/cppcheck' % self.qaworkdir)) if len(fns_cppcheck) > 0: binary = os.path.abspath(fns_cppcheck[-1]) else: binary = 'cppcheck' print 'USING BINARY :', binary # Get version command = [binary, '--version'] print 'USING VERSION :', run_command(command, verbose=False)[0].strip() # Call Cppcheck command = [binary] + get_source_filenames(config, 'cpp') + \ ['-q', '--enable=all', '--std=c++11', '--xml', '--suppress=missingIncludeSystem', '--suppress=unusedFunction'] xml_str = run_command(command)[1] etree = ElementTree.fromstring(xml_str) # Parse the output of Cppcheck into standard return values counter = Counter() messages = set([]) for error in etree: if 'file' not in error.attrib: continue key = '%15s %40s %30s' % ( error.attrib['severity'], error.attrib['file'].ljust(40), error.attrib['id'].ljust(30), ) counter[key] += 1 text = '%s %s %s' % (error.attrib['severity'], error.attrib['id'], error.attrib['msg']) messages.add(Message(error.attrib['file'], int(error.attrib['line']), None, text)) return counter, messages
def get_stats(self, config): """Run tests using pydocstyle. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ["pydocstyle", "--version"] version = run_command(command, verbose=False)[0].strip() print "USING : pydocstyle", version # Call pydocstyle in the directories containing Python code. All files will be # checked, including test files. Missing tests are ignored (D103) because they are # already detected by PyLint in a better way. command = ( ["pydocstyle", "--match=.*\\.py", "--add-ignore=D103"] + config["py_packages"] + get_source_filenames(config, "py", unpackaged_only=True) ) output = run_command(command, has_failed=has_failed)[1] # Parse the standard output of pydocstyle counter = Counter() messages = set([]) lines = output.split("\n")[:-1] while len(lines) > 0: if "WARNING: " in lines[0]: lines.pop(0) else: words = lines.pop(0).split() filename, lineno = words[0].split(":") code, description = lines.pop(0).split(":", 1) code = code.strip() description = description.strip() key = "%s %s" % (code, filename) message = Message(filename, int(lineno), None, "%s %s" % (code, description)) counter[key] += 1 messages.add(message) return counter, messages
def get_stats(self, config, args): """Run tests using doxygen. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ['doxygen', '--version'] print 'USING : doxygen', run_command( command, verbose=False)[0].strip() # Call doxygen in the doc subdirectory, mute output because it only confuses command = ['doxygen', self.doxyconf_file] run_command(command, cwd=config['doxygen_root']) # Parse the file doxygen_warnings log file counter = Counter() messages = set([]) prefix = os.getcwd() + '/' fn_warnings = os.path.join(config['doxygen_root'], config['doxygen_warnings']) with open(fn_warnings, 'r') as f: # Doxygen sometimes wraps lines in the warnings log. That is sad, but we # have to handle it. for line in unwrapped_iter(f): location, description = line.split(None, 1) filename, lineno = location.split(':')[:2] if filename.startswith(prefix): filename = filename[len(prefix):] message = Message(filename, int(lineno), None, description) # Sadly, doxygen sometimes generates duplicate messages for no good # reason, which leads to incorrect counters and incorrectly failing tests. # We need to check this explicitly... if message not in messages: counter[filename] += 1 messages.add(message) return counter, messages
def get_stats(self, config, args): """Run tests using doxygen. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ['doxygen', '--version'] print 'USING : doxygen', run_command(command, verbose=False)[0].strip() # Call doxygen in the doc subdirectory, mute output because it only confuses command = ['doxygen', self.doxyconf_file] run_command(command, cwd=config['doxygen_root']) # Parse the file doxygen_warnings log file counter = Counter() messages = set([]) prefix = os.getcwd() + '/' fn_warnings = os.path.join(config['doxygen_root'], config['doxygen_warnings']) with open(fn_warnings, 'r') as f: # Doxygen sometimes wraps lines in the warnings log. That is sad, but we # have to handle it. for line in unwrapped_iter(f): location, description = line.split(None, 1) filename, lineno = location.split(':')[:2] if filename.startswith(prefix): filename = filename[len(prefix):] message = Message(filename, int(lineno), None, description) # Sadly, doxygen sometimes generates duplicate messages for no good # reason, which leads to incorrect counters and incorrectly failing tests. # We need to check this explicitly... if message not in messages: counter[filename] += 1 messages.add(message) return counter, messages
def get_stats(self, config, args): """Run tests using cpplint.py. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version print 'USING : cpplint.py update #456' # Call cpplint command = [ self.cpplint_file, '--linelength=100', '--filter=-runtime/int' ] command += get_source_filenames(config, 'cpp') output = run_command(command, has_failed=has_failed)[1] # Parse the output of cpplint into standard return values counter = Counter() messages = set([]) for line in output.split('\n')[:-1]: if line.startswith('Done') or line.startswith('Total'): continue words = line.split() filename, lineno = words[0].split(':')[:2] description = ' '.join(words[1:-2]) tag = words[-2] priority = words[-1] counter['%3s %-30s' % (priority, tag)] += 1 messages.add( Message(filename, int(lineno), None, '%s %s %s' % (priority, tag, description))) return counter, messages
def get_stats(self, config, args): """Run tests using cpplint.py. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version print 'USING : cpplint.py update #456' # Call cpplint command = [self.cpplint_file, '--linelength=100', '--filter=-runtime/int'] command += get_source_filenames(config, 'cpp') output = run_command(command, has_failed=has_failed)[1] # Parse the output of cpplint into standard return values counter = Counter() messages = set([]) for line in output.split('\n')[:-1]: if line.startswith('Done') or line.startswith('Total'): continue words = line.split() filename, lineno = words[0].split(':')[:2] description = ' '.join(words[1:-2]) tag = words[-2] priority = words[-1] counter['%3s %-30s' % (priority, tag)] += 1 messages.add(Message(filename, int(lineno), None, '%s %s %s' % ( priority, tag, description))) return counter, messages
def get_stats(self, config): """Run tests using nosetests with coverage analysis. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ['nosetests', '--version'] print 'USING :', run_command(command, verbose=False)[0].strip() command = ['coverage', '--version'] print 'USING :', run_command(command, verbose=False)[0].split('\n')[0] # Results will be stored in the following variables counter = Counter() messages = set([]) # Run fast unit tests with nosetests, with coverage command = ['nosetests', '-v', '-a', '!slow', '--with-coverage', '--cover-erase', '--cover-branches', '--cover-package=%s' % ','.join(config['py_packages'])] + \ config['py_directories'] output = run_command(command)[0] lines = [line.strip() for line in output.split('\n')] # Parse the output of the unit tests iline = 0 for line in lines: if len(line) == 0: break elif line.endswith('FAIL'): counter['unit_tests_failed'] += 1 messages.add(Message(None, None, None, 'nosetests ' + line)) elif line.endswith('ERROR'): counter['unit_tests_error'] += 1 messages.add(Message(None, None, None, 'nosetests ' + line)) iline += 1 # Run the coverage program for a full report. This separate call is needed # since coverage-4.1. fn_coverage = '%s/coverage.xml' % self.qaworkdir command = ['coverage', 'xml', '-o', fn_coverage, '--omit=%s' % ','.join(config['py_test_files'])] output = run_command(command)[0] # Parse coverage xml output et = ElementTree.parse(fn_coverage) for class_tag in et.getroot().iter('class'): filename = class_tag.attrib['filename'] for line_tag in class_tag.iter('line'): if line_tag.attrib['hits'] == '0': line = int(line_tag.attrib['number']) branch_ends = line_tag.get('missing-branches') if branch_ends is not None: for branch_end in branch_ends.split(','): if branch_end.isdigit(): delta = int(branch_end) - line msg = Message(filename, line, None, 'Missed branch to line %+i' % (delta)) else: msg = Message(filename, line, None, 'Missed branch to %s' % branch_end) messages.add(msg) counter[filename] += 1 messages.add(Message(filename, line, None, 'Missed line')) counter[filename] += 1 return counter, messages
def get_stats(self, config, args): """Run tests using pydocstyle. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ['pydocstyle', '--version'] version = run_command(command, verbose=False)[0].strip() print 'USING : pydocstyle', version default_match = '({0})'.format(config['default_match']) output = '' # apply trapdoor with custom configurations first for custom_config in config['custom'].values(): match = custom_config['match'] ignore = custom_config['ignore'] # keep track of files that have been selected already # (this will be used to select files that have not been included in the configurations) default_match = '(?!{0}){1}'.format(match, default_match) # Call pydocstyle in the directories containing Python code. All files will be # checked, including test files. Missing docstrings are ignored because they are # detected by PyLint in a better way. output += run_command( [ 'pydocstyle', '--match={0}'.format(match), '--add-ignore={0}'.format(ignore) ] + config['py_packages'] + get_source_filenames(config, 'py', unpackaged_only=True), has_failed=has_failed)[1] # run trapdoor with default configuration on all the files that have not been tested yet output += run_command( [ 'pydocstyle', '--match={0}'.format(default_match), '--add-ignore={0}'.format(config['default_ignore']) ] + config['py_packages'] + get_source_filenames(config, 'py', unpackaged_only=True), has_failed=has_failed)[1] # Parse the standard output of pydocstyle counter = Counter() messages = set([]) lines = output.split('\n')[:-1] while len(lines) > 0: if 'WARNING: ' in lines[0]: lines.pop(0) else: words = lines.pop(0).split() filename, lineno = words[0].split(':') code, description = lines.pop(0).split(':', 1) code = code.strip() description = description.strip() key = '%s %s' % (code, filename) message = Message(filename, int(lineno), None, '%s %s' % (code, description)) counter[key] += 1 messages.add(message) return counter, messages
def get_stats(self, config, args): """Run tests using nosetests with coverage analysis. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ['nosetests', '--version'] print 'USING :', run_command(command, verbose=False)[0].strip() command = ['coverage', '--version'] print 'USING :', run_command( command, verbose=False)[0].split('\n')[0] # Results will be stored in the following variables counter = Counter() messages = set([]) # Run fast unit tests with nosetests, with coverage command = ['nosetests', '-v', '-a', '!slow', '--with-coverage', '--cover-erase', '--cover-branches', '--cover-package=%s' % ','.join(config['py_packages'])] + \ config['py_directories'] if args.nproc > 1: command.extend( ['--processes=%s' % args.nproc, '--process-timeout=600']) output = run_command(command)[0] lines = [line.strip() for line in output.split('\n')] # Parse the output of the unit tests iline = 0 for line in lines: if len(line) == 0: break elif line.endswith('FAIL'): counter['unit_tests_failed'] += 1 messages.add(Message(None, None, None, 'nosetests ' + line)) elif line.endswith('ERROR'): counter['unit_tests_error'] += 1 messages.add(Message(None, None, None, 'nosetests ' + line)) iline += 1 # Run the coverage program for a full report. This separate call is needed # since coverage-4.1. fn_coverage = '%s/coverage.xml' % self.qaworkdir command = [ 'coverage', 'xml', '-o', fn_coverage, '--omit=%s' % ','.join(config['py_test_files']) ] output = run_command(command)[0] # Parse coverage xml output et = ElementTree.parse(fn_coverage) for class_tag in et.getroot().iter('class'): filename = class_tag.attrib['filename'] with open(filename) as fsource: source_lines = fsource.readlines() for line_tag in class_tag.iter('line'): if line_tag.attrib['hits'] == '0': line = int(line_tag.attrib['number']) if excluded_from_coverage(source_lines[line - 1]): continue branch_ends = line_tag.get('missing-branches') if branch_ends is not None: for branch_end in branch_ends.split(','): if branch_end.isdigit(): delta = int(branch_end) - line msg = Message( filename, line, None, 'Missed branch to line %+i' % (delta)) else: msg = Message( filename, line, None, 'Missed branch to %s' % branch_end) messages.add(msg) counter[filename] += 1 messages.add(Message(filename, line, None, 'Missed line')) counter[filename] += 1 return counter, messages
def get_stats(self, config, args): """Run tests using nosetests with coverage analysis. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # Get version command = ["nosetests", "--version"] print "USING :", run_command(command, verbose=False)[0].strip() command = ["coverage", "--version"] print "USING :", run_command(command, verbose=False)[0].split("\n")[0] # Results will be stored in the following variables counter = Counter() messages = set([]) # Run fast unit tests with nosetests, with coverage command = [ "nosetests", "-v", "-A", "not (slow or rt)", "--with-coverage", "--cover-erase", "--cover-branches", "--cover-package=%s" % ",".join(config["py_packages"]), ] + config["py_directories"] if args.nproc > 1: command.extend(["--processes=%s" % args.nproc, "--process-timeout=600"]) output = run_command(command)[0] lines = [line.strip() for line in output.split("\n")] # Parse the output of the unit tests iline = 0 for line in lines: if len(line) == 0: break elif line.endswith("FAIL"): counter["unit_tests_failed"] += 1 messages.add(Message(None, None, None, "nosetests " + line)) elif line.endswith("ERROR"): counter["unit_tests_error"] += 1 messages.add(Message(None, None, None, "nosetests " + line)) iline += 1 # Run the coverage program for a full report. This separate call is needed # since coverage-4.1. fn_coverage = "%s/coverage.xml" % self.qaworkdir command = ["coverage", "xml", "-o", fn_coverage, "--omit=%s" % ",".join(config["py_test_files"])] output = run_command(command)[0] # Parse coverage xml output et = ElementTree.parse(fn_coverage) for class_tag in et.getroot().iter("class"): filename = class_tag.attrib["filename"] with open(filename) as fsource: source_lines = fsource.readlines() for line_tag in class_tag.iter("line"): if line_tag.attrib["hits"] == "0": line = int(line_tag.attrib["number"]) if excluded_from_coverage(source_lines[line - 1]): continue branch_ends = line_tag.get("missing-branches") if branch_ends is not None: for branch_end in branch_ends.split(","): if branch_end.isdigit(): delta = int(branch_end) - line msg = Message(filename, line, None, "Missed branch to line %+i" % (delta)) else: msg = Message(filename, line, None, "Missed branch to %s" % branch_end) messages.add(msg) counter[filename] += 1 messages.add(Message(filename, line, None, "Missed line")) counter[filename] += 1 return counter, messages
def get_stats(self, config, args): """Run tests using Pylint. Parameters ---------- config : dict The dictionary loaded from ``trapdoor.cfg``. args : argparse.Namespace The result of parsing the command line arguments. Returns ------- counter : collections.Counter Counts of the number of messages of a specific type in a certain file. messages : Set([]) of strings All errors encountered in the current branch. """ # get default rcfile qatooldir = os.path.dirname(os.path.abspath(__file__)) default_rc_file = os.path.join(self.qaworkdir, config['default_rc']) # FIXME: not too sure if this should be in prepare shutil.copy(os.path.join(qatooldir, os.path.basename(default_rc_file)), default_rc_file) # get Pylint version command = ['pylint', '--version', '--rcfile={0}'.format(default_rc_file)] version_info = ''.join(run_command(command, verbose=False)[0].split('\n')[:2]) print 'USING :', version_info # Collect python files (pylint ignore is quite bad.. need to ignore manually) py_extra = get_source_filenames(config, 'py', unpackaged_only=True) def get_filenames(file_or_dir, exclude=tuple()): """Recursively finds all of the files within the given file or directory. Avoids the files and directories specified in exclude. Parameters ---------- file_or_dir : str File or directory exclude : tuple Files or directories to ignore Returns ------- list of files as a relative path """ output = [] if os.path.isfile(file_or_dir) and file_or_dir not in exclude: output.append(file_or_dir) elif os.path.isdir(file_or_dir): for dirpath, _dirnames, filenames in os.walk(file_or_dir): # check if directory is allowed if any(os.path.samefile(dirpath, i) for i in exclude): continue for filename in filenames: # check if filename is allowed if (os.path.splitext(filename)[1] != '.py' or filename in exclude or any(os.path.samefile(os.path.join(dirpath, filename), i) for i in exclude)): continue output.append(os.path.join(dirpath, filename)) return output output = '' exclude_files = [] # run pylint test using each configuration for custom_config in config['custom'].values(): rc_file = os.path.join(self.qaworkdir, custom_config['rc']) shutil.copy(os.path.join(qatooldir, os.path.basename(rc_file)), rc_file) # collect files py_files = [] for custom_file in custom_config['files']: py_files.extend(get_filenames(custom_file)) # call Pylint output += run_command(['pylint'] + py_files + ['--rcfile={0}'.format(rc_file), '-j 2', ], has_failed=has_failed)[0] # exclude directories/files exclude_files.extend(py_files) # get files that have not been run py_files = [] for py_file in config['py_packages'] + py_extra: py_files.extend(get_filenames(py_file, exclude=exclude_files + config['py_exclude'])) # call Pylint output += run_command(['pylint'] + py_files + ['--rcfile={0}'.format(default_rc_file), '-j 2', ], has_failed=has_failed)[0] # parse the output of Pylint into standard return values lines = output.split('\n')[:-1] score = lines[-2].split()[6] print 'SCORE :', score counter = Counter() messages = set([]) for line in lines: # skip lines that don't contain error messages if '.py:' not in line: continue if line.startswith('Report'): break # extract error information msg_id, _keyword, location, msg = line.split(' ', 3) counter[msg_id] += 1 filename, pos = location.split(':') lineno, charno = pos.split(',') lineno = int(lineno) charno = int(charno) if charno == 0: charno = None messages.add(Message(filename, lineno, charno, '%s %s' % (msg_id, msg))) return counter, messages