Skip to content

Commit 52c59d9

Browse files
committed
main: add compability checks
Signed-off-by: Filipe Laíns <[email protected]>
1 parent 0c87b9c commit 52c59d9

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ repos:
1919
exclude: docs/.*|tests/.*|noxfile.py
2020
- id: mypy
2121
name: mypy (Python 2)
22-
additional_dependencies: ["pathlib2"]
22+
additional_dependencies: ["pathlib2", "build<0.6.0", "packaging<21.0"]
2323
exclude: docs/.*|tests/.*|tools/.*|noxfile.py
2424
args: ["-2"]
2525

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ requires-python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
1313
requires = [
1414
"configparser >= 3.5; python_version < '3'",
1515
"importlib-resources; python_version < '3.7'",
16+
"build >= 0.2.0", # not a hard runtime requirement -- we can softfail
17+
"packaging", # not a hard runtime requirement -- we can softfail
1618
]
1719

1820
[tool.flit.scripts]

src/installer/__main__.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import distutils.dist
66
import os
77
import os.path
8+
import platform
89
import sys
910
import sysconfig
11+
import warnings
1012

1113
import installer
1214
import installer.destinations
@@ -15,6 +17,7 @@
1517
from installer._compat.typing import TYPE_CHECKING
1618

1719
if TYPE_CHECKING:
20+
from email.message import Message
1821
from typing import Any, Dict, List, Optional, Sequence, Union
1922

2023
from installer._compat.typing import Text
@@ -51,6 +54,12 @@ def main_parser(): # type: () -> argparse.ArgumentParser
5154
action="store_false",
5255
help="disable optimization",
5356
)
57+
parser.add_argument(
58+
"--skip-dependency-check",
59+
"-s",
60+
action="store_true",
61+
help="don't check if the wheel dependencies are met",
62+
)
5463
return parser
5564

5665

@@ -100,6 +109,47 @@ def generate_bytecode(record_dict, scheme_dict, levels, stripdir=None):
100109
_compile_records(record_dict, scheme_dict, compile_args)
101110

102111

112+
def check_python_version(metadata): # type: (Message) -> None
113+
"""Check if the project support the current interpreter."""
114+
try:
115+
import packaging.specifiers
116+
except ImportError:
117+
warnings.warn(
118+
"'packaging' module not available, "
119+
"skiping python version compatibility check"
120+
)
121+
122+
requirement = metadata["Requires-Python"]
123+
if not requirement:
124+
return
125+
126+
versions = requirement.split(",")
127+
for version in versions:
128+
specifier = packaging.specifiers.Specifier(version)
129+
if platform.python_version() not in specifier:
130+
raise RuntimeError(
131+
"Incompatible python version, needed: {}".format(version)
132+
)
133+
134+
135+
def check_dependencies(metadata): # type: (Message) -> None
136+
"""Check if the project dependencies are met."""
137+
try:
138+
import build
139+
except ImportError:
140+
warnings.warn("'build' module not available, skiping dependency check")
141+
142+
missing = {
143+
unmet
144+
for requirement in metadata.get_all("Requires-Dist") or []
145+
for unmet_list in build.check_dependency(requirement)
146+
for unmet in unmet_list
147+
}
148+
if missing:
149+
missing_list = ", ".join(missing)
150+
raise RuntimeError("Missing requirements: {}".format(missing_list))
151+
152+
103153
def main(cli_args, program=None):
104154
# type: (Sequence[str], Optional[str]) -> None
105155
"""Process arguments and perform the install."""
@@ -111,6 +161,13 @@ def main(cli_args, program=None):
111161
bytecode_stripdir = None # type: Optional[str]
112162

113163
with installer.sources.WheelFile.open(args.wheel) as source:
164+
# compability checks
165+
metadata_contents = source.read_dist_info("METADATA")
166+
metadata = installer.utils.parse_metadata_file(metadata_contents)
167+
check_python_version(metadata)
168+
if not args.skip_dependency_check:
169+
check_dependencies(metadata)
170+
114171
scheme_dict = get_scheme_dict(source.distribution)
115172

116173
# prepend DESTDIR to scheme paths

0 commit comments

Comments
 (0)