4949logger = logging .get_logger (__name__ ) # pylint: disable=invalid-name
5050
5151
52- PACKAGE_DISTRIBUTION_MAPPING = importlib .metadata .packages_distributions ()
52+ @functools .cache
53+ def _package_distribution_mapping () -> dict [str , list [str ]]:
54+ return importlib .metadata .packages_distributions ()
5355
5456
5557def _candidate_distribution_names (pkg_name : str ) -> list [str ]:
@@ -61,7 +63,7 @@ def _candidate_distribution_names(pkg_name: str) -> list[str]:
6163 """
6264 # Per PEP 503, underscores and hyphens are equivalent in package names.
6365 normalized_pkg_name = pkg_name .replace ("_" , "-" )
64- distributions = PACKAGE_DISTRIBUTION_MAPPING .get (pkg_name , [])
66+ distributions = _package_distribution_mapping () .get (pkg_name , [])
6567 candidates = [
6668 * (name for name in (normalized_pkg_name , pkg_name ) if name in distributions ),
6769 * distributions ,
@@ -77,21 +79,26 @@ def _is_package_available(pkg_name: str, return_version: bool = False) -> tuple[
7779 package_exists = spec is not None
7880 package_version = "N/A"
7981 if package_exists and return_version :
80- for distribution_name in _candidate_distribution_names (pkg_name ):
81- try :
82- package_version = importlib .metadata .version (distribution_name )
83- break
84- except importlib .metadata .PackageNotFoundError :
85- continue
86- else :
87- # No metadata under any candidate name (editable install without a `dist-info`, for example).
88- # Last resort: importing defeats the lazy imports these checks guard, costing every
89- # `import transformers` the package's whole import tree.
90- package = importlib .import_module (pkg_name )
91- package_version = getattr (package , "__version__" , "N/A" )
92- # No version + no __file__ means a namespace package (PEP 420) shadowing on sys.path, not a real install.
93- if package_version == "N/A" and getattr (package , "__file__" , None ) is None :
94- package_exists = False
82+ try :
83+ # Most packages are distributed under their import name. Try it before building the mapping, which
84+ # stats every file of each distribution without a `top_level.txt`, `torch` >= 2.14 among them
85+ package_version = importlib .metadata .version (pkg_name )
86+ except importlib .metadata .PackageNotFoundError :
87+ for distribution_name in _candidate_distribution_names (pkg_name ):
88+ try :
89+ package_version = importlib .metadata .version (distribution_name )
90+ break
91+ except importlib .metadata .PackageNotFoundError :
92+ continue
93+ else :
94+ # No metadata under any candidate name (editable install without a `dist-info`, for example).
95+ # Last resort: importing defeats the lazy imports these checks guard, costing every
96+ # `import transformers` the package's whole import tree.
97+ package = importlib .import_module (pkg_name )
98+ package_version = getattr (package , "__version__" , "N/A" )
99+ # No version + no __file__ means a namespace package (PEP 420) shadowing on sys.path, not a real install.
100+ if package_version == "N/A" and getattr (package , "__file__" , None ) is None :
101+ package_exists = False
95102 logger .debug (f"Detected { pkg_name } version: { package_version } " )
96103
97104 if return_version :
@@ -1227,7 +1234,7 @@ def is_flash_attn_2_available(kernels_fallback_ok: bool = False) -> bool:
12271234 is_available , flash_attn_version = _is_package_available ("flash_attn" , return_version = True )
12281235 # FA4 is also distributed under "flash_attn", hence we need to check the naming here
12291236 is_available = is_available and "flash-attn" in [
1230- pkg .replace ("_" , "-" ) for pkg in PACKAGE_DISTRIBUTION_MAPPING .get ("flash_attn" , [])
1237+ pkg .replace ("_" , "-" ) for pkg in _package_distribution_mapping () .get ("flash_attn" , [])
12311238 ]
12321239
12331240 # Only allow versions >= 2.3.3 to avoid very old legacy workarounds that are now 2+ years old
@@ -1260,7 +1267,7 @@ def is_flash_attn_3_available(kernels_fallback_ok: bool = False) -> bool:
12601267 is_available = _is_package_available ("flash_attn_interface" )[0 ]
12611268 # Resolving and ensuring the proper name of FA3 being associated
12621269 is_available = is_available and "flash-attn-3" in [
1263- pkg .replace ("_" , "-" ) for pkg in PACKAGE_DISTRIBUTION_MAPPING .get ("flash_attn_interface" , [])
1270+ pkg .replace ("_" , "-" ) for pkg in _package_distribution_mapping () .get ("flash_attn_interface" , [])
12641271 ]
12651272 if is_available and is_torch_cuda_available ():
12661273 return True
@@ -1289,7 +1296,7 @@ def is_flash_attn_4_available() -> bool:
12891296 # NOTE: FA2 seems to distribute the `cute` subdirectory even if only FA2 has been installed
12901297 # -> check for the proper (normalized) distribution name
12911298 is_available = is_available and "flash-attn-4" in [
1292- pkg .replace ("_" , "-" ) for pkg in PACKAGE_DISTRIBUTION_MAPPING .get ("flash_attn" , [])
1299+ pkg .replace ("_" , "-" ) for pkg in _package_distribution_mapping () .get ("flash_attn" , [])
12931300 ]
12941301
12951302 return is_available and is_torch_cuda_available ()
@@ -1300,7 +1307,7 @@ def is_flash_attn_greater_or_equal(library_version: str) -> bool:
13001307 is_available , flash_attn_version = _is_package_available ("flash_attn" , return_version = True )
13011308 # FA4 is also distributed under "flash_attn", hence we need to check the naming here
13021309 is_available = is_available and "flash-attn" in [
1303- pkg .replace ("_" , "-" ) for pkg in PACKAGE_DISTRIBUTION_MAPPING .get ("flash_attn" , [])
1310+ pkg .replace ("_" , "-" ) for pkg in _package_distribution_mapping () .get ("flash_attn" , [])
13041311 ]
13051312
13061313 if not is_available :
0 commit comments