From 85b8c63164d4c8464a6cfca70085be11a49618bd Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Fri, 7 Jun 2019 13:34:31 +0100 Subject: [PATCH 1/3] TST/CLN: return pytest MarkDecorator from td.skip_if_no --- pandas/tests/io/test_html.py | 6 ++--- pandas/util/_test_decorators.py | 42 ++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py index 225503cddceee..bd6fc6f57c496 100644 --- a/pandas/tests/io/test_html.py +++ b/pandas/tests/io/test_html.py @@ -77,10 +77,8 @@ def test_same_ordering(datapath): @pytest.mark.parametrize("flavor", [ - pytest.param('bs4', marks=pytest.mark.skipif( - not td.safe_import('lxml'), reason='No bs4')), - pytest.param('lxml', marks=pytest.mark.skipif( - not td.safe_import('lxml'), reason='No lxml'))], scope="class") + pytest.param('bs4', marks=td.skip_if_no('lxml')), + pytest.param('lxml', marks=td.skip_if_no('lxml'))], scope="class") class TestReadHtml: @pytest.fixture(autouse=True) diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index 5fa56c8505358..585c20c309c40 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -99,36 +99,40 @@ def _skip_if_no_scipy(): def skip_if_no(package, min_version=None): """ - Generic function to help skip test functions when required packages are not + Generic function to help skip tests when required packages are not present on the testing system. - Intended for use as a decorator, this function will wrap the decorated - function with a pytest ``skip_if`` mark. During a pytest test suite - execution, that mark will attempt to import the specified ``package`` and - optionally ensure it meets the ``min_version``. If the import and version - check are unsuccessful, then the decorated function will be skipped. + This function returns a pytest mark with a skip condition that will be + evaluated during test collection. An attempt will be made to import the + specified ``package`` and optionally ensure it meets the ``min_version`` + + The mark can be used as either a decorator for a test function or to be + applied to parameters in pytest.mark.parametrize calls or parametrized + fixtures. + + If the import and version check are unsuccessful, then the test function + (or test case when used in conjunction with parametrization) will be + skipped. Parameters ---------- package: str - The name of the package required by the decorated function + The name of the required package. min_version: str or None, default None - Optional minimum version of the package required by the decorated - function + Optional minimum version of the package. Returns ------- - decorated_func: function - The decorated function wrapped within a pytest ``skip_if`` mark + _pytest.mark.structures.MarkDecorator + a pytest.mark.skipif to use as either a test decorator or a + parametrization mark. """ - def decorated_func(func): - msg = "Could not import '{}'".format(package) - if min_version: - msg += " satisfying a min_version of {}".format(min_version) - return pytest.mark.skipif( - not safe_import(package, min_version=min_version), reason=msg - )(func) - return decorated_func + msg = "Could not import '{}'".format(package) + if min_version: + msg += " satisfying a min_version of {}".format(min_version) + return pytest.mark.skipif( + not safe_import(package, min_version=min_version), reason=msg + ) skip_if_no_mpl = pytest.mark.skipif(_skip_if_no_mpl(), From ce49853bda2f15855fe9517ec455d0fa6091f864 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Sat, 8 Jun 2019 17:37:55 +0100 Subject: [PATCH 2/3] add type annotations --- pandas/util/_test_decorators.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index 585c20c309c40..7aa72d82e8556 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -24,6 +24,7 @@ def test_foo(): For more information, refer to the ``pytest`` documentation on ``skipif``. """ import locale +from typing import Any, Callable, Optional import pytest @@ -33,6 +34,9 @@ def test_foo(): from pandas.core.computation.expressions import ( _NUMEXPR_INSTALLED, _USE_NUMEXPR) +Decorator = Callable[[Callable[..., Optional[Any]]], + Callable[..., Optional[Any]]] + def safe_import(mod_name, min_version=None): """ @@ -97,7 +101,7 @@ def _skip_if_no_scipy(): safe_import('scipy.signal')) -def skip_if_no(package, min_version=None): +def skip_if_no(package: str, min_version: Optional[str] = None) -> Decorator: """ Generic function to help skip tests when required packages are not present on the testing system. From c982e196b9208112a14bbefa2fb732f841a74c88 Mon Sep 17 00:00:00 2001 From: Simon Hawkins Date: Sat, 8 Jun 2019 18:42:38 +0100 Subject: [PATCH 3/3] use MarkDecorator for annotation --- pandas/util/_test_decorators.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py index 7aa72d82e8556..4cc316ffdd7ab 100644 --- a/pandas/util/_test_decorators.py +++ b/pandas/util/_test_decorators.py @@ -24,8 +24,9 @@ def test_foo(): For more information, refer to the ``pytest`` documentation on ``skipif``. """ import locale -from typing import Any, Callable, Optional +from typing import Optional +from _pytest.mark.structures import MarkDecorator import pytest from pandas.compat import is_platform_32bit, is_platform_windows @@ -34,9 +35,6 @@ def test_foo(): from pandas.core.computation.expressions import ( _NUMEXPR_INSTALLED, _USE_NUMEXPR) -Decorator = Callable[[Callable[..., Optional[Any]]], - Callable[..., Optional[Any]]] - def safe_import(mod_name, min_version=None): """ @@ -101,7 +99,10 @@ def _skip_if_no_scipy(): safe_import('scipy.signal')) -def skip_if_no(package: str, min_version: Optional[str] = None) -> Decorator: +def skip_if_no( + package: str, + min_version: Optional[str] = None +) -> MarkDecorator: """ Generic function to help skip tests when required packages are not present on the testing system.