def get_stats(self, config, args): """Count number of bad tests. 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. """ # Output variables counter = Counter() messages = set([]) # Find all (sub)package names, from which one should not import directly packages = [] for filename in get_source_filenames(config, 'py'): if filename.endswith('/__init__.py'): packages.append(filename[:-12].replace('/', '.')) # Loop all python and cython files for filename in get_source_filenames(config, 'py'): # Only consider relevant files if os.path.basename(filename).startswith('test_'): continue if filename.endswith('/__init__.py'): continue if 'data/examples/' in filename: continue # Look for bad imports with codecs.open(filename, encoding='utf-8') as f: for lineno, line in enumerate(f): for package in packages: if u'from %s import' % package in line and \ line != u'from %s import __version__\n' % package: counter['Wrong imports in %s' % filename] += 1 text = 'Wrong import from %s' % package messages.add( Message(filename, lineno + 1, None, text)) return counter, messages
def get_stats(self, config, args): """Count number of bad tests. 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. """ # Output variables counter = Counter() messages = set([]) # Find all (sub)package names, from which one should not import directly packages = [] for filename in get_source_filenames(config, 'py'): if filename.endswith('/__init__.py'): packages.append(filename[:-12].replace('/', '.')) # Loop all python and cython files for filename in get_source_filenames(config, 'py'): # Only consider relevant files if os.path.basename(filename).startswith('test_'): continue if filename.endswith('/__init__.py'): continue if 'data/examples/' in filename: continue # Look for bad imports with codecs.open(filename, encoding='utf-8') as f: for lineno, line in enumerate(f): for package in packages: if u'from %s import' % package in line and \ line != u'from %s import __version__\n' % package: counter['Wrong imports in %s' % filename] += 1 text = 'Wrong import from %s' % package messages.add(Message(filename, lineno + 1, None, text)) 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 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 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, 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): """Count number of bad tests. 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. """ # Output variables counter = Counter() messages = set([]) # Make sure we test the source tree and not some locally installed copy of HORTON. sys.path.insert(0, ".") # Find all module names and load namespaces namespace = {} for filename in get_source_filenames(config, "py"): # Skip irrelevant files if filename.endswith("/__init__.py"): continue if os.path.basename(filename).startswith("test_"): continue # remove extension and replace / by . modulename = filename[: filename.rfind(".")].replace("/", ".") # Skip if this modulename is not part of a package in_package = False for packagename in config["py_packages"]: if modulename.startswith(packagename): in_package = True break if not in_package: continue # Check all public names of the module. module = importlib.import_module(modulename) names = dir(module) if "__all__" in names: for name in names: if name in module.__all__: namespace.setdefault(name, []).append(modulename) if name in config["py_invalid_names"]: counter["Invalid name in namespace"] += 1 messages.add(Message(filename, None, None, "Invalid name in namespace: %s" % name)) else: counter["Missing __all__"] += 1 messages.add(Message(filename, None, None, "Missing __all__")) # Detect collisions for name, modules in namespace.iteritems(): if len(modules) > 1: counter["Namespace collision"] += 1 text = "Name '%s' found in modules %s" % (name, " ".join(modules)) messages.add(Message(None, None, None, text)) return counter, messages
def get_stats(self, config, args): """Count number of bad tests. 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. """ # Output variables counter = Counter() messages = set([]) # Make sure we test the source tree and not some locally installed copy of HORTON. sys.path.insert(0, '.') # Find all module names and load namespaces namespace = {} for filename in get_source_filenames(config, 'py'): # Skip irrelevant files if filename.endswith('/__init__.py'): continue if os.path.basename(filename).startswith('test_'): continue # remove extension and replace / by . modulename = filename[:filename.rfind('.')].replace('/', '.') # Skip if this modulename is not part of a package in_package = False for packagename in config['py_packages']: if modulename.startswith(packagename): in_package = True break if not in_package: continue # Check all public names of the module. module = importlib.import_module(modulename) names = dir(module) if '__all__' in names: for name in names: if name in module.__all__: namespace.setdefault(name, []).append(modulename) if name in config['py_invalid_names']: counter['Invalid name in namespace'] += 1 messages.add(Message(filename, None, None, 'Invalid name in namespace: %s' % name)) else: counter['Missing __all__'] += 1 messages.add(Message(filename, None, None, 'Missing __all__')) # Detect collisions for name, modules in namespace.iteritems(): if len(modules) > 1: counter['Namespace collision'] += 1 text = 'Name \'%s\' found in modules %s' % (name, ' '.join(modules)) messages.add(Message(None, None, None, text)) 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