Skip to content

Commit

Permalink
Merging in pull request #3, which adds support for pep8, and fixing a…
Browse files Browse the repository at this point in the history
… few merge conflicts with the development branch
  • Loading branch information
carlio committed Jan 2, 2014
2 parents d35bfff + 0076a06 commit 9d96a26
Show file tree
Hide file tree
Showing 23 changed files with 466 additions and 133 deletions.
14 changes: 2 additions & 12 deletions README.md
Expand Up @@ -82,7 +82,7 @@ Prospector has a configurable 'strictness' level which will determine how harshl
prospector --strictness high
```

Possible values are `low`, `medium` and `high`.
Possible values are `verylow`, `low`, `medium`, `high`, `veryhigh`.

Additionally, you can turn off all documentation warnings using the `--no-doc-warnings` flag.

Expand All @@ -99,20 +99,10 @@ Prospector is available under the GPLv2 License.
Currently, prospector runs the following tools:

* Pylint
<<<<<<< HEAD
* McCabe complexity
=======
* pyflakes
>>>>>>> remotes/jayclassless/pyflakes
* pep8 (with pep8-naming)

Future support is planned for:

* pep8
<<<<<<< HEAD
* pyflakes
=======
* McCabe complexity
>>>>>>> remotes/jayclassless/pyflakes

## Supported frameworks and libraries

Expand Down
2 changes: 1 addition & 1 deletion prospector/__pkginfo__.py
@@ -1,6 +1,6 @@

VERSION = (0, 4)
version = (0, 3, 1)


def get_version():
return '.'.join([str(v) for v in VERSION])
3 changes: 3 additions & 0 deletions prospector/adaptor/base.py
Expand Up @@ -9,3 +9,6 @@ def adapt_mccabe(self, tool):

def adapt_pyflakes(self, tool):
pass

def adapt_pep8(self, style_guide):
pass
14 changes: 14 additions & 0 deletions prospector/adaptor/profile.py
Expand Up @@ -13,7 +13,11 @@ def adapt_pylint(self, linter):
for msg_id in self.profile.pylint['disable']:
try:
linter.disable(msg_id)

# pylint: disable=W0704
except UnknownMessage:
# If the msg_id doesn't exist in PyLint any more,
# don't worry about it.
pass

options = self.profile.pylint['options']
Expand All @@ -40,3 +44,13 @@ def adapt_pyflakes(self, tool):
tool.ignore_codes
+ tuple(self.profile.pyflakes['disable'])
))

def adapt_pep8(self, style_guide):
style_guide.options.ignore = tuple(set(
style_guide.options.ignore
+ tuple(self.profile.pep8['disable'])
))

if 'max-line-length' in self.profile.pep8['options']:
style_guide.options.max_line_length = \
self.profile.pep8['options']['max-line-length']
19 changes: 11 additions & 8 deletions prospector/autodetect.py
Expand Up @@ -13,12 +13,12 @@
def find_from_imports(file_contents):
names = set()
for line in file_contents.split('\n'):
m = _IMPORT_REGEX.match(line)
if m is None:
m = _FROM_IMPORT_REGEX.match(line)
if m is None:
match = _IMPORT_REGEX.match(line)
if match is None:
match = _FROM_IMPORT_REGEX.match(line)
if match is None:
continue
import_names = m.group(1).split('.')
import_names = match.group(1).split('.')
for import_name in import_names:
if import_name in LIBRARY_ADAPTORS:
names.add(import_name)
Expand All @@ -34,8 +34,8 @@ def find_from_path(path):
if os.path.isdir(item_path):
names |= find_from_path(item_path)
elif not os.path.islink(item_path) and item_path.endswith('.py'):
with open(item_path) as f:
names |= find_from_imports(f.read())
with open(item_path) as fip:
names |= find_from_imports(fip.read())

if len(names) == max_possible:
# don't continue on recursing, there's no point!
Expand All @@ -48,7 +48,8 @@ def find_from_requirements(path):
reqs = find_requirements(path)
names = []
for requirement in reqs:
if requirement.name is not None and requirement.name.lower() in LIBRARY_ADAPTORS:
if requirement.name is not None \
and requirement.name.lower() in LIBRARY_ADAPTORS:
names.append(requirement.name.lower())
return names

Expand All @@ -59,6 +60,8 @@ def autodetect_libraries(path):

try:
adaptor_names = find_from_requirements(path)

# pylint: disable=W0704
except RequirementsNotFound:
pass

Expand Down
5 changes: 3 additions & 2 deletions prospector/formatters/__init__.py
@@ -1,6 +1,7 @@
from prospector.formatters import json, text
from prospector.formatters import json, text, grouped

FORMATTERS = {
'json': json.format_messages,
'text': text.format_messages
'text': text.format_messages,
'grouped': grouped.format_messages,
}
43 changes: 43 additions & 0 deletions prospector/formatters/grouped.py
@@ -0,0 +1,43 @@
import sys

from collections import defaultdict

from .text import _SUMMARY_TEMPLATE


__all__ = (
'format_messages',
)


def format_messages(summary, messages):
if summary:
sys.stdout.write("Check Information\n=================\n")
sys.stdout.write(_SUMMARY_TEMPLATE % summary)
sys.stdout.write('\n\n')

if not messages:
return

# pylint: disable=W0108
groups = defaultdict(lambda: defaultdict(list))

for message in messages:
groups[message.location.path][message.location.line].append(message)

sys.stdout.write("Messages\n========\n\n")
for filename in sorted(groups.keys()):
sys.stdout.write('%s\n' % filename)

for line in sorted(groups[filename].keys(), key=lambda x: int(x)):
sys.stdout.write(' Line: %s\n' % line)

for msg in groups[filename][line]:
sys.stdout.write(
' %(source)s: %(code)s / %(message)s' % msg.as_dict(),
)
if msg.location.character:
sys.stdout.write(' (col %s)' % msg.location.character)
sys.stdout.write('\n')

sys.stdout.write('\n')
66 changes: 46 additions & 20 deletions prospector/profiles/profile.py
Expand Up @@ -4,19 +4,24 @@

class ProfileNotFound(Exception):
def __init__(self, name, filepath):
super(ProfileNotFound, self).__init__()
self.name = name
self.filepath = filepath

def __repr__(self):
return "Could not find profile %s at %s" % (self.name, self.filepath)


_empty_data = {
_EMPTY_DATA = {
'inherits': [],
'mccabe': {
'disable': [],
'options': {},
},
'pep8': {
'disable': [],
'options': {},
},
'pyflakes': {
'disable': [],
'options': {},
Expand All @@ -42,14 +47,17 @@ def _load_content(name, basedir=None):
# assume that this is a full path that we can load
filename = name
else:
basedir = basedir or os.path.join(os.path.dirname(__file__), 'profiles')
basedir = basedir or os.path.join(
os.path.dirname(__file__),
'profiles',
)
filename = os.path.join(basedir, '%s.yaml' % name)

if not os.path.exists(filename):
raise ProfileNotFound(name, os.path.abspath(filename))

with open(filename) as f:
return f.read()
with open(filename) as fct:
return fct.read()


def from_file(name, basedir=None):
Expand All @@ -64,7 +72,11 @@ def _load_profile(name, basedir=None, inherits_set=None):

for inheritsed in profile.inherits:
if inheritsed not in inherits_set:
inheritsed_profile, sub_inherits_set = _load_profile(inheritsed, basedir, inherits_set)
inheritsed_profile, sub_inherits_set = _load_profile(
inheritsed,
basedir,
inherits_set,
)
profile.merge(inheritsed_profile)
inherits_set |= sub_inherits_set

Expand All @@ -77,31 +89,40 @@ def parse_profile(name, contents):
name = os.path.splitext(os.path.basename(name))[0]
data = yaml.load(contents)
if data is None:
# this happens if a completely empty YAML file is passed in to parse_profile, for example
data = dict(_empty_data)
# this happens if a completely empty YAML file is passed in to
# parse_profile, for example
data = dict(_EMPTY_DATA)
else:
data = _merge_dict(_empty_data, data, d1_priority=False)
data = _merge_dict(_EMPTY_DATA, data, dict1_priority=False)
return StrictnessProfile(name, data)


def _merge_dict(d1, d2, dedup_lists=False, d1_priority=True):
def _merge_dict(dict1, dict2, dedup_lists=False, dict1_priority=True):
newdict = {}
newdict.update(d1)
newdict.update(dict1)

for key, value in d2.iteritems():
if key not in d1:
for key, value in dict2.iteritems():
if key not in dict1:
newdict[key] = value
elif value is None and d1[key] is not None:
newdict[key] = d1[key]
elif d1[key] is None and value is not None:
elif value is None and dict1[key] is not None:
newdict[key] = dict1[key]
elif dict1[key] is None and value is not None:
newdict[key] = value
elif type(value) != type(d1[key]):
raise ValueError("Could not merge conflicting types %s and %s" % (type(value), type(d1[key])))
elif type(value) != type(dict1[key]):
raise ValueError("Could not merge conflicting types %s and %s" % (
type(value),
type(dict1[key]),
))
elif isinstance(value, dict):
newdict[key] = _merge_dict(d1[key], value, dedup_lists, d1_priority)
newdict[key] = _merge_dict(
dict1[key],
value,
dedup_lists,
dict1_priority,
)
elif isinstance(value, (list, tuple)):
newdict[key] = list(set(d1[key]) | set(value))
elif not d1_priority:
newdict[key] = list(set(dict1[key]) | set(value))
elif not dict1_priority:
newdict[key] = value

return newdict
Expand All @@ -111,9 +132,12 @@ class StrictnessProfile(object):

def __init__(self, name, profile_dict):
self.name = name

self.mccabe = profile_dict['mccabe']
self.pep8 = profile_dict['pep8']
self.pyflakes = profile_dict['pyflakes']
self.pylint = profile_dict['pylint']

self.inherits = profile_dict['inherits']
self.ignore = profile_dict['ignore']

Expand All @@ -122,6 +146,7 @@ def to_profile_dict(self):
'inherits': self.inherits,
'ignore': self.ignore,
'mccabe': self.mccabe,
'pep8': self.pep8,
'pyflakes': self.pyflakes,
'pylint': self.pylint
}
Expand All @@ -130,6 +155,7 @@ def merge(self, other_profile):
self.ignore = list(set(self.ignore + other_profile.ignore))
self.inherits = list(set(self.inherits + other_profile.inherits))
self.mccabe = _merge_dict(self.mccabe, other_profile.mccabe)
self.pep8 = _merge_dict(self.pep8, other_profile.pep8)
self.pyflakes = _merge_dict(self.pyflakes, other_profile.pyflakes)
self.pylint = _merge_dict(self.pylint, other_profile.pylint)

Expand Down
1 change: 0 additions & 1 deletion prospector/profiles/profiles/no_doc_warnings.yaml
@@ -1,4 +1,3 @@

pylint:
disable:
- C0112
Expand Down
1 change: 0 additions & 1 deletion prospector/profiles/profiles/no_test_warnings.yaml
@@ -1,4 +1,3 @@

ignore:
- ^tests?/?
- /tests?(/|$)
Expand Down
9 changes: 8 additions & 1 deletion prospector/profiles/profiles/strictness_high.yaml
Expand Up @@ -23,4 +23,11 @@ pylint:
max-branches: 15
max-statements: 60
min-public-methods: 1
max-public-methods: 20
max-public-methods: 20

pep8:
disable:
- E304
- W291
- W292
- W391
7 changes: 7 additions & 0 deletions prospector/profiles/profiles/strictness_low.yaml
Expand Up @@ -39,3 +39,10 @@ pyflakes:
disable:
- FL0001
- FL0013

pep8:
disable:
- E501
- E711
- E712
- E721

0 comments on commit 9d96a26

Please sign in to comment.