Hello community,

here is the log from the commit of package python-mccabe for openSUSE:Factory 
checked in at 2017-04-19 17:56:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-mccabe (Old)
 and      /work/SRC/openSUSE:Factory/.python-mccabe.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-mccabe"

Wed Apr 19 17:56:33 2017 rev:7 rq:479716 version:0.6.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-mccabe/python-mccabe.changes      
2015-05-15 09:03:05.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.python-mccabe.new/python-mccabe.changes 
2017-04-19 17:56:34.458798710 +0200
@@ -1,0 +2,46 @@
+Mon Mar  6 14:03:34 UTC 2017 - [email protected]
+
+- update for singlespec
+- enable tests
+
+-------------------------------------------------------------------
+Mon Feb 20 10:36:41 UTC 2017 - [email protected]
+
+- Use pypi.io and https in Source
+
+-------------------------------------------------------------------
+Wed Feb 15 08:55:16 UTC 2017 - [email protected]
+
+- update to version 0.6.1:
+  * Fix signature for PathGraphingAstVisitor.default to match the
+    signature for ASTVisitor
+
+- update to version 0.6.0:
+  * Add support for Python 3.6
+  * Fix handling for missing statement types
+
+- update to version 0.5.3:
+  * Report actual column number of violation instead of the start
+    of the line
+
+- update to version 0.5.2:
+  * When opening files ourselves, make sure we always name the file
+    variable
+
+- update to version 0.5.1:
+  * Set default maximum complexity to -1 on the class itself
+
+- update to version 0.5.0:
+  * PyCon 2016 PDX release
+  * Add support for Flake8 3.0
+
+- update to version 0.4.0:
+  * Stop testing on Python 3.2
+  * Add support for async/await keywords on Python 3.5 from PEP 0492
+
+- update to version 0.3.1:
+  * Include test_mccabe.py in releases.
+  * Always coerce the max_complexity value from Flake8’s entry-point
+    to an integer.
+
+-------------------------------------------------------------------

Old:
----
  mccabe-0.3.tar.gz

New:
----
  mccabe-0.6.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-mccabe.spec ++++++
--- /var/tmp/diff_new_pack.7v64sO/_old  2017-04-19 17:56:35.194694598 +0200
+++ /var/tmp/diff_new_pack.7v64sO/_new  2017-04-19 17:56:35.198694033 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-mccabe
 #
-# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,22 +16,21 @@
 #
 
 
+%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-mccabe
-Version:        0.3
+Version:        0.6.1
 Release:        0
 Summary:        McCabe checker, plugin for flake8
 License:        MIT
 Group:          Development/Languages/Python
 Url:            https://github.com/flintwork/mccabe
