You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
93 lines
2.3 KiB
93 lines
2.3 KiB
9 months ago
|
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
|
||
|
|
||
|
import importlib.metadata
|
||
|
import itertools
|
||
|
import string
|
||
|
from typing import Dict, List, Tuple
|
||
|
|
||
|
|
||
|
def _tuple_from_text(version: str) -> Tuple:
|
||
|
text_parts = version.split(".")
|
||
|
int_parts = []
|
||
|
for text_part in text_parts:
|
||
|
digit_prefix = "".join(
|
||
|
itertools.takewhile(lambda x: x in string.digits, text_part)
|
||
|
)
|
||
|
try:
|
||
|
int_parts.append(int(digit_prefix))
|
||
|
except Exception:
|
||
|
break
|
||
|
return tuple(int_parts)
|
||
|
|
||
|
|
||
|
def _version_check(
|
||
|
requirement: str,
|
||
|
) -> bool:
|
||
|
"""Is the requirement fulfilled?
|
||
|
|
||
|
The requirement must be of the form
|
||
|
|
||
|
package>=version
|
||
|
"""
|
||
|
package, minimum = requirement.split(">=")
|
||
|
try:
|
||
|
version = importlib.metadata.version(package)
|
||
|
except Exception:
|
||
|
return False
|
||
|
t_version = _tuple_from_text(version)
|
||
|
t_minimum = _tuple_from_text(minimum)
|
||
|
if t_version < t_minimum:
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
|
||
|
_cache: Dict[str, bool] = {}
|
||
|
|
||
|
|
||
|
def have(feature: str) -> bool:
|
||
|
"""Is *feature* available?
|
||
|
|
||
|
This tests if all optional packages needed for the
|
||
|
feature are available and recent enough.
|
||
|
|
||
|
Returns ``True`` if the feature is available,
|
||
|
and ``False`` if it is not or if metadata is
|
||
|
missing.
|
||
|
"""
|
||
|
value = _cache.get(feature)
|
||
|
if value is not None:
|
||
|
return value
|
||
|
requirements = _requirements.get(feature)
|
||
|
if requirements is None:
|
||
|
# we make a cache entry here for consistency not performance
|
||
|
_cache[feature] = False
|
||
|
return False
|
||
|
ok = True
|
||
|
for requirement in requirements:
|
||
|
if not _version_check(requirement):
|
||
|
ok = False
|
||
|
break
|
||
|
_cache[feature] = ok
|
||
|
return ok
|
||
|
|
||
|
|
||
|
def force(feature: str, enabled: bool) -> None:
|
||
|
"""Force the status of *feature* to be *enabled*.
|
||
|
|
||
|
This method is provided as a workaround for any cases
|
||
|
where importlib.metadata is ineffective, or for testing.
|
||
|
"""
|
||
|
_cache[feature] = enabled
|
||
|
|
||
|
|
||
|
_requirements: Dict[str, List[str]] = {
|
||
|
### BEGIN generated requirements
|
||
|
"dnssec": ["cryptography>=41"],
|
||
|
"doh": ["httpcore>=1.0.0", "httpx>=0.26.0", "h2>=4.1.0"],
|
||
|
"doq": ["aioquic>=0.9.25"],
|
||
|
"idna": ["idna>=3.6"],
|
||
|
"trio": ["trio>=0.23"],
|
||
|
"wmi": ["wmi>=1.5.1"],
|
||
|
### END generated requirements
|
||
|
}
|