1
1
import os
2
2
import re
3
3
from itertools import chain
4
+ from typing import BinaryIO , Dict , Iterator , List , Optional , Sequence , Set , Tuple
4
5
5
6
from click import unstyle
7
+ from click .core import Context
8
+ from pip ._internal .models .format_control import FormatControl
9
+ from pip ._internal .req .req_install import InstallRequirement
10
+ from pip ._vendor .packaging .markers import Marker
6
11
7
12
from .logging import log
8
13
from .utils import (
39
44
strip_comes_from_line_re = re .compile (r" \(line \d+\)$" )
40
45
41
46
42
- def _comes_from_as_string (ireq ) :
47
+ def _comes_from_as_string (ireq : InstallRequirement ) -> str :
43
48
if isinstance (ireq .comes_from , str ):
44
49
return strip_comes_from_line_re .sub ("" , ireq .comes_from )
45
50
return key_from_ireq (ireq .comes_from )
@@ -48,22 +53,22 @@ def _comes_from_as_string(ireq):
48
53
class OutputWriter :
49
54
def __init__ (
50
55
self ,
51
- dst_file ,
52
- click_ctx ,
53
- dry_run ,
54
- emit_header ,
55
- emit_index_url ,
56
- emit_trusted_host ,
57
- annotate ,
58
- generate_hashes ,
59
- default_index_url ,
60
- index_urls ,
61
- trusted_hosts ,
62
- format_control ,
63
- allow_unsafe ,
64
- find_links ,
65
- emit_find_links ,
66
- ):
56
+ dst_file : BinaryIO ,
57
+ click_ctx : Context ,
58
+ dry_run : bool ,
59
+ emit_header : bool ,
60
+ emit_index_url : bool ,
61
+ emit_trusted_host : bool ,
62
+ annotate : bool ,
63
+ generate_hashes : bool ,
64
+ default_index_url : str ,
65
+ index_urls : Sequence [ str ] ,
66
+ trusted_hosts : Sequence [ str ] ,
67
+ format_control : FormatControl ,
68
+ allow_unsafe : bool ,
69
+ find_links : List [ str ] ,
70
+ emit_find_links : bool ,
71
+ ) -> None :
67
72
self .dst_file = dst_file
68
73
self .click_ctx = click_ctx
69
74
self .dry_run = dry_run
@@ -80,10 +85,10 @@ def __init__(
80
85
self .find_links = find_links
81
86
self .emit_find_links = emit_find_links
82
87
83
- def _sort_key (self , ireq ) :
88
+ def _sort_key (self , ireq : InstallRequirement ) -> Tuple [ bool , str ] :
84
89
return (not ireq .editable , str (ireq .req ).lower ())
85
90
86
- def write_header (self ):
91
+ def write_header (self ) -> Iterator [ str ] :
87
92
if self .emit_header :
88
93
yield comment ("#" )
89
94
yield comment ("# This file is autogenerated by pip-compile" )
@@ -95,31 +100,31 @@ def write_header(self):
95
100
yield comment (f"# { compile_command } " )
96
101
yield comment ("#" )
97
102
98
- def write_index_options (self ):
103
+ def write_index_options (self ) -> Iterator [ str ] :
99
104
if self .emit_index_url :
100
105
for index , index_url in enumerate (dedup (self .index_urls )):
101
106
if index_url .rstrip ("/" ) == self .default_index_url :
102
107
continue
103
108
flag = "--index-url" if index == 0 else "--extra-index-url"
104
109
yield f"{ flag } { index_url } "
105
110
106
- def write_trusted_hosts (self ):
111
+ def write_trusted_hosts (self ) -> Iterator [ str ] :
107
112
if self .emit_trusted_host :
108
113
for trusted_host in dedup (self .trusted_hosts ):
109
114
yield f"--trusted-host { trusted_host } "
110
115
111
- def write_format_controls (self ):
116
+ def write_format_controls (self ) -> Iterator [ str ] :
112
117
for nb in dedup (sorted (self .format_control .no_binary )):
113
118
yield f"--no-binary { nb } "
114
119
for ob in dedup (sorted (self .format_control .only_binary )):
115
120
yield f"--only-binary { ob } "
116
121
117
- def write_find_links (self ):
122
+ def write_find_links (self ) -> Iterator [ str ] :
118
123
if self .emit_find_links :
119
124
for find_link in dedup (self .find_links ):
120
125
yield f"--find-links { find_link } "
121
126
122
- def write_flags (self ):
127
+ def write_flags (self ) -> Iterator [ str ] :
123
128
emitted = False
124
129
for line in chain (
125
130
self .write_index_options (),
@@ -132,9 +137,15 @@ def write_flags(self):
132
137
if emitted :
133
138
yield ""
134
139
135
- def _iter_lines (self , results , unsafe_requirements = None , markers = None , hashes = None ):
140
+ def _iter_lines (
141
+ self ,
142
+ results : Set [InstallRequirement ],
143
+ unsafe_requirements : Optional [Set [InstallRequirement ]] = None ,
144
+ markers : Optional [Dict [str , Marker ]] = None ,
145
+ hashes : Optional [Dict [InstallRequirement , Set [str ]]] = None ,
146
+ ) -> Iterator [str ]:
136
147
# default values
137
- unsafe_requirements = unsafe_requirements or []
148
+ unsafe_requirements = unsafe_requirements or set ()
138
149
markers = markers or {}
139
150
hashes = hashes or {}
140
151
@@ -160,8 +171,7 @@ def _iter_lines(self, results, unsafe_requirements=None, markers=None, hashes=No
160
171
packages = {r for r in results if r .name not in UNSAFE_PACKAGES }
161
172
162
173
if packages :
163
- packages = sorted (packages , key = self ._sort_key )
164
- for ireq in packages :
174
+ for ireq in sorted (packages , key = self ._sort_key ):
165
175
if has_hashes and not hashes .get (ireq ):
166
176
yield MESSAGE_UNHASHED_PACKAGE
167
177
warn_uninstallable = True
@@ -172,7 +182,6 @@ def _iter_lines(self, results, unsafe_requirements=None, markers=None, hashes=No
172
182
yielded = True
173
183
174
184
if unsafe_requirements :
175
- unsafe_requirements = sorted (unsafe_requirements , key = self ._sort_key )
176
185
yield ""
177
186
yielded = True
178
187
if has_hashes and not self .allow_unsafe :
@@ -181,7 +190,7 @@ def _iter_lines(self, results, unsafe_requirements=None, markers=None, hashes=No
181
190
else :
182
191
yield MESSAGE_UNSAFE_PACKAGES
183
192
184
- for ireq in unsafe_requirements :
193
+ for ireq in sorted ( unsafe_requirements , key = self . _sort_key ) :
185
194
ireq_key = key_from_ireq (ireq )
186
195
if not self .allow_unsafe :
187
196
yield comment (f"# { ireq_key } " )
@@ -198,15 +207,26 @@ def _iter_lines(self, results, unsafe_requirements=None, markers=None, hashes=No
198
207
if warn_uninstallable :
199
208
log .warning (MESSAGE_UNINSTALLABLE )
200
209
201
- def write (self , results , unsafe_requirements , markers , hashes ):
210
+ def write (
211
+ self ,
212
+ results : Set [InstallRequirement ],
213
+ unsafe_requirements : Set [InstallRequirement ],
214
+ markers : Dict [str , Marker ],
215
+ hashes : Optional [Dict [InstallRequirement , Set [str ]]],
216
+ ) -> None :
202
217
203
218
for line in self ._iter_lines (results , unsafe_requirements , markers , hashes ):
204
219
log .info (line )
205
220
if not self .dry_run :
206
221
self .dst_file .write (unstyle (line ).encode ())
207
222
self .dst_file .write (os .linesep .encode ())
208
223
209
- def _format_requirement (self , ireq , marker = None , hashes = None ):
224
+ def _format_requirement (
225
+ self ,
226
+ ireq : InstallRequirement ,
227
+ marker : Optional [Marker ] = None ,
228
+ hashes : Optional [Dict [InstallRequirement , Set [str ]]] = None ,
229
+ ) -> str :
210
230
ireq_hashes = (hashes if hashes is not None else {}).get (ireq )
211
231
212
232
line = format_requirement (ireq , marker = marker , hashes = ireq_hashes )
@@ -224,15 +244,17 @@ def _format_requirement(self, ireq, marker=None, hashes=None):
224
244
}
225
245
elif ireq .comes_from :
226
246
required_by .add (_comes_from_as_string (ireq ))
247
+
227
248
if required_by :
228
- required_by = sorted (required_by )
229
- if len (required_by ) == 1 :
230
- source = required_by [0 ]
249
+ sorted_required_by = sorted (required_by )
250
+ if len (sorted_required_by ) == 1 :
251
+ source = sorted_required_by [0 ]
231
252
annotation = " # via " + source
232
253
else :
233
254
annotation_lines = [" # via" ]
234
- for source in required_by :
255
+ for source in sorted_required_by :
235
256
annotation_lines .append (" # " + source )
236
257
annotation = "\n " .join (annotation_lines )
237
258
line = f"{ line } \n { comment (annotation )} "
259
+
238
260
return line
0 commit comments