Skip to content

Commit

Permalink
Merging in PR #78 from @guykisel, but making changes to cope with the…
Browse files Browse the repository at this point in the history
… new configuration manager introduced in #74 and #10
  • Loading branch information
carlio committed Jan 2, 2015
2 parents 2270d4f + 56ce6fa commit cdd5bc0
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 43 deletions.
24 changes: 12 additions & 12 deletions prospector/config/__init__.py
Expand Up @@ -12,8 +12,16 @@ class ProspectorConfig(object):

def __init__(self):
self.config, self.arguments = self._configure_prospector()
self.path = self._get_work_path(self.config, self.arguments)
self.profile, self.profile_names, self.strictness = self._get_profile(self.path, self.config)

self.paths = self._get_work_path(self.config, self.arguments)
self.explicit_file_mode = all(map(os.path.isfile, self.paths))

if os.path.isdir(self.paths[0]):
self.workdir = self.paths[0]
else:
self.workdir = os.getcwd()

self.profile, self.profile_names, self.strictness = self._get_profile(self.workdir, self.config)
self.libraries = self._find_used_libraries(self.config)
self.tools_to_run = self._determine_tool_runners(self.config, self.profile)
self.ignores = self._determine_ignores(self.config, self.profile, self.libraries)
Expand Down Expand Up @@ -53,15 +61,7 @@ def _get_work_path(self, config, arguments):
paths = arguments['checkpath']
else:
paths = [os.getcwd()]
# TODO: Currently prospector can only handle one path at a time. This is
# because the automatic loading of configuration files becomes complicated
# to explain when multiple paths are to be checked. Should each path allow
# its own configuration? Or should one single global configuration be used?
# If so, where from?
# See the discussion:
# https://github.com/landscapeio/prospector/issues/61
# https://github.com/landscapeio/prospector/pull/68
return paths[0]
return paths

def _get_profile(self, path, config):
# Use other specialty profiles based on options
Expand Down Expand Up @@ -137,7 +137,7 @@ def _find_used_libraries(self, config):

# Bring in adaptors that we automatically detect are needed
if config.autodetect:
for name, adaptor in autodetect_libraries(self.path):
for name, adaptor in autodetect_libraries(self.workdir):
libraries.append(name)

