From 8936817ec2fcce8a99b3ca71e07de8574428eb28 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 16 Mar 2015 18:18:28 -0300 Subject: [PATCH 1/4] Added pytest-plugin and test --- setup.py | 3 ++- typesafety/pytest.ini | 2 ++ typesafety/pytest_typesafety.py | 28 +++++++++++++++++++++++ typesafety/pytests/check_pytest_plugin.py | 26 +++++++++++++++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 typesafety/pytest.ini create mode 100644 typesafety/pytest_typesafety.py create mode 100644 typesafety/pytests/check_pytest_plugin.py 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/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..d38c9e7 --- /dev/null +++ b/typesafety/pytest_typesafety.py @@ -0,0 +1,28 @@ + + + +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 __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..eebb1be --- /dev/null +++ b/typesafety/pytests/check_pytest_plugin.py @@ -0,0 +1,26 @@ +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]) From 08ebb6f8de0427dd2071c2aaddd63667d9862296 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 16 Mar 2015 18:21:01 -0300 Subject: [PATCH 2/4] Updated tox to run tests for pytest plugin --- tox.ini | 3 +++ 1 file changed, 3 insertions(+) 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 From d57c4581d40e2af8a4a66ddf32ec1d45f39585fe Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 16 Mar 2015 18:32:47 -0300 Subject: [PATCH 3/4] Added licensing and updated readme --- AUTHORS | 1 + README.rst | 17 +++++++++++++---- typesafety/pytest_typesafety.py | 17 ++++++++++++++++- typesafety/pytests/check_pytest_plugin.py | 20 ++++++++++++++++++++ 4 files changed, 50 insertions(+), 5 deletions(-) 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/typesafety/pytest_typesafety.py b/typesafety/pytest_typesafety.py index d38c9e7..806e2dc 100644 --- a/typesafety/pytest_typesafety.py +++ b/typesafety/pytest_typesafety.py @@ -1,4 +1,19 @@ - +# +# 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): diff --git a/typesafety/pytests/check_pytest_plugin.py b/typesafety/pytests/check_pytest_plugin.py index eebb1be..7dbb9d1 100644 --- a/typesafety/pytests/check_pytest_plugin.py +++ b/typesafety/pytests/check_pytest_plugin.py @@ -1,3 +1,23 @@ +# +# 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 From 3f47531654e0f452b1f5bde3dc19395583adcafd Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Mon, 16 Mar 2015 23:08:04 -0300 Subject: [PATCH 4/4] Deactivating typesafety during plugin unconfigure --- typesafety/pytest_typesafety.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/typesafety/pytest_typesafety.py b/typesafety/pytest_typesafety.py index 806e2dc..90ef5c0 100644 --- a/typesafety/pytest_typesafety.py +++ b/typesafety/pytest_typesafety.py @@ -36,6 +36,12 @@ def pytest_configure(config): 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(