Skip to content

Commit 268d9e2

Browse files
committed
main: add compability checks
Signed-off-by: Filipe Laíns <[email protected]>
1 parent e32e93d commit 268d9e2

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", "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't softfail
17+
"packaging", # not a hard runtime requirement -- we can't 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,9 +5,11 @@
55
import distutils.dist
66
import os
77
import os.path
8+
import platform
89
import py_compile
910
import sys
1011
import sysconfig
12+
import warnings
1113

1214
import installer
1315
import installer.destinations
@@ -16,6 +18,7 @@
1618
from installer._compat.typing import TYPE_CHECKING
1719

1820
if TYPE_CHECKING:
21+
from email.message import Message
1922
from typing import Any, Dict, List, Optional, Sequence, Union
2023

2124
from installer._compat.typing import Text
@@ -51,6 +54,12 @@ def main_parser(): # type: () -> argparse.ArgumentParser
5154
action="store_true",
5255
help="enable 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

@@ -102,6 +111,47 @@ def generate_bytecode(record_dict, scheme_dict, levels, stripdir=None):
102111
_compile_records(record_dict, scheme_dict, compile_args)
103112

104113

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

115165
with installer.sources.WheelFile.open(args.wheel) as source:
166+
# compability checks
167+
metadata_contents = source.read_dist_info("METADATA")
168+
metadata = installer.utils.parse_metadata_file(metadata_contents)
169+
check_python_version(metadata)
170+
if not args.skip_dependency_check:
171+
check_dependencies(metadata)
172+
116173
scheme_dict = get_scheme_dict(source.distribution)
117174

118175
# prepend DESTDIR to scheme paths

0 commit comments

Comments
 (0)