-Source:         
http://pypi.python.org/packages/source/m/mccabe/mccabe-%{version}.tar.gz
-BuildRequires:  python-devel
-BuildRequires:  python-setuptools
+Source:         
https://pypi.io/packages/source/m/mccabe/mccabe-%{version}.tar.gz
+BuildRequires:  %{python_module pytest-runner}
+BuildRequires:  %{python_module setuptools}
+BuildRequires:  python-rpm-macros
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-%if 0%{?suse_version} && 0%{?suse_version} <= 1110
-%{!?python_sitelib: %global python_sitelib %(python -c "from 
distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%else
 BuildArch:      noarch
-%endif
+%python_subpackages
 
 %description
 Ned's script to check McCabe complexity.
@@ -41,12 +40,15 @@
 %setup -q -n mccabe-%{version}
 
 %build
-python setup.py build
+%python_build
 
 %install
-python setup.py install --prefix=%{_prefix} --root=%{buildroot}
+%python_install
 
-%files
+%check
+%python_exec %{_bindir}/py.test
+
+%files %{python_files}
 %defattr(-,root,root,-)
 %doc LICENSE README.rst
 %{python_sitelib}/*

++++++ mccabe-0.3.tar.gz -> mccabe-0.6.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/MANIFEST.in new/mccabe-0.6.1/MANIFEST.in
--- old/mccabe-0.3/MANIFEST.in  2014-04-25 22:47:01.000000000 +0200
+++ new/mccabe-0.6.1/MANIFEST.in        2017-01-23 13:24:16.000000000 +0100
@@ -1 +1,3 @@
-include LICENSE README.rst
+include LICENSE
+include README.rst
+include test_mccabe.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/PKG-INFO new/mccabe-0.6.1/PKG-INFO
--- old/mccabe-0.3/PKG-INFO     2014-12-17 02:23:10.000000000 +0100
+++ new/mccabe-0.6.1/PKG-INFO   2017-01-26 23:13:05.000000000 +0100
@@ -1,10 +1,10 @@
 Metadata-Version: 1.1
 Name: mccabe
-Version: 0.3
+Version: 0.6.1
 Summary: McCabe checker, plugin for flake8
-Home-page: https://github.com/flintwork/mccabe
-Author: Florent Xicluna
-Author-email: [email protected]
+Home-page: https://github.com/pycqa/mccabe
+Author: Ian Cordasco
+Author-email: [email protected]
 License: Expat license
 Description: McCabe complexity checker
         =========================
@@ -73,6 +73,56 @@
         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
         ````````````````
         
@@ -109,13 +159,18 @@
         
 Keywords: flake8 mccabe
 Platform: UNKNOWN
-Classifier: Development Status :: 3 - Alpha
+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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/README.rst new/mccabe-0.6.1/README.rst
--- old/mccabe-0.3/README.rst   2014-12-17 01:15:26.000000000 +0100
+++ new/mccabe-0.6.1/README.rst 2017-01-26 23:11:16.000000000 +0100
@@ -65,6 +65,56 @@
 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
 ````````````````
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/mccabe.egg-info/PKG-INFO 
new/mccabe-0.6.1/mccabe.egg-info/PKG-INFO
--- old/mccabe-0.3/mccabe.egg-info/PKG-INFO     2014-12-17 02:23:10.000000000 
+0100
+++ new/mccabe-0.6.1/mccabe.egg-info/PKG-INFO   2017-01-26 23:13:05.000000000 
+0100
@@ -1,10 +1,10 @@
 Metadata-Version: 1.1
 Name: mccabe
-Version: 0.3
+Version: 0.6.1
 Summary: McCabe checker, plugin for flake8
-Home-page: https://github.com/flintwork/mccabe
-Author: Florent Xicluna
-Author-email: [email protected]
+Home-page: https://github.com/pycqa/mccabe
+Author: Ian Cordasco
+Author-email: [email protected]
 License: Expat license
 Description: McCabe complexity checker
         =========================
@@ -73,6 +73,56 @@
         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
         ````````````````
         
@@ -109,13 +159,18 @@
         
 Keywords: flake8 mccabe
 Platform: UNKNOWN
-Classifier: Development Status :: 3 - Alpha
+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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/mccabe.egg-info/SOURCES.txt 
new/mccabe-0.6.1/mccabe.egg-info/SOURCES.txt
--- old/mccabe-0.3/mccabe.egg-info/SOURCES.txt  2014-12-17 02:23:10.000000000 
+0100
+++ new/mccabe-0.6.1/mccabe.egg-info/SOURCES.txt        2017-01-26 
23:13:05.000000000 +0100
@@ -4,6 +4,7 @@
 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/mccabe.py new/mccabe-0.6.1/mccabe.py
--- old/mccabe-0.3/mccabe.py    2014-12-17 02:21:04.000000000 +0100
+++ new/mccabe-0.6.1/mccabe.py  2017-01-26 23:10:14.000000000 +0100
@@ -7,6 +7,8 @@
 
 import optparse
 import sys
+import tokenize
+
 from collections import defaultdict
 try:
     import ast
@@ -14,7 +16,7 @@
 except ImportError:   # Python 2.5
     from flake8.util import ast, iter_child_nodes
 
-__version__ = '0.3'
+__version__ = '0.6.1'
 
 
 class ASTVisitor(object):
@@ -59,10 +61,11 @@
 
 
 class PathGraph(object):
-    def __init__(self, name, entity, lineno):
+    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):
@@ -114,7 +117,7 @@
         else:
             entity = node.name
 
-        name = '%d:1: %r' % (node.lineno, entity)
+        name = '%d:%d: %r' % (node.lineno, node.col_offset, entity)
 
         if self.graph is not None:
             # closure
@@ -126,13 +129,15 @@
             self.graph.connect(pathnode, bottom)
             self.tail = bottom
         else:
-            self.graph = PathGraph(name, entity, node.lineno)
+            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 + "."
@@ -155,16 +160,17 @@
         name = "Stmt %d" % lineno
         self.appendPathNode(name)
 
-    visitAssert = visitAssign = visitAugAssign = visitDelete = visitPrint = \
-        visitRaise = visitYield = visitImport = visitCall = visitSubscript = \
-        visitPass = visitContinue = visitBreak = visitGlobal = visitReturn = \
-        visitSimpleStatement
+    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)
 
-    visitFor = visitWhile = visitLoop
+    visitAsyncFor = visitFor = visitWhile = visitLoop
 
     def visitIf(self, node):
         name = "If %d" % node.lineno
@@ -174,7 +180,7 @@
         """create the subgraphs representing any `if` and `for` statements"""
         if self.graph is None:
             # global loop
-            self.graph = PathGraph(name, name, node.lineno)
+            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
@@ -216,6 +222,8 @@
         self.appendPathNode(name)
         self.dispatch_list(node.body)
 
+    visitAsyncWith = visitWith
+
 
 class McCabeChecker(object):
     """McCabe cyclomatic complexity checker."""
@@ -223,20 +231,33 @@
     version = __version__
     _code = 'C901'
     _error_tmpl = "C901 %r is too complex (%d)"
-    max_complexity = 0
+    max_complexity = -1
 
     def __init__(self, tree, filename):
         self.tree = tree
 
     @classmethod
     def add_options(cls, parser):
-        parser.add_option('--max-complexity', default=-1, action='store',
-                          type='int', help="McCabe complexity threshold")
-        parser.config_options.append('max-complexity')
+        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 = options.max_complexity
+        cls.max_complexity = int(options.max_complexity)
 
     def run(self):
         if self.max_complexity < 0:
@@ -246,7 +267,7 @@
         for graph in visitor.graphs.values():
             if graph.complexity() > self.max_complexity:
                 text = self._error_tmpl % (graph.entity, graph.complexity())
-                yield graph.lineno, 0, text, type(self)
+                yield graph.lineno, graph.column, text, type(self)
 
 
 def get_code_complexity(code, threshold=7, filename='stdin'):
@@ -275,6 +296,23 @@
     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:]
@@ -287,8 +325,7 @@
 
     options, args = opar.parse_args(argv)
 
-    with open(args[0], "rU") as mod:
-        code = mod.read()
+    code = _read(args[0])
     tree = compile(code, args[0], "exec", ast.PyCF_ONLY_AST)
     visitor = PathGraphingAstVisitor()
     visitor.preorder(tree, visitor)
@@ -296,7 +333,8 @@
     if options.dot:
         print('graph {')
         for graph in visitor.graphs.values():
-            if not options.threshold or graph.complexity() >= 
options.threshold:
+            if (not options.threshold or
+                    graph.complexity() >= options.threshold):
                 graph.to_dot()
         print('}')
     else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/setup.cfg new/mccabe-0.6.1/setup.cfg
--- old/mccabe-0.3/setup.cfg    2014-12-17 02:23:10.000000000 +0100
+++ new/mccabe-0.6.1/setup.cfg  2017-01-26 23:13:05.000000000 +0100
@@ -1,8 +1,10 @@
 [wheel]
 universal = 1
 
+[aliases]
+test = pytest
+
 [egg_info]
-tag_svn_revision = 0
-tag_date = 0
 tag_build = 
+tag_date = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/setup.py new/mccabe-0.6.1/setup.py
--- old/mccabe-0.3/setup.py     2014-04-25 23:21:22.000000000 +0200
+++ new/mccabe-0.6.1/setup.py   2017-01-23 13:24:16.000000000 +0100
@@ -27,27 +27,33 @@
     keywords='flake8 mccabe',
     author='Tarek Ziade',
     author_email='[email protected]',
-    maintainer='Florent Xicluna',
-    maintainer_email='[email protected]',
-    url='https://github.com/flintwork/mccabe',
+    maintainer='Ian Cordasco',
+    maintainer_email='[email protected]',
+    url='https://github.com/pycqa/mccabe',
     license='Expat license',
     py_modules=['mccabe'],
     zip_safe=False,
-    test_suite='test_mccabe',
+    setup_requires=['pytest-runner'],
+    tests_require=['pytest'],
     entry_points={
         'flake8.extension': [
             'C90 = mccabe:McCabeChecker',
         ],
     },
     classifiers=[
-        'Development Status :: 3 - Alpha',
+        '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',
     ],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/mccabe-0.3/test_mccabe.py 
new/mccabe-0.6.1/test_mccabe.py
--- old/mccabe-0.3/test_mccabe.py       1970-01-01 01:00:00.000000000 +0100
+++ new/mccabe-0.6.1/test_mccabe.py     2017-01-23 13:24:16.000000000 +0100
@@ -0,0 +1,234 @@
+import 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()


Reply via email to