From 7753dc8ff3cdbac43d1ed65eb7e27f76c436407b Mon Sep 17 00:00:00 2001 From: Alejandro Pereira Date: Mon, 19 Oct 2015 17:18:58 -0300 Subject: [PATCH] Initial commit --- .gitignore | 4 ++++ README.md | 2 -- README.rst | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ flake8_mock.py | 55 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 51 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+), 2 deletions(-) create mode 100644 .gitignore delete mode 100644 README.md create mode 100644 README.rst create mode 100644 flake8_mock.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa62446 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.egg-info +*.pyc +dist +build diff --git a/README.md b/README.md deleted file mode 100644 index 059bfb8..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# flake8-mock -Provides checking mock non-existent methods diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..87a1be8 --- /dev/null +++ b/README.rst @@ -0,0 +1,65 @@ +Flake8 Mock plugin +================== + +Remember that a mock’s job is to say, “You got it, boss” whenever anyone calls +it. It will do real work, like raising an exception, when one of its convenience +methods is called, like assert_called_once_with. But it won’t do real work when +you call a method that only resembles a convenience method, such as +assert_called_once (no _with!). Sometimes the developer may not notice that +is using an non-existent method because is not getting an output error telling +him that. And for some reason can also forget to try the test cases to fail +making sure that also fails!. + +This plugin provides checking possible non-existent methods for ``flake8``, +the Python code checker. + + +Installation +------------ + +You can install or upgrade ``flake8-debugger`` with these commands:: + + $ pip install flake8-debugger + $ pip install --upgrade flake8-debugger + + +List of non-existent methods checked +------------------------------------ + * ``assert_calls`` + * ``assert_not_called`` + * ``assert_called`` + * ``assert_called_once`` + * ``not_called`` + * ``called_once`` + * ``called_once_with`` + + +Plugin for Flake8 +----------------- + +When both ``flake8 2.2`` and ``flake8-mock`` are installed, the plugin is +available in ``flake8``:: + + $ flake8 --version + 2.0 (pep8: 1.5.7, flake8-mock: 0.1dev, pyflakes: 0.8.1) + + +Example output +-------------- + +Once you run flake8, you can have something like:: + + $ flake8 test_file.py + test_file.py:27:1: T002 assert_calls is a non-existen method. + test_file.py:28:1: T002 called_once_with is a non-existen method. + test_file.py:39:1: T002 not_called is a non-existen method. + test_file.py:40:1: T002 assert_called is a non-existen method. + + +Changes +------- + +0.1dev (unreleased) +```````````````` +* First release + diff --git a/flake8_mock.py b/flake8_mock.py new file mode 100644 index 0000000..96da3f4 --- /dev/null +++ b/flake8_mock.py @@ -0,0 +1,55 @@ +# coding: utf-8 + +from sys import stdin + +import compiler +import tokenize + + +__version__ = '0.1' + +NON_EXISTENT_METHODS = [ + 'assert_calls', + 'assert_not_called', + 'assert_called', + 'assert_called_once', + 'not_called', + 'called_once', + 'called_once_with', +] +_code = 'T002' # Not Defined yet +ERROR_MESSAGE = "T002 %s is a non-existen method." + + +def get_noqa_lines(code): + tokens = tokenize.generate_tokens(lambda L=iter(code): next(L)) + noqa = [token[2][0] for token in tokens if token[0] == tokenize.COMMENT + and (token[1].endswith('noqa') or (isinstance(token[0], str) and + token[0].endswith('noqa')))] + return noqa + + +class MockChecker(object): + name = 'flake8-mock' + version = __version__ + + def __init__(self, tree, filename='(none)', builtins=None): + self.tree = tree + self.filename = (filename == 'stdin' and stdin) or filename + self.errors = [] + + def visitGetattr(self, node): + if (node.lineno not in self.noqa_lines) \ + and node.attrname in NON_EXISTENT_METHODS: + self.errors.append({ + "message": ERROR_MESSAGE % node.attrname, + "line": node.lineno, + }) + + def run(self): + with open(self.filename, 'r') as file_to_check: + self.noqa_lines = get_noqa_lines(file_to_check.readlines()) + ast = compiler.parseFile(self.filename) + compiler.walk(ast, self) + for error in self.errors: + yield (error.get("line"), 0, error.get("message"), type(self)) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..6194c3e --- /dev/null +++ b/setup.py @@ -0,0 +1,51 @@ +# coding: utf-8 + +from __future__ import with_statement +from setuptools import setup + + +def get_version(fname='flake8_mock.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='flake8-mock', + version=get_version(), + description="Provides checking mock non-existent methods", + long_description=get_long_description(), + keywords='flake8 mock', + author='Alejandro Pereira', + author_email='alepereira.dev@gmail.com', + url='https://github.com/aleGpereira/flake8-mock', + license='GNU', + py_modules=['flake8_mock'], + zip_safe=False, + entry_points={ + 'flake8.extension': [ + 'flake8_mock = flake8_mock:MockChecker', + ], + }, + classifiers=[ + 'Development Status :: 1 - Alpha', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU License', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Software Development :: Quality Assurance', + ], +)