7
7
import os
8
8
import warnings
9
9
from functools import lru_cache
10
- from importlib .metadata import PackageNotFoundError
10
+ from importlib .metadata import PackageNotFoundError , distribution
11
11
from importlib .metadata import version as _version
12
12
from importlib .util import find_spec
13
13
from types import ModuleType
@@ -128,7 +128,9 @@ def _check_requirement(self) -> None:
128
128
try :
129
129
req = Requirement (self .requirement )
130
130
pkg_version = Version (_version (req .name ))
131
- self .available = req .specifier .contains (pkg_version )
131
+ self .available = req .specifier .contains (pkg_version ) and (
132
+ not req .extras or self ._check_extras_available (req )
133
+ )
132
134
except (PackageNotFoundError , InvalidVersion ) as ex :
133
135
self .available = False
134
136
self .message = f"{ ex .__class__ .__name__ } : { ex } . HINT: Try running `pip install -U { self .requirement !r} `"
@@ -143,6 +145,9 @@ def _check_requirement(self) -> None:
143
145
self .available = module_available (module )
144
146
if self .available :
145
147
self .message = f"Module { module !r} available"
148
+ self .message = (
149
+ f"Requirement { self .requirement !r} not met. HINT: Try running `pip install -U { self .requirement !r} `"
150
+ )
146
151
147
152
def _check_module (self ) -> None :
148
153
assert self .module # noqa: S101; needed for typing
@@ -160,6 +165,34 @@ def _check_available(self) -> None:
160
165
if getattr (self , "available" , True ) and self .module :
161
166
self ._check_module ()
162
167
168
+ def _check_extras_available (self , requirement : Requirement ) -> bool :
169
+ if not requirement .extras :
170
+ return True
171
+
172
+ extra_requirements = self ._get_extra_requirements (requirement )
173
+
174
+ if not extra_requirements :
175
+ # The specified extra is not found in the package metadata
176
+ return False
177
+
178
+ # Verify each extra requirement is installed
179
+ for extra_req in extra_requirements :
180
+ try :
181
+ extra_dist = distribution (extra_req .name )
182
+ extra_installed_version = Version (extra_dist .version )
183
+ if extra_req .specifier and not extra_req .specifier .contains (extra_installed_version ):
184
+ return False
185
+ except importlib .metadata .PackageNotFoundError :
186
+ return False
187
+
188
+ return True
189
+
190
+ def _get_extra_requirements (self , requirement : Requirement ) -> List [Requirement ]:
191
+ dist = distribution (requirement .name )
192
+ # Get the required dependencies for the specified extras
193
+ extra_requirements = dist .metadata .get_all ("Requires-Dist" ) or []
194
+ return [Requirement (r ) for r in extra_requirements if any (extra in r for extra in requirement .extras )]
195
+
163
196
def __bool__ (self ) -> bool :
164
197
"""Format as bool."""
165
198
self ._check_available ()
0 commit comments