Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/dask/_compatibility.py: 37%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from __future__ import annotations
3import importlib
4import sys
5import types
6import warnings
7from typing import Literal
9if sys.version_info >= (3, 12):
10 import importlib.metadata as importlib_metadata
11else:
12 import importlib_metadata
13from packaging.version import Version
15PY_VERSION = Version(".".join(map(str, sys.version_info[:3])))
17EMSCRIPTEN = sys.platform == "emscripten"
19LINUX = sys.platform == "linux"
20MACOS = sys.platform == "darwin"
21WINDOWS = sys.platform == "win32"
24VERSIONS = {
25 "numpy": "1.21.0",
26 "pandas": "2.0.0",
27 "bokeh": "3.1.0",
28 "jinja2": "2.10.3",
29 "pyarrow": "14.0.1",
30 "lz4": "4.3.2",
31}
33# A mapping from import name to package name (on PyPI) for packages where
34# these two names are different.
36INSTALL_MAPPING = {
37 "sqlalchemy": "SQLAlchemy",
38 "tables": "pytables",
39}
42def get_version(module: types.ModuleType) -> str:
43 try:
44 return module.__version__
45 except AttributeError as e: # pragma: no cover
46 raise ImportError(f"Can't determine version for {module.__name__}") from e
49def import_optional_dependency(
50 name: str,
51 extra: str = "",
52 min_version: str | None = None,
53 *,
54 errors: Literal["raise", "warn", "ignore"] = "raise",
55) -> types.ModuleType | None:
56 """
57 Import an optional dependency.
59 By default, if a dependency is missing an ImportError with a nice
60 message will be raised. If a dependency is present, but too old,
61 we raise.
63 Parameters
64 ----------
65 name : str
66 The module name.
67 extra : str
68 Additional text to include in the ImportError message.
69 errors : str {'raise', 'warn', 'ignore'}
70 What to do when a dependency is not found or its version is too old.
72 * raise : Raise an ImportError
73 * warn : Only applicable when a module's version is to old.
74 Warns that the version is too old and returns None
75 * ignore: If the module is not installed, return None, otherwise,
76 return the module, even if the version is too old.
77 It's expected that users validate the version locally when
78 using ``errors="ignore"`` (see. ``io/html.py``)
79 min_version : str, default None
80 Specify a minimum version that is different from the global pandas
81 minimum version required.
82 Returns
83 -------
84 maybe_module : Optional[ModuleType]
85 The imported module, when found and the version is correct.
86 None is returned when the package is not found and `errors`
87 is False, or when the package's version is too old and `errors`
88 is ``'warn'`` or ``'ignore'``.
89 """
90 assert errors in {"warn", "raise", "ignore"}
92 package_name = INSTALL_MAPPING.get(name)
93 install_name = package_name if package_name is not None else name
95 msg = (
96 f"Missing optional dependency '{install_name}'. {extra} "
97 f"Use pip or conda to install {install_name}."
98 )
99 try:
100 # NOTE: Use `importlib_metadata.distribution` check to differentiate
101 # between something that's importable (e.g. a directory named `xarray`)
102 # and the library we want to check for (i.e. the `xarray`` library)
103 importlib_metadata.distribution(name)
104 module = importlib.import_module(name)
105 except (importlib_metadata.PackageNotFoundError, ImportError) as err:
106 if errors == "raise":
107 raise ImportError(msg) from err
108 return None
110 # Handle submodules: if we have submodule, grab parent module from sys.modules
111 parent = name.split(".")[0]
112 if parent != name:
113 install_name = parent
114 module_to_get = sys.modules[install_name]
115 else:
116 module_to_get = module
117 minimum_version = min_version if min_version is not None else VERSIONS.get(parent)
118 if minimum_version:
119 version = get_version(module_to_get)
120 if version and Version(version) < Version(minimum_version):
121 msg = (
122 f"Dask requires version '{minimum_version}' or newer of '{parent}' "
123 f"(version '{version}' currently installed)."
124 )
125 if errors == "warn":
126 warnings.warn(msg, UserWarning)
127 return None
128 elif errors == "raise":
129 raise ImportError(msg)
130 else:
131 return None
133 return module