From ebca301a84df79c478d8f004e4dbbcbf614813f1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 23 Jan 2016 21:21:58 -0600 Subject: [PATCH 1/4] Switch tests to pytest --- setup.cfg | 3 +++ setup.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 5e40900..519ba68 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,5 @@ [wheel] universal = 1 + +[aliases] +test = pytest diff --git a/setup.py b/setup.py index fb8b970..bf8d7d7 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,8 @@ def get_long_description(): 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', From f78c92a76495327ba44a64edb247cc789b290c94 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 23 Jan 2016 21:22:34 -0600 Subject: [PATCH 2/4] Add test for async keywords added in PEP 0492 --- test_mccabe.py | 25 +++++++++++++++++++++++++ tox.ini | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/test_mccabe.py b/test_mccabe.py index 07d8d78..edc2f45 100644 --- a/test_mccabe.py +++ b/test_mccabe.py @@ -5,6 +5,8 @@ except ImportError: from io import StringIO +import pytest + import mccabe from mccabe import get_code_complexity @@ -84,6 +86,23 @@ def c(): 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 + + +def foo(): + yield from [1, 2, 3] +""" + def get_complexity_number(snippet, strio, max=0): """Get the complexity number from the printed string.""" @@ -164,6 +183,12 @@ def test_trivial(self): 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.""" + self.assert_complexity(async_keywords, 5) + class RegressionTests(unittest.TestCase): def setUp(self): diff --git a/tox.ini b/tox.ini index a472aa4..6e7e690 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py26,py27,py33,py34,flake8 + py26,py27,py33,py34,py35,flake8 [testenv] deps = From ae23e02040cbdbf15bb134809efc48a1b3e3a72a Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 23 Jan 2016 21:22:54 -0600 Subject: [PATCH 3/4] Add support for recognizing async keyword usage --- mccabe.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mccabe.py b/mccabe.py index f5ef5d9..72b8bdd 100644 --- a/mccabe.py +++ b/mccabe.py @@ -133,6 +133,8 @@ def visitFunctionDef(self, node): 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 + "." @@ -158,13 +160,13 @@ def visitSimpleStatement(self, node): visitAssert = visitAssign = visitAugAssign = visitDelete = visitPrint = \ visitRaise = visitYield = visitImport = visitCall = visitSubscript = \ visitPass = visitContinue = visitBreak = visitGlobal = visitReturn = \ - visitSimpleStatement + visitAwait = visitSimpleStatement 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 @@ -216,6 +218,8 @@ def visitWith(self, node): self.appendPathNode(name) self.dispatch_list(node.body) + visitAsyncWith = visitWith + class McCabeChecker(object): """McCabe cyclomatic complexity checker.""" From 4155ad6aac8fd424102fffe5b6eb1ea9ba2e752b Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 23 Jan 2016 21:24:32 -0600 Subject: [PATCH 4/4] Simplify async keywords test --- test_mccabe.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/test_mccabe.py b/test_mccabe.py index edc2f45..44fb565 100644 --- a/test_mccabe.py +++ b/test_mccabe.py @@ -97,10 +97,6 @@ async def foobar(a, b, c): async for x in a: pass - - -def foo(): - yield from [1, 2, 3] """ @@ -187,7 +183,8 @@ def test_try_else(self): reason="Async keywords are only valid on Python 3.5+") def test_async_keywords(self): """Validate that we properly process async keyword usage.""" - self.assert_complexity(async_keywords, 5) + complexity = get_complexity_number(async_keywords, self.strio) + self.assertEqual(complexity, 3) class RegressionTests(unittest.TestCase):