Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/dask/_compatibility.py: 34%

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

56 statements  

1from __future__ import annotations 

2 

3import importlib 

4import sys 

5import types 

6import warnings 

7from typing import Literal 

8 

9if sys.version_info >= (3, 12): 

10 import importlib.metadata as importlib_metadata 

11else: 

12 import importlib_metadata 

13from packaging.version import Version 

14 

15PY_VERSION = Version(".".join(map(str, sys.version_info[:3]))) 

16 

17EMSCRIPTEN = sys.platform == "emscripten" 

18 

19LINUX = sys.platform == "linux" 

20MACOS = sys.platform == "darwin" 

21WINDOWS = sys.platform == "win32" 

22 

23 

24def entry_points(group=None): 

25 warnings.warn( 

26 "`dask._compatibility.entry_points` has been replaced by `importlib_metadata.entry_points` and will be removed " 

27 "in a future version. Please use `importlib_metadata.entry_points` instead.", 

28 DeprecationWarning, 

29 stacklevel=2, 

30 ) 

31 return importlib_metadata.entry_points(group=group) 

32 

33 

34VERSIONS = { 

35 "numpy": "1.21.0", 

36 "pandas": "2.0.0", 

37 "bokeh": "3.1.0", 

38 "jinja2": "2.10.3", 

39 "pyarrow": "14.0.1", 

40 "lz4": "4.3.2", 

41} 

42 

43# A mapping from import name to package name (on PyPI) for packages where 

44# these two names are different. 

45 

46INSTALL_MAPPING = { 

47 "sqlalchemy": "SQLAlchemy", 

48 "tables": "pytables", 

49} 

50 

51 

52def get_version(module: types.ModuleType) -> str: 

53 version = getattr(module, "__version__", None) 

54 

55 if version is None: 

56 raise ImportError(f"Can't determine version for {module.__name__}") 

57 if module.__name__ == "psycopg2": 

58 # psycopg2 appends " (dt dec pq3 ext lo64)" to it's version 

59 version = version.split()[0] 

60 return version 

61 

62 

63def import_optional_dependency( 

64 name: str, 

65 extra: str = "", 

66 min_version: str | None = None, 

67 *, 

68 errors: Literal["raise", "warn", "ignore"] = "raise", 

69) -> types.ModuleType | None: 

70 """ 

71 Import an optional dependency. 

72 

73 By default, if a dependency is missing an ImportError with a nice 

74 message will be raised. If a dependency is present, but too old, 

75 we raise. 

76 

77 Parameters 

78 ---------- 

79 name : str 

80 The module name. 

81 extra : str 

82 Additional text to include in the ImportError message. 

83 errors : str {'raise', 'warn', 'ignore'} 

84 What to do when a dependency is not found or its version is too old. 

85 

86 * raise : Raise an ImportError 

87 * warn : Only applicable when a module's version is to old. 

88 Warns that the version is too old and returns None 

89 * ignore: If the module is not installed, return None, otherwise, 

90 return the module, even if the version is too old. 

91 It's expected that users validate the version locally when 

92 using ``errors="ignore"`` (see. ``io/html.py``) 

93 min_version : str, default None 

94 Specify a minimum version that is different from the global pandas 

95 minimum version required. 

96 Returns 

97 ------- 

98 maybe_module : Optional[ModuleType] 

99 The imported module, when found and the version is correct. 

100 None is returned when the package is not found and `errors` 

101 is False, or when the package's version is too old and `errors` 

102 is ``'warn'`` or ``'ignore'``. 

103 """ 

104 assert errors in {"warn", "raise", "ignore"} 

105 

106 package_name = INSTALL_MAPPING.get(name) 

107 install_name = package_name if package_name is not None else name 

108 

109 msg = ( 

110 f"Missing optional dependency '{install_name}'. {extra} " 

111 f"Use pip or conda to install {install_name}." 

112 ) 

113 try: 

114 # NOTE: Use `importlib_metadata.distribution` check to differentiate 

115 # between something that's importable (e.g. a directory named `xarray`) 

116 # and the library we want to check for (i.e. the `xarray`` library) 

117 importlib_metadata.distribution(name) 

118 module = importlib.import_module(name) 

119 except (importlib_metadata.PackageNotFoundError, ImportError) as err: 

120 if errors == "raise": 

121 raise ImportError(msg) from err 

122 return None 

123 

124 # Handle submodules: if we have submodule, grab parent module from sys.modules 

125 parent = name.split(".")[0] 

126 if parent != name: 

127 install_name = parent 

128 module_to_get = sys.modules[install_name] 

129 else: 

130 module_to_get = module 

131 minimum_version = min_version if min_version is not None else VERSIONS.get(parent) 

132 if minimum_version: 

133 version = get_version(module_to_get) 

134 if version and Version(version) < Version(minimum_version): 

135 msg = ( 

136 f"Dask requires version '{minimum_version}' or newer of '{parent}' " 

137 f"(version '{version}' currently installed)." 

138 ) 

139 if errors == "warn": 

140 warnings.warn(msg, UserWarning) 

141 return None 

142 elif errors == "raise": 

143 raise ImportError(msg) 

144 else: 

145 return None 

146 

147 return module