def _determine_profiles(self): # Use the strictness profile if self.config.strictness: self.profiles.append('strictness_%s' % self.config.strictness) # Use other specialty profiles based on options if not self.config.doc_warnings: self.profiles.append('no_doc_warnings') if not self.config.test_warnings: self.profiles.append('no_test_warnings') if not self.config.style_warnings: self.profiles.append('no_pep8') if self.config.full_pep8: self.profiles.append('full_pep8') # Use the specified profiles self.profiles += self.config.profiles self.profile_adaptor = ProfileAdaptor(self.profiles) self.adaptors.append(self.profile_adaptor)
class Prospector(object): def __init__(self, config, path): self.config = config self.path = path self.adaptors = [] self.libraries = [] self.profiles = [] self.profile_adaptor = None self.tool_runners = [] self.ignores = [] self._determine_adapters() self._determine_profiles() self._determine_tool_runners() self._determine_ignores() def _determine_adapters(self): # Bring in the common adaptor if self.config.common_plugin: self.adaptors.append(CommonAdaptor()) # Bring in adaptors that we automatically detect are needed if self.config.autodetect: for name, adaptor in autodetect_libraries(self.path): self.libraries.append(name) self.adaptors.append(adaptor) # Bring in adaptors for the specified libraries for name in self.config.uses: if name not in self.libraries: self.libraries.append(name) self.adaptors.append(LIBRARY_ADAPTORS[name]()) def _determine_profiles(self): # Use the strictness profile if self.config.strictness: self.profiles.append('strictness_%s' % self.config.strictness) # Use other specialty profiles based on options if not self.config.doc_warnings: self.profiles.append('no_doc_warnings') if not self.config.test_warnings: self.profiles.append('no_test_warnings') if not self.config.style_warnings: self.profiles.append('no_pep8') if self.config.full_pep8: self.profiles.append('full_pep8') # Use the specified profiles self.profiles += self.config.profiles self.profile_adaptor = ProfileAdaptor(self.profiles) self.adaptors.append(self.profile_adaptor) def _determine_tool_runners(self): for tool in self.config.tools: if self.profile_adaptor.is_tool_enabled(tool): self.tool_runners.append(tools.TOOLS[tool]()) def _determine_ignores(self): # Grab ignore patterns from the profile adapter ignores = [ re.compile(ignore) for ignore in self.profile_adaptor.profile.ignore ] # Grab ignore patterns from the options ignores += [re.compile(patt) for patt in self.config.ignore_patterns] # Grab ignore paths from the options boundary = r"(^|/|\\)%s(/|\\|$)" ignores += [ re.compile(boundary % re.escape(ignore_path)) for ignore_path in self.config.ignore_paths ] # Add any specified by the other adaptors for adaptor in self.adaptors: if hasattr(adaptor.__class__, 'ignore_patterns'): ignores += [re.compile(p) for p in adaptor.ignore_patterns] self.ignores = ignores def process_messages(self, messages): for message in messages: if self.config.absolute_paths: message.to_absolute_path(self.path) else: message.to_relative_path(self.path) if self.config.blending: messages = blender.blend(messages) return messages def execute(self): summary = { 'started': datetime.now(), 'libraries': self.libraries, 'strictness': self.config.strictness, 'profiles': self.profiles, 'adaptors': [adaptor.name for adaptor in self.adaptors], 'tools': self.config.tools, } # Prep the tools. for tool in self.tool_runners: tool.prepare(self.path, self.ignores, self.config, self.adaptors) # Run the tools messages = [] for tool in self.tool_runners: try: messages += tool.run() except Exception: # pylint: disable=W0703 if self.config.die_on_tool_error: raise else: for name, cls in tools.TOOLS.items(): if cls == tool.__class__: toolname = name break else: toolname = 'Unknown' loc = Location(self.path, None, None, None, None) msg = 'Tool %s failed to run (exception was raised)' % ( toolname, ) message = Message( toolname, 'failure', loc, message=msg, ) messages.append(message) messages = self.process_messages(messages) summary['message_count'] = len(messages) summary['completed'] = datetime.now() delta = (summary['completed'] - summary['started']) summary['time_taken'] = '%0.2f' % delta.total_seconds() return summary, messages
def _determine_profiles(self): # Use other specialty profiles based on options if not self.config.doc_warnings: self.profiles.append('no_doc_warnings') if not self.config.test_warnings: self.profiles.append('no_test_warnings') if not self.config.style_warnings: self.profiles.append('no_pep8') if self.config.full_pep8: self.profiles.append('full_pep8') # Use the specified profiles profile_provided = False if len(self.config.profiles) > 0: profile_provided = True self.profiles += self.config.profiles # if there is a '.prospector.yaml' or a '.prospector/prospector.yaml' # file then we'll include that prospector_yaml = os.path.join(self.path, '.prospector.yaml') if os.path.exists(prospector_yaml) and os.path.isfile(prospector_yaml): profile_provided = True self.profiles.append(prospector_yaml) prospector_yaml = os.path.join(self.path, 'prospector', 'prospector.yaml') if os.path.exists(prospector_yaml) and os.path.isfile('prospector'): profile_provided = True self.profiles.append(prospector_yaml) if not profile_provided: # Use the strictness profile only if no profile has been given if self.config.strictness: self.profiles = ['strictness_%s' % self.config.strictness] + self.profiles self.strictness = self.config.strictness else: self.strictness = 'from profile' # the profile path is # * anything provided as an argument # * a directory called .prospector in the check path # * the check path # * prospector provided profiles profile_path = self.config.profile_path prospector_dir = os.path.join(self.path, '.prospector') if os.path.exists(prospector_dir) and os.path.isdir(prospector_dir): profile_path.append(prospector_dir) profile_path.append(self.path) provided = os.path.join(os.path.dirname(__file__), 'profiles/profiles') profile_path.append(provided) try: self.profile_adaptor = ProfileAdaptor(self.profiles, profile_path) except ProfileNotFound as nfe: sys.stderr.write("Failed to run:\nCould not find profile %s. Search path: %s\n" % (nfe.name, ':'.join(nfe.profile_path))) sys.exit(1) self.adaptors.append(self.profile_adaptor)
class Prospector(object): def __init__(self, config, path): self.config = config self.path = path if os.path.isdir(path): self.rootpath = path else: self.rootpath = os.getcwd() self.adaptors = [] self.libraries = [] self.profiles = [] self.profile_adaptor = None self.tool_runners = [] self.ignores = [] self.strictness = None self.tools_to_run = [] self.summary = None self.messages = None self._determine_adapters() self._determine_profiles() self._determine_tool_runners() self._determine_ignores() def _determine_adapters(self): # Bring in the common adaptor if self.config.common_plugin: self.adaptors.append(CommonAdaptor()) # Bring in adaptors that we automatically detect are needed if self.config.autodetect: for name, adaptor in autodetect_libraries(self.path): self.libraries.append(name) self.adaptors.append(adaptor) # Bring in adaptors for the specified libraries for name in self.config.uses: if name not in self.libraries: self.libraries.append(name) self.adaptors.append(LIBRARY_ADAPTORS[name]()) def _determine_profiles(self): # Use other specialty profiles based on options if not self.config.doc_warnings: self.profiles.append('no_doc_warnings') if not self.config.test_warnings: self.profiles.append('no_test_warnings') if not self.config.style_warnings: self.profiles.append('no_pep8') if self.config.full_pep8: self.profiles.append('full_pep8') # Use the specified profiles profile_provided = False if len(self.config.profiles) > 0: profile_provided = True self.profiles += self.config.profiles # if there is a '.prospector.yaml' or a '.prospector/prospector.yaml' # file then we'll include that prospector_yaml = os.path.join(self.path, '.prospector.yaml') if os.path.exists(prospector_yaml) and os.path.isfile(prospector_yaml): profile_provided = True self.profiles.append(prospector_yaml) prospector_yaml = os.path.join(self.path, 'prospector', 'prospector.yaml') if os.path.exists(prospector_yaml) and os.path.isfile('prospector'): profile_provided = True self.profiles.append(prospector_yaml) if not profile_provided: # Use the strictness profile only if no profile has been given if self.config.strictness: self.profiles = ['strictness_%s' % self.config.strictness] + self.profiles self.strictness = self.config.strictness else: self.strictness = 'from profile' # the profile path is # * anything provided as an argument # * a directory called .prospector in the check path # * the check path # * prospector provided profiles profile_path = self.config.profile_path prospector_dir = os.path.join(self.path, '.prospector') if os.path.exists(prospector_dir) and os.path.isdir(prospector_dir): profile_path.append(prospector_dir) profile_path.append(self.path) provided = os.path.join(os.path.dirname(__file__), 'profiles/profiles') profile_path.append(provided) try: self.profile_adaptor = ProfileAdaptor(self.profiles, profile_path) except ProfileNotFound as nfe: sys.stderr.write("Failed to run:\nCould not find profile %s. Search path: %s\n" % (nfe.name, ':'.join(nfe.profile_path))) sys.exit(1) self.adaptors.append(self.profile_adaptor) def _determine_tool_runners(self): if self.config.tools is None: # we had no command line settings for an explicit list of # tools, so we use the defaults to_run = set(DEFAULT_TOOLS) # we can also use any that the profiles dictate for tool in tools.TOOLS.keys(): if self.profile_adaptor.is_tool_enabled(tool): to_run.add(tool) else: to_run = set(self.config.tools) # profiles have no say in the list of tools run when # a command line is specified for tool in self.config.with_tools: to_run.add(tool) for tool in self.config.without_tools: to_run.remove(tool) if self.config.tools is None and len(self.config.with_tools) == 0 and len(self.config.without_tools) == 0: for tool in tools.TOOLS.keys(): enabled = self.profile_adaptor.is_tool_enabled(tool) if enabled is None: enabled = tool in DEFAULT_TOOLS if tool in to_run and not enabled: to_run.remove(tool) self.tools_to_run = sorted(list(to_run)) for tool in self.tools_to_run: self.tool_runners.append(tools.TOOLS[tool]()) def _determine_ignores(self): # Grab ignore patterns from the profile adapter ignores = [ re.compile(ignore) for ignore in self.profile_adaptor.profile.ignore ] # Grab ignore patterns from the options ignores += [ re.compile(patt) for patt in self.config.ignore_patterns ] # Grab ignore paths from the options boundary = r"(^|/|\\)%s(/|\\|$)" ignores += [ re.compile(boundary % re.escape(ignore_path)) for ignore_path in self.config.ignore_paths ] # Add any specified by the other adaptors for adaptor in self.adaptors: if hasattr(adaptor.__class__, 'ignore_patterns'): ignores += [re.compile(p) for p in adaptor.ignore_patterns] self.ignores = ignores def process_messages(self, messages): for message in messages: if self.config.absolute_paths: message.to_absolute_path(self.rootpath) else: message.to_relative_path(self.rootpath) if self.config.blending: messages = blender.blend(messages) return postfilter.filter_messages(messages) def execute(self): summary = { 'started': datetime.now(), 'libraries': self.libraries, 'strictness': self.strictness, 'profiles': self.profiles, 'adaptors': [adaptor.name for adaptor in self.adaptors], 'tools': self.tools_to_run, } # Find the files and packages in a common way, so that each tool # gets the same list. found_files = find_python(self.ignores, self.path) # Prep the tools. for tool in self.tool_runners: tool.prepare(found_files, self.config, self.adaptors) # Run the tools messages = [] for tool in self.tool_runners: try: messages += tool.run() except Exception: # pylint: disable=W0703 if self.config.die_on_tool_error: raise else: for name, cls in tools.TOOLS.items(): if cls == tool.__class__: toolname = name break else: toolname = 'Unknown' loc = Location(self.path, None, None, None, None) msg = 'Tool %s failed to run (exception was raised)' % ( toolname, ) message = Message( toolname, 'failure', loc, message=msg, ) messages.append(message) messages = self.process_messages(messages) summary['message_count'] = len(messages) summary['completed'] = datetime.now() # Timedelta.total_seconds() is not available # on Python<=2.6 so we calculate it ourselves # See issue #60 and http://stackoverflow.com/a/3694895 delta = (summary['completed'] - summary['started']) total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 1e6) / 1e6 summary['time_taken'] = '%0.2f' % total_seconds self.summary = summary self.messages = messages def get_summary(self): return self.summary def get_messages(self): return self.messages def print_messages(self, write_to=None): write_to = write_to or sys.stdout # Get the output formatter if self.config.output_format is not None: output_format = self.config.output_format else: output_format = self.profile_adaptor.get_output_format() if output_format is None: output_format = 'text' self.summary['formatter'] = output_format formatter = FORMATTERS[output_format](self.summary, self.messages) # Produce the output write_to.write(formatter.render( summary=not self.config.messages_only, messages=not self.config.summary_only, )) write_to.write('\n')
def run(): parser = make_arg_parser() args = parser.parse_args() if args.version: sys.stdout.write("Prospector version %s\n" % __pkginfo__.get_version()) sys.exit(0) summary = { 'started': datetime.now() } path = args.path or os.path.abspath(os.getcwd()) try: formatter = FORMATTERS[args.output_format] summary['formatter'] = args.output_format except KeyError: _die("Formatter %s is not valid - possible values are %s" % ( args.output_format, ', '.join(FORMATTERS.keys()), )) libraries_used = [] profiles = [] adaptors = [] if not args.no_common_plugin: adaptors.append(CommonAdaptor()) if not args.no_autodetect: for libname, adaptor in autodetect_libraries(path): libraries_used.append(libname) adaptors.append(adaptor) strictness = args.strictness strictness_options = ('veryhigh', 'high', 'medium', 'low', 'verylow') if strictness not in strictness_options: possible = ', '.join(strictness_options) _die( "%s is not a valid value for strictness - possible values are %s" % (strictness, possible) ) else: profiles.append('strictness_%s' % strictness) summary['strictness'] = strictness for library in args.uses: if library not in LIBRARY_ADAPTORS: possible = ', '.join(LIBRARY_ADAPTORS.keys()) _die( "Library/framework %s is not valid - possible values are %s" % (library, possible) ) libraries_used.append(library) adaptors.append(LIBRARY_ADAPTORS[library]()) summary['libraries'] = ', '.join(libraries_used) if not args.doc_warnings: profiles.append('no_doc_warnings') if not args.test_warnings: profiles.append('no_test_warnings') if args.no_style_warnings: profiles.append('no_pep8') profiles += args.profiles profile_adaptor = ProfileAdaptor(profiles) adaptors.append(profile_adaptor) summary['adaptors'] = [] for adaptor in adaptors: summary['adaptors'].append(adaptor.name) summary['adaptors'] = ', '.join(summary['adaptors']) tool_runners = [] tool_names = args.tools or tools.DEFAULT_TOOLS for tool in tool_names: if not tool in tools.TOOLS: _die("Tool %s is not valid - possible values are %s" % ( tool, ', '.join(tools.TOOLS.keys()) )) if not profile_adaptor.is_tool_enabled(tool): continue tool_runners.append(tools.TOOLS[tool]()) summary['tools'] = ', '.join(tool_names) ignore = [re.compile(ignore) for ignore in profile_adaptor.profile.ignore] for tool in tool_runners: tool.prepare(path, ignore, args, adaptors) messages = [] for tool in tool_runners: try: messages += tool.run() except Exception: if args.die_on_tool_error: raise loc = Location(path, None, None, None, None) message = "Tool %s failed to run (exception was raised)" % tool.__class__.__name__ msg = Message(tool.__class__.__name__, 'failure', loc, message=message) messages.append(msg) for message in messages: if args.absolute_paths: message.to_absolute_path(path) else: message.to_relative_path(path) if not args.no_blending: messages = blender.blend(messages) summary['message_count'] = len(messages) summary['completed'] = datetime.now() delta = (summary['completed'] - summary['started']) summary['time_taken'] = '%0.2f' % delta.total_seconds() summary['started'] = str(summary['started']) summary['completed'] = str(summary['completed']) if args.messages_only: summary = None if args.summary_only: messages = None formatter(summary, messages) sys.exit(0)
class Prospector(object): def __init__(self, config, path): self.config = config self.path = path self.adaptors = [] self.libraries = [] self.profiles = [] self.profile_adaptor = None self.tool_runners = [] self.ignores = [] self._determine_adapters() self._determine_profiles() self._determine_tool_runners() self._determine_ignores() def _determine_adapters(self): # Bring in the common adaptor if self.config.common_plugin: self.adaptors.append(CommonAdaptor()) # Bring in adaptors that we automatically detect are needed if self.config.autodetect: for name, adaptor in autodetect_libraries(self.path): self.libraries.append(name) self.adaptors.append(adaptor) # Bring in adaptors for the specified libraries for name in self.config.uses: if name not in self.libraries: self.libraries.append(name) self.adaptors.append(LIBRARY_ADAPTORS[name]()) def _determine_profiles(self): # Use the strictness profile if self.config.strictness: self.profiles.append('strictness_%s' % self.config.strictness) # Use other specialty profiles based on options if not self.config.doc_warnings: self.profiles.append('no_doc_warnings') if not self.config.test_warnings: self.profiles.append('no_test_warnings') if not self.config.style_warnings: self.profiles.append('no_pep8') if self.config.full_pep8: self.profiles.append('full_pep8') # Use the specified profiles self.profiles += self.config.profiles self.profile_adaptor = ProfileAdaptor(self.profiles) self.adaptors.append(self.profile_adaptor) def _determine_tool_runners(self): for tool in self.config.tools: if self.profile_adaptor.is_tool_enabled(tool): self.tool_runners.append(tools.TOOLS[tool]()) def _determine_ignores(self): # Grab ignore patterns from the profile adapter ignores = [ re.compile(ignore) for ignore in self.profile_adaptor.profile.ignore ] # Grab ignore patterns from the options ignores += [ re.compile(patt) for patt in self.config.ignore_patterns ] # Grab ignore paths from the options boundary = r"(^|/|\\)%s(/|\\|$)" ignores += [ re.compile(boundary % re.escape(ignore_path)) for ignore_path in self.config.ignore_paths ] # Add any specified by the other adaptors for adaptor in self.adaptors: if hasattr(adaptor.__class__, 'ignore_patterns'): ignores += [re.compile(p) for p in adaptor.ignore_patterns] self.ignores = ignores def process_messages(self, messages): for message in messages: if self.config.absolute_paths: message.to_absolute_path(self.path) else: message.to_relative_path(self.path) if self.config.blending: messages = blender.blend(messages) return messages def execute(self): summary = { 'started': datetime.now(), 'libraries': self.libraries, 'strictness': self.config.strictness, 'profiles': self.profiles, 'adaptors': [adaptor.name for adaptor in self.adaptors], 'tools': self.config.tools, } # Prep the tools. for tool in self.tool_runners: tool.prepare(self.path, self.ignores, self.config, self.adaptors) # Run the tools messages = [] for tool in self.tool_runners: try: messages += tool.run() except Exception: # pylint: disable=W0703 if self.config.die_on_tool_error: raise else: for name, cls in tools.TOOLS.items(): if cls == tool.__class__: toolname = name break else: toolname = 'Unknown' loc = Location(self.path, None, None, None, None) msg = 'Tool %s failed to run (exception was raised)' % ( toolname, ) message = Message( toolname, 'failure', loc, message=msg, ) messages.append(message) messages = self.process_messages(messages) summary['message_count'] = len(messages) summary['completed'] = datetime.now() delta = (summary['completed'] - summary['started']) summary['time_taken'] = '%0.2f' % delta.total_seconds() return summary, messages