Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TST: return pytest MarkDecorator from td.skip_if_no #26735

Merged
merged 4 commits into from
Jun 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions pandas/tests/io/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some of these in test_excel as well. Not sure if you meant to do all in this PR or not but if so worth a double check of other modules

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left them intentionally to avoid conflicts with your PRs.

have checked other modules, no other use of safe_import except one case of a test decorator where I think skip_if_no could be used directly. (change that in this PR?)

@pytest.mark.skipif(td.safe_import('gcsfs'),
reason='Only check when gcsfs not installed')
def test_gcs_not_present_exception():

and test_safe_import.

pytest.param('lxml', marks=td.skip_if_no('lxml'))], scope="class")
class TestReadHtml:

@pytest.fixture(autouse=True)
Expand Down
49 changes: 29 additions & 20 deletions pandas/util/_test_decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def test_foo():
For more information, refer to the ``pytest`` documentation on ``skipif``.
"""
import locale
from typing import Optional

from _pytest.mark.structures import MarkDecorator
import pytest

from pandas.compat import is_platform_32bit, is_platform_windows
Expand Down Expand Up @@ -97,38 +99,45 @@ def _skip_if_no_scipy():
safe_import('scipy.signal'))


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why wouldn’t you make this MarkDecorator)

def skip_if_no(package, min_version=None):
def skip_if_no(
package: str,
min_version: Optional[str] = None
) -> MarkDecorator:
"""
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(),
Expand Down