diff --git a/AUTHORS b/AUTHORS index 5f04e27..b285f0a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,3 +3,4 @@ Attila M. Magyar Laszlo Attila Toth Imre Halasz Medgyes Akos Adam +Bruno Oliveira diff --git a/README.rst b/README.rst index 3b84699..eaf1e7b 100644 --- a/README.rst +++ b/README.rst @@ -37,17 +37,26 @@ Testing with typesafety ======================= Typesafety is meant to be used during testing. True, the checker can be -turned on in production code but the performace slowdown can make this +turned on in production code but the performance slowdown can make this undesirable. -Currently, our preferred tool for running unit tests is nosetests. Using -the typesafety tool with nose is very simple: +Typesafety comes with builtin plugins for two popular testing frameworks, +`nosetests `_ and `pytest `_ +(our preferred tool at Balabit is nosetests), and using it is very simple. + +For nose: :: $ nosetests --enable-typesafety mymodule -And voila! Type checking is enabled for the module ``mymodule``. +And similarly for pytest: + +:: + + $ py.test --enable-typesafety mymodule + +And voila! Type checking is enabled for the module ``mymodule`` during tests. Enabling typesafety manually ---------------------------- diff --git a/setup.py b/setup.py index a96efcd..be97c7a 100755 --- a/setup.py +++ b/setup.py @@ -67,7 +67,8 @@ entry_points={ 'nose.plugins.0.10': [ 'typesafety = typesafety.noseplugin:TypesafetyPlugin' - ] + ], + 'pytest11': ['pytest_typesafety = typesafety.pytest_typesafety'], }, requires=[ 'nose', diff --git a/tox.ini b/tox.ini index d8dee39..a5e10ee 100644 --- a/tox.ini +++ b/tox.ini @@ -4,6 +4,7 @@ envlist=py34,py33,py32 [testenv] deps= nose + pytest mock pep8 pylint @@ -15,12 +16,14 @@ commands= nosetests --with-coverage --with-doctest typesafety behave --format progress2 {toxinidir}/scripts/copyright.py --check . + py.test typesafety [testenv:py32] # Note that some of the dependences are given with exact versioning # because previous versions do not support Python 3.2 anymore. deps= nose + pytest mock pep8 logilab-common==0.62.1 diff --git a/typesafety/pytest.ini b/typesafety/pytest.ini new file mode 100644 index 0000000..731fa16 --- /dev/null +++ b/typesafety/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +python_files = check_pytest_*.py \ No newline at end of file diff --git a/typesafety/pytest_typesafety.py b/typesafety/pytest_typesafety.py new file mode 100644 index 0000000..90ef5c0 --- /dev/null +++ b/typesafety/pytest_typesafety.py @@ -0,0 +1,49 @@ +# +# Copyright (c) 2013-2015 BalaBit +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + + +def pytest_addoption(parser): + parser.addoption( + '-T', '--enable-typesafety', action='append', metavar='MODULE', + help='Enable typesafety for the given modules' + ) + + +def pytest_configure(config): + if config.getoption('enable_typesafety'): + import typesafety + import functools + + enabled_for = tuple( + mod.split('.') for mod in config.getoption('enable_typesafety') + ) + filter_func = functools.partial(__check_need_activate, + enabled_for=enabled_for) + typesafety.activate(filter_func=filter_func) + + +def pytest_unconfigure(config): + if config.getoption('enable_typesafety'): + import typesafety + typesafety.deactivate() + + +def __check_need_activate(module_name, enabled_for): + module_name = module_name.split('.') + return any( + module_name[:len(name)] == name for name in enabled_for + ) diff --git a/typesafety/pytests/check_pytest_plugin.py b/typesafety/pytests/check_pytest_plugin.py new file mode 100644 index 0000000..7dbb9d1 --- /dev/null +++ b/typesafety/pytests/check_pytest_plugin.py @@ -0,0 +1,46 @@ +# +# Copyright (c) 2013-2015 BalaBit +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +""" +Test module for the pytest plugin; named "check_*" instead of "test_*" so +nosetests doesn't try to collect it. +""" +import pytest + +# pylint: disable=invalid-name +pytest_plugins = 'pytester' + + +@pytest.mark.parametrize('enabled', [True, False]) +def test_enabled(testdir, enabled): + testdir.makepyfile( + identity=''' + def identity(i: int): + return i + ''', + test_identity=''' + from identity import identity + def test_identity(): + assert identity("name") == "name" + ''') + + args = ['test_identity.py'] + if enabled: + args = ['--enable-typesafety', 'identity'] + args + result = testdir.runpytest(*args) + + expected = "*1 failed*" if enabled else "*1 passed*" + result.stdout.fnmatch_lines([expected])