Skip to content

Commit

Permalink
Fix #39
Browse files Browse the repository at this point in the history
Added -i, --ignore option
  • Loading branch information
rubik committed Dec 24, 2013
1 parent b277ffe commit 523ae92
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 24 deletions.
29 changes: 18 additions & 11 deletions radon/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,17 @@ def _print_cc_results(path, results, show_complexity):
return average_cc, len(results)


def analyze_cc(paths, exclude, min, max, order_function):
def analyze_cc(paths, exclude, ignore, min, max, order_function):
'''Analyze the files located under `paths`.
:param paths: A list of paths to analyze.
:param exclude: A comma-separated string of fnmatch patterns.
:param ignore: A comma-separated string of patterns to ignore.
:param min: The minimum rank to output.
:param max: The maximum rank to output.
:param order_function: Can be `SCORE`, `LINES` or `ALPHA`, to sort the
results respectively by CC score, line number or name.'''
for name in iter_filenames(paths, exclude):
for name in iter_filenames(paths, exclude, ignore):
with open(name) as fobj:
try:
results = sorted_results(cc_visit(fobj.read()), order_function)
Expand All @@ -115,19 +116,21 @@ def analyze_cc(paths, exclude, min, max, order_function):


@program.command
def mi(multi=True, exclude=None, show=False, *paths):
def mi(multi=True, exclude=None, ignore=None, show=False, *paths):
'''Analyze the given Python modules and compute the Maintainability Index.
The maintainability index (MI) is a compound metric, with the primary aim
being to determine how easy it will be to maintain a particular body of
code.
:param -e, --exclude <str>: Comma separated list of patterns to exclude
:param -m, --multi: If given, multiline strings are counted as comments
:param -s, --show: If given, the actual MI value is shown in results
:param -e, --exclude <str>: Comma separated list of patterns to exclude.
:param -i, --ignore <str>: Comma separated list of patterns to ignore.
Radon won't even descend into those directories.
:param -m, --multi: If given, multiline strings are counted as comments.
:param -s, --show: If given, the actual MI value is shown in results.
:param paths: The modules or packages to analyze.
'''
for name in iter_filenames(paths, exclude):
for name in iter_filenames(paths, exclude, ignore):
with open(name) as fobj:
try:
result = mi_visit(fobj.read(), multi)
Expand All @@ -146,7 +149,7 @@ def mi(multi=True, exclude=None, show=False, *paths):

@program.command
def cc(path, min='A', max='F', show_complexity=False, average=False,
exclude=None, order='SCORE', json=False, *more_paths):
exclude=None, ignore=None, order='SCORE', json=False, *more_paths):
'''Analyze the given Python modules and compute Cyclomatic
Complexity (CC).
Expand All @@ -158,6 +161,8 @@ def cc(path, min='A', max='F', show_complexity=False, average=False,
:param -x, --max <str>: The maximum complexity to display (default to F).
:param -e, --exclude <str>: Comma separated list of patterns to exclude.
By default hidden directories (those starting with '.') are excluded.
:param -i, --ignore <str>: Comma separated list of patterns to ignore.
Radon won't even descend into them.
:param -s, --show_complexity: Whether or not to show the actual complexity score
together with the A-F rank. Default to False.
:param -a, --average: If True, at the end of the analysis display the average
Expand All @@ -173,7 +178,7 @@ def cc(path, min='A', max='F', show_complexity=False, average=False,
average_cc = .0
analyzed = 0
order_function = getattr(cc_mod, order.upper(), getattr(cc_mod, 'SCORE'))
cc_data = analyze_cc(paths, exclude, min, max, order_function)
cc_data = analyze_cc(paths, exclude, ignore, min, max, order_function)
if json:
result = {}
for key, data in cc_data:
Expand All @@ -194,7 +199,7 @@ def cc(path, min='A', max='F', show_complexity=False, average=False,


@program.command
def raw(exclude=None, summary=False, *paths):
def raw(exclude=None, ignore=None, summary=False, *paths):
'''Analyze the given Python modules and compute raw metrics.
Raw metrics include:
Expand All @@ -215,14 +220,16 @@ def raw(exclude=None, summary=False, *paths):
:param -e, --exclude <str>: Comma separated list of patterns to exclude.
By default hidden directories (those starting with '.') are excluded.
:param -i, --ignore <str>: Comma separated list of patterns to ignore.
Radon won't even descend into those directories.
:param -s, --summary: If given, at the end of the analysis display the
summary of the gathered metrics. Default to False.
:param paths: The modules or packages to analyze.
'''
headers = ['LOC', 'LLOC', 'SLOC', 'Comments', 'Multi', 'Blank']
sum_metrics = collections.defaultdict(int, zip(headers, [0] * 6))

for path in iter_filenames(paths, exclude):
for path in iter_filenames(paths, exclude, ignore):
with open(path) as fobj:
log(path)
try:
Expand Down
37 changes: 24 additions & 13 deletions radon/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,49 @@
import operator
import itertools
from functools import reduce
from pathfinder import find_paths, FnmatchFilter, NotFilter, FileFilter
from pathfinder import (find_paths, FnmatchFilter, NotFilter, FileFilter,
DirectoryFilter)
from radon.visitors import Function
from radon.complexity import cc_rank


def iter_filenames(paths, exclude=None):
def iter_filenames(paths, exclude=None, ignore=None):
'''A generator that yields all sub-paths of the ones specified in `paths`.
Optional exclude filters can be passed as a comma-separated string of
fnmatch patterns.'''
finder = lambda path: build_finder(path, build_filter(exclude))
finder = lambda path: build_finder(path, build_filter(exclude),
build_ignore(ignore))
return itertools.chain(*map(finder, paths))


def build_finder(path, filter):
def build_finder(path, filter, ignore):
'''Construct a path finder for the specified `path` and with the specified
`filter`. Hidden directories are ignored by default.'''
if os.path.isfile(path):
return (path,)
return find_paths(path, filter=filter, ignore=FnmatchFilter('*/.*'))
return find_paths(path, filter=filter, ignore=ignore)


def build_filter(exclude=None):
def build_filter(exclude):
'''Construct a filter from a comma-separated string of fnmatch patterns.'''
excluded = [FnmatchFilter(e) for e in (exclude or '').split(',') if e]
f = FileFilter() & FnmatchFilter('*.py')
if excluded:
f &= NotFilter(
reduce(operator.or_, excluded[1:], excluded[0])
)
return f
return build_custom(exclude, FileFilter() & FnmatchFilter('*.py'),
NotFilter)


def build_ignore(ignore):
'''Construct an ignore filter from a comma-separated string of fnmatch
patterns.'''
return build_custom(ignore, DirectoryFilter(), add=[FnmatchFilter('*/.*')])


def build_custom(pattern, start, final=lambda x: x, op=operator.or_, add=[]):
patt = [FnmatchFilter(p) for p in (pattern or '').split(',') if p] + add
if patt:
start &= final(
reduce(op, patt[1:], patt[0])
)
return start

def cc_to_dict(obj):
'''Convert a list of results into a dictionary. This is meant for JSON
dumping.'''
Expand Down

0 comments on commit 523ae92

Please sign in to comment.