summaryrefslogtreecommitdiff
path: root/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py
diff options
context:
space:
mode:
authorShubham Saini <shubham6405@gmail.com>2019-08-05 08:32:33 +0000
committerShubham Saini <shubham6405@gmail.com>2019-08-05 08:32:33 +0000
commit227b2d30a8675b44918f9d9ca89b24144a938215 (patch)
tree9f8e6a28724514b6fdf463a9ab2067a7ef309b72 /venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py
parent842a8cfbbbdb1f92889d892e4859dbd5d40c5be8 (diff)
removing venv files
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py')
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py1115
1 files changed, 0 insertions, 1115 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py
deleted file mode 100644
index 9dd1523..0000000
--- a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/req/req_install.py
+++ /dev/null
@@ -1,1115 +0,0 @@
1from __future__ import absolute_import
2
3import logging
4import os
5import re
6import shutil
7import sys
8import sysconfig
9import traceback
10import warnings
11import zipfile
12from distutils.util import change_root
13from email.parser import FeedParser # type: ignore
14
15from pip._vendor import pkg_resources, pytoml, six
16from pip._vendor.packaging import specifiers
17from pip._vendor.packaging.markers import Marker
18from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
19from pip._vendor.packaging.utils import canonicalize_name
20from pip._vendor.packaging.version import parse as parse_version
21from pip._vendor.packaging.version import Version
22from pip._vendor.pkg_resources import RequirementParseError, parse_requirements
23
24from pip._internal import wheel
25from pip._internal.build_env import BuildEnvironment
26from pip._internal.compat import native_str
27from pip._internal.download import (
28 is_archive_file, is_url, path_to_url, url_to_path,
29)
30from pip._internal.exceptions import InstallationError, UninstallationError
31from pip._internal.locations import (
32 PIP_DELETE_MARKER_FILENAME, running_under_virtualenv,
33)
34from pip._internal.req.req_uninstall import UninstallPathSet
35from pip._internal.utils.deprecation import RemovedInPip11Warning
36from pip._internal.utils.hashes import Hashes
37from pip._internal.utils.logging import indent_log
38from pip._internal.utils.misc import (
39 _make_build_dir, ask_path_exists, backup_dir, call_subprocess,
40 display_path, dist_in_site_packages, dist_in_usersite, ensure_dir,
41 get_installed_version, is_installable_dir, read_text_file, rmtree,
42)
43from pip._internal.utils.setuptools_build import SETUPTOOLS_SHIM
44from pip._internal.utils.temp_dir import TempDirectory
45from pip._internal.utils.ui import open_spinner
46from pip._internal.vcs import vcs
47from pip._internal.wheel import Wheel, move_wheel_files
48
49logger = logging.getLogger(__name__)
50
51operators = specifiers.Specifier._operators.keys()
52
53
54def _strip_extras(path):
55 m = re.match(r'^(.+)(\[[^\]]+\])$', path)
56 extras = None
57 if m:
58 path_no_extras = m.group(1)
59 extras = m.group(2)
60 else:
61 path_no_extras = path
62
63 return path_no_extras, extras
64
65
66class InstallRequirement(object):
67 """
68 Represents something that may be installed later on, may have information
69 about where to fetch the relavant requirement and also contains logic for
70 installing the said requirement.
71 """
72
73 def __init__(self, req, comes_from, source_dir=None, editable=False,
74 link=None, update=True, markers=None,
75 isolated=False, options=None, wheel_cache=None,
76 constraint=False, extras=()):
77 assert req is None or isinstance(req, Requirement), req
78 self.req = req
79 self.comes_from = comes_from
80 self.constraint = constraint
81 if source_dir is not None:
82 self.source_dir = os.path.normpath(os.path.abspath(source_dir))
83 else:
84 self.source_dir = None
85 self.editable = editable
86
87 self._wheel_cache = wheel_cache
88 if link is not None:
89 self.link = self.original_link = link
90 else:
91 from pip._internal.index import Link
92 self.link = self.original_link = req and req.url and Link(req.url)
93
94 if extras:
95 self.extras = extras
96 elif req:
97 self.extras = {
98 pkg_resources.safe_extra(extra) for extra in req.extras
99 }
100 else:
101 self.extras = set()
102 if markers is not None:
103 self.markers = markers
104 else:
105 self.markers = req and req.marker
106 self._egg_info_path = None
107 # This holds the pkg_resources.Distribution object if this requirement
108 # is already available:
109 self.satisfied_by = None
110 # This hold the pkg_resources.Distribution object if this requirement
111 # conflicts with another installed distribution:
112 self.conflicts_with = None
113 # Temporary build location
114 self._temp_build_dir = TempDirectory(kind="req-build")
115 # Used to store the global directory where the _temp_build_dir should
116 # have been created. Cf _correct_build_location method.
117 self._ideal_build_dir = None
118 # True if the editable should be updated:
119 self.update = update
120 # Set to True after successful installation
121 self.install_succeeded = None
122 # UninstallPathSet of uninstalled distribution (for possible rollback)
123 self.uninstalled_pathset = None
124 self.options = options if options else {}
125 # Set to True after successful preparation of this requirement
126 self.prepared = False
127 self.is_direct = False
128
129 self.isolated = isolated
130 self.build_env = BuildEnvironment(no_clean=True)
131
132 @classmethod
133 def from_editable(cls, editable_req, comes_from=None, isolated=False,
134 options=None, wheel_cache=None, constraint=False):
135 from pip._internal.index import Link
136
137 name, url, extras_override = parse_editable(editable_req)
138 if url.startswith('file:'):
139 source_dir = url_to_path(url)
140 else:
141 source_dir = None
142
143 if name is not None:
144 try:
145 req = Requirement(name)
146 except InvalidRequirement:
147 raise InstallationError("Invalid requirement: '%s'" % name)
148 else:
149 req = None
150 return cls(
151 req, comes_from, source_dir=source_dir,
152 editable=True,
153 link=Link(url),
154 constraint=constraint,
155 isolated=isolated,
156 options=options if options else {},
157 wheel_cache=wheel_cache,
158 extras=extras_override or (),
159 )
160
161 @classmethod
162 def from_req(cls, req, comes_from=None, isolated=False, wheel_cache=None):
163 try:
164 req = Requirement(req)
165 except InvalidRequirement:
166 raise InstallationError("Invalid requirement: '%s'" % req)
167 if req.url:
168 raise InstallationError(
169 "Direct url requirement (like %s) are not allowed for "
170 "dependencies" % req
171 )
172 return cls(req, comes_from, isolated=isolated, wheel_cache=wheel_cache)
173
174 @classmethod
175 def from_line(
176 cls, name, comes_from=None, isolated=False, options=None,
177 wheel_cache=None, constraint=False):
178 """Creates an InstallRequirement from a name, which might be a
179 requirement, directory containing 'setup.py', filename, or URL.
180 """
181 from pip._internal.index import Link
182
183 if is_url(name):
184 marker_sep = '; '
185 else:
186 marker_sep = ';'
187 if marker_sep in name:
188 name, markers = name.split(marker_sep, 1)
189 markers = markers.strip()
190 if not markers:
191 markers = None
192 else:
193 markers = Marker(markers)
194 else:
195 markers = None
196 name = name.strip()
197 req = None
198 path = os.path.normpath(os.path.abspath(name))
199 link = None
200 extras = None
201
202 if is_url(name):
203 link = Link(name)
204 else:
205 p, extras = _strip_extras(path)
206 looks_like_dir = os.path.isdir(p) and (
207 os.path.sep in name or
208 (os.path.altsep is not None and os.path.altsep in name) or
209 name.startswith('.')
210 )
211 if looks_like_dir:
212 if not is_installable_dir(p):
213 raise InstallationError(
214 "Directory %r is not installable. File 'setup.py' "
215 "not found." % name
216 )
217 link = Link(path_to_url(p))
218 elif is_archive_file(p):
219 if not os.path.isfile(p):
220 logger.warning(
221 'Requirement %r looks like a filename, but the '
222 'file does not exist',
223 name
224 )
225 link = Link(path_to_url(p))
226
227 # it's a local file, dir, or url
228 if link:
229 # Handle relative file URLs
230 if link.scheme == 'file' and re.search(r'\.\./', link.url):
231 link = Link(
232 path_to_url(os.path.normpath(os.path.abspath(link.path))))
233 # wheel file
234 if link.is_wheel:
235 wheel = Wheel(link.filename) # can raise InvalidWheelFilename
236 req = "%s==%s" % (wheel.name, wheel.version)
237 else:
238 # set the req to the egg fragment. when it's not there, this
239 # will become an 'unnamed' requirement
240 req = link.egg_fragment
241
242 # a requirement specifier
243 else:
244 req = name
245
246 if extras:
247 extras = Requirement("placeholder" + extras.lower()).extras
248 else:
249 extras = ()
250 if req is not None:
251 try:
252 req = Requirement(req)
253 except InvalidRequirement:
254 if os.path.sep in req:
255 add_msg = "It looks like a path."
256 add_msg += deduce_helpful_msg(req)
257 elif '=' in req and not any(op in req for op in operators):
258 add_msg = "= is not a valid operator. Did you mean == ?"
259 else:
260 add_msg = traceback.format_exc()
261 raise InstallationError(
262 "Invalid requirement: '%s'\n%s" % (req, add_msg))
263 return cls(
264 req, comes_from, link=link, markers=markers,
265 isolated=isolated,
266 options=options if options else {},
267 wheel_cache=wheel_cache,
268 constraint=constraint,
269 extras=extras,
270 )
271
272 def __str__(self):
273 if self.req:
274 s = str(self.req)
275 if self.link:
276 s += ' from %s' % self.link.url
277 else:
278 s = self.link.url if self.link else None
279 if self.satisfied_by is not None:
280 s += ' in %s' % display_path(self.satisfied_by.location)
281 if self.comes_from:
282 if isinstance(self.comes_from, six.string_types):
283 comes_from = self.comes_from
284 else:
285 comes_from = self.comes_from.from_path()
286 if comes_from:
287 s += ' (from %s)' % comes_from
288 return s
289
290 def __repr__(self):
291 return '<%s object: %s editable=%r>' % (
292 self.__class__.__name__, str(self), self.editable)
293
294 def populate_link(self, finder, upgrade, require_hashes):
295 """Ensure that if a link can be found for this, that it is found.
296
297 Note that self.link may still be None - if Upgrade is False and the
298 requirement is already installed.
299
300 If require_hashes is True, don't use the wheel cache, because cached
301 wheels, always built locally, have different hashes than the files
302 downloaded from the index server and thus throw false hash mismatches.
303 Furthermore, cached wheels at present have undeterministic contents due
304 to file modification times.
305 """
306 if self.link is None:
307 self.link = finder.find_requirement(self, upgrade)
308 if self._wheel_cache is not None and not require_hashes:
309 old_link = self.link
310 self.link = self._wheel_cache.get(self.link, self.name)
311 if old_link != self.link:
312 logger.debug('Using cached wheel link: %s', self.link)
313
314 @property
315 def specifier(self):
316 return self.req.specifier
317
318 @property
319 def is_pinned(self):
320 """Return whether I am pinned to an exact version.
321
322 For example, some-package==1.2 is pinned; some-package>1.2 is not.
323 """
324 specifiers = self.specifier
325 return (len(specifiers) == 1 and
326 next(iter(specifiers)).operator in {'==', '==='})
327
328 def from_path(self):
329 if self.req is None:
330 return None
331 s = str(self.req)
332 if self.comes_from:
333 if isinstance(self.comes_from, six.string_types):
334 comes_from = self.comes_from
335 else:
336 comes_from = self.comes_from.from_path()
337 if comes_from:
338 s += '->' + comes_from
339 return s
340
341 def build_location(self, build_dir):
342 assert build_dir is not None
343 if self._temp_build_dir.path is not None:
344 return self._temp_build_dir.path
345 if self.req is None:
346 # for requirement via a path to a directory: the name of the
347 # package is not available yet so we create a temp directory
348 # Once run_egg_info will have run, we'll be able
349 # to fix it via _correct_build_location
350 # Some systems have /tmp as a symlink which confuses custom
351 # builds (such as numpy). Thus, we ensure that the real path
352 # is returned.
353 self._temp_build_dir.create()
354 self._ideal_build_dir = build_dir
355
356 return self._temp_build_dir.path
357 if self.editable:
358 name = self.name.lower()
359 else:
360 name = self.name
361 # FIXME: Is there a better place to create the build_dir? (hg and bzr
362 # need this)
363 if not os.path.exists(build_dir):
364 logger.debug('Creating directory %s', build_dir)
365 _make_build_dir(build_dir)
366 return os.path.join(build_dir, name)
367
368 def _correct_build_location(self):
369 """Move self._temp_build_dir to self._ideal_build_dir/self.req.name
370
371 For some requirements (e.g. a path to a directory), the name of the
372 package is not available until we run egg_info, so the build_location
373 will return a temporary directory and store the _ideal_build_dir.
374
375 This is only called by self.egg_info_path to fix the temporary build
376 directory.
377 """
378 if self.source_dir is not None:
379 return
380 assert self.req is not None
381 assert self._temp_build_dir.path
382 assert self._ideal_build_dir.path
383 old_location = self._temp_build_dir.path
384 self._temp_build_dir.path = None
385
386 new_location = self.build_location(self._ideal_build_dir)
387 if os.path.exists(new_location):
388 raise InstallationError(
389 'A package already exists in %s; please remove it to continue'
390 % display_path(new_location))
391 logger.debug(
392 'Moving package %s from %s to new location %s',
393 self, display_path(old_location), display_path(new_location),
394 )
395 shutil.move(old_location, new_location)
396 self._temp_build_dir.path = new_location
397 self._ideal_build_dir = None
398 self.source_dir = os.path.normpath(os.path.abspath(new_location))
399 self._egg_info_path = None
400
401 @property
402 def name(self):
403 if self.req is None:
404 return None
405 return native_str(pkg_resources.safe_name(self.req.name))
406
407 @property
408 def setup_py_dir(self):
409 return os.path.join(
410 self.source_dir,
411 self.link and self.link.subdirectory_fragment or '')
412
413 @property
414 def setup_py(self):
415 assert self.source_dir, "No source dir for %s" % self
416
417 setup_py = os.path.join(self.setup_py_dir, 'setup.py')
418
419 # Python2 __file__ should not be unicode
420 if six.PY2 and isinstance(setup_py, six.text_type):
421 setup_py = setup_py.encode(sys.getfilesystemencoding())
422
423 return setup_py
424
425 @property
426 def pyproject_toml(self):
427 assert self.source_dir, "No source dir for %s" % self
428
429 pp_toml = os.path.join(self.setup_py_dir, 'pyproject.toml')
430
431 # Python2 __file__ should not be unicode
432 if six.PY2 and isinstance(pp_toml, six.text_type):
433 pp_toml = pp_toml.encode(sys.getfilesystemencoding())
434
435 return pp_toml
436
437 def get_pep_518_info(self):
438 """Get a list of the packages required to build the project, if any,
439 and a flag indicating whether pyproject.toml is present, indicating
440 that the build should be isolated.
441
442 Build requirements can be specified in a pyproject.toml, as described
443 in PEP 518. If this file exists but doesn't specify build
444 requirements, pip will default to installing setuptools and wheel.
445 """
446 if os.path.isfile(self.pyproject_toml):
447 with open(self.pyproject_toml) as f:
448 pp_toml = pytoml.load(f)
449 build_sys = pp_toml.get('build-system', {})
450 return (build_sys.get('requires', ['setuptools', 'wheel']), True)
451 return (['setuptools', 'wheel'], False)
452
453 def run_egg_info(self):
454 assert self.source_dir
455 if self.name:
456 logger.debug(
457 'Running setup.py (path:%s) egg_info for package %s',
458 self.setup_py, self.name,
459 )
460 else:
461 logger.debug(
462 'Running setup.py (path:%s) egg_info for package from %s',
463 self.setup_py, self.link,
464 )
465
466 with indent_log():
467 script = SETUPTOOLS_SHIM % self.setup_py
468 base_cmd = [sys.executable, '-c', script]
469 if self.isolated:
470 base_cmd += ["--no-user-cfg"]
471 egg_info_cmd = base_cmd + ['egg_info']
472 # We can't put the .egg-info files at the root, because then the
473 # source code will be mistaken for an installed egg, causing
474 # problems
475 if self.editable:
476 egg_base_option = []
477 else:
478 egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info')
479 ensure_dir(egg_info_dir)
480 egg_base_option = ['--egg-base', 'pip-egg-info']
481 with self.build_env:
482 call_subprocess(
483 egg_info_cmd + egg_base_option,
484 cwd=self.setup_py_dir,
485 show_stdout=False,
486 command_desc='python setup.py egg_info')
487
488 if not self.req:
489 if isinstance(parse_version(self.pkg_info()["Version"]), Version):
490 op = "=="
491 else:
492 op = "==="
493 self.req = Requirement(
494 "".join([
495 self.pkg_info()["Name"],
496 op,
497 self.pkg_info()["Version"],
498 ])
499 )
500 self._correct_build_location()
501 else:
502 metadata_name = canonicalize_name(self.pkg_info()["Name"])
503 if canonicalize_name(self.req.name) != metadata_name:
504 logger.warning(
505 'Running setup.py (path:%s) egg_info for package %s '
506 'produced metadata for project name %s. Fix your '
507 '#egg=%s fragments.',
508 self.setup_py, self.name, metadata_name, self.name
509 )
510 self.req = Requirement(metadata_name)
511
512 def egg_info_data(self, filename):
513 if self.satisfied_by is not None:
514 if not self.satisfied_by.has_metadata(filename):
515 return None
516 return self.satisfied_by.get_metadata(filename)
517 assert self.source_dir
518 filename = self.egg_info_path(filename)
519 if not os.path.exists(filename):
520 return None
521 data = read_text_file(filename)
522 return data
523
524 def egg_info_path(self, filename):
525 if self._egg_info_path is None:
526 if self.editable:
527 base = self.source_dir
528 else:
529 base = os.path.join(self.setup_py_dir, 'pip-egg-info')
530 filenames = os.listdir(base)
531 if self.editable:
532 filenames = []
533 for root, dirs, files in os.walk(base):
534 for dir in vcs.dirnames:
535 if dir in dirs:
536 dirs.remove(dir)
537 # Iterate over a copy of ``dirs``, since mutating
538 # a list while iterating over it can cause trouble.
539 # (See https://github.com/pypa/pip/pull/462.)
540 for dir in list(dirs):
541 # Don't search in anything that looks like a virtualenv
542 # environment
543 if (
544 os.path.lexists(
545 os.path.join(root, dir, 'bin', 'python')
546 ) or
547 os.path.exists(
548 os.path.join(
549 root, dir, 'Scripts', 'Python.exe'
550 )
551 )):
552 dirs.remove(dir)
553 # Also don't search through tests
554 elif dir == 'test' or dir == 'tests':
555 dirs.remove(dir)
556 filenames.extend([os.path.join(root, dir)
557 for dir in dirs])
558 filenames = [f for f in filenames if f.endswith('.egg-info')]
559
560 if not filenames:
561 raise InstallationError(
562 'No files/directories in %s (from %s)' % (base, filename)
563 )
564 assert filenames, \
565 "No files/directories in %s (from %s)" % (base, filename)
566
567 # if we have more than one match, we pick the toplevel one. This
568 # can easily be the case if there is a dist folder which contains
569 # an extracted tarball for testing purposes.
570 if len(filenames) > 1:
571 filenames.sort(
572 key=lambda x: x.count(os.path.sep) +
573 (os.path.altsep and x.count(os.path.altsep) or 0)
574 )
575 self._egg_info_path = os.path.join(base, filenames[0])
576 return os.path.join(self._egg_info_path, filename)
577
578 def pkg_info(self):
579 p = FeedParser()
580 data = self.egg_info_data('PKG-INFO')
581 if not data:
582 logger.warning(
583 'No PKG-INFO file found in %s',
584 display_path(self.egg_info_path('PKG-INFO')),
585 )
586 p.feed(data or '')
587 return p.close()
588
589 _requirements_section_re = re.compile(r'\[(.*?)\]')
590
591 @property
592 def installed_version(self):
593 return get_installed_version(self.name)
594
595 def assert_source_matches_version(self):
596 assert self.source_dir
597 version = self.pkg_info()['version']
598 if self.req.specifier and version not in self.req.specifier:
599 logger.warning(
600 'Requested %s, but installing version %s',
601 self,
602 version,
603 )
604 else:
605 logger.debug(
606 'Source in %s has version %s, which satisfies requirement %s',
607 display_path(self.source_dir),
608 version,
609 self,
610 )
611
612 def update_editable(self, obtain=True):
613 if not self.link:
614 logger.debug(
615 "Cannot update repository at %s; repository location is "
616 "unknown",
617 self.source_dir,
618 )
619 return
620 assert self.editable
621 assert self.source_dir
622 if self.link.scheme == 'file':
623 # Static paths don't get updated
624 return
625 assert '+' in self.link.url, "bad url: %r" % self.link.url
626 if not self.update:
627 return
628 vc_type, url = self.link.url.split('+', 1)
629 backend = vcs.get_backend(vc_type)
630 if backend:
631 vcs_backend = backend(self.link.url)
632 if obtain:
633 vcs_backend.obtain(self.source_dir)
634 else:
635 vcs_backend.export(self.source_dir)
636 else:
637 assert 0, (
638 'Unexpected version control type (in %s): %s'
639 % (self.link, vc_type))
640
641 def uninstall(self, auto_confirm=False, verbose=False,
642 use_user_site=False):
643 """
644 Uninstall the distribution currently satisfying this requirement.
645
646 Prompts before removing or modifying files unless
647 ``auto_confirm`` is True.
648
649 Refuses to delete or modify files outside of ``sys.prefix`` -
650 thus uninstallation within a virtual environment can only
651 modify that virtual environment, even if the virtualenv is
652 linked to global site-packages.
653
654 """
655 if not self.check_if_exists(use_user_site):
656 logger.warning("Skipping %s as it is not installed.", self.name)
657 return
658 dist = self.satisfied_by or self.conflicts_with
659
660 uninstalled_pathset = UninstallPathSet.from_dist(dist)
661 uninstalled_pathset.remove(auto_confirm, verbose)
662 return uninstalled_pathset
663
664 def archive(self, build_dir):
665 assert self.source_dir
666 create_archive = True
667 archive_name = '%s-%s.zip' % (self.name, self.pkg_info()["version"])
668 archive_path = os.path.join(build_dir, archive_name)
669 if os.path.exists(archive_path):
670 response = ask_path_exists(
671 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)bort ' %
672 display_path(archive_path), ('i', 'w', 'b', 'a'))
673 if response == 'i':
674 create_archive = False
675 elif response == 'w':
676 logger.warning('Deleting %s', display_path(archive_path))
677 os.remove(archive_path)
678 elif response == 'b':
679 dest_file = backup_dir(archive_path)
680 logger.warning(
681 'Backing up %s to %s',
682 display_path(archive_path),
683 display_path(dest_file),
684 )
685 shutil.move(archive_path, dest_file)
686 elif response == 'a':
687 sys.exit(-1)
688 if create_archive:
689 zip = zipfile.ZipFile(
690 archive_path, 'w', zipfile.ZIP_DEFLATED,
691 allowZip64=True
692 )
693 dir = os.path.normcase(os.path.abspath(self.setup_py_dir))
694 for dirpath, dirnames, filenames in os.walk(dir):
695 if 'pip-egg-info' in dirnames:
696 dirnames.remove('pip-egg-info')
697 for dirname in dirnames:
698 dirname = os.path.join(dirpath, dirname)
699 name = self._clean_zip_name(dirname, dir)
700 zipdir = zipfile.ZipInfo(self.name + '/' + name + '/')
701 zipdir.external_attr = 0x1ED << 16 # 0o755
702 zip.writestr(zipdir, '')
703 for filename in filenames:
704 if filename == PIP_DELETE_MARKER_FILENAME:
705 continue
706 filename = os.path.join(dirpath, filename)
707 name = self._clean_zip_name(filename, dir)
708 zip.write(filename, self.name + '/' + name)
709 zip.close()
710 logger.info('Saved %s', display_path(archive_path))
711
712 def _clean_zip_name(self, name, prefix):
713 assert name.startswith(prefix + os.path.sep), (
714 "name %r doesn't start with prefix %r" % (name, prefix)
715 )
716 name = name[len(prefix) + 1:]
717 name = name.replace(os.path.sep, '/')
718 return name
719
720 def match_markers(self, extras_requested=None):
721 if not extras_requested:
722 # Provide an extra to safely evaluate the markers
723 # without matching any extra
724 extras_requested = ('',)
725 if self.markers is not None:
726 return any(
727 self.markers.evaluate({'extra': extra})
728 for extra in extras_requested)
729 else:
730 return True
731
732 def install(self, install_options, global_options=None, root=None,
733 home=None, prefix=None, warn_script_location=True,
734 use_user_site=False, pycompile=True):
735 global_options = global_options if global_options is not None else []
736 if self.editable:
737 self.install_editable(
738 install_options, global_options, prefix=prefix,
739 )
740 return
741 if self.is_wheel:
742 version = wheel.wheel_version(self.source_dir)
743 wheel.check_compatibility(version, self.name)
744
745 self.move_wheel_files(
746 self.source_dir, root=root, prefix=prefix, home=home,
747 warn_script_location=warn_script_location,
748 use_user_site=use_user_site, pycompile=pycompile,
749 )
750 self.install_succeeded = True
751 return
752
753 # Extend the list of global and install options passed on to
754 # the setup.py call with the ones from the requirements file.
755 # Options specified in requirements file override those
756 # specified on the command line, since the last option given
757 # to setup.py is the one that is used.
758 global_options = list(global_options) + \
759 self.options.get('global_options', [])
760 install_options = list(install_options) + \
761 self.options.get('install_options', [])
762
763 if self.isolated:
764 global_options = global_options + ["--no-user-cfg"]
765
766 with TempDirectory(kind="record") as temp_dir:
767 record_filename = os.path.join(temp_dir.path, 'install-record.txt')
768 install_args = self.get_install_args(
769 global_options, record_filename, root, prefix, pycompile,
770 )
771 msg = 'Running setup.py install for %s' % (self.name,)
772 with open_spinner(msg) as spinner:
773 with indent_log():
774 with self.build_env:
775 call_subprocess(
776 install_args + install_options,
777 cwd=self.setup_py_dir,
778 show_stdout=False,
779 spinner=spinner,
780 )
781
782 if not os.path.exists(record_filename):
783 logger.debug('Record file %s not found', record_filename)
784 return
785 self.install_succeeded = True
786
787 def prepend_root(path):
788 if root is None or not os.path.isabs(path):
789 return path
790 else:
791 return change_root(root, path)
792
793 with open(record_filename) as f:
794 for line in f:
795 directory = os.path.dirname(line)
796 if directory.endswith('.egg-info'):
797 egg_info_dir = prepend_root(directory)
798 break
799 else:
800 logger.warning(
801 'Could not find .egg-info directory in install record'
802 ' for %s',
803 self,
804 )
805 # FIXME: put the record somewhere
806 # FIXME: should this be an error?
807 return
808 new_lines = []
809 with open(record_filename) as f:
810 for line in f:
811 filename = line.strip()
812 if os.path.isdir(filename):
813 filename += os.path.sep
814 new_lines.append(
815 os.path.relpath(prepend_root(filename), egg_info_dir)
816 )
817 new_lines.sort()
818 ensure_dir(egg_info_dir)
819 inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt')
820 with open(inst_files_path, 'w') as f:
821 f.write('\n'.join(new_lines) + '\n')
822
823 def ensure_has_source_dir(self, parent_dir):
824 """Ensure that a source_dir is set.
825
826 This will create a temporary build dir if the name of the requirement
827 isn't known yet.
828
829 :param parent_dir: The ideal pip parent_dir for the source_dir.
830 Generally src_dir for editables and build_dir for sdists.
831 :return: self.source_dir
832 """
833 if self.source_dir is None:
834 self.source_dir = self.build_location(parent_dir)
835 return self.source_dir
836
837 def get_install_args(self, global_options, record_filename, root, prefix,
838 pycompile):
839 install_args = [sys.executable, "-u"]
840 install_args.append('-c')
841 install_args.append(SETUPTOOLS_SHIM % self.setup_py)
842 install_args += list(global_options) + \
843 ['install', '--record', record_filename]
844 install_args += ['--single-version-externally-managed']
845
846 if root is not None:
847 install_args += ['--root', root]
848 if prefix is not None:
849 install_args += ['--prefix', prefix]
850
851 if pycompile:
852 install_args += ["--compile"]
853 else:
854 install_args += ["--no-compile"]
855
856 if running_under_virtualenv():
857 py_ver_str = 'python' + sysconfig.get_python_version()
858 install_args += ['--install-headers',
859 os.path.join(sys.prefix, 'include', 'site',
860 py_ver_str, self.name)]
861
862 return install_args
863
864 def remove_temporary_source(self):
865 """Remove the source files from this requirement, if they are marked
866 for deletion"""
867 if self.source_dir and os.path.exists(
868 os.path.join(self.source_dir, PIP_DELETE_MARKER_FILENAME)):
869 logger.debug('Removing source in %s', self.source_dir)
870 rmtree(self.source_dir)
871 self.source_dir = None
872 self._temp_build_dir.cleanup()
873 self.build_env.cleanup()
874
875 def install_editable(self, install_options,
876 global_options=(), prefix=None):
877 logger.info('Running setup.py develop for %s', self.name)
878
879 if self.isolated:
880 global_options = list(global_options) + ["--no-user-cfg"]
881
882 if prefix:
883 prefix_param = ['--prefix={}'.format(prefix)]
884 install_options = list(install_options) + prefix_param
885
886 with indent_log():
887 # FIXME: should we do --install-headers here too?
888 with self.build_env:
889 call_subprocess(
890 [
891 sys.executable,
892 '-c',
893 SETUPTOOLS_SHIM % self.setup_py
894 ] +
895 list(global_options) +
896 ['develop', '--no-deps'] +
897 list(install_options),
898
899 cwd=self.setup_py_dir,
900 show_stdout=False,
901 )
902
903 self.install_succeeded = True
904
905 def check_if_exists(self, use_user_site):
906 """Find an installed distribution that satisfies or conflicts
907 with this requirement, and set self.satisfied_by or
908 self.conflicts_with appropriately.
909 """
910 if self.req is None:
911 return False
912 try:
913 # get_distribution() will resolve the entire list of requirements
914 # anyway, and we've already determined that we need the requirement
915 # in question, so strip the marker so that we don't try to
916 # evaluate it.
917 no_marker = Requirement(str(self.req))
918 no_marker.marker = None
919 self.satisfied_by = pkg_resources.get_distribution(str(no_marker))
920 if self.editable and self.satisfied_by:
921 self.conflicts_with = self.satisfied_by
922 # when installing editables, nothing pre-existing should ever
923 # satisfy
924 self.satisfied_by = None
925 return True
926 except pkg_resources.DistributionNotFound:
927 return False
928 except pkg_resources.VersionConflict:
929 existing_dist = pkg_resources.get_distribution(
930 self.req.name
931 )
932 if use_user_site:
933 if dist_in_usersite(existing_dist):
934 self.conflicts_with = existing_dist
935 elif (running_under_virtualenv() and
936 dist_in_site_packages(existing_dist)):
937 raise InstallationError(
938 "Will not install to the user site because it will "
939 "lack sys.path precedence to %s in %s" %
940 (existing_dist.project_name, existing_dist.location)
941 )
942 else:
943 self.conflicts_with = existing_dist
944 return True
945
946 @property
947 def is_wheel(self):
948 return self.link and self.link.is_wheel
949
950 def move_wheel_files(self, wheeldir, root=None, home=None, prefix=None,
951 warn_script_location=True, use_user_site=False,
952 pycompile=True):
953 move_wheel_files(
954 self.name, self.req, wheeldir,
955 user=use_user_site,
956 home=home,
957 root=root,
958 prefix=prefix,
959 pycompile=pycompile,
960 isolated=self.isolated,
961 warn_script_location=warn_script_location,
962 )
963
964 def get_dist(self):
965 """Return a pkg_resources.Distribution built from self.egg_info_path"""
966 egg_info = self.egg_info_path('').rstrip(os.path.sep)
967 base_dir = os.path.dirname(egg_info)
968 metadata = pkg_resources.PathMetadata(base_dir, egg_info)
969 dist_name = os.path.splitext(os.path.basename(egg_info))[0]
970 return pkg_resources.Distribution(
971 os.path.dirname(egg_info),
972 project_name=dist_name,
973 metadata=metadata,
974 )
975
976 @property
977 def has_hash_options(self):
978 """Return whether any known-good hashes are specified as options.
979
980 These activate --require-hashes mode; hashes specified as part of a
981 URL do not.
982
983 """
984 return bool(self.options.get('hashes', {}))
985
986 def hashes(self, trust_internet=True):
987 """Return a hash-comparer that considers my option- and URL-based
988 hashes to be known-good.
989
990 Hashes in URLs--ones embedded in the requirements file, not ones
991 downloaded from an index server--are almost peers with ones from
992 flags. They satisfy --require-hashes (whether it was implicitly or
993 explicitly activated) but do not activate it. md5 and sha224 are not
994 allowed in flags, which should nudge people toward good algos. We
995 always OR all hashes together, even ones from URLs.
996
997 :param trust_internet: Whether to trust URL-based (#md5=...) hashes
998 downloaded from the internet, as by populate_link()
999
1000 """
1001 good_hashes = self.options.get('hashes', {}).copy()
1002 link = self.link if trust_internet else self.original_link
1003 if link and link.hash:
1004 good_hashes.setdefault(link.hash_name, []).append(link.hash)
1005 return Hashes(good_hashes)
1006
1007
1008def _strip_postfix(req):
1009 """
1010 Strip req postfix ( -dev, 0.2, etc )
1011 """
1012 # FIXME: use package_to_requirement?
1013 match = re.search(r'^(.*?)(?:-dev|-\d.*)$', req)
1014 if match:
1015 # Strip off -dev, -0.2, etc.
1016 warnings.warn(
1017 "#egg cleanup for editable urls will be dropped in the future",
1018 RemovedInPip11Warning,
1019 )
1020 req = match.group(1)
1021 return req
1022
1023
1024def parse_editable(editable_req):
1025 """Parses an editable requirement into:
1026 - a requirement name
1027 - an URL
1028 - extras
1029 - editable options
1030 Accepted requirements:
1031 svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir
1032 .[some_extra]
1033 """
1034
1035 from pip._internal.index import Link
1036
1037 url = editable_req
1038
1039 # If a file path is specified with extras, strip off the extras.
1040 url_no_extras, extras = _strip_extras(url)
1041
1042 if os.path.isdir(url_no_extras):
1043 if not os.path.exists(os.path.join(url_no_extras, 'setup.py')):
1044 raise InstallationError(
1045 "Directory %r is not installable. File 'setup.py' not found." %
1046 url_no_extras
1047 )
1048 # Treating it as code that has already been checked out
1049 url_no_extras = path_to_url(url_no_extras)
1050
1051 if url_no_extras.lower().startswith('file:'):
1052 package_name = Link(url_no_extras).egg_fragment
1053 if extras:
1054 return (
1055 package_name,
1056 url_no_extras,
1057 Requirement("placeholder" + extras.lower()).extras,
1058 )
1059 else:
1060 return package_name, url_no_extras, None
1061
1062 for version_control in vcs:
1063 if url.lower().startswith('%s:' % version_control):
1064 url = '%s+%s' % (version_control, url)
1065 break
1066
1067 if '+' not in url:
1068 raise InstallationError(
1069 '%s should either be a path to a local project or a VCS url '
1070 'beginning with svn+, git+, hg+, or bzr+' %
1071 editable_req
1072 )
1073
1074 vc_type = url.split('+', 1)[0].lower()
1075
1076 if not vcs.get_backend(vc_type):
1077 error_message = 'For --editable=%s only ' % editable_req + \
1078 ', '.join([backend.name + '+URL' for backend in vcs.backends]) + \
1079 ' is currently supported'
1080 raise InstallationError(error_message)
1081
1082 package_name = Link(url).egg_fragment
1083 if not package_name:
1084 raise InstallationError(
1085 "Could not detect requirement name for '%s', please specify one "
1086 "with #egg=your_package_name" % editable_req
1087 )
1088 return _strip_postfix(package_name), url, None
1089
1090
1091def deduce_helpful_msg(req):
1092 """Returns helpful msg in case requirements file does not exist,
1093 or cannot be parsed.
1094
1095 :params req: Requirements file path
1096 """
1097 msg = ""
1098 if os.path.exists(req):
1099 msg = " It does exist."
1100 # Try to parse and check if it is a requirements file.
1101 try:
1102 with open(req, 'r') as fp:
1103 # parse first line only
1104 next(parse_requirements(fp.read()))
1105 msg += " The argument you provided " + \
1106 "(%s) appears to be a" % (req) + \
1107 " requirements file. If that is the" + \
1108 " case, use the '-r' flag to install" + \
1109 " the packages specified within it."
1110 except RequirementParseError:
1111 logger.debug("Cannot parse '%s' as requirements \
1112 file" % (req), exc_info=1)
1113 else:
1114 msg += " File '%s' does not exist." % (req)
1115 return msg