Skip to content

Commit d9ae308

Browse files
authored
CLN: Simplify optional dependency (#39083)
1 parent 2ce81ae commit d9ae308

File tree

10 files changed

+31
-64
lines changed

10 files changed

+31
-64
lines changed

pandas/compat/_optional.py

+15-16
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,7 @@ def _get_version(module: types.ModuleType) -> str:
6262
def import_optional_dependency(
6363
name: str,
6464
extra: str = "",
65-
raise_on_missing: bool = True,
66-
on_version: str = "raise",
65+
errors: str = "raise",
6766
min_version: Optional[str] = None,
6867
):
6968
"""
@@ -79,29 +78,30 @@ def import_optional_dependency(
7978
The module name.
8079
extra : str
8180
Additional text to include in the ImportError message.
82-
raise_on_missing : bool, default True
83-
Whether to raise if the optional dependency is not found.
84-
When False and the module is not present, None is returned.
85-
on_version : str {'raise', 'warn'}
86-
What to do when a dependency's version is too old.
81+
errors : str {'raise', 'warn', 'ignore'}
82+
What to do when a dependency is not found or its version is too old.
8783
8884
* raise : Raise an ImportError
89-
* warn : Warn that the version is too old. Returns None
90-
* ignore: Return the module, even if the version is too old.
85+
* warn : Only applicable when a module's version is to old.
86+
Warns that the version is too old and returns None
87+
* ignore: If the module is not installed, return None, otherwise,
88+
return the module, even if the version is too old.
9189
It's expected that users validate the version locally when
92-
using ``on_version="ignore"`` (see. ``io/html.py``)
90+
using ``errors="ignore"`` (see. ``io/html.py``)
9391
min_version : str, default None
9492
Specify a minimum version that is different from the global pandas
9593
minimum version required.
9694
Returns
9795
-------
9896
maybe_module : Optional[ModuleType]
9997
The imported module, when found and the version is correct.
100-
None is returned when the package is not found and `raise_on_missing`
101-
is False, or when the package's version is too old and `on_version`
98+
None is returned when the package is not found and `errors`
99+
is False, or when the package's version is too old and `errors`
102100
is ``'warn'``.
103101
"""
104102

103+
assert errors in {"warn", "raise", "ignore"}
104+
105105
package_name = INSTALL_MAPPING.get(name)
106106
install_name = package_name if package_name is not None else name
107107

@@ -112,7 +112,7 @@ def import_optional_dependency(
112112
try:
113113
module = importlib.import_module(name)
114114
except ImportError:
115-
if raise_on_missing:
115+
if errors == "raise":
116116
raise ImportError(msg) from None
117117
else:
118118
return None
@@ -128,15 +128,14 @@ def import_optional_dependency(
128128
if minimum_version:
129129
version = _get_version(module_to_get)
130130
if distutils.version.LooseVersion(version) < minimum_version:
131-
assert on_version in {"warn", "raise", "ignore"}
132131
msg = (
133132
f"Pandas requires version '{minimum_version}' or newer of '{parent}' "
134133
f"(version '{version}' currently installed)."
135134
)
136-
if on_version == "warn":
135+
if errors == "warn":
137136
warnings.warn(msg, UserWarning)
138137
return None
139-
elif on_version == "raise":
138+
elif errors == "raise":
140139
raise ImportError(msg)
141140

142141
return module

pandas/core/computation/check.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from pandas.compat._optional import import_optional_dependency
22

3-
ne = import_optional_dependency("numexpr", raise_on_missing=False, on_version="warn")
3+
ne = import_optional_dependency("numexpr", errors="warn")
44
NUMEXPR_INSTALLED = ne is not None
55
if NUMEXPR_INSTALLED:
66
NUMEXPR_VERSION = ne.__version__

pandas/core/nanops.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
from pandas.core.construction import extract_array
3636

37-
bn = import_optional_dependency("bottleneck", raise_on_missing=False, on_version="warn")
37+
bn = import_optional_dependency("bottleneck", errors="warn")
3838
_BOTTLENECK_INSTALLED = bn is not None
3939
_USE_BOTTLENECK = False
4040

pandas/io/excel/_base.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -1043,12 +1043,7 @@ def __init__(
10431043
self._io = stringify_path(path_or_buffer)
10441044

10451045
# Determine xlrd version if installed
1046-
if (
1047-
import_optional_dependency(
1048-
"xlrd", raise_on_missing=False, on_version="ignore"
1049-
)
1050-
is None
1051-
):
1046+
if import_optional_dependency("xlrd", errors="ignore") is None:
10521047
xlrd_version = None
10531048
else:
10541049
import xlrd

pandas/io/excel/_util.py

+3-11
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,14 @@ def get_default_engine(ext, mode="reader"):
5757
assert mode in ["reader", "writer"]
5858
if mode == "writer":
5959
# Prefer xlsxwriter over openpyxl if installed
60-
xlsxwriter = import_optional_dependency(
61-
"xlsxwriter", raise_on_missing=False, on_version="warn"
62-
)
60+
xlsxwriter = import_optional_dependency("xlsxwriter", errors="warn")
6361
if xlsxwriter:
6462
_default_writers["xlsx"] = "xlsxwriter"
6563
return _default_writers[ext]
6664
else:
6765
if (
68-
import_optional_dependency(
69-
"openpyxl", raise_on_missing=False, on_version="ignore"
70-
)
71-
is None
72-
and import_optional_dependency(
73-
"xlrd", raise_on_missing=False, on_version="ignore"
74-
)
75-
is not None
66+
import_optional_dependency("openpyxl", errors="ignore") is None
67+
and import_optional_dependency("xlrd", errors="ignore") is not None
7668
):
7769
# if no openpyxl but xlrd installed, return xlrd
7870
# the version is handled elsewhere

pandas/io/html.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,13 @@ def _importers():
3939
return
4040

4141
global _HAS_BS4, _HAS_LXML, _HAS_HTML5LIB
42-
bs4 = import_optional_dependency("bs4", raise_on_missing=False, on_version="ignore")
42+
bs4 = import_optional_dependency("bs4", errors="ignore")
4343
_HAS_BS4 = bs4 is not None
4444

45-
lxml = import_optional_dependency(
46-
"lxml.etree", raise_on_missing=False, on_version="ignore"
47-
)
45+
lxml = import_optional_dependency("lxml.etree", errors="ignore")
4846
_HAS_LXML = lxml is not None
4947

50-
html5lib = import_optional_dependency(
51-
"html5lib", raise_on_missing=False, on_version="ignore"
52-
)
48+
html5lib = import_optional_dependency("html5lib", errors="ignore")
5349
_HAS_HTML5LIB = html5lib is not None
5450

5551
_IMPORTS = True

pandas/tests/io/excel/__init__.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@
2424
]
2525

2626

27-
if (
28-
import_optional_dependency("xlrd", raise_on_missing=False, on_version="ignore")
29-
is None
30-
):
27+
if import_optional_dependency("xlrd", errors="ignore") is None:
3128
xlrd_version = None
3229
else:
3330
import xlrd

pandas/tests/io/excel/test_xlrd.py

+2-12
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,7 @@ def test_excel_table_sheet_by_index(datapath, read_ext):
5252
def test_excel_file_warning_with_xlsx_file(datapath):
5353
# GH 29375
5454
path = datapath("io", "data", "excel", "test1.xlsx")
55-
has_openpyxl = (
56-
import_optional_dependency(
57-
"openpyxl", raise_on_missing=False, on_version="ignore"
58-
)
59-
is not None
60-
)
55+
has_openpyxl = import_optional_dependency("openpyxl", errors="ignore") is not None
6156
if not has_openpyxl:
6257
with tm.assert_produces_warning(
6358
FutureWarning,
@@ -73,12 +68,7 @@ def test_excel_file_warning_with_xlsx_file(datapath):
7368
def test_read_excel_warning_with_xlsx_file(datapath):
7469
# GH 29375
7570
path = datapath("io", "data", "excel", "test1.xlsx")
76-
has_openpyxl = (
77-
import_optional_dependency(
78-
"openpyxl", raise_on_missing=False, on_version="ignore"
79-
)
80-
is not None
81-
)
71+
has_openpyxl = import_optional_dependency("openpyxl", errors="ignore") is not None
8272
if not has_openpyxl:
8373
if xlrd_version >= "2":
8474
with pytest.raises(

pandas/tests/test_optional_dependency.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_import_optional():
1313
with pytest.raises(ImportError, match=match):
1414
import_optional_dependency("notapackage")
1515

16-
result = import_optional_dependency("notapackage", raise_on_missing=False)
16+
result = import_optional_dependency("notapackage", errors="ignore")
1717
assert result is None
1818

1919

@@ -38,7 +38,7 @@ def test_bad_version(monkeypatch):
3838
assert result is module
3939

4040
with tm.assert_produces_warning(UserWarning):
41-
result = import_optional_dependency("fakemodule", on_version="warn")
41+
result = import_optional_dependency("fakemodule", errors="warn")
4242
assert result is None
4343

4444
module.__version__ = "1.0.0" # exact match is OK
@@ -63,7 +63,7 @@ def test_submodule(monkeypatch):
6363
import_optional_dependency("fakemodule.submodule")
6464

6565
with tm.assert_produces_warning(UserWarning):
66-
result = import_optional_dependency("fakemodule.submodule", on_version="warn")
66+
result = import_optional_dependency("fakemodule.submodule", errors="warn")
6767
assert result is None
6868

6969
module.__version__ = "1.0.0" # exact match is OK

pandas/util/_print_versions.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ def _get_dependency_info() -> Dict[str, JSONSerializable]:
8080

8181
result: Dict[str, JSONSerializable] = {}
8282
for modname in deps:
83-
mod = import_optional_dependency(
84-
modname, raise_on_missing=False, on_version="ignore"
85-
)
83+
mod = import_optional_dependency(modname, errors="ignore")
8684
result[modname] = _get_version(mod) if mod else None
8785
return result
8886

0 commit comments

Comments
 (0)