mccabe-0.6.1/0000775000175000017500000000000013042472161014332 5ustar icordascicordasc00000000000000mccabe-0.6.1/test_mccabe.py0000664000175000017500000001362513041372760017167 0ustar icordascicordasc00000000000000import unittest import sys try: from StringIO import StringIO except ImportError: from io import StringIO import pytest import mccabe from mccabe import get_code_complexity # Snippets are put outside of testcases because of spacing issue that would # otherwise occur with triple quoted strings. trivial = 'def f(): pass' expr_as_statement = '''\ def f(): """docstring""" ''' sequential = """\ def f(n): k = n + 4 s = k + n return s """ sequential_unencapsulated = """\ k = 2 + 4 s = k + 3 """ if_elif_else_dead_path = """\ def f(n): if n > 3: return "bigger than three" elif n > 4: return "is never executed" else: return "smaller than or equal to three" """ for_loop = """\ def f(): for i in range(10): print(i) """ for_else = """\ def f(mylist): for i in mylist: print(i) else: print(None) """ recursive = """\ def f(n): if n > 4: return f(n - 1) else: return n """ nested_functions = """\ def a(): def b(): def c(): pass c() b() """ try_else = """\ try: print(1) except TypeA: print(2) except TypeB: print(3) else: print(4) """ async_keywords = """\ async def foobar(a, b, c): await whatever(a, b, c) if await b: pass async with c: pass async for x in a: pass """ annotated_assign = """\ def f(): x: Any = None """ def get_complexity_number(snippet, strio, max=0): """Get the complexity number from the printed string.""" # Report from the lowest complexity number. get_code_complexity(snippet, max) strio_val = strio.getvalue() if strio_val: return int(strio_val.split()[-1].strip("()")) else: return None class McCabeTestCase(unittest.TestCase): def setUp(self): # If not assigned to sys.stdout then getvalue() won't capture anything. self._orig_stdout = sys.stdout sys.stdout = self.strio = StringIO() def tearDown(self): # https://mail.python.org/pipermail/tutor/2012-January/088031.html self.strio.close() sys.stdout = self._orig_stdout def assert_complexity(self, snippet, max): complexity = get_complexity_number(snippet, self.strio) self.assertEqual(complexity, max) # should have the same complexity when inside a function as well. infunc = 'def f():\n ' + snippet.replace('\n', '\n ') complexity = get_complexity_number(infunc, self.strio) self.assertEqual(complexity, max) def test_print_message(self): get_code_complexity(sequential, 0) printed_message = self.strio.getvalue() self.assertEqual(printed_message, "stdin:1:1: C901 'f' is too complex (1)\n") def test_sequential_snippet(self): complexity = get_complexity_number(sequential, self.strio) self.assertEqual(complexity, 1) def test_sequential_unencapsulated_snippet(self): complexity = get_complexity_number(sequential_unencapsulated, self.strio) self.assertEqual(complexity, None) def test_if_elif_else_dead_path_snippet(self): complexity = get_complexity_number(if_elif_else_dead_path, self.strio) # Paths that will never be executed are counted! self.assertEqual(complexity, 3) def test_for_loop_snippet(self): complexity = get_complexity_number(for_loop, self.strio) # The for loop adds an execution path; sometimes it won't be run. self.assertEqual(complexity, 2) def test_for_else_snippet(self): complexity = get_complexity_number(for_else, self.strio) # The for loop doesn't add an execution path, but its `else` does self.assertEqual(complexity, 2) def test_recursive_snippet(self): complexity = get_complexity_number(recursive, self.strio) self.assertEqual(complexity, 2) def test_nested_functions_snippet(self): complexity = get_complexity_number(nested_functions, self.strio) self.assertEqual(complexity, 3) def test_trivial(self): """The most-trivial program should pass a max-complexity=1 test""" complexity = get_complexity_number(trivial, self.strio, max=1) self.assertEqual(complexity, None) printed_message = self.strio.getvalue() self.assertEqual(printed_message, "") def test_expr_as_statement(self): complexity = get_complexity_number(expr_as_statement, self.strio) self.assertEqual(complexity, 1) def test_try_else(self): self.assert_complexity(try_else, 4) @pytest.mark.skipif(sys.version_info < (3, 5), reason="Async keywords are only valid on Python 3.5+") def test_async_keywords(self): """Validate that we properly process async keyword usage.""" complexity = get_complexity_number(async_keywords, self.strio) self.assertEqual(complexity, 3) @pytest.mark.skipif( sys.version_info < (3, 6), reason="Annotated assignments are only valid on Python 3.6+", ) def test_annotated_assignment(self): complexity = get_complexity_number(annotated_assign, self.strio) self.assertEqual(complexity, 1) class RegressionTests(unittest.TestCase): def setUp(self): self.original_complexity = mccabe.McCabeChecker.max_complexity def tearDown(self): mccabe.McCabeChecker.max_complexity = self.original_complexity def test_max_complexity_is_always_an_int(self): """Ensure bug #32 does not regress.""" class _options(object): max_complexity = None options = _options() options.max_complexity = '16' self.assertEqual(0, mccabe.McCabeChecker.max_complexity) mccabe.McCabeChecker.parse_options(options) self.assertEqual(16, mccabe.McCabeChecker.max_complexity) if __name__ == "__main__": unittest.main() mccabe-0.6.1/mccabe.py0000664000175000017500000002470513042471706016132 0ustar icordascicordasc00000000000000""" Meager code path measurement tool. Ned Batchelder http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html MIT License. """ from __future__ import with_statement import optparse import sys import tokenize from collections import defaultdict try: import ast from ast import iter_child_nodes except ImportError: # Python 2.5 from flake8.util import ast, iter_child_nodes __version__ = '0.6.1' class ASTVisitor(object): """Performs a depth-first walk of the AST.""" def __init__(self): self.node = None self._cache = {} def default(self, node, *args): for child in iter_child_nodes(node): self.dispatch(child, *args) def dispatch(self, node, *args): self.node = node klass = node.__class__ meth = self._cache.get(klass) if meth is None: className = klass.__name__ meth = getattr(self.visitor, 'visit' + className, self.default) self._cache[klass] = meth return meth(node, *args) def preorder(self, tree, visitor, *args): """Do preorder walk of tree using visitor""" self.visitor = visitor visitor.visit = self.dispatch self.dispatch(tree, *args) # XXX *args make sense? class PathNode(object): def __init__(self, name, look="circle"): self.name = name self.look = look def to_dot(self): print('node [shape=%s,label="%s"] %d;' % ( self.look, self.name, self.dot_id())) def dot_id(self): return id(self) class PathGraph(object): def __init__(self, name, entity, lineno, column=0): self.name = name self.entity = entity self.lineno = lineno self.column = column self.nodes = defaultdict(list) def connect(self, n1, n2): self.nodes[n1].append(n2) # Ensure that the destination node is always counted. self.nodes[n2] = [] def to_dot(self): print('subgraph {') for node in self.nodes: node.to_dot() for node, nexts in self.nodes.items(): for next in nexts: print('%s -- %s;' % (node.dot_id(), next.dot_id())) print('}') def complexity(self): """ Return the McCabe complexity for the graph. V-E+2 """ num_edges = sum([len(n) for n in self.nodes.values()]) num_nodes = len(self.nodes) return num_edges - num_nodes + 2 class PathGraphingAstVisitor(ASTVisitor): """ A visitor for a parsed Abstract Syntax Tree which finds executable statements. """ def __init__(self): super(PathGraphingAstVisitor, self).__init__() self.classname = "" self.graphs = {} self.reset() def reset(self): self.graph = None self.tail = None def dispatch_list(self, node_list): for node in node_list: self.dispatch(node) def visitFunctionDef(self, node): if self.classname: entity = '%s%s' % (self.classname, node.name) else: entity = node.name name = '%d:%d: %r' % (node.lineno, node.col_offset, entity) if self.graph is not None: # closure pathnode = self.appendPathNode(name) self.tail = pathnode self.dispatch_list(node.body) bottom = PathNode("", look='point') self.graph.connect(self.tail, bottom) self.graph.connect(pathnode, bottom) self.tail = bottom else: self.graph = PathGraph(name, entity, node.lineno, node.col_offset) pathnode = PathNode(name) self.tail = pathnode self.dispatch_list(node.body) self.graphs["%s%s" % (self.classname, node.name)] = self.graph self.reset() visitAsyncFunctionDef = visitFunctionDef def visitClassDef(self, node): old_classname = self.classname self.classname += node.name + "." self.dispatch_list(node.body) self.classname = old_classname def appendPathNode(self, name): if not self.tail: return pathnode = PathNode(name) self.graph.connect(self.tail, pathnode) self.tail = pathnode return pathnode def visitSimpleStatement(self, node): if node.lineno is None: lineno = 0 else: lineno = node.lineno name = "Stmt %d" % lineno self.appendPathNode(name) def default(self, node, *args): if isinstance(node, ast.stmt): self.visitSimpleStatement(node) else: super(PathGraphingAstVisitor, self).default(node, *args) def visitLoop(self, node): name = "Loop %d" % node.lineno self._subgraph(node, name) visitAsyncFor = visitFor = visitWhile = visitLoop def visitIf(self, node): name = "If %d" % node.lineno self._subgraph(node, name) def _subgraph(self, node, name, extra_blocks=()): """create the subgraphs representing any `if` and `for` statements""" if self.graph is None: # global loop self.graph = PathGraph(name, name, node.lineno, node.col_offset) pathnode = PathNode(name) self._subgraph_parse(node, pathnode, extra_blocks) self.graphs["%s%s" % (self.classname, name)] = self.graph self.reset() else: pathnode = self.appendPathNode(name) self._subgraph_parse(node, pathnode, extra_blocks) def _subgraph_parse(self, node, pathnode, extra_blocks): """parse the body and any `else` block of `if` and `for` statements""" loose_ends = [] self.tail = pathnode self.dispatch_list(node.body) loose_ends.append(self.tail) for extra in extra_blocks: self.tail = pathnode self.dispatch_list(extra.body) loose_ends.append(self.tail) if node.orelse: self.tail = pathnode self.dispatch_list(node.orelse) loose_ends.append(self.tail) else: loose_ends.append(pathnode) if pathnode: bottom = PathNode("", look='point') for le in loose_ends: self.graph.connect(le, bottom) self.tail = bottom def visitTryExcept(self, node): name = "TryExcept %d" % node.lineno self._subgraph(node, name, extra_blocks=node.handlers) visitTry = visitTryExcept def visitWith(self, node): name = "With %d" % node.lineno self.appendPathNode(name) self.dispatch_list(node.body) visitAsyncWith = visitWith class McCabeChecker(object): """McCabe cyclomatic complexity checker.""" name = 'mccabe' version = __version__ _code = 'C901' _error_tmpl = "C901 %r is too complex (%d)" max_complexity = -1 def __init__(self, tree, filename): self.tree = tree @classmethod def add_options(cls, parser): flag = '--max-complexity' kwargs = { 'default': -1, 'action': 'store', 'type': 'int', 'help': 'McCabe complexity threshold', 'parse_from_config': 'True', } config_opts = getattr(parser, 'config_options', None) if isinstance(config_opts, list): # Flake8 2.x kwargs.pop('parse_from_config') parser.add_option(flag, **kwargs) parser.config_options.append('max-complexity') else: parser.add_option(flag, **kwargs) @classmethod def parse_options(cls, options): cls.max_complexity = int(options.max_complexity) def run(self): if self.max_complexity < 0: return visitor = PathGraphingAstVisitor() visitor.preorder(self.tree, visitor) for graph in visitor.graphs.values(): if graph.complexity() > self.max_complexity: text = self._error_tmpl % (graph.entity, graph.complexity()) yield graph.lineno, graph.column, text, type(self) def get_code_complexity(code, threshold=7, filename='stdin'): try: tree = compile(code, filename, "exec", ast.PyCF_ONLY_AST) except SyntaxError: e = sys.exc_info()[1] sys.stderr.write("Unable to parse %s: %s\n" % (filename, e)) return 0 complx = [] McCabeChecker.max_complexity = threshold for lineno, offset, text, check in McCabeChecker(tree, filename).run(): complx.append('%s:%d:1: %s' % (filename, lineno, text)) if len(complx) == 0: return 0 print('\n'.join(complx)) return len(complx) def get_module_complexity(module_path, threshold=7): """Returns the complexity of a module""" with open(module_path, "rU") as mod: code = mod.read() return get_code_complexity(code, threshold, filename=module_path) def _read(filename): if (2, 5) < sys.version_info < (3, 0): with open(filename, 'rU') as f: return f.read() elif (3, 0) <= sys.version_info < (4, 0): """Read the source code.""" try: with open(filename, 'rb') as f: (encoding, _) = tokenize.detect_encoding(f.readline) except (LookupError, SyntaxError, UnicodeError): # Fall back if file encoding is improperly declared with open(filename, encoding='latin-1') as f: return f.read() with open(filename, 'r', encoding=encoding) as f: return f.read() def main(argv=None): if argv is None: argv = sys.argv[1:] opar = optparse.OptionParser() opar.add_option("-d", "--dot", dest="dot", help="output a graphviz dot file", action="store_true") opar.add_option("-m", "--min", dest="threshold", help="minimum complexity for output", type="int", default=1) options, args = opar.parse_args(argv) code = _read(args[0]) tree = compile(code, args[0], "exec", ast.PyCF_ONLY_AST) visitor = PathGraphingAstVisitor() visitor.preorder(tree, visitor) if options.dot: print('graph {') for graph in visitor.graphs.values(): if (not options.threshold or graph.complexity() >= options.threshold): graph.to_dot() print('}') else: for graph in visitor.graphs.values(): if graph.complexity() >= options.threshold: print(graph.name, graph.complexity()) if __name__ == '__main__': main(sys.argv[1:]) mccabe-0.6.1/LICENSE0000664000175000017500000000230513041372760015342 0ustar icordascicordasc00000000000000Copyright © Ned Batchelder Copyright © 2011-2013 Tarek Ziade Copyright © 2013 Florent Xicluna Licensed under the terms of the Expat License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mccabe-0.6.1/README.rst0000664000175000017500000000634413042472004016024 0ustar icordascicordasc00000000000000McCabe complexity checker ========================= Ned's script to check McCabe complexity. This module provides a plugin for ``flake8``, the Python code checker. Installation ------------ You can install, upgrade, uninstall ``mccabe`` with these commands:: $ pip install mccabe $ pip install --upgrade mccabe $ pip uninstall mccabe Standalone script ----------------- The complexity checker can be used directly:: $ python -m mccabe --min 5 mccabe.py ("185:1: 'PathGraphingAstVisitor.visitIf'", 5) ("71:1: 'PathGraph.to_dot'", 5) ("245:1: 'McCabeChecker.run'", 5) ("283:1: 'main'", 7) ("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5) ("257:1: 'get_code_complexity'", 5) Plugin for Flake8 ----------------- When both ``flake8 2.0`` and ``mccabe`` are installed, the plugin is available in ``flake8``:: $ flake8 --version 2.0 (pep8: 1.4.2, pyflakes: 0.6.1, mccabe: 0.2) By default the plugin is disabled. Use the ``--max-complexity`` switch to enable it. It will emit a warning if the McCabe complexity of a function is higher that the value:: $ flake8 --max-complexity 10 coolproject ... coolproject/mod.py:1204:1: C901 'CoolFactory.prepare' is too complex (14) This feature is quite useful to detect over-complex code. According to McCabe, anything that goes beyond 10 is too complex. Links ----- * Feedback and ideas: http://mail.python.org/mailman/listinfo/code-quality * Cyclomatic complexity: http://en.wikipedia.org/wiki/Cyclomatic_complexity. * Ned Batchelder's script: http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html Changes ------- 0.6.1 - 2017-01-26 `````````````````` * Fix signature for ``PathGraphingAstVisitor.default`` to match the signature for ``ASTVisitor`` 0.6.0 - 2017-01-23 `````````````````` * Add support for Python 3.6 * Fix handling for missing statement types 0.5.3 - 2016-12-14 `````````````````` * Report actual column number of violation instead of the start of the line 0.5.2 - 2016-07-31 `````````````````` * When opening files ourselves, make sure we always name the file variable 0.5.1 - 2016-07-28 `````````````````` * Set default maximum complexity to -1 on the class itself 0.5.0 - 2016-05-30 `````````````````` * PyCon 2016 PDX release * Add support for Flake8 3.0 0.4.0 - 2016-01-27 `````````````````` * Stop testing on Python 3.2 * Add support for async/await keywords on Python 3.5 from PEP 0492 0.3.1 - 2015-06-14 `````````````````` * Include ``test_mccabe.py`` in releases. * Always coerce the ``max_complexity`` value from Flake8's entry-point to an integer. 0.3 - 2014-12-17 ```````````````` * Computation was wrong: the mccabe complexity starts at 1, not 2. * The ``max-complexity`` value is now inclusive. E.g.: if the value is 10 and the reported complexity is 10, then it passes. * Add tests. 0.2.1 - 2013-04-03 `````````````````` * Do not require ``setuptools`` in setup.py. It works around an issue with ``pip`` and Python 3. 0.2 - 2013-02-22 ```````````````` * Rename project to ``mccabe``. * Provide ``flake8.extension`` setuptools entry point. * Read ``max-complexity`` from the configuration file. * Rename argument ``min_complexity`` to ``threshold``. 0.1 - 2013-02-11 ```````````````` * First release mccabe-0.6.1/setup.py0000664000175000017500000000346413041372760016056 0ustar icordascicordasc00000000000000# -*- coding: utf-8 -*- from __future__ import with_statement from setuptools import setup def get_version(fname='mccabe.py'): with open(fname) as f: for line in f: if line.startswith('__version__'): return eval(line.split('=')[-1]) def get_long_description(): descr = [] for fname in ('README.rst',): with open(fname) as f: descr.append(f.read()) return '\n\n'.join(descr) setup( name='mccabe', version=get_version(), description="McCabe checker, plugin for flake8", long_description=get_long_description(), keywords='flake8 mccabe', author='Tarek Ziade', author_email='tarek@ziade.org', maintainer='Ian Cordasco', maintainer_email='graffatcolmingov@gmail.com', url='https://github.com/pycqa/mccabe', license='Expat license', py_modules=['mccabe'], zip_safe=False, setup_requires=['pytest-runner'], tests_require=['pytest'], entry_points={ 'flake8.extension': [ 'C90 = mccabe:McCabeChecker', ], }, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ], ) mccabe-0.6.1/PKG-INFO0000664000175000017500000001263713042472161015440 0ustar icordascicordasc00000000000000Metadata-Version: 1.1 Name: mccabe Version: 0.6.1 Summary: McCabe checker, plugin for flake8 Home-page: https://github.com/pycqa/mccabe Author: Ian Cordasco Author-email: graffatcolmingov@gmail.com License: Expat license Description: McCabe complexity checker ========================= Ned's script to check McCabe complexity. This module provides a plugin for ``flake8``, the Python code checker. Installation ------------ You can install, upgrade, uninstall ``mccabe`` with these commands:: $ pip install mccabe $ pip install --upgrade mccabe $ pip uninstall mccabe Standalone script ----------------- The complexity checker can be used directly:: $ python -m mccabe --min 5 mccabe.py ("185:1: 'PathGraphingAstVisitor.visitIf'", 5) ("71:1: 'PathGraph.to_dot'", 5) ("245:1: 'McCabeChecker.run'", 5) ("283:1: 'main'", 7) ("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5) ("257:1: 'get_code_complexity'", 5) Plugin for Flake8 ----------------- When both ``flake8 2.0`` and ``mccabe`` are installed, the plugin is available in ``flake8``:: $ flake8 --version 2.0 (pep8: 1.4.2, pyflakes: 0.6.1, mccabe: 0.2) By default the plugin is disabled. Use the ``--max-complexity`` switch to enable it. It will emit a warning if the McCabe complexity of a function is higher that the value:: $ flake8 --max-complexity 10 coolproject ... coolproject/mod.py:1204:1: C901 'CoolFactory.prepare' is too complex (14) This feature is quite useful to detect over-complex code. According to McCabe, anything that goes beyond 10 is too complex. Links ----- * Feedback and ideas: http://mail.python.org/mailman/listinfo/code-quality * Cyclomatic complexity: http://en.wikipedia.org/wiki/Cyclomatic_complexity. * Ned Batchelder's script: http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html Changes ------- 0.6.1 - 2017-01-26 `````````````````` * Fix signature for ``PathGraphingAstVisitor.default`` to match the signature for ``ASTVisitor`` 0.6.0 - 2017-01-23 `````````````````` * Add support for Python 3.6 * Fix handling for missing statement types 0.5.3 - 2016-12-14 `````````````````` * Report actual column number of violation instead of the start of the line 0.5.2 - 2016-07-31 `````````````````` * When opening files ourselves, make sure we always name the file variable 0.5.1 - 2016-07-28 `````````````````` * Set default maximum complexity to -1 on the class itself 0.5.0 - 2016-05-30 `````````````````` * PyCon 2016 PDX release * Add support for Flake8 3.0 0.4.0 - 2016-01-27 `````````````````` * Stop testing on Python 3.2 * Add support for async/await keywords on Python 3.5 from PEP 0492 0.3.1 - 2015-06-14 `````````````````` * Include ``test_mccabe.py`` in releases. * Always coerce the ``max_complexity`` value from Flake8's entry-point to an integer. 0.3 - 2014-12-17 ```````````````` * Computation was wrong: the mccabe complexity starts at 1, not 2. * The ``max-complexity`` value is now inclusive. E.g.: if the value is 10 and the reported complexity is 10, then it passes. * Add tests. 0.2.1 - 2013-04-03 `````````````````` * Do not require ``setuptools`` in setup.py. It works around an issue with ``pip`` and Python 3. 0.2 - 2013-02-22 ```````````````` * Rename project to ``mccabe``. * Provide ``flake8.extension`` setuptools entry point. * Read ``max-complexity`` from the configuration file. * Rename argument ``min_complexity`` to ``threshold``. 0.1 - 2013-02-11 ```````````````` * First release Keywords: flake8 mccabe Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Quality Assurance mccabe-0.6.1/mccabe.egg-info/0000775000175000017500000000000013042472161017236 5ustar icordascicordasc00000000000000mccabe-0.6.1/mccabe.egg-info/entry_points.txt0000664000175000017500000000005713042472161022536 0ustar icordascicordasc00000000000000[flake8.extension] C90 = mccabe:McCabeChecker mccabe-0.6.1/mccabe.egg-info/dependency_links.txt0000664000175000017500000000000113042472161023304 0ustar icordascicordasc00000000000000 mccabe-0.6.1/mccabe.egg-info/SOURCES.txt0000664000175000017500000000040013042472161021114 0ustar icordascicordasc00000000000000LICENSE MANIFEST.in README.rst mccabe.py setup.cfg setup.py test_mccabe.py mccabe.egg-info/PKG-INFO mccabe.egg-info/SOURCES.txt mccabe.egg-info/dependency_links.txt mccabe.egg-info/entry_points.txt mccabe.egg-info/not-zip-safe mccabe.egg-info/top_level.txtmccabe-0.6.1/mccabe.egg-info/PKG-INFO0000664000175000017500000001263713042472161020344 0ustar icordascicordasc00000000000000Metadata-Version: 1.1 Name: mccabe Version: 0.6.1 Summary: McCabe checker, plugin for flake8 Home-page: https://github.com/pycqa/mccabe Author: Ian Cordasco Author-email: graffatcolmingov@gmail.com License: Expat license Description: McCabe complexity checker ========================= Ned's script to check McCabe complexity. This module provides a plugin for ``flake8``, the Python code checker. Installation ------------ You can install, upgrade, uninstall ``mccabe`` with these commands:: $ pip install mccabe $ pip install --upgrade mccabe $ pip uninstall mccabe Standalone script ----------------- The complexity checker can be used directly:: $ python -m mccabe --min 5 mccabe.py ("185:1: 'PathGraphingAstVisitor.visitIf'", 5) ("71:1: 'PathGraph.to_dot'", 5) ("245:1: 'McCabeChecker.run'", 5) ("283:1: 'main'", 7) ("203:1: 'PathGraphingAstVisitor.visitTryExcept'", 5) ("257:1: 'get_code_complexity'", 5) Plugin for Flake8 ----------------- When both ``flake8 2.0`` and ``mccabe`` are installed, the plugin is available in ``flake8``:: $ flake8 --version 2.0 (pep8: 1.4.2, pyflakes: 0.6.1, mccabe: 0.2) By default the plugin is disabled. Use the ``--max-complexity`` switch to enable it. It will emit a warning if the McCabe complexity of a function is higher that the value:: $ flake8 --max-complexity 10 coolproject ... coolproject/mod.py:1204:1: C901 'CoolFactory.prepare' is too complex (14) This feature is quite useful to detect over-complex code. According to McCabe, anything that goes beyond 10 is too complex. Links ----- * Feedback and ideas: http://mail.python.org/mailman/listinfo/code-quality * Cyclomatic complexity: http://en.wikipedia.org/wiki/Cyclomatic_complexity. * Ned Batchelder's script: http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html Changes ------- 0.6.1 - 2017-01-26 `````````````````` * Fix signature for ``PathGraphingAstVisitor.default`` to match the signature for ``ASTVisitor`` 0.6.0 - 2017-01-23 `````````````````` * Add support for Python 3.6 * Fix handling for missing statement types 0.5.3 - 2016-12-14 `````````````````` * Report actual column number of violation instead of the start of the line 0.5.2 - 2016-07-31 `````````````````` * When opening files ourselves, make sure we always name the file variable 0.5.1 - 2016-07-28 `````````````````` * Set default maximum complexity to -1 on the class itself 0.5.0 - 2016-05-30 `````````````````` * PyCon 2016 PDX release * Add support for Flake8 3.0 0.4.0 - 2016-01-27 `````````````````` * Stop testing on Python 3.2 * Add support for async/await keywords on Python 3.5 from PEP 0492 0.3.1 - 2015-06-14 `````````````````` * Include ``test_mccabe.py`` in releases. * Always coerce the ``max_complexity`` value from Flake8's entry-point to an integer. 0.3 - 2014-12-17 ```````````````` * Computation was wrong: the mccabe complexity starts at 1, not 2. * The ``max-complexity`` value is now inclusive. E.g.: if the value is 10 and the reported complexity is 10, then it passes. * Add tests. 0.2.1 - 2013-04-03 `````````````````` * Do not require ``setuptools`` in setup.py. It works around an issue with ``pip`` and Python 3. 0.2 - 2013-02-22 ```````````````` * Rename project to ``mccabe``. * Provide ``flake8.extension`` setuptools entry point. * Read ``max-complexity`` from the configuration file. * Rename argument ``min_complexity`` to ``threshold``. 0.1 - 2013-02-11 ```````````````` * First release Keywords: flake8 mccabe Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Topic :: Software Development :: Quality Assurance mccabe-0.6.1/mccabe.egg-info/top_level.txt0000664000175000017500000000000713042472161021765 0ustar icordascicordasc00000000000000mccabe mccabe-0.6.1/mccabe.egg-info/not-zip-safe0000664000175000017500000000000113041375037021467 0ustar icordascicordasc00000000000000 mccabe-0.6.1/MANIFEST.in0000664000175000017500000000007213041372760016072 0ustar icordascicordasc00000000000000include LICENSE include README.rst include test_mccabe.py mccabe-0.6.1/setup.cfg0000664000175000017500000000012613042472161016152 0ustar icordascicordasc00000000000000[wheel] universal = 1 [aliases] test = pytest [egg_info] tag_build = tag_date = 0