5
5
import distutils .dist
6
6
import os
7
7
import os .path
8
+ import platform
8
9
import sys
9
10
import sysconfig
11
+ import warnings
10
12
11
13
import installer
12
14
import installer .destinations
15
17
from installer ._compat .typing import TYPE_CHECKING
16
18
17
19
if TYPE_CHECKING :
20
+ from email .message import Message
18
21
from typing import Any , Dict , List , Optional , Sequence , Union
19
22
20
23
from installer ._compat .typing import Text
@@ -51,6 +54,12 @@ def main_parser(): # type: () -> argparse.ArgumentParser
51
54
action = "store_false" ,
52
55
help = "disable 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
@@ -100,6 +109,47 @@ def generate_bytecode(record_dict, scheme_dict, levels, stripdir=None):
100
109
_compile_records (record_dict , scheme_dict , compile_args )
101
110
102
111
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
+
103
153
def main (cli_args , program = None ):
104
154
# type: (Sequence[str], Optional[str]) -> None
105
155
"""Process arguments and perform the install."""
@@ -111,6 +161,13 @@ def main(cli_args, program=None):
111
161
bytecode_stripdir = None # type: Optional[str]
112
162
113
163
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
+
114
171
scheme_dict = get_scheme_dict (source .distribution )
115
172
116
173
# prepend DESTDIR to scheme paths
0 commit comments