diff options
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py')
-rw-r--r-- | venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py | 338 |
1 files changed, 0 insertions, 338 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py deleted file mode 100644 index 9e6ef41..0000000 --- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_file.py +++ /dev/null | |||
@@ -1,338 +0,0 @@ | |||
1 | """ | ||
2 | Requirements file parsing | ||
3 | """ | ||
4 | |||
5 | from __future__ import absolute_import | ||
6 | |||
7 | import optparse | ||
8 | import os | ||
9 | import re | ||
10 | import shlex | ||
11 | import sys | ||
12 | |||
13 | from pip._vendor.six.moves import filterfalse | ||
14 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
15 | |||
16 | from pip._internal import cmdoptions | ||
17 | from pip._internal.download import get_file_content | ||
18 | from pip._internal.exceptions import RequirementsFileParseError | ||
19 | from pip._internal.req.req_install import InstallRequirement | ||
20 | |||
21 | __all__ = ['parse_requirements'] | ||
22 | |||
23 | SCHEME_RE = re.compile(r'^(http|https|file):', re.I) | ||
24 | COMMENT_RE = re.compile(r'(^|\s)+#.*$') | ||
25 | |||
26 | # Matches environment variable-style values in '${MY_VARIABLE_1}' with the | ||
27 | # variable name consisting of only uppercase letters, digits or the '_' | ||
28 | # (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, | ||
29 | # 2013 Edition. | ||
30 | ENV_VAR_RE = re.compile(r'(?P<var>\$\{(?P<name>[A-Z0-9_]+)\})') | ||
31 | |||
32 | SUPPORTED_OPTIONS = [ | ||
33 | cmdoptions.constraints, | ||
34 | cmdoptions.editable, | ||
35 | cmdoptions.requirements, | ||
36 | cmdoptions.no_index, | ||
37 | cmdoptions.index_url, | ||
38 | cmdoptions.find_links, | ||
39 | cmdoptions.extra_index_url, | ||
40 | cmdoptions.always_unzip, | ||
41 | cmdoptions.no_binary, | ||
42 | cmdoptions.only_binary, | ||
43 | cmdoptions.pre, | ||
44 | cmdoptions.process_dependency_links, | ||
45 | cmdoptions.trusted_host, | ||
46 | cmdoptions.require_hashes, | ||
47 | ] | ||
48 | |||
49 | # options to be passed to requirements | ||
50 | SUPPORTED_OPTIONS_REQ = [ | ||
51 | cmdoptions.install_options, | ||
52 | cmdoptions.global_options, | ||
53 | cmdoptions.hash, | ||
54 | ] | ||
55 | |||
56 | # the 'dest' string values | ||
57 | SUPPORTED_OPTIONS_REQ_DEST = [o().dest for o in SUPPORTED_OPTIONS_REQ] | ||
58 | |||
59 | |||
60 | def parse_requirements(filename, finder=None, comes_from=None, options=None, | ||
61 | session=None, constraint=False, wheel_cache=None): | ||
62 | """Parse a requirements file and yield InstallRequirement instances. | ||
63 | |||
64 | :param filename: Path or url of requirements file. | ||
65 | :param finder: Instance of pip.index.PackageFinder. | ||
66 | :param comes_from: Origin description of requirements. | ||
67 | :param options: cli options. | ||
68 | :param session: Instance of pip.download.PipSession. | ||
69 | :param constraint: If true, parsing a constraint file rather than | ||
70 | requirements file. | ||
71 | :param wheel_cache: Instance of pip.wheel.WheelCache | ||
72 | """ | ||
73 | if session is None: | ||
74 | raise TypeError( | ||
75 | "parse_requirements() missing 1 required keyword argument: " | ||
76 | "'session'" | ||
77 | ) | ||
78 | |||
79 | _, content = get_file_content( | ||
80 | filename, comes_from=comes_from, session=session | ||
81 | ) | ||
82 | |||
83 | lines_enum = preprocess(content, options) | ||
84 | |||
85 | for line_number, line in lines_enum: | ||
86 | req_iter = process_line(line, filename, line_number, finder, | ||
87 | comes_from, options, session, wheel_cache, | ||
88 | constraint=constraint) | ||
89 | for req in req_iter: | ||
90 | yield req | ||
91 | |||
92 | |||
93 | def preprocess(content, options): | ||
94 | """Split, filter, and join lines, and return a line iterator | ||
95 | |||
96 | :param content: the content of the requirements file | ||
97 | :param options: cli options | ||
98 | """ | ||
99 | lines_enum = enumerate(content.splitlines(), start=1) | ||
100 | lines_enum = join_lines(lines_enum) | ||
101 | lines_enum = ignore_comments(lines_enum) | ||
102 | lines_enum = skip_regex(lines_enum, options) | ||
103 | lines_enum = expand_env_variables(lines_enum) | ||
104 | return lines_enum | ||
105 | |||
106 | |||
107 | def process_line(line, filename, line_number, finder=None, comes_from=None, | ||
108 | options=None, session=None, wheel_cache=None, | ||
109 | constraint=False): | ||
110 | """Process a single requirements line; This can result in creating/yielding | ||
111 | requirements, or updating the finder. | ||
112 | |||
113 | For lines that contain requirements, the only options that have an effect | ||
114 | are from SUPPORTED_OPTIONS_REQ, and they are scoped to the | ||
115 | requirement. Other options from SUPPORTED_OPTIONS may be present, but are | ||
116 | ignored. | ||
117 | |||
118 | For lines that do not contain requirements, the only options that have an | ||
119 | effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may | ||
120 | be present, but are ignored. These lines may contain multiple options | ||
121 | (although our docs imply only one is supported), and all our parsed and | ||
122 | affect the finder. | ||
123 | |||
124 | :param constraint: If True, parsing a constraints file. | ||
125 | :param options: OptionParser options that we may update | ||
126 | """ | ||
127 | parser = build_parser(line) | ||
128 | defaults = parser.get_default_values() | ||
129 | defaults.index_url = None | ||
130 | if finder: | ||
131 | # `finder.format_control` will be updated during parsing | ||
132 | defaults.format_control = finder.format_control | ||
133 | args_str, options_str = break_args_options(line) | ||
134 | if sys.version_info < (2, 7, 3): | ||
135 | # Prior to 2.7.3, shlex cannot deal with unicode entries | ||
136 | options_str = options_str.encode('utf8') | ||
137 | opts, _ = parser.parse_args(shlex.split(options_str), defaults) | ||
138 | |||
139 | # preserve for the nested code path | ||
140 | line_comes_from = '%s %s (line %s)' % ( | ||
141 | '-c' if constraint else '-r', filename, line_number, | ||
142 | ) | ||
143 | |||
144 | # yield a line requirement | ||
145 | if args_str: | ||
146 | isolated = options.isolated_mode if options else False | ||
147 | if options: | ||
148 | cmdoptions.check_install_build_global(options, opts) | ||
149 | # get the options that apply to requirements | ||
150 | req_options = {} | ||
151 | for dest in SUPPORTED_OPTIONS_REQ_DEST: | ||
152 | if dest in opts.__dict__ and opts.__dict__[dest]: | ||
153 | req_options[dest] = opts.__dict__[dest] | ||
154 | yield InstallRequirement.from_line( | ||
155 | args_str, line_comes_from, constraint=constraint, | ||
156 | isolated=isolated, options=req_options, wheel_cache=wheel_cache | ||
157 | ) | ||
158 | |||
159 | # yield an editable requirement | ||
160 | elif opts.editables: | ||
161 | isolated = options.isolated_mode if options else False | ||
162 | yield InstallRequirement.from_editable( | ||
163 | opts.editables[0], comes_from=line_comes_from, | ||
164 | constraint=constraint, isolated=isolated, wheel_cache=wheel_cache | ||
165 | ) | ||
166 | |||
167 | # parse a nested requirements file | ||
168 | elif opts.requirements or opts.constraints: | ||
169 | if opts.requirements: | ||
170 | req_path = opts.requirements[0] | ||
171 | nested_constraint = False | ||
172 | else: | ||
173 | req_path = opts.constraints[0] | ||
174 | nested_constraint = True | ||
175 | # original file is over http | ||
176 | if SCHEME_RE.search(filename): | ||
177 | # do a url join so relative paths work | ||
178 | req_path = urllib_parse.urljoin(filename, req_path) | ||
179 | # original file and nested file are paths | ||
180 | elif not SCHEME_RE.search(req_path): | ||
181 | # do a join so relative paths work | ||
182 | req_path = os.path.join(os.path.dirname(filename), req_path) | ||
183 | # TODO: Why not use `comes_from='-r {} (line {})'` here as well? | ||
184 | parser = parse_requirements( | ||
185 | req_path, finder, comes_from, options, session, | ||
186 | constraint=nested_constraint, wheel_cache=wheel_cache | ||
187 | ) | ||
188 | for req in parser: | ||
189 | yield req | ||
190 | |||
191 | # percolate hash-checking option upward | ||
192 | elif opts.require_hashes: | ||
193 | options.require_hashes = opts.require_hashes | ||
194 | |||
195 | # set finder options | ||
196 | elif finder: | ||
197 | if opts.index_url: | ||
198 | finder.index_urls = [opts.index_url] | ||
199 | if opts.no_index is True: | ||
200 | finder.index_urls = [] | ||
201 | if opts.extra_index_urls: | ||
202 | finder.index_urls.extend(opts.extra_index_urls) | ||
203 | if opts.find_links: | ||
204 | # FIXME: it would be nice to keep track of the source | ||
205 | # of the find_links: support a find-links local path | ||
206 | # relative to a requirements file. | ||
207 | value = opts.find_links[0] | ||
208 | req_dir = os.path.dirname(os.path.abspath(filename)) | ||
209 | relative_to_reqs_file = os.path.join(req_dir, value) | ||
210 | if os.path.exists(relative_to_reqs_file): | ||
211 | value = relative_to_reqs_file | ||
212 | finder.find_links.append(value) | ||
213 | if opts.pre: | ||
214 | finder.allow_all_prereleases = True | ||
215 | if opts.process_dependency_links: | ||
216 | finder.process_dependency_links = True | ||
217 | if opts.trusted_hosts: | ||
218 | finder.secure_origins.extend( | ||
219 | ("*", host, "*") for host in opts.trusted_hosts) | ||
220 | |||
221 | |||
222 | def break_args_options(line): | ||
223 | """Break up the line into an args and options string. We only want to shlex | ||
224 | (and then optparse) the options, not the args. args can contain markers | ||
225 | which are corrupted by shlex. | ||
226 | """ | ||
227 | tokens = line.split(' ') | ||
228 | args = [] | ||
229 | options = tokens[:] | ||
230 | for token in tokens: | ||
231 | if token.startswith('-') or token.startswith('--'): | ||
232 | break | ||
233 | else: | ||
234 | args.append(token) | ||
235 | options.pop(0) | ||
236 | return ' '.join(args), ' '.join(options) | ||
237 | |||
238 | |||
239 | def build_parser(line): | ||
240 | """ | ||
241 | Return a parser for parsing requirement lines | ||
242 | """ | ||
243 | parser = optparse.OptionParser(add_help_option=False) | ||
244 | |||
245 | option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ | ||
246 | for option_factory in option_factories: | ||
247 | option = option_factory() | ||
248 | parser.add_option(option) | ||
249 | |||
250 | # By default optparse sys.exits on parsing errors. We want to wrap | ||
251 | # that in our own exception. | ||
252 | def parser_exit(self, msg): | ||
253 | # add offending line | ||
254 | msg = 'Invalid requirement: %s\n%s' % (line, msg) | ||
255 | raise RequirementsFileParseError(msg) | ||
256 | parser.exit = parser_exit | ||
257 | |||
258 | return parser | ||
259 | |||
260 | |||
261 | def join_lines(lines_enum): | ||
262 | """Joins a line ending in '\' with the previous line (except when following | ||
263 | comments). The joined line takes on the index of the first line. | ||
264 | """ | ||
265 | primary_line_number = None | ||
266 | new_line = [] | ||
267 | for line_number, line in lines_enum: | ||
268 | if not line.endswith('\\') or COMMENT_RE.match(line): | ||
269 | if COMMENT_RE.match(line): | ||
270 | # this ensures comments are always matched later | ||
271 | line = ' ' + line | ||
272 | if new_line: | ||
273 | new_line.append(line) | ||
274 | yield primary_line_number, ''.join(new_line) | ||
275 | new_line = [] | ||
276 | else: | ||
277 | yield line_number, line | ||
278 | else: | ||
279 | if not new_line: | ||
280 | primary_line_number = line_number | ||
281 | new_line.append(line.strip('\\')) | ||
282 | |||
283 | # last line contains \ | ||
284 | if new_line: | ||
285 | yield primary_line_number, ''.join(new_line) | ||
286 | |||
287 | # TODO: handle space after '\'. | ||
288 | |||
289 | |||
290 | def ignore_comments(lines_enum): | ||
291 | """ | ||
292 | Strips comments and filter empty lines. | ||
293 | """ | ||
294 | for line_number, line in lines_enum: | ||
295 | line = COMMENT_RE.sub('', line) | ||
296 | line = line.strip() | ||
297 | if line: | ||
298 | yield line_number, line | ||
299 | |||
300 | |||
301 | def skip_regex(lines_enum, options): | ||
302 | """ | ||
303 | Skip lines that match '--skip-requirements-regex' pattern | ||
304 | |||
305 | Note: the regex pattern is only built once | ||
306 | """ | ||
307 | skip_regex = options.skip_requirements_regex if options else None | ||
308 | if skip_regex: | ||
309 | pattern = re.compile(skip_regex) | ||
310 | lines_enum = filterfalse(lambda e: pattern.search(e[1]), lines_enum) | ||
311 | return lines_enum | ||
312 | |||
313 | |||
314 | def expand_env_variables(lines_enum): | ||
315 | """Replace all environment variables that can be retrieved via `os.getenv`. | ||
316 | |||
317 | The only allowed format for environment variables defined in the | ||
318 | requirement file is `${MY_VARIABLE_1}` to ensure two things: | ||
319 | |||
320 | 1. Strings that contain a `$` aren't accidentally (partially) expanded. | ||
321 | 2. Ensure consistency across platforms for requirement files. | ||
322 | |||
323 | These points are the result of a discusssion on the `github pull | ||
324 | request #3514 <https://github.com/pypa/pip/pull/3514>`_. | ||
325 | |||
326 | Valid characters in variable names follow the `POSIX standard | ||
327 | <http://pubs.opengroup.org/onlinepubs/9699919799/>`_ and are limited | ||
328 | to uppercase letter, digits and the `_` (underscore). | ||
329 | """ | ||
330 | for line_number, line in lines_enum: | ||
331 | for env_var, var_name in ENV_VAR_RE.findall(line): | ||
332 | value = os.getenv(var_name) | ||
333 | if not value: | ||
334 | continue | ||
335 | |||
336 | line = line.replace(env_var, value) | ||
337 | |||
338 | yield line_number, line | ||