diff --git a/pandas/tests/arrays/interval/test_interval.py b/pandas/tests/arrays/interval/test_interval.py
index 8d4022112f2a4..e16ef37e8799d 100644
--- a/pandas/tests/arrays/interval/test_interval.py
+++ b/pandas/tests/arrays/interval/test_interval.py
@@ -1,8 +1,6 @@
import numpy as np
import pytest
-import pandas.util._test_decorators as td
-
import pandas as pd
from pandas import (
Index,
@@ -249,12 +247,8 @@ def test_min_max(self, left_right_dtypes, index_or_series_or_array):
# Arrow interaction
-pyarrow_skip = td.skip_if_no("pyarrow")
-
-
-@pyarrow_skip
def test_arrow_extension_type():
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
from pandas.core.arrays.arrow.extension_types import ArrowIntervalType
@@ -269,9 +263,8 @@ def test_arrow_extension_type():
assert hash(p1) != hash(p3)
-@pyarrow_skip
def test_arrow_array():
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
from pandas.core.arrays.arrow.extension_types import ArrowIntervalType
@@ -299,9 +292,8 @@ def test_arrow_array():
pa.array(intervals, type=ArrowIntervalType(pa.float64(), "left"))
-@pyarrow_skip
def test_arrow_array_missing():
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
from pandas.core.arrays.arrow.extension_types import ArrowIntervalType
@@ -329,14 +321,13 @@ def test_arrow_array_missing():
assert result.storage.equals(expected)
-@pyarrow_skip
@pytest.mark.parametrize(
"breaks",
[[0.0, 1.0, 2.0, 3.0], date_range("2017", periods=4, freq="D")],
ids=["float", "datetime64[ns]"],
)
def test_arrow_table_roundtrip(breaks):
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
from pandas.core.arrays.arrow.extension_types import ArrowIntervalType
@@ -363,14 +354,13 @@ def test_arrow_table_roundtrip(breaks):
tm.assert_frame_equal(result, expected[0:0])
-@pyarrow_skip
@pytest.mark.parametrize(
"breaks",
[[0.0, 1.0, 2.0, 3.0], date_range("2017", periods=4, freq="D")],
ids=["float", "datetime64[ns]"],
)
def test_arrow_table_roundtrip_without_metadata(breaks):
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
arr = IntervalArray.from_breaks(breaks)
arr[1] = None
@@ -386,12 +376,11 @@ def test_arrow_table_roundtrip_without_metadata(breaks):
tm.assert_frame_equal(result, df)
-@pyarrow_skip
def test_from_arrow_from_raw_struct_array():
# in case pyarrow lost the Interval extension type (eg on parquet roundtrip
# with datetime64[ns] subtype, see GH-45881), still allow conversion
# from arrow to IntervalArray
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
arr = pa.array([{"left": 0, "right": 1}, {"left": 1, "right": 2}])
dtype = pd.IntervalDtype(np.dtype("int64"), closed="neither")
diff --git a/pandas/tests/arrays/string_/test_string.py b/pandas/tests/arrays/string_/test_string.py
index 5ca95bd00f136..cfd3314eb5944 100644
--- a/pandas/tests/arrays/string_/test_string.py
+++ b/pandas/tests/arrays/string_/test_string.py
@@ -5,8 +5,6 @@
import numpy as np
import pytest
-import pandas.util._test_decorators as td
-
from pandas.core.dtypes.common import is_dtype_equal
import pandas as pd
@@ -420,10 +418,9 @@ def test_arrow_array(dtype):
assert arr.equals(expected)
-@td.skip_if_no("pyarrow")
def test_arrow_roundtrip(dtype, string_storage2):
# roundtrip possible from arrow 1.0.0
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
data = pd.array(["a", "b", None], dtype=dtype)
df = pd.DataFrame({"a": data})
@@ -438,10 +435,9 @@ def test_arrow_roundtrip(dtype, string_storage2):
assert result.loc[2, "a"] is pd.NA
-@td.skip_if_no("pyarrow")
def test_arrow_load_from_zero_chunks(dtype, string_storage2):
# GH-41040
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
data = pd.array([], dtype=dtype)
df = pd.DataFrame({"a": data})
diff --git a/pandas/tests/frame/test_api.py b/pandas/tests/frame/test_api.py
index ac6e883ac3966..7ca5df0451d19 100644
--- a/pandas/tests/frame/test_api.py
+++ b/pandas/tests/frame/test_api.py
@@ -7,10 +7,7 @@
from pandas._config.config import option_context
-from pandas.util._test_decorators import (
- async_mark,
- skip_if_no,
-)
+from pandas.util._test_decorators import async_mark
import pandas as pd
from pandas import (
@@ -373,9 +370,9 @@ def test_constructor_expanddim(self):
with pytest.raises(AttributeError, match=msg):
df._constructor_expanddim(np.arange(27).reshape(3, 3, 3))
- @skip_if_no("jinja2")
def test_inspect_getmembers(self):
# GH38740
+ pytest.importorskip("jinja2")
df = DataFrame()
msg = "DataFrame._data is deprecated"
with tm.assert_produces_warning(
diff --git a/pandas/tests/frame/test_ufunc.py b/pandas/tests/frame/test_ufunc.py
index 74afb573793a9..305c0f8bba8ce 100644
--- a/pandas/tests/frame/test_ufunc.py
+++ b/pandas/tests/frame/test_ufunc.py
@@ -4,8 +4,6 @@
import numpy as np
import pytest
-import pandas.util._test_decorators as td
-
import pandas as pd
import pandas._testing as tm
from pandas.api.types import is_extension_array_dtype
@@ -247,18 +245,14 @@ def test_alignment_deprecation_enforced():
np.add(s2, df1)
-@td.skip_if_no("numba")
def test_alignment_deprecation_many_inputs_enforced():
# Enforced in 2.0
# https://github.com/pandas-dev/pandas/issues/39184
# test that the deprecation also works with > 2 inputs -> using a numba
# written ufunc for this because numpy itself doesn't have such ufuncs
- from numba import (
- float64,
- vectorize,
- )
+ numba = pytest.importorskip("numba")
- @vectorize([float64(float64, float64, float64)])
+ @numba.vectorize([numba.float64(numba.float64, numba.float64, numba.float64)])
def my_ufunc(x, y, z):
return x + y + z
diff --git a/pandas/tests/generic/test_to_xarray.py b/pandas/tests/generic/test_to_xarray.py
index 1fbd82f01213b..d6eacf4f9079b 100644
--- a/pandas/tests/generic/test_to_xarray.py
+++ b/pandas/tests/generic/test_to_xarray.py
@@ -1,8 +1,6 @@
import numpy as np
import pytest
-import pandas.util._test_decorators as td
-
from pandas import (
Categorical,
DataFrame,
@@ -12,8 +10,9 @@
)
import pandas._testing as tm
+pytest.importorskip("xarray")
+
-@td.skip_if_no("xarray")
class TestDataFrameToXArray:
@pytest.fixture
def df(self):
@@ -84,7 +83,6 @@ def test_to_xarray_with_multiindex(self, df):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("xarray")
class TestSeriesToXArray:
def test_to_xarray_index_types(self, index_flat):
index = index_flat
diff --git a/pandas/tests/groupby/aggregate/test_numba.py b/pandas/tests/groupby/aggregate/test_numba.py
index 19fbac682dccb..ee694129f7118 100644
--- a/pandas/tests/groupby/aggregate/test_numba.py
+++ b/pandas/tests/groupby/aggregate/test_numba.py
@@ -2,7 +2,6 @@
import pytest
from pandas.errors import NumbaUtilError
-import pandas.util._test_decorators as td
from pandas import (
DataFrame,
@@ -16,8 +15,9 @@
pytestmark = pytest.mark.single_cpu
-@td.skip_if_no("numba")
def test_correct_function_signature():
+ pytest.importorskip("numba")
+
def incorrect_function(x):
return sum(x) * 2.7
@@ -32,8 +32,9 @@ def incorrect_function(x):
data.groupby("key")["data"].agg(incorrect_function, engine="numba")
-@td.skip_if_no("numba")
def test_check_nopython_kwargs():
+ pytest.importorskip("numba")
+
def incorrect_function(values, index):
return sum(values) * 2.7
@@ -48,13 +49,14 @@ def incorrect_function(values, index):
data.groupby("key")["data"].agg(incorrect_function, engine="numba", a=1)
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
# Filter warnings when parallel=True and the function can't be parallelized by Numba
@pytest.mark.parametrize("jit", [True, False])
@pytest.mark.parametrize("pandas_obj", ["Series", "DataFrame"])
@pytest.mark.parametrize("as_index", [True, False])
def test_numba_vs_cython(jit, pandas_obj, nogil, parallel, nopython, as_index):
+ pytest.importorskip("numba")
+
def func_numba(values, index):
return np.mean(values) * 2.7
@@ -78,13 +80,14 @@ def func_numba(values, index):
tm.assert_equal(result, expected)
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
# Filter warnings when parallel=True and the function can't be parallelized by Numba
@pytest.mark.parametrize("jit", [True, False])
@pytest.mark.parametrize("pandas_obj", ["Series", "DataFrame"])
def test_cache(jit, pandas_obj, nogil, parallel, nopython):
# Test that the functions are cached correctly if we switch functions
+ pytest.importorskip("numba")
+
def func_1(values, index):
return np.mean(values) - 3.4
@@ -120,8 +123,9 @@ def func_2(values, index):
tm.assert_equal(result, expected)
-@td.skip_if_no("numba")
def test_use_global_config():
+ pytest.importorskip("numba")
+
def func_1(values, index):
return np.mean(values) - 3.4
@@ -135,7 +139,6 @@ def func_1(values, index):
tm.assert_frame_equal(expected, result)
-@td.skip_if_no("numba")
@pytest.mark.parametrize(
"agg_kwargs",
[
@@ -146,6 +149,7 @@ def func_1(values, index):
],
)
def test_multifunc_numba_vs_cython_frame(agg_kwargs):
+ pytest.importorskip("numba")
data = DataFrame(
{
0: ["a", "a", "b", "b", "a"],
@@ -160,7 +164,6 @@ def test_multifunc_numba_vs_cython_frame(agg_kwargs):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("numba")
@pytest.mark.parametrize(
"agg_kwargs,expected_func",
[
@@ -181,6 +184,7 @@ def test_multifunc_numba_vs_cython_frame(agg_kwargs):
],
)
def test_multifunc_numba_udf_frame(agg_kwargs, expected_func):
+ pytest.importorskip("numba")
data = DataFrame(
{
0: ["a", "a", "b", "b", "a"],
@@ -197,12 +201,12 @@ def test_multifunc_numba_udf_frame(agg_kwargs, expected_func):
tm.assert_frame_equal(result, expected, check_dtype=False)
-@td.skip_if_no("numba")
@pytest.mark.parametrize(
"agg_kwargs",
[{"func": ["min", "max"]}, {"func": "min"}, {"min_val": "min", "max_val": "max"}],
)
def test_multifunc_numba_vs_cython_series(agg_kwargs):
+ pytest.importorskip("numba")
labels = ["a", "a", "b", "b", "a"]
data = Series([1.0, 2.0, 3.0, 4.0, 5.0])
grouped = data.groupby(labels)
@@ -216,7 +220,6 @@ def test_multifunc_numba_vs_cython_series(agg_kwargs):
tm.assert_series_equal(result, expected)
-@td.skip_if_no("numba")
@pytest.mark.single_cpu
@pytest.mark.parametrize(
"data,agg_kwargs",
@@ -250,6 +253,7 @@ def test_multifunc_numba_vs_cython_series(agg_kwargs):
],
)
def test_multifunc_numba_kwarg_propagation(data, agg_kwargs):
+ pytest.importorskip("numba")
labels = ["a", "a", "b", "b", "a"]
grouped = data.groupby(labels)
result = grouped.agg(**agg_kwargs, engine="numba", engine_kwargs={"parallel": True})
@@ -260,9 +264,10 @@ def test_multifunc_numba_kwarg_propagation(data, agg_kwargs):
tm.assert_series_equal(result, expected)
-@td.skip_if_no("numba")
def test_args_not_cached():
# GH 41647
+ pytest.importorskip("numba")
+
def sum_last(values, index, n):
return values[-n:].sum()
@@ -277,9 +282,10 @@ def sum_last(values, index, n):
tm.assert_series_equal(result, expected)
-@td.skip_if_no("numba")
def test_index_data_correctly_passed():
# GH 43133
+ pytest.importorskip("numba")
+
def f(values, index):
return np.mean(index)
@@ -291,10 +297,10 @@ def f(values, index):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("numba")
def test_engine_kwargs_not_cached():
# If the user passes a different set of engine_kwargs don't return the same
# jitted function
+ pytest.importorskip("numba")
nogil = True
parallel = False
nopython = True
@@ -319,9 +325,10 @@ def func_kwargs(values, index):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
def test_multiindex_one_key(nogil, parallel, nopython):
+ pytest.importorskip("numba")
+
def numba_func(values, index):
return 1
@@ -334,8 +341,9 @@ def numba_func(values, index):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("numba")
def test_multiindex_multi_key_not_supported(nogil, parallel, nopython):
+ pytest.importorskip("numba")
+
def numba_func(values, index):
return 1
@@ -347,8 +355,8 @@ def numba_func(values, index):
)
-@td.skip_if_no("numba")
def test_multilabel_numba_vs_cython(numba_supported_reductions):
+ pytest.importorskip("numba")
reduction, kwargs = numba_supported_reductions
df = DataFrame(
{
@@ -368,8 +376,8 @@ def test_multilabel_numba_vs_cython(numba_supported_reductions):
tm.assert_frame_equal(direct_res, direct_expected)
-@td.skip_if_no("numba")
def test_multilabel_udf_numba_vs_cython():
+ pytest.importorskip("numba")
df = DataFrame(
{
"A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "foo"],
diff --git a/pandas/tests/groupby/test_numba.py b/pandas/tests/groupby/test_numba.py
index 7d4440b595dff..e36c248c99ad6 100644
--- a/pandas/tests/groupby/test_numba.py
+++ b/pandas/tests/groupby/test_numba.py
@@ -1,7 +1,5 @@
import pytest
-import pandas.util._test_decorators as td
-
from pandas import (
DataFrame,
Series,
@@ -10,8 +8,9 @@
pytestmark = pytest.mark.single_cpu
+pytest.importorskip("numba")
+
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
# Filter warnings when parallel=True and the function can't be parallelized by Numba
class TestEngine:
diff --git a/pandas/tests/groupby/test_timegrouper.py b/pandas/tests/groupby/test_timegrouper.py
index 9f7f537ac2402..3b4daa3625af4 100644
--- a/pandas/tests/groupby/test_timegrouper.py
+++ b/pandas/tests/groupby/test_timegrouper.py
@@ -11,8 +11,6 @@
import pytest
import pytz
-import pandas.util._test_decorators as td
-
import pandas as pd
from pandas import (
DataFrame,
@@ -906,11 +904,12 @@ def test_groupby_apply_timegrouper_with_nat_apply_squeeze(
)
tm.assert_frame_equal(res, expected)
- @td.skip_if_no("numba")
@pytest.mark.single_cpu
def test_groupby_agg_numba_timegrouper_with_nat(
self, groupby_with_truncated_bingrouper
):
+ pytest.importorskip("numba")
+
# See discussion in GH#43487
gb = groupby_with_truncated_bingrouper
diff --git a/pandas/tests/groupby/transform/test_numba.py b/pandas/tests/groupby/transform/test_numba.py
index 965691e31d772..61fcc930f116a 100644
--- a/pandas/tests/groupby/transform/test_numba.py
+++ b/pandas/tests/groupby/transform/test_numba.py
@@ -2,7 +2,6 @@
import pytest
from pandas.errors import NumbaUtilError
-import pandas.util._test_decorators as td
from pandas import (
DataFrame,
@@ -14,8 +13,9 @@
pytestmark = pytest.mark.single_cpu
-@td.skip_if_no("numba")
def test_correct_function_signature():
+ pytest.importorskip("numba")
+
def incorrect_function(x):
return x + 1
@@ -30,8 +30,9 @@ def incorrect_function(x):
data.groupby("key")["data"].transform(incorrect_function, engine="numba")
-@td.skip_if_no("numba")
def test_check_nopython_kwargs():
+ pytest.importorskip("numba")
+
def incorrect_function(values, index):
return values + 1
@@ -46,13 +47,14 @@ def incorrect_function(values, index):
data.groupby("key")["data"].transform(incorrect_function, engine="numba", a=1)
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
# Filter warnings when parallel=True and the function can't be parallelized by Numba
@pytest.mark.parametrize("jit", [True, False])
@pytest.mark.parametrize("pandas_obj", ["Series", "DataFrame"])
@pytest.mark.parametrize("as_index", [True, False])
def test_numba_vs_cython(jit, pandas_obj, nogil, parallel, nopython, as_index):
+ pytest.importorskip("numba")
+
def func(values, index):
return values + 1
@@ -76,13 +78,14 @@ def func(values, index):
tm.assert_equal(result, expected)
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
# Filter warnings when parallel=True and the function can't be parallelized by Numba
@pytest.mark.parametrize("jit", [True, False])
@pytest.mark.parametrize("pandas_obj", ["Series", "DataFrame"])
def test_cache(jit, pandas_obj, nogil, parallel, nopython):
# Test that the functions are cached correctly if we switch functions
+ pytest.importorskip("numba")
+
def func_1(values, index):
return values + 1
@@ -117,8 +120,9 @@ def func_2(values, index):
tm.assert_equal(result, expected)
-@td.skip_if_no("numba")
def test_use_global_config():
+ pytest.importorskip("numba")
+
def func_1(values, index):
return values + 1
@@ -133,11 +137,11 @@ def func_1(values, index):
# TODO: Test more than just reductions (e.g. actually test transformations once we have
-@td.skip_if_no("numba")
@pytest.mark.parametrize(
"agg_func", [["min", "max"], "min", {"B": ["min", "max"], "C": "sum"}]
)
def test_string_cython_vs_numba(agg_func, numba_supported_reductions):
+ pytest.importorskip("numba")
agg_func, kwargs = numba_supported_reductions
data = DataFrame(
{0: ["a", "a", "b", "b", "a"], 1: [1.0, 2.0, 3.0, 4.0, 5.0]}, columns=[0, 1]
@@ -153,9 +157,10 @@ def test_string_cython_vs_numba(agg_func, numba_supported_reductions):
tm.assert_series_equal(result, expected)
-@td.skip_if_no("numba")
def test_args_not_cached():
# GH 41647
+ pytest.importorskip("numba")
+
def sum_last(values, index, n):
return values[-n:].sum()
@@ -170,9 +175,10 @@ def sum_last(values, index, n):
tm.assert_series_equal(result, expected)
-@td.skip_if_no("numba")
def test_index_data_correctly_passed():
# GH 43133
+ pytest.importorskip("numba")
+
def f(values, index):
return index - 1
@@ -182,10 +188,10 @@ def f(values, index):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("numba")
def test_engine_kwargs_not_cached():
# If the user passes a different set of engine_kwargs don't return the same
# jitted function
+ pytest.importorskip("numba")
nogil = True
parallel = False
nopython = True
@@ -210,9 +216,10 @@ def func_kwargs(values, index):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
def test_multiindex_one_key(nogil, parallel, nopython):
+ pytest.importorskip("numba")
+
def numba_func(values, index):
return 1
@@ -225,8 +232,9 @@ def numba_func(values, index):
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("numba")
def test_multiindex_multi_key_not_supported(nogil, parallel, nopython):
+ pytest.importorskip("numba")
+
def numba_func(values, index):
return 1
@@ -238,8 +246,8 @@ def numba_func(values, index):
)
-@td.skip_if_no("numba")
def test_multilabel_numba_vs_cython(numba_supported_reductions):
+ pytest.importorskip("numba")
reduction, kwargs = numba_supported_reductions
df = DataFrame(
{
@@ -255,8 +263,8 @@ def test_multilabel_numba_vs_cython(numba_supported_reductions):
tm.assert_frame_equal(res_agg, expected_agg)
-@td.skip_if_no("numba")
def test_multilabel_udf_numba_vs_cython():
+ pytest.importorskip("numba")
df = DataFrame(
{
"A": ["foo", "bar", "foo", "bar", "foo", "bar", "foo", "foo"],
diff --git a/pandas/tests/io/excel/test_readers.py b/pandas/tests/io/excel/test_readers.py
index 7df5b928858d8..b0a5998a47679 100644
--- a/pandas/tests/io/excel/test_readers.py
+++ b/pandas/tests/io/excel/test_readers.py
@@ -632,13 +632,12 @@ def test_dtype_backend_and_dtype(self, read_ext):
)
tm.assert_frame_equal(result, df)
- @td.skip_if_no("pyarrow")
def test_dtype_backend_string(self, read_ext, string_storage):
# GH#36712
if read_ext in (".xlsb", ".xls"):
pytest.skip(f"No engine for filetype: '{read_ext}'")
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
with pd.option_context("mode.string_storage", string_storage):
df = DataFrame(
diff --git a/pandas/tests/io/formats/style/test_matplotlib.py b/pandas/tests/io/formats/style/test_matplotlib.py
index 1485bd64e4b57..fb7a77f1ddb27 100644
--- a/pandas/tests/io/formats/style/test_matplotlib.py
+++ b/pandas/tests/io/formats/style/test_matplotlib.py
@@ -1,3 +1,5 @@
+import gc
+
import numpy as np
import pytest
@@ -15,6 +17,26 @@
from pandas.io.formats.style import Styler
+@pytest.fixture(autouse=True)
+def mpl_cleanup():
+ # matplotlib/testing/decorators.py#L24
+ # 1) Resets units registry
+ # 2) Resets rc_context
+ # 3) Closes all figures
+ mpl = pytest.importorskip("matplotlib")
+ mpl_units = pytest.importorskip("matplotlib.units")
+ plt = pytest.importorskip("matplotlib.pyplot")
+ orig_units_registry = mpl_units.registry.copy()
+ with mpl.rc_context():
+ mpl.use("template")
+ yield
+ mpl_units.registry.clear()
+ mpl_units.registry.update(orig_units_registry)
+ plt.close("all")
+ # https://matplotlib.org/stable/users/prev_whats_new/whats_new_3.6.0.html#garbage-collection-is-no-longer-run-on-figure-close # noqa: E501
+ gc.collect(1)
+
+
@pytest.fixture
def df():
return DataFrame([[1, 2], [2, 4]], columns=["A", "B"])
diff --git a/pandas/tests/io/formats/test_to_excel.py b/pandas/tests/io/formats/test_to_excel.py
index 2a0f9f59972ef..927a9f4961f6f 100644
--- a/pandas/tests/io/formats/test_to_excel.py
+++ b/pandas/tests/io/formats/test_to_excel.py
@@ -7,7 +7,6 @@
import pytest
from pandas.errors import CSSWarning
-import pandas.util._test_decorators as td
import pandas._testing as tm
@@ -336,12 +335,11 @@ def tests_css_named_colors_valid():
assert len(color) == 6 and all(c in upper_hexs for c in color)
-@td.skip_if_no_mpl
def test_css_named_colors_from_mpl_present():
- from matplotlib.colors import CSS4_COLORS as mpl_colors
+ mpl_colors = pytest.importorskip("matplotlib.colors")
pd_colors = CSSToExcelConverter.NAMED_COLORS
- for name, color in mpl_colors.items():
+ for name, color in mpl_colors.CSS4_COLORS.items():
assert name in pd_colors and pd_colors[name] == color[1:]
diff --git a/pandas/tests/io/formats/test_to_string.py b/pandas/tests/io/formats/test_to_string.py
index 96761db8bf752..0c260f0af0a8d 100644
--- a/pandas/tests/io/formats/test_to_string.py
+++ b/pandas/tests/io/formats/test_to_string.py
@@ -5,8 +5,6 @@
import numpy as np
import pytest
-import pandas.util._test_decorators as td
-
from pandas import (
DataFrame,
Series,
@@ -342,9 +340,9 @@ def test_to_string_max_rows_zero(data, expected):
assert result == expected
-@td.skip_if_no("pyarrow")
def test_to_string_string_dtype():
# GH#50099
+ pytest.importorskip("pyarrow")
df = DataFrame({"x": ["foo", "bar", "baz"], "y": ["a", "b", "c"], "z": [1, 2, 3]})
df = df.astype(
{"x": "string[pyarrow]", "y": "string[python]", "z": "int64[pyarrow]"}
diff --git a/pandas/tests/io/parser/test_network.py b/pandas/tests/io/parser/test_network.py
index dd702259a9558..613284ad096d2 100644
--- a/pandas/tests/io/parser/test_network.py
+++ b/pandas/tests/io/parser/test_network.py
@@ -76,10 +76,10 @@ def tips_df(datapath):
@pytest.mark.usefixtures("s3_resource")
@td.skip_if_not_us_locale()
class TestS3:
- @td.skip_if_no("s3fs")
def test_parse_public_s3_bucket(self, s3_public_bucket_with_data, tips_df, s3so):
# more of an integration test due to the not-public contents portion
# can probably mock this though.
+ pytest.importorskip("s3fs")
for ext, comp in [("", None), (".gz", "gzip"), (".bz2", "bz2")]:
df = read_csv(
f"s3://{s3_public_bucket_with_data.name}/tips.csv" + ext,
@@ -90,9 +90,9 @@ def test_parse_public_s3_bucket(self, s3_public_bucket_with_data, tips_df, s3so)
assert not df.empty
tm.assert_frame_equal(df, tips_df)
- @td.skip_if_no("s3fs")
def test_parse_private_s3_bucket(self, s3_private_bucket_with_data, tips_df, s3so):
# Read public file from bucket with not-public contents
+ pytest.importorskip("s3fs")
df = read_csv(
f"s3://{s3_private_bucket_with_data.name}/tips.csv", storage_options=s3so
)
@@ -254,10 +254,10 @@ def test_write_s3_csv_fails(self, tips_df, s3so):
)
@pytest.mark.xfail(reason="GH#39155 s3fs upgrade", strict=False)
- @td.skip_if_no("pyarrow")
def test_write_s3_parquet_fails(self, tips_df, s3so):
# GH 27679
# Attempting to write to an invalid S3 path should raise
+ pytest.importorskip("pyarrow")
import botocore
# GH 34087
@@ -329,11 +329,11 @@ def test_read_s3_with_hash_in_key(self, s3_public_bucket_with_data, tips_df, s3s
)
tm.assert_frame_equal(tips_df, result)
- @td.skip_if_no("pyarrow")
def test_read_feather_s3_file_path(
self, s3_public_bucket_with_data, feather_file, s3so
):
# GH 29055
+ pytest.importorskip("pyarrow")
expected = read_feather(feather_file)
res = read_feather(
f"s3://{s3_public_bucket_with_data.name}/simple_dataset.feather",
diff --git a/pandas/tests/io/parser/test_upcast.py b/pandas/tests/io/parser/test_upcast.py
index 7cfaac997e3b1..bc4c4c2e24e9c 100644
--- a/pandas/tests/io/parser/test_upcast.py
+++ b/pandas/tests/io/parser/test_upcast.py
@@ -5,7 +5,6 @@
_maybe_upcast,
na_values,
)
-import pandas.util._test_decorators as td
import pandas as pd
from pandas import NA
@@ -85,11 +84,10 @@ def test_maybe_upcaste_all_nan():
tm.assert_extension_array_equal(result, expected)
-@td.skip_if_no("pyarrow")
@pytest.mark.parametrize("val", [na_values[np.object_], "c"])
def test_maybe_upcast_object(val, string_storage):
# GH#36712
- import pyarrow as pa
+ pa = pytest.importorskip("pyarrow")
with pd.option_context("mode.string_storage", string_storage):
arr = np.array(["a", "b", val], dtype=np.object_)
diff --git a/pandas/tests/io/test_common.py b/pandas/tests/io/test_common.py
index 435b9bdade944..a7ece6a6d7b08 100644
--- a/pandas/tests/io/test_common.py
+++ b/pandas/tests/io/test_common.py
@@ -147,9 +147,8 @@ def test_bytesiowrapper_returns_correct_bytes(self):
assert result == data.encode("utf-8")
# Test that pyarrow can handle a file opened with get_handle
- @td.skip_if_no("pyarrow")
def test_get_handle_pyarrow_compat(self):
- from pyarrow import csv
+ pa_csv = pytest.importorskip("pyarrow.csv")
# Test latin1, ucs-2, and ucs-4 chars
data = """a,b,c
@@ -161,7 +160,7 @@ def test_get_handle_pyarrow_compat(self):
)
s = StringIO(data)
with icom.get_handle(s, "rb", is_text=False) as handles:
- df = csv.read_csv(handles.handle).to_pandas()
+ df = pa_csv.read_csv(handles.handle).to_pandas()
tm.assert_frame_equal(df, expected)
assert not s.closed
diff --git a/pandas/tests/io/test_fsspec.py b/pandas/tests/io/test_fsspec.py
index fe5818620b9a9..030505f617b97 100644
--- a/pandas/tests/io/test_fsspec.py
+++ b/pandas/tests/io/test_fsspec.py
@@ -140,17 +140,18 @@ def test_excel_options(fsspectest):
assert fsspectest.test[0] == "read"
-@td.skip_if_no("fastparquet")
def test_to_parquet_new_file(cleared_fs, df1):
"""Regression test for writing to a not-yet-existent GCS Parquet file."""
+ pytest.importorskip("fastparquet")
+
df1.to_parquet(
"memory://test/test.csv", index=True, engine="fastparquet", compression=None
)
-@td.skip_if_no("pyarrow")
def test_arrowparquet_options(fsspectest):
"""Regression test for writing to a not-yet-existent GCS Parquet file."""
+ pytest.importorskip("pyarrow")
df = DataFrame({"a": [0]})
df.to_parquet(
"testmem://test/test.csv",
@@ -168,9 +169,10 @@ def test_arrowparquet_options(fsspectest):
@td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) fastparquet
-@td.skip_if_no("fastparquet")
def test_fastparquet_options(fsspectest):
"""Regression test for writing to a not-yet-existent GCS Parquet file."""
+ pytest.importorskip("fastparquet")
+
df = DataFrame({"a": [0]})
df.to_parquet(
"testmem://test/test.csv",
@@ -188,8 +190,8 @@ def test_fastparquet_options(fsspectest):
@pytest.mark.single_cpu
-@td.skip_if_no("s3fs")
def test_from_s3_csv(s3_public_bucket_with_data, tips_file, s3so):
+ pytest.importorskip("s3fs")
tm.assert_equal(
read_csv(
f"s3://{s3_public_bucket_with_data.name}/tips.csv", storage_options=s3so
@@ -213,8 +215,8 @@ def test_from_s3_csv(s3_public_bucket_with_data, tips_file, s3so):
@pytest.mark.single_cpu
@pytest.mark.parametrize("protocol", ["s3", "s3a", "s3n"])
-@td.skip_if_no("s3fs")
def test_s3_protocols(s3_public_bucket_with_data, tips_file, protocol, s3so):
+ pytest.importorskip("s3fs")
tm.assert_equal(
read_csv(
f"{protocol}://{s3_public_bucket_with_data.name}/tips.csv",
@@ -226,9 +228,10 @@ def test_s3_protocols(s3_public_bucket_with_data, tips_file, protocol, s3so):
@pytest.mark.single_cpu
@td.skip_array_manager_not_yet_implemented # TODO(ArrayManager) fastparquet
-@td.skip_if_no("s3fs")
-@td.skip_if_no("fastparquet")
def test_s3_parquet(s3_public_bucket, s3so, df1):
+ pytest.importorskip("fastparquet")
+ pytest.importorskip("s3fs")
+
fn = f"s3://{s3_public_bucket.name}/test.parquet"
df1.to_parquet(
fn, index=False, engine="fastparquet", compression=None, storage_options=s3so
@@ -244,8 +247,8 @@ def test_not_present_exception():
read_csv("memory://test/test.csv")
-@td.skip_if_no("pyarrow")
def test_feather_options(fsspectest):
+ pytest.importorskip("pyarrow")
df = DataFrame({"a": [0]})
df.to_feather("testmem://mockfile", storage_options={"test": "feather_write"})
assert fsspectest.test[0] == "feather_write"
@@ -291,16 +294,16 @@ def test_stata_options(fsspectest):
tm.assert_frame_equal(df, out.astype("int64"))
-@td.skip_if_no("tabulate")
def test_markdown_options(fsspectest):
+ pytest.importorskip("tabulate")
df = DataFrame({"a": [0]})
df.to_markdown("testmem://mockfile", storage_options={"test": "md_write"})
assert fsspectest.test[0] == "md_write"
assert fsspectest.cat("testmem://mockfile")
-@td.skip_if_no("pyarrow")
def test_non_fsspec_options():
+ pytest.importorskip("pyarrow")
with pytest.raises(ValueError, match="storage_options"):
read_csv("localfile", storage_options={"a": True})
with pytest.raises(ValueError, match="storage_options"):
diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py
index cafe690e338d6..6cf90749e5b30 100644
--- a/pandas/tests/io/test_html.py
+++ b/pandas/tests/io/test_html.py
@@ -70,10 +70,9 @@ def assert_framelist_equal(list1, list2, *args, **kwargs):
assert not frame_i.empty, "frames are both empty"
-@td.skip_if_no("bs4")
-@td.skip_if_no("html5lib")
def test_bs4_version_fails(monkeypatch, datapath):
- import bs4
+ bs4 = pytest.importorskip("bs4")
+ pytest.importorskip("html5lib")
monkeypatch.setattr(bs4, "__version__", "4.2")
with pytest.raises(ImportError, match="Pandas requires version"):
@@ -89,10 +88,11 @@ def test_invalid_flavor():
read_html(StringIO(url), match="google", flavor=flavor)
-@td.skip_if_no("bs4")
-@td.skip_if_no("lxml")
-@td.skip_if_no("html5lib")
def test_same_ordering(datapath):
+ pytest.importorskip("bs4")
+ pytest.importorskip("lxml")
+ pytest.importorskip("html5lib")
+
filename = datapath("io", "data", "html", "valid_markup.html")
dfs_lxml = read_html(filename, index_col=0, flavor=["lxml"])
dfs_bs4 = read_html(filename, index_col=0, flavor=["bs4"])
diff --git a/pandas/tests/io/test_orc.py b/pandas/tests/io/test_orc.py
index 571d9d5536e20..8483eb0d5c159 100644
--- a/pandas/tests/io/test_orc.py
+++ b/pandas/tests/io/test_orc.py
@@ -8,8 +8,6 @@
import numpy as np
import pytest
-import pandas.util._test_decorators as td
-
import pandas as pd
from pandas import read_orc
import pandas._testing as tm
@@ -243,10 +241,11 @@ def test_orc_reader_snappy_compressed(dirpath):
tm.assert_equal(expected, got)
-@td.skip_if_no("pyarrow", min_version="7.0.0")
def test_orc_roundtrip_file(dirpath):
# GH44554
# PyArrow gained ORC write support with the current argument order
+ pytest.importorskip("pyarrow")
+
data = {
"boolean1": np.array([False, True], dtype="bool"),
"byte1": np.array([1, 100], dtype="int8"),
@@ -267,10 +266,11 @@ def test_orc_roundtrip_file(dirpath):
tm.assert_equal(expected, got)
-@td.skip_if_no("pyarrow", min_version="7.0.0")
def test_orc_roundtrip_bytesio():
# GH44554
# PyArrow gained ORC write support with the current argument order
+ pytest.importorskip("pyarrow")
+
data = {
"boolean1": np.array([False, True], dtype="bool"),
"byte1": np.array([1, 100], dtype="int8"),
@@ -290,17 +290,18 @@ def test_orc_roundtrip_bytesio():
tm.assert_equal(expected, got)
-@td.skip_if_no("pyarrow", min_version="7.0.0")
def test_orc_writer_dtypes_not_supported(orc_writer_dtypes_not_supported):
# GH44554
# PyArrow gained ORC write support with the current argument order
+ pytest.importorskip("pyarrow")
+
msg = "The dtype of one or more columns is not supported yet."
with pytest.raises(NotImplementedError, match=msg):
orc_writer_dtypes_not_supported.to_orc()
-@td.skip_if_no("pyarrow", min_version="7.0.0")
def test_orc_dtype_backend_pyarrow():
+ pytest.importorskip("pyarrow")
df = pd.DataFrame(
{
"string": list("abc"),
@@ -334,9 +335,9 @@ def test_orc_dtype_backend_pyarrow():
tm.assert_frame_equal(result, expected)
-@td.skip_if_no("pyarrow", min_version="7.0.0")
def test_orc_dtype_backend_numpy_nullable():
# GH#50503
+ pytest.importorskip("pyarrow")
df = pd.DataFrame(
{
"string": list("abc"),
diff --git a/pandas/tests/io/test_parquet.py b/pandas/tests/io/test_parquet.py
index 5399cabb61ec3..283d86227c79e 100644
--- a/pandas/tests/io/test_parquet.py
+++ b/pandas/tests/io/test_parquet.py
@@ -19,7 +19,6 @@
pa_version_under8p0,
pa_version_under13p0,
)
-import pandas.util._test_decorators as td
import pandas as pd
import pandas._testing as tm
@@ -830,7 +829,6 @@ def test_s3_roundtrip(self, df_compat, s3_public_bucket, pa, s3so):
)
@pytest.mark.single_cpu
- @td.skip_if_no("s3fs") # also requires flask
@pytest.mark.parametrize(
"partition_col",
[
@@ -841,6 +839,7 @@ def test_s3_roundtrip(self, df_compat, s3_public_bucket, pa, s3so):
def test_s3_roundtrip_for_dir(
self, df_compat, s3_public_bucket, pa, partition_col, s3so
):
+ pytest.importorskip("s3fs")
# GH #26388
expected_df = df_compat.copy()
@@ -868,15 +867,15 @@ def test_s3_roundtrip_for_dir(
repeat=1,
)
- @td.skip_if_no("pyarrow")
def test_read_file_like_obj_support(self, df_compat):
+ pytest.importorskip("pyarrow")
buffer = BytesIO()
df_compat.to_parquet(buffer)
df_from_buf = read_parquet(buffer)
tm.assert_frame_equal(df_compat, df_from_buf)
- @td.skip_if_no("pyarrow")
def test_expand_user(self, df_compat, monkeypatch):
+ pytest.importorskip("pyarrow")
monkeypatch.setenv("HOME", "TestingUser")
monkeypatch.setenv("USERPROFILE", "TestingUser")
with pytest.raises(OSError, match=r".*TestingUser.*"):
@@ -928,10 +927,10 @@ def test_write_with_schema(self, pa):
out_df = df.astype(bool)
check_round_trip(df, pa, write_kwargs={"schema": schema}, expected=out_df)
- @td.skip_if_no("pyarrow")
def test_additional_extension_arrays(self, pa):
# test additional ExtensionArrays that are supported through the
# __arrow_array__ protocol
+ pytest.importorskip("pyarrow")
df = pd.DataFrame(
{
"a": pd.Series([1, 2, 3], dtype="Int64"),
@@ -944,17 +943,17 @@ def test_additional_extension_arrays(self, pa):
df = pd.DataFrame({"a": pd.Series([1, 2, 3, None], dtype="Int64")})
check_round_trip(df, pa)
- @td.skip_if_no("pyarrow")
def test_pyarrow_backed_string_array(self, pa, string_storage):
# test ArrowStringArray supported through the __arrow_array__ protocol
+ pytest.importorskip("pyarrow")
df = pd.DataFrame({"a": pd.Series(["a", None, "c"], dtype="string[pyarrow]")})
with pd.option_context("string_storage", string_storage):
check_round_trip(df, pa, expected=df.astype(f"string[{string_storage}]"))
- @td.skip_if_no("pyarrow")
def test_additional_extension_types(self, pa):
# test additional ExtensionArrays that are supported through the
# __arrow_array__ protocol + by defining a custom ExtensionType
+ pytest.importorskip("pyarrow")
df = pd.DataFrame(
{
"c": pd.IntervalIndex.from_tuples([(0, 1), (1, 2), (3, 4)]),
@@ -1003,9 +1002,9 @@ def test_timezone_aware_index(self, request, pa, timezone_aware_date_list):
# this use-case sets the resolution to 1 minute
check_round_trip(df, pa, check_dtype=False)
- @td.skip_if_no("pyarrow")
def test_filter_row_groups(self, pa):
# https://github.com/pandas-dev/pandas/issues/26551
+ pytest.importorskip("pyarrow")
df = pd.DataFrame({"a": list(range(0, 3))})
with tm.ensure_clean() as path:
df.to_parquet(path, pa)
diff --git a/pandas/tests/io/test_pickle.py b/pandas/tests/io/test_pickle.py
index d66d5d532962c..ac24dc21bab38 100644
--- a/pandas/tests/io/test_pickle.py
+++ b/pandas/tests/io/test_pickle.py
@@ -456,8 +456,8 @@ def mock_urlopen_read(*args, **kwargs):
tm.assert_frame_equal(df, result)
-@td.skip_if_no("fsspec")
def test_pickle_fsspec_roundtrip():
+ pytest.importorskip("fsspec")
with tm.ensure_clean():
mockurl = "memory://mockfile"
df = tm.makeDataFrame()
diff --git a/pandas/tests/io/test_s3.py b/pandas/tests/io/test_s3.py
index 35250f1dd3081..9ee3c09631d0e 100644
--- a/pandas/tests/io/test_s3.py
+++ b/pandas/tests/io/test_s3.py
@@ -2,8 +2,6 @@
import pytest
-import pandas.util._test_decorators as td
-
from pandas import read_csv
@@ -19,10 +17,10 @@ def test_streaming_s3_objects():
read_csv(body)
-@td.skip_if_no("s3fs")
@pytest.mark.single_cpu
def test_read_without_creds_from_pub_bucket(s3_public_bucket_with_data, s3so):
# GH 34626
+ pytest.importorskip("s3fs")
result = read_csv(
f"s3://{s3_public_bucket_with_data.name}/tips.csv",
nrows=3,
@@ -31,7 +29,6 @@ def test_read_without_creds_from_pub_bucket(s3_public_bucket_with_data, s3so):
assert len(result) == 3
-@td.skip_if_no("s3fs")
@pytest.mark.single_cpu
def test_read_with_creds_from_pub_bucket(s3_public_bucket_with_data, monkeypatch, s3so):
# Ensure we can read from a public bucket with credentials
@@ -39,6 +36,7 @@ def test_read_with_creds_from_pub_bucket(s3_public_bucket_with_data, monkeypatch
# temporary workaround as moto fails for botocore >= 1.11 otherwise,
# see https://github.com/spulec/moto/issues/1924 & 1952
+ pytest.importorskip("s3fs")
monkeypatch.setenv("AWS_ACCESS_KEY_ID", "foobar_key")
monkeypatch.setenv("AWS_SECRET_ACCESS_KEY", "foobar_secret")
df = read_csv(
diff --git a/pandas/tests/io/xml/test_to_xml.py b/pandas/tests/io/xml/test_to_xml.py
index a6ed15f56d8d4..37251a58b0c11 100644
--- a/pandas/tests/io/xml/test_to_xml.py
+++ b/pandas/tests/io/xml/test_to_xml.py
@@ -866,17 +866,17 @@ def test_encoding_option_str(xml_baby_names, parser):
assert output == encoding_expected
-@td.skip_if_no("lxml")
def test_correct_encoding_file(xml_baby_names):
+ pytest.importorskip("lxml")
df_file = read_xml(xml_baby_names, encoding="ISO-8859-1", parser="lxml")
with tm.ensure_clean("test.xml") as path:
df_file.to_xml(path, index=False, encoding="ISO-8859-1", parser="lxml")
-@td.skip_if_no("lxml")
@pytest.mark.parametrize("encoding", ["UTF-8", "UTF-16", "ISO-8859-1"])
def test_wrong_encoding_option_lxml(xml_baby_names, parser, encoding):
+ pytest.importorskip("lxml")
df_file = read_xml(xml_baby_names, encoding="ISO-8859-1", parser="lxml")
with tm.ensure_clean("test.xml") as path:
@@ -891,8 +891,8 @@ def test_misspelled_encoding(parser, geom_df):
# PRETTY PRINT
-@td.skip_if_no("lxml")
def test_xml_declaration_pretty_print(geom_df):
+ pytest.importorskip("lxml")
expected = """\
@@ -1004,18 +1004,18 @@ def test_unknown_parser(geom_df):
"""
-@td.skip_if_no("lxml")
def test_stylesheet_file_like(xsl_row_field_output, mode, geom_df):
+ pytest.importorskip("lxml")
with open(
xsl_row_field_output, mode, encoding="utf-8" if mode == "r" else None
) as f:
assert geom_df.to_xml(stylesheet=f) == xsl_expected
-@td.skip_if_no("lxml")
def test_stylesheet_io(xsl_row_field_output, mode, geom_df):
# note: By default the bodies of untyped functions are not checked,
# consider using --check-untyped-defs
+ pytest.importorskip("lxml")
xsl_obj: BytesIO | StringIO # type: ignore[annotation-unchecked]
with open(
@@ -1031,8 +1031,8 @@ def test_stylesheet_io(xsl_row_field_output, mode, geom_df):
assert output == xsl_expected
-@td.skip_if_no("lxml")
def test_stylesheet_buffered_reader(xsl_row_field_output, mode, geom_df):
+ pytest.importorskip("lxml")
with open(
xsl_row_field_output, mode, encoding="utf-8" if mode == "r" else None
) as f:
@@ -1043,23 +1043,21 @@ def test_stylesheet_buffered_reader(xsl_row_field_output, mode, geom_df):
assert output == xsl_expected
-@td.skip_if_no("lxml")
def test_stylesheet_wrong_path(geom_df):
- from lxml.etree import XMLSyntaxError
+ lxml_etree = pytest.importorskip("lxml.etree")
xsl = os.path.join("data", "xml", "row_field_output.xslt")
with pytest.raises(
- XMLSyntaxError,
+ lxml_etree.XMLSyntaxError,
match=("Start tag expected, '<' not found"),
):
geom_df.to_xml(stylesheet=xsl)
-@td.skip_if_no("lxml")
@pytest.mark.parametrize("val", ["", b""])
def test_empty_string_stylesheet(val, geom_df):
- from lxml.etree import XMLSyntaxError
+ lxml_etree = pytest.importorskip("lxml.etree")
msg = "|".join(
[
@@ -1070,13 +1068,12 @@ def test_empty_string_stylesheet(val, geom_df):
]
)
- with pytest.raises(XMLSyntaxError, match=msg):
+ with pytest.raises(lxml_etree.XMLSyntaxError, match=msg):
geom_df.to_xml(stylesheet=val)
-@td.skip_if_no("lxml")
def test_incorrect_xsl_syntax(geom_df):
- from lxml.etree import XMLSyntaxError
+ lxml_etree = pytest.importorskip("lxml.etree")
xsl = """\
@@ -1099,13 +1096,14 @@ def test_incorrect_xsl_syntax(geom_df):
"""
- with pytest.raises(XMLSyntaxError, match=("Opening and ending tag mismatch")):
+ with pytest.raises(
+ lxml_etree.XMLSyntaxError, match=("Opening and ending tag mismatch")
+ ):
geom_df.to_xml(stylesheet=xsl)
-@td.skip_if_no("lxml")
def test_incorrect_xsl_eval(geom_df):
- from lxml.etree import XSLTParseError
+ lxml_etree = pytest.importorskip("lxml.etree")
xsl = """\
@@ -1128,13 +1126,12 @@ def test_incorrect_xsl_eval(geom_df):
"""
- with pytest.raises(XSLTParseError, match=("failed to compile")):
+ with pytest.raises(lxml_etree.XSLTParseError, match=("failed to compile")):
geom_df.to_xml(stylesheet=xsl)
-@td.skip_if_no("lxml")
def test_incorrect_xsl_apply(geom_df):
- from lxml.etree import XSLTApplyError
+ lxml_etree = pytest.importorskip("lxml.etree")
xsl = """\
@@ -1148,7 +1145,7 @@ def test_incorrect_xsl_apply(geom_df):
"""
- with pytest.raises(XSLTApplyError, match=("Cannot resolve URI")):
+ with pytest.raises(lxml_etree.XSLTApplyError, match=("Cannot resolve URI")):
with tm.ensure_clean("test.xml") as path:
geom_df.to_xml(path, stylesheet=xsl)
@@ -1171,8 +1168,8 @@ def test_stylesheet_with_etree(geom_df):
geom_df.to_xml(parser="etree", stylesheet=xsl)
-@td.skip_if_no("lxml")
def test_style_to_csv(geom_df):
+ pytest.importorskip("lxml")
xsl = """\
@@ -1200,8 +1197,8 @@ def test_style_to_csv(geom_df):
assert out_csv == out_xml
-@td.skip_if_no("lxml")
def test_style_to_string(geom_df):
+ pytest.importorskip("lxml")
xsl = """\
@@ -1234,8 +1231,8 @@ def test_style_to_string(geom_df):
assert out_xml == out_str
-@td.skip_if_no("lxml")
def test_style_to_json(geom_df):
+ pytest.importorskip("lxml")
xsl = """\
@@ -1365,10 +1362,9 @@ def test_unsuported_compression(parser, geom_df):
@pytest.mark.single_cpu
-@td.skip_if_no("s3fs")
-@td.skip_if_no("lxml")
def test_s3_permission_output(parser, s3_public_bucket, geom_df):
- import s3fs
+ s3fs = pytest.importorskip("s3fs")
+ pytest.importorskip("lxml")
with tm.external_error_raised((PermissionError, FileNotFoundError)):
fs = s3fs.S3FileSystem(anon=True)
diff --git a/pandas/tests/io/xml/test_xml.py b/pandas/tests/io/xml/test_xml.py
index 19668c2c4cfc0..d36fcdc0f4431 100644
--- a/pandas/tests/io/xml/test_xml.py
+++ b/pandas/tests/io/xml/test_xml.py
@@ -246,9 +246,9 @@
)
-@td.skip_if_no("lxml")
def test_literal_xml_deprecation():
# GH 53809
+ pytest.importorskip("lxml")
msg = (
"Passing literal xml to 'read_xml' is deprecated and "
"will be removed in a future version. To read from a "
@@ -287,8 +287,8 @@ def read_xml_iterparse_comp(comp_path, compression_only, **kwargs):
# FILE / URL
-@td.skip_if_no("lxml")
def test_parser_consistency_file(xml_books):
+ pytest.importorskip("lxml")
df_file_lxml = read_xml(xml_books, parser="lxml")
df_file_etree = read_xml(xml_books, parser="etree")
@@ -459,10 +459,9 @@ def test_file_handle_close(xml_books, parser):
assert not f.closed
-@td.skip_if_no("lxml")
@pytest.mark.parametrize("val", ["", b""])
def test_empty_string_lxml(val):
- from lxml.etree import XMLSyntaxError
+ lxml_etree = pytest.importorskip("lxml.etree")
msg = "|".join(
[
@@ -471,7 +470,7 @@ def test_empty_string_lxml(val):
r"None \(line 0\)",
]
)
- with pytest.raises(XMLSyntaxError, match=msg):
+ with pytest.raises(lxml_etree.XMLSyntaxError, match=msg):
if isinstance(val, str):
read_xml(StringIO(val), parser="lxml")
else:
@@ -504,8 +503,8 @@ def test_wrong_file_path(parser):
@pytest.mark.network
@pytest.mark.single_cpu
-@td.skip_if_no("lxml")
def test_url(httpserver, xml_file):
+ pytest.importorskip("lxml")
with open(xml_file, encoding="utf-8") as f:
httpserver.serve_content(content=f.read())
df_url = read_xml(httpserver.url, xpath=".//book[count(*)=4]")
@@ -586,8 +585,8 @@ def test_whitespace(parser):
# XPATH
-@td.skip_if_no("lxml")
def test_empty_xpath_lxml(xml_books):
+ pytest.importorskip("lxml")
with pytest.raises(ValueError, match=("xpath does not return any nodes")):
read_xml(xml_books, xpath=".//python", parser="lxml")
@@ -599,11 +598,10 @@ def test_bad_xpath_etree(xml_books):
read_xml(xml_books, xpath=".//[book]", parser="etree")
-@td.skip_if_no("lxml")
def test_bad_xpath_lxml(xml_books):
- from lxml.etree import XPathEvalError
+ lxml_etree = pytest.importorskip("lxml.etree")
- with pytest.raises(XPathEvalError, match=("Invalid expression")):
+ with pytest.raises(lxml_etree.XPathEvalError, match=("Invalid expression")):
read_xml(xml_books, xpath=".//[book]", parser="lxml")
@@ -659,8 +657,8 @@ def test_prefix_namespace(parser):
tm.assert_frame_equal(df_iter, df_expected)
-@td.skip_if_no("lxml")
def test_consistency_default_namespace():
+ pytest.importorskip("lxml")
df_lxml = read_xml(
StringIO(xml_default_nmsp),
xpath=".//ns:row",
@@ -678,8 +676,8 @@ def test_consistency_default_namespace():
tm.assert_frame_equal(df_lxml, df_etree)
-@td.skip_if_no("lxml")
def test_consistency_prefix_namespace():
+ pytest.importorskip("lxml")
df_lxml = read_xml(
StringIO(xml_prefix_nmsp),
xpath=".//doc:row",
@@ -710,17 +708,16 @@ def test_missing_prefix_definition_etree(kml_cta_rail_lines):
read_xml(kml_cta_rail_lines, xpath=".//kml:Placemark", parser="etree")
-@td.skip_if_no("lxml")
def test_missing_prefix_definition_lxml(kml_cta_rail_lines):
- from lxml.etree import XPathEvalError
+ lxml_etree = pytest.importorskip("lxml.etree")
- with pytest.raises(XPathEvalError, match=("Undefined namespace prefix")):
+ with pytest.raises(lxml_etree.XPathEvalError, match=("Undefined namespace prefix")):
read_xml(kml_cta_rail_lines, xpath=".//kml:Placemark", parser="lxml")
-@td.skip_if_no("lxml")
@pytest.mark.parametrize("key", ["", None])
def test_none_namespace_prefix(key):
+ pytest.importorskip("lxml")
with pytest.raises(
TypeError, match=("empty namespace prefix is not supported in XPath")
):
@@ -832,8 +829,8 @@ def test_empty_elems_only(parser):
read_xml(StringIO(xml), xpath="./row", elems_only=True, parser=parser)
-@td.skip_if_no("lxml")
def test_attribute_centric_xml():
+ pytest.importorskip("lxml")
xml = """\
@@ -1062,8 +1059,8 @@ def test_ascii_encoding(xml_baby_names, parser):
read_xml(xml_baby_names, encoding="ascii", parser=parser)
-@td.skip_if_no("lxml")
def test_parser_consistency_with_encoding(xml_baby_names):
+ pytest.importorskip("lxml")
df_xpath_lxml = read_xml(xml_baby_names, parser="lxml", encoding="ISO-8859-1")
df_xpath_etree = read_xml(xml_baby_names, parser="etree", encoding="iso-8859-1")
@@ -1085,8 +1082,8 @@ def test_parser_consistency_with_encoding(xml_baby_names):
tm.assert_frame_equal(df_iter_lxml, df_iter_etree)
-@td.skip_if_no("lxml")
def test_wrong_encoding_for_lxml():
+ pytest.importorskip("lxml")
# GH#45133
data = """
@@ -1132,8 +1129,8 @@ def test_wrong_parser(xml_books):
# STYLESHEET
-@td.skip_if_no("lxml")
def test_stylesheet_file(kml_cta_rail_lines, xsl_flatten_doc):
+ pytest.importorskip("lxml")
df_style = read_xml(
kml_cta_rail_lines,
xpath=".//k:Placemark",
@@ -1159,8 +1156,8 @@ def test_stylesheet_file(kml_cta_rail_lines, xsl_flatten_doc):
tm.assert_frame_equal(df_kml, df_iter)
-@td.skip_if_no("lxml")
def test_stylesheet_file_like(kml_cta_rail_lines, xsl_flatten_doc, mode):
+ pytest.importorskip("lxml")
with open(xsl_flatten_doc, mode, encoding="utf-8" if mode == "r" else None) as f:
df_style = read_xml(
kml_cta_rail_lines,
@@ -1172,10 +1169,10 @@ def test_stylesheet_file_like(kml_cta_rail_lines, xsl_flatten_doc, mode):
tm.assert_frame_equal(df_kml, df_style)
-@td.skip_if_no("lxml")
def test_stylesheet_io(kml_cta_rail_lines, xsl_flatten_doc, mode):
# note: By default the bodies of untyped functions are not checked,
# consider using --check-untyped-defs
+ pytest.importorskip("lxml")
xsl_obj: BytesIO | StringIO # type: ignore[annotation-unchecked]
with open(xsl_flatten_doc, mode, encoding="utf-8" if mode == "r" else None) as f:
@@ -1194,8 +1191,8 @@ def test_stylesheet_io(kml_cta_rail_lines, xsl_flatten_doc, mode):
tm.assert_frame_equal(df_kml, df_style)
-@td.skip_if_no("lxml")
def test_stylesheet_buffered_reader(kml_cta_rail_lines, xsl_flatten_doc, mode):
+ pytest.importorskip("lxml")
with open(xsl_flatten_doc, mode, encoding="utf-8" if mode == "r" else None) as f:
xsl_obj = f.read()
@@ -1209,8 +1206,8 @@ def test_stylesheet_buffered_reader(kml_cta_rail_lines, xsl_flatten_doc, mode):
tm.assert_frame_equal(df_kml, df_style)
-@td.skip_if_no("lxml")
def test_style_charset():
+ pytest.importorskip("lxml")
xml = "<中文標籤>12
中文標籤>"
xsl = """\
@@ -1238,17 +1235,17 @@ def test_style_charset():
tm.assert_frame_equal(df_orig, df_style)
-@td.skip_if_no("lxml")
def test_not_stylesheet(kml_cta_rail_lines, xml_books):
- from lxml.etree import XSLTParseError
+ lxml_etree = pytest.importorskip("lxml.etree")
- with pytest.raises(XSLTParseError, match=("document is not a stylesheet")):
+ with pytest.raises(
+ lxml_etree.XSLTParseError, match=("document is not a stylesheet")
+ ):
read_xml(kml_cta_rail_lines, stylesheet=xml_books)
-@td.skip_if_no("lxml")
def test_incorrect_xsl_syntax(kml_cta_rail_lines):
- from lxml.etree import XMLSyntaxError
+ lxml_etree = pytest.importorskip("lxml.etree")
xsl = """\
"""
with pytest.raises(
- XMLSyntaxError, match=("Extra content at the end of the document")
+ lxml_etree.XMLSyntaxError, match=("Extra content at the end of the document")
):
read_xml(kml_cta_rail_lines, stylesheet=xsl)
-@td.skip_if_no("lxml")
def test_incorrect_xsl_eval(kml_cta_rail_lines):
- from lxml.etree import XSLTParseError
+ lxml_etree = pytest.importorskip("lxml.etree")
xsl = """\
"""
- with pytest.raises(XSLTParseError, match=("failed to compile")):
+ with pytest.raises(lxml_etree.XSLTParseError, match=("failed to compile")):
read_xml(kml_cta_rail_lines, stylesheet=xsl)
-@td.skip_if_no("lxml")
def test_incorrect_xsl_apply(kml_cta_rail_lines):
- from lxml.etree import XSLTApplyError
+ lxml_etree = pytest.importorskip("lxml.etree")
xsl = """\
@@ -1320,27 +1315,26 @@ def test_incorrect_xsl_apply(kml_cta_rail_lines):
"""
- with pytest.raises(XSLTApplyError, match=("Cannot resolve URI")):
+ with pytest.raises(lxml_etree.XSLTApplyError, match=("Cannot resolve URI")):
read_xml(kml_cta_rail_lines, stylesheet=xsl)
-@td.skip_if_no("lxml")
def test_wrong_stylesheet(kml_cta_rail_lines, xml_data_path):
- from lxml.etree import XMLSyntaxError
+ xml_etree = pytest.importorskip("lxml.etree")
xsl = xml_data_path / "flatten.xsl"
with pytest.raises(
- XMLSyntaxError,
+ xml_etree.XMLSyntaxError,
match=("Start tag expected, '<' not found"),
):
read_xml(kml_cta_rail_lines, stylesheet=xsl)
-@td.skip_if_no("lxml")
def test_stylesheet_file_close(kml_cta_rail_lines, xsl_flatten_doc, mode):
# note: By default the bodies of untyped functions are not checked,
# consider using --check-untyped-defs
+ pytest.importorskip("lxml")
xsl_obj: BytesIO | StringIO # type: ignore[annotation-unchecked]
with open(xsl_flatten_doc, mode, encoding="utf-8" if mode == "r" else None) as f:
@@ -1354,17 +1348,17 @@ def test_stylesheet_file_close(kml_cta_rail_lines, xsl_flatten_doc, mode):
assert not f.closed
-@td.skip_if_no("lxml")
def test_stylesheet_with_etree(kml_cta_rail_lines, xsl_flatten_doc):
+ pytest.importorskip("lxml")
with pytest.raises(
ValueError, match=("To use stylesheet, you need lxml installed")
):
read_xml(kml_cta_rail_lines, parser="etree", stylesheet=xsl_flatten_doc)
-@td.skip_if_no("lxml")
@pytest.mark.parametrize("val", ["", b""])
def test_empty_stylesheet(val):
+ pytest.importorskip("lxml")
msg = (
"Passing literal xml to 'read_xml' is deprecated and "
"will be removed in a future version. To read from a "
@@ -1667,8 +1661,8 @@ def test_empty_data(xml_books, parser):
)
-@td.skip_if_no("lxml")
def test_online_stylesheet():
+ pytest.importorskip("lxml")
xml = """\
@@ -1998,9 +1992,9 @@ def test_unsuported_compression(parser):
@pytest.mark.network
@pytest.mark.single_cpu
-@td.skip_if_no("s3fs")
-@td.skip_if_no("lxml")
def test_s3_parser_consistency(s3_public_bucket_with_data, s3so):
+ pytest.importorskip("s3fs")
+ pytest.importorskip("lxml")
s3 = f"s3://{s3_public_bucket_with_data.name}/books.xml"
df_lxml = read_xml(s3, parser="lxml", storage_options=s3so)
diff --git a/pandas/tests/plotting/test_hist_method.py b/pandas/tests/plotting/test_hist_method.py
index a2f68d587523b..6bab3d910d879 100644
--- a/pandas/tests/plotting/test_hist_method.py
+++ b/pandas/tests/plotting/test_hist_method.py
@@ -626,9 +626,9 @@ def test_hist_secondary_primary(self):
assert ax.left_ax.get_yaxis().get_visible()
assert ax.get_yaxis().get_visible()
- @td.skip_if_no_mpl
def test_hist_with_nans_and_weights(self):
# GH 48884
+ mpl_patches = pytest.importorskip("matplotlib.patches")
df = DataFrame(
[[np.nan, 0.2, 0.3], [0.4, np.nan, np.nan], [0.7, 0.8, 0.9]],
columns=list("abc"),
@@ -637,15 +637,15 @@ def test_hist_with_nans_and_weights(self):
no_nan_df = DataFrame([[0.4, 0.2, 0.3], [0.7, 0.8, 0.9]], columns=list("abc"))
no_nan_weights = np.array([[0.3, 0.25, 0.25], [0.45, 0.45, 0.45]])
- from matplotlib.patches import Rectangle
-
_, ax0 = mpl.pyplot.subplots()
df.plot.hist(ax=ax0, weights=weights)
- rects = [x for x in ax0.get_children() if isinstance(x, Rectangle)]
+ rects = [x for x in ax0.get_children() if isinstance(x, mpl_patches.Rectangle)]
heights = [rect.get_height() for rect in rects]
_, ax1 = mpl.pyplot.subplots()
no_nan_df.plot.hist(ax=ax1, weights=no_nan_weights)
- no_nan_rects = [x for x in ax1.get_children() if isinstance(x, Rectangle)]
+ no_nan_rects = [
+ x for x in ax1.get_children() if isinstance(x, mpl_patches.Rectangle)
+ ]
no_nan_heights = [rect.get_height() for rect in no_nan_rects]
assert all(h0 == h1 for h0, h1 in zip(heights, no_nan_heights))
diff --git a/pandas/tests/series/test_api.py b/pandas/tests/series/test_api.py
index bd33f499711db..be63d9500ce73 100644
--- a/pandas/tests/series/test_api.py
+++ b/pandas/tests/series/test_api.py
@@ -4,8 +4,6 @@
import numpy as np
import pytest
-from pandas.util._test_decorators import skip_if_no
-
import pandas as pd
from pandas import (
DataFrame,
@@ -166,9 +164,9 @@ def test_attrs(self):
result = s + 1
assert result.attrs == {"version": 1}
- @skip_if_no("jinja2")
def test_inspect_getmembers(self):
# GH38782
+ pytest.importorskip("jinja2")
ser = Series(dtype=object)
msg = "Series._data is deprecated"
with tm.assert_produces_warning(
diff --git a/pandas/tests/test_downstream.py b/pandas/tests/test_downstream.py
index 01efb01e63e1c..e81c2f9c086b0 100644
--- a/pandas/tests/test_downstream.py
+++ b/pandas/tests/test_downstream.py
@@ -2,7 +2,6 @@
Testing that we work in the downstream packages
"""
import array
-import importlib
import subprocess
import sys
@@ -28,16 +27,6 @@
from pandas.core.arrays.timedeltas import sequence_to_td64ns
-def import_module(name):
- # we *only* want to skip if the module is truly not available
- # and NOT just an actual import error because of pandas changes
-
- try:
- return importlib.import_module(name)
- except ModuleNotFoundError:
- pytest.skip(f"skipping as {name} not available")
-
-
@pytest.fixture
def df():
return DataFrame({"A": [1, 2, 3]})
@@ -49,10 +38,8 @@ def test_dask(df):
olduse = pd.get_option("compute.use_numexpr")
try:
- toolz = import_module("toolz") # noqa: F841
- dask = import_module("dask") # noqa: F841
-
- import dask.dataframe as dd
+ pytest.importorskip("toolz")
+ dd = pytest.importorskip("dask.dataframe")
ddf = dd.from_pandas(df, npartitions=3)
assert ddf.A is not None
@@ -67,9 +54,8 @@ def test_dask_ufunc():
olduse = pd.get_option("compute.use_numexpr")
try:
- dask = import_module("dask") # noqa: F841
- import dask.array as da
- import dask.dataframe as dd
+ da = pytest.importorskip("dask.array")
+ dd = pytest.importorskip("dask.dataframe")
s = Series([1.5, 2.3, 3.7, 4.0])
ds = dd.from_pandas(s, npartitions=2)
@@ -81,11 +67,10 @@ def test_dask_ufunc():
pd.set_option("compute.use_numexpr", olduse)
-@td.skip_if_no("dask")
def test_construct_dask_float_array_int_dtype_match_ndarray():
# GH#40110 make sure we treat a float-dtype dask array with the same
# rules we would for an ndarray
- import dask.dataframe as dd
+ dd = pytest.importorskip("dask.dataframe")
arr = np.array([1, 2.5, 3])
darr = dd.from_array(arr)
@@ -109,17 +94,15 @@ def test_construct_dask_float_array_int_dtype_match_ndarray():
def test_xarray(df):
- xarray = import_module("xarray") # noqa: F841
+ pytest.importorskip("xarray")
assert df.to_xarray() is not None
-@td.skip_if_no("cftime")
-@td.skip_if_no("xarray", "0.21.0")
def test_xarray_cftimeindex_nearest():
# https://github.com/pydata/xarray/issues/3751
- import cftime
- import xarray
+ cftime = pytest.importorskip("cftime")
+ xarray = pytest.importorskip("xarray", minversion="0.21.0")
times = xarray.cftime_range("0001", periods=2)
key = cftime.DatetimeGregorian(2000, 1, 1)
@@ -151,8 +134,7 @@ def test_oo_optimized_datetime_index_unpickle():
def test_statsmodels():
- statsmodels = import_module("statsmodels") # noqa: F841
- import statsmodels.formula.api as smf
+ smf = pytest.importorskip("statsmodels.formula.api")
df = DataFrame(
{"Lottery": range(5), "Literacy": range(5), "Pop1831": range(100, 105)}
@@ -161,7 +143,7 @@ def test_statsmodels():
def test_scikit_learn():
- sklearn = import_module("sklearn") # noqa: F841
+ pytest.importorskip("sklearn")
from sklearn import (
datasets,
svm,
@@ -174,7 +156,7 @@ def test_scikit_learn():
def test_seaborn():
- seaborn = import_module("seaborn")
+ seaborn = pytest.importorskip("seaborn")
tips = DataFrame(
{"day": pd.date_range("2023", freq="D", periods=5), "total_bill": range(5)}
)
@@ -184,15 +166,14 @@ def test_seaborn():
def test_pandas_gbq():
# Older versions import from non-public, non-existent pandas funcs
pytest.importorskip("pandas_gbq", minversion="0.10.0")
- pandas_gbq = import_module("pandas_gbq") # noqa: F841
def test_pandas_datareader():
- pandas_datareader = import_module("pandas_datareader") # noqa: F841
+ pytest.importorskip("pandas_datareader")
def test_pyarrow(df):
- pyarrow = import_module("pyarrow")
+ pyarrow = pytest.importorskip("pyarrow")
table = pyarrow.Table.from_pandas(df)
result = table.to_pandas()
tm.assert_frame_equal(result, df)
@@ -200,7 +181,7 @@ def test_pyarrow(df):
def test_yaml_dump(df):
# GH#42748
- yaml = import_module("yaml")
+ yaml = pytest.importorskip("yaml")
dumped = yaml.dump(df)
@@ -256,9 +237,7 @@ def test_frame_setitem_dask_array_into_new_col():
olduse = pd.get_option("compute.use_numexpr")
try:
- dask = import_module("dask") # noqa: F841
-
- import dask.array as da
+ da = pytest.importorskip("dask.array")
dda = da.array([1, 2])
df = DataFrame({"a": ["a", "b"]})
@@ -353,3 +332,21 @@ def test_from_obscure_array(dtype, array_likes):
result = idx_cls(arr)
expected = idx_cls(data)
tm.assert_index_equal(result, expected)
+
+
+def test_xarray_coerce_unit():
+ # GH44053
+ xr = pytest.importorskip("xarray")
+
+ arr = xr.DataArray([1, 2, 3])
+ result = pd.to_datetime(arr, unit="ns")
+ expected = DatetimeIndex(
+ [
+ "1970-01-01 00:00:00.000000001",
+ "1970-01-01 00:00:00.000000002",
+ "1970-01-01 00:00:00.000000003",
+ ],
+ dtype="datetime64[ns]",
+ freq=None,
+ )
+ tm.assert_index_equal(result, expected)
diff --git a/pandas/tests/tools/test_to_datetime.py b/pandas/tests/tools/test_to_datetime.py
index e5dfae169453f..83b4949bc32cd 100644
--- a/pandas/tests/tools/test_to_datetime.py
+++ b/pandas/tests/tools/test_to_datetime.py
@@ -3540,25 +3540,6 @@ def test_empty_string_datetime_coerce__unit():
tm.assert_index_equal(expected, result)
-@td.skip_if_no("xarray")
-def test_xarray_coerce_unit():
- # GH44053
- import xarray as xr
-
- arr = xr.DataArray([1, 2, 3])
- result = to_datetime(arr, unit="ns")
- expected = DatetimeIndex(
- [
- "1970-01-01 00:00:00.000000001",
- "1970-01-01 00:00:00.000000002",
- "1970-01-01 00:00:00.000000003",
- ],
- dtype="datetime64[ns]",
- freq=None,
- )
- tm.assert_index_equal(result, expected)
-
-
@pytest.mark.parametrize("cache", [True, False])
def test_to_datetime_monotonic_increasing_index(cache):
# GH28238
diff --git a/pandas/tests/window/test_online.py b/pandas/tests/window/test_online.py
index 5974de0ae4009..8c4fb1fe6872b 100644
--- a/pandas/tests/window/test_online.py
+++ b/pandas/tests/window/test_online.py
@@ -6,7 +6,6 @@
is_platform_mac,
is_platform_windows,
)
-import pandas.util._test_decorators as td
from pandas import (
DataFrame,
@@ -24,8 +23,9 @@
),
]
+pytest.importorskip("numba")
+
-@td.skip_if_no("numba")
@pytest.mark.filterwarnings("ignore")
# Filter warnings when parallel=True and the function can't be parallelized by Numba
class TestEWM:
diff --git a/pandas/util/_test_decorators.py b/pandas/util/_test_decorators.py
index 59f30cd4e6e8f..03011a1ffe622 100644
--- a/pandas/util/_test_decorators.py
+++ b/pandas/util/_test_decorators.py
@@ -82,15 +82,6 @@ def safe_import(mod_name: str, min_version: str | None = None):
return False
-def _skip_if_no_mpl() -> bool:
- mod = safe_import("matplotlib")
- if mod:
- mod.use("Agg")
- return False
- else:
- return True
-
-
def _skip_if_not_us_locale() -> bool:
lang, _ = locale.getlocale()
if lang != "en_US":
@@ -136,9 +127,10 @@ def skip_if_no(package: str, min_version: str | None = None) -> pytest.MarkDecor
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
+ The mark can be used as either a decorator for a test class or to be
applied to parameters in pytest.mark.parametrize calls or parametrized
- fixtures.
+ fixtures. Use pytest.importorskip if an imported moduled is later needed
+ or for test functions.
If the import and version check are unsuccessful, then the test function
(or test case when used in conjunction with parametrization) will be
@@ -165,10 +157,9 @@ def skip_if_no(package: str, min_version: str | None = None) -> pytest.MarkDecor
)
-skip_if_no_mpl = pytest.mark.skipif(
- _skip_if_no_mpl(), reason="Missing matplotlib dependency"
+skip_if_mpl = pytest.mark.skipif(
+ bool(safe_import("matplotlib")), reason="matplotlib is present"
)
-skip_if_mpl = pytest.mark.skipif(not _skip_if_no_mpl(), reason="matplotlib is present")
skip_if_32bit = pytest.mark.skipif(not IS64, reason="skipping for 32 bit")
skip_if_windows = pytest.mark.skipif(is_platform_windows(), reason="Running on Windows")
skip_if_not_us_locale = pytest.mark.skipif(