# Bring in adaptors for the specified libraries
Expand Down
3 changes: 2 additions & 1 deletion prospector/config/configuration.py
Expand Up @@ -272,7 +272,8 @@ def build_command_line_source(prog=None, description='Performs static analysis o
positional = (
('checkpath', {
'help': 'The path to a Python project to inspect. Defaults to PWD'
' if not specified.',
' if not specified. If multiple paths are specified,'
' they must all be files (no directories).',
'metavar': 'PATH',
'nargs': '*',
}),
Expand Down
42 changes: 24 additions & 18 deletions prospector/finder.py
@@ -1,22 +1,22 @@
import os


class SingleFile(object):
class SingleFiles(object):
"""
When prospector is run in 'single file mode' - that is,
the argument is a python module rather than a directory -
then we'll use this object instead of the FoundFiles to
give all the functionality needed to check a single file.
"""
def __init__(self, filepath):
self.filepath = filepath
self.rootpath = os.getcwd()
def __init__(self, files, rootpath):
self.files = files
self.rootpath = rootpath

def _check(self, checkpath, abspath=True):
if abspath:
checkpath = os.path.abspath(checkpath)
return checkpath == os.path.abspath(self.filepath)
return checkpath == self.filepath
return checkpath in map(os.path.abspath, self.files)
return checkpath in self.files

def check_module(self, filepath, abspath=True, even_if_ignored=False):
return self._check(filepath, abspath)
Expand All @@ -28,25 +28,30 @@ def check_file(self, filepath, abspath=True, even_if_ignored=False):
return self._check(filepath, abspath)

def iter_file_paths(self, abspath=True, include_ignored=False):
yield os.path.abspath(self.filepath) if abspath else self.filepath
for filepath in self.files:
yield os.path.abspath(filepath) if abspath else filepath

def iter_package_paths(self, abspath=True, include_ignored=False):
yield os.path.abspath(self.filepath) if abspath else self.filepath
for filepath in self.files:
yield os.path.abspath(filepath) if abspath else filepath

def iter_directory_paths(self, abspath=True, include_ignored=False):
yield os.path.abspath(self.filepath) if abspath else self.filepath
for filepath in self.files:
filepath = os.path.dirname(filepath)
yield os.path.abspath(filepath) if abspath else filepath

def iter_module_paths(self, abspath=True, include_ignored=False):
yield os.path.abspath(self.filepath) if abspath else self.filepath
for filepath in self.files:
yield os.path.abspath(filepath) if abspath else filepath

def to_absolute_path(self, path):
return os.path.abspath(os.path.join(self.rootpath, path))

def get_minimal_syspath(self, absolute_paths=True):
path = os.path.dirname(self.filepath)
paths = list(set(map(os.path.dirname, self.files)))
if absolute_paths:
path = os.path.abspath(path)
return [path]
paths = map(os.path.abspath, paths)
return [self.rootpath] + paths


class FoundFiles(object):
Expand Down Expand Up @@ -199,15 +204,16 @@ def _find_paths(ignore, curpath, rootpath):
return files, modules, packages, directories


def find_python(ignores, path_argument):
def find_python(ignores, paths, explicit_file_mode, workdir=None):
"""
Returns a FoundFiles class containing a list of files, packages, directories,
where files are simply all python (.py) files, packages are directories
containing an `__init__.py` file, and directories is a list of all directories.
All paths are relative to the dirpath argument.
"""
if os.path.isdir(path_argument):
files, modules, directories, packages = _find_paths(ignores, path_argument, path_argument)
return FoundFiles(path_argument, files, modules, directories, packages, ignores)
if explicit_file_mode:
return SingleFiles(paths, workdir or os.getcwd())
else:
return SingleFile(path_argument)
assert len(paths) == 1
files, modules, directories, packages = _find_paths(ignores, paths[0], paths[0])
return FoundFiles(paths[0], files, modules, directories, packages, ignores)
1 change: 1 addition & 0 deletions prospector/formatters/text.py
Expand Up @@ -11,6 +11,7 @@

class TextFormatter(Formatter):
summary_labels = (
('path', 'Path'),
('started', 'Started'),
('completed', 'Finished'),
('time_taken', 'Time Taken', lambda x: '%s seconds' % x),
Expand Down
26 changes: 15 additions & 11 deletions prospector/run.py
Expand Up @@ -20,21 +20,15 @@
class Prospector(object):
def __init__(self, config):
self.config = config

if os.path.isdir(config.path):
self.rootpath = config.path
else:
self.rootpath = os.getcwd()

self.summary = None
self.messages = None

def process_messages(self, messages):
for message in messages:
if self.config.absolute_paths:
message.to_absolute_path(self.rootpath)
message.to_absolute_path(self.config.workdir)
else:
message.to_relative_path(self.rootpath)
message.to_relative_path(self.config.workdir)
if self.config.blending:
messages = blender.blend(messages)

Expand All @@ -47,7 +41,8 @@ def execute(self):
}
summary.update(self.config.get_summary_information())

found_files = find_python(self.config.ignores, self.config.path)
found_files = find_python(self.config.ignores, self.config.paths,
self.config.explicit_file_mode, self.config.workdir)

# Run the tools
messages = []
Expand All @@ -65,7 +60,7 @@ def execute(self):
else:
toolname = 'Unknown'

loc = Location(self.config.path, None, None, None, None)
loc = Location(self.config.workdir, None, None, None, None)
msg = 'Tool %s failed to run (exception was raised)' % (
toolname,
)
Expand Down Expand Up @@ -105,10 +100,12 @@ def print_messages(self, write_to=None):
self.summary['formatter'] = output_format
formatter = FORMATTERS[output_format](self.summary, self.messages)

print_messages = not self.config.summary_only and self.messages

# Produce the output
write_to.write(formatter.render(
summary=not self.config.messages_only,
messages=not self.config.summary_only,
messages=print_messages,
))
write_to.write('\n')

Expand All @@ -127,6 +124,13 @@ def main():
# Get our configuration
config = ProspectorConfig()

paths = config.paths
if len(paths) > 1 and not all([os.path.isfile(path) for path in paths]):
sys.stderr.write('\nIn multi-path mode, all inputs must be files, '
'not directories.\n\n')
get_parser().print_usage()
sys.exit(2)

# Make it so
prospector = Prospector(config)
prospector.execute()
Expand Down
2 changes: 1 addition & 1 deletion prospector/tools/pylint/__init__.py
Expand Up @@ -166,7 +166,7 @@ def configure(self, prospector_config, found_files):
if pylintrc is None:
pylintrc = find_pylintrc()
if pylintrc is None:
pylintrc_path = os.path.join(prospector_config.path, '.pylintrc')
pylintrc_path = os.path.join(prospector_config.workdir, '.pylintrc')
if os.path.exists(pylintrc_path):
pylintrc = pylintrc_path

Expand Down

0 comments on commit cdd5bc0

Please sign in to comment.