-
Notifications
You must be signed in to change notification settings - Fork 50
Description
Problem description
In the previous pkg_resources
package, this issue can be solved with the following code (link):
import pkg_resources
from pkg_resources import DistributionNotFound, VersionConflict
# dependencies can be any iterable with strings,
# e.g. file line-by-line iterator
dependencies = [
'Werkzeug>=0.6.1',
'Flask>=0.9',
]
# here, if a dependency is not met, a DistributionNotFound or VersionConflict
# exception is thrown.
pkg_resources.require(dependencies)
However, pkg_resources
has been deprecated, so this method is not recommended for continued use. In the migration guide provided in the importlib_metadata
documentation, there is no new interface that is completely equivalent to pkg_resources.require
. Therefore, we need to use the import_metadata
library (native in Python 3.8 or higher) and the packaging
library to achieve this functionality.
I have currently implemented a version, the code is here: https://github.com/HansBug/hbutils/blob/main/hbutils/system/python/package.py#L202, where the most critical part is the _yield_reqs_to_install
function, which checks a requirement and its sub-requirements included in its extra one by one, and enumerates the unsatisfied requirements. By calling this iterator function, the check of whether a requirement is satisfied can be achieved. This is the core code of the function:
def _yield_reqs_to_install(req: Requirement, current_extra: str = ''):
if req.marker and not req.marker.evaluate({'extra': current_extra}):
return
try:
version = importlib_metadata.distribution(req.name).version
except importlib_metadata.PackageNotFoundError: # req not installed
yield req
else:
if req.specifier.contains(version):
for child_req in (importlib_metadata.metadata(req.name).get_all('Requires-Dist') or []):
child_req_obj = Requirement(child_req)
need_check, ext = False, None
for extra in req.extras:
if child_req_obj.marker and child_req_obj.marker.evaluate({'extra': extra}):
need_check = True
ext = extra
break
if need_check: # check for extra reqs
yield from _yield_reqs_to_install(child_req_obj, ext)
else: # main version not match
yield req
def check_reqs(reqs: List[str]) -> bool:
"""
Overview:
Check if the given requirements are all satisfied.
:param reqs: List of requirements.
:return satisfied: All the requirements in ``reqs`` satisfied or not.
Examples::
>>> from hbutils.system import check_reqs
>>> check_reqs(['pip>=20.0'])
True
>>> check_reqs(['pip~=19.2'])
False
>>> check_reqs(['pip>=20.0', 'setuptools>=50.0'])
True
.. note::
If a requirement's marker is not satisfied in this environment,
**it will be ignored** instead of return ``False``.
"""
return all(map(lambda x: _check_req(Requirement(x)), reqs))
Of course, if you need this function immediately, you can simply
pip install hbutils>=0.9.0
and then
from hbutils.system import check_reqs
print(check_reqs(['pip>=20.0']))
print(check_reqs(['pip~=19.2']))
print(check_reqs(['pip>=20.0', 'setuptools>=50.0']))
hbutils
is a universal toolkit library containing various common functions, and the project address is https://github.com/HansBug/hbutils. It will be maintained for a long time.