5
5
import distutils .dist
6
6
import os
7
7
import os .path
8
+ import platform
8
9
import py_compile
9
10
import sys
10
11
import sysconfig
12
+ import warnings
11
13
12
14
import installer
13
15
import installer .destinations
16
18
from installer ._compat .typing import TYPE_CHECKING
17
19
18
20
if TYPE_CHECKING :
21
+ from email .message import Message
19
22
from typing import Any , Dict , List , Optional , Sequence , Union
20
23
21
24
from installer ._compat .typing import Text
@@ -51,6 +54,12 @@ def main_parser(): # type: () -> argparse.ArgumentParser
51
54
action = "store_true" ,
52
55
help = "enable optimization" ,
53
56
)
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
+ )
54
63
return parser
55
64
56
65
@@ -102,6 +111,47 @@ def generate_bytecode(record_dict, scheme_dict, levels, stripdir=None):
102
111
_compile_records (record_dict , scheme_dict , compile_args )
103
112
104
113
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
+
105
155
def main (cli_args , program = None ):
106
156
# type: (Sequence[str], Optional[str]) -> None
107
157
"""Process arguments and perform the install."""
@@ -113,6 +163,13 @@ def main(cli_args, program=None):
113
163
bytecode_stripdir = None # type: Optional[str]
114
164
115
165
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
+
116
173
scheme_dict = get_scheme_dict (source .distribution )
117
174
118
175
# prepend DESTDIR to scheme paths
0 commit comments