Пример #1
0
    def resolve_reqs(self,
                     download_dir,
                     ireq,
                     wheel_cache,
                     setup_requires={},
                     dist=None):
        results = None
        setup_requires = {}
        dist = None
        ireq.isolated = False
        ireq._wheel_cache = wheel_cache

        try:
            from pipenv.patched.notpip._internal.operations.prepare import RequirementPreparer
        except ImportError:
            # Pip 9 and below
            reqset = RequirementSet(
                self.build_dir,
                self.source_dir,
                download_dir=download_dir,
                wheel_download_dir=self._wheel_download_dir,
                session=self.session,
                ignore_installed=True,
                ignore_compatibility=False,
                wheel_cache=wheel_cache)
            results = reqset._prepare_file(self.finder,
                                           ireq,
                                           ignore_requires_python=True)
        else:
            # pip >= 10
            preparer_kwargs = {
                'build_dir': self.build_dir,
                'src_dir': self.source_dir,
                'download_dir': download_dir,
                'wheel_download_dir': self._wheel_download_dir,
                'progress_bar': 'off',
                'build_isolation': False
            }
            resolver_kwargs = {
                'finder': self.finder,
                'session': self.session,
                'upgrade_strategy': "to-satisfy-only",
                'force_reinstall': True,
                'ignore_dependencies': False,
                'ignore_requires_python': True,
                'ignore_installed': True,
                'isolated': False,
                'wheel_cache': wheel_cache,
                'use_user_site': False,
                'ignore_compatibility': False
            }
            resolver = None
            preparer = None
            with RequirementTracker() as req_tracker:
                # Pip 18 uses a requirement tracker to prevent fork bombs
                if req_tracker:
                    preparer_kwargs['req_tracker'] = req_tracker
                preparer = RequirementPreparer(**preparer_kwargs)
                resolver_kwargs['preparer'] = preparer
                reqset = RequirementSet()
                ireq.is_direct = True
                # reqset.add_requirement(ireq)
                resolver = PipResolver(**resolver_kwargs)
                resolver.require_hashes = False
                results = resolver._resolve_one(reqset, ireq)

        cleanup_fn = getattr(reqset, "cleanup_files", None)
        if cleanup_fn is not None:
            try:
                cleanup_fn()
            except OSError:
                pass

        if ireq.editable and (not ireq.source_dir
                              or not os.path.exists(ireq.source_dir)):
            if ireq.editable:
                self._source_dir = TemporaryDirectory(fs_str("source"))
                ireq.ensure_has_source_dir(self.source_dir)

        if ireq.editable and (ireq.source_dir
                              and os.path.exists(ireq.source_dir)):
            # Collect setup_requires info from local eggs.
            # Do this after we call the preparer on these reqs to make sure their
            # egg info has been created
            from pipenv.utils import chdir
            with chdir(ireq.setup_py_dir):
                try:
                    from setuptools.dist import distutils
                    dist = distutils.core.run_setup(ireq.setup_py)
                except InstallationError:
                    ireq.run_egg_info()
                except (TypeError, ValueError, AttributeError):
                    pass
                if not dist:
                    try:
                        dist = ireq.get_dist()
                    except (ImportError, ValueError, TypeError,
                            AttributeError):
                        pass
        if ireq.editable and dist:
            setup_requires = getattr(dist, "extras_require", None)
            if not setup_requires:
                setup_requires = {
                    "setup_requires": getattr(dist, "setup_requires", None)
                }
            if not getattr(ireq, 'req', None):
                try:
                    ireq.req = dist.as_requirement() if dist else None
                except (ValueError, TypeError) as e:
                    pass

            # Convert setup_requires dict into a somewhat usable form.
            if setup_requires:
                for section in setup_requires:
                    python_version = section
                    not_python = not (section.startswith('[')
                                      and ':' in section)

                    # This is for cleaning up :extras: formatted markers
                    # by adding them to the results of the resolver
                    # since any such extra would have been returned as a result anyway
                    for value in setup_requires[section]:
                        # This is a marker.
                        if value.startswith('[') and ':' in value:
                            python_version = value[1:-1]
                            not_python = False
                        # Strip out other extras.
                        if value.startswith('[') and ':' not in value:
                            not_python = True

                        if ':' not in value:
                            try:
                                if not not_python:
                                    results.add(
                                        InstallRequirement.from_line(
                                            "{0}{1}".format(
                                                value, python_version).replace(
                                                    ':', ';')))
                            # Anything could go wrong here -- can't be too careful.
                            except Exception:
                                pass

            # this section properly creates 'python_version' markers for cross-python
            # virtualenv creation and for multi-python compatibility.
            requires_python = reqset.requires_python if hasattr(
                reqset, 'requires_python') else resolver.requires_python
            if requires_python:
                marker_str = ''
                # This corrects a logic error from the previous code which said that if
                # we Encountered any 'requires_python' attributes, basically only create a
                # single result no matter how many we resolved.  This should fix
                # a majority of the remaining non-deterministic resolution issues.
                if any(
                        requires_python.startswith(op)
                        for op in Specifier._operators.keys()):
                    # We are checking first if we have  leading specifier operator
                    # if not, we can assume we should be doing a == comparison
                    specifierset = SpecifierSet(requires_python)
                    # for multiple specifiers, the correct way to represent that in
                    # a specifierset is `Requirement('fakepkg; python_version<"3.0,>=2.6"')`
                    from passa.internals.specifiers import cleanup_pyspecs
                    marker_str = str(
                        Marker(" and ".join(
                            dedup([
                                "python_version {0[0]} '{0[1]}'".format(spec)
                                for spec in cleanup_pyspecs(specifierset)
                            ]))))
                # The best way to add markers to a requirement is to make a separate requirement
                # with only markers on it, and then to transfer the object istelf
                marker_to_add = Requirement(
                    'fakepkg; {0}'.format(marker_str)).marker
                if ireq in results:
                    results.remove(ireq)
                print(marker_to_add)
                ireq.req.marker = marker_to_add

        results = set(results) if results else set()
        return results, ireq
Пример #2
0
    def get_legacy_dependencies(self, ireq):
        """
        Given a pinned or an editable InstallRequirement, returns a set of
        dependencies (also InstallRequirements, but not necessarily pinned).
        They indicate the secondary dependencies for the given requirement.
        """
        if not (ireq.editable or is_pinned_requirement(ireq)):
            raise TypeError(
                'Expected pinned or editable InstallRequirement, got {}'.
                format(ireq))

        if ireq not in self._dependencies_cache:
            if ireq.editable and (ireq.source_dir
                                  and os.path.exists(ireq.source_dir)):
                # No download_dir for locally available editable requirements.
                # If a download_dir is passed, pip will  unnecessarely
                # archive the entire source directory
                download_dir = None
            elif ireq.link and not ireq.link.is_artifact:
                # No download_dir for VCS sources.  This also works around pip
                # using git-checkout-index, which gets rid of the .git dir.
                download_dir = None
            else:
                download_dir = self._download_dir
                if not os.path.isdir(download_dir):
                    os.makedirs(download_dir)
            if not os.path.isdir(self._wheel_download_dir):
                os.makedirs(self._wheel_download_dir)
            # Collect setup_requires info from local eggs.
            # Do this after we call the preparer on these reqs to make sure their
            # egg info has been created
            setup_requires = {}
            dist = None
            if ireq.editable:
                try:
                    dist = ireq.get_dist()
                except InstallationError:
                    ireq.run_egg_info()
                    dist = ireq.get_dist()
                except (TypeError, ValueError, AttributeError):
                    pass
                else:
                    if dist.has_metadata('requires.txt'):
                        setup_requires = self.finder.get_extras_links(
                            dist.get_metadata_lines('requires.txt'))
            try:
                # Pip 9 and below
                reqset = RequirementSet(
                    self.build_dir,
                    self.source_dir,
                    download_dir=download_dir,
                    wheel_download_dir=self._wheel_download_dir,
                    session=self.session,
                    ignore_installed=True,
                    ignore_compatibility=False,
                    wheel_cache=self.wheel_cache,
                )
                result = reqset._prepare_file(self.finder,
                                              ireq,
                                              ignore_requires_python=True)
            except TypeError:
                # Pip >= 10 (new resolver!)
                preparer = RequirementPreparer(
                    build_dir=self.build_dir,
                    src_dir=self.source_dir,
                    download_dir=download_dir,
                    wheel_download_dir=self._wheel_download_dir,
                    progress_bar='off',
                    build_isolation=False)
                reqset = RequirementSet()
                ireq.is_direct = True
                reqset.add_requirement(ireq)
                self.resolver = PipResolver(preparer=preparer,
                                            finder=self.finder,
                                            session=self.session,
                                            upgrade_strategy="to-satisfy-only",
                                            force_reinstall=True,
                                            ignore_dependencies=False,
                                            ignore_requires_python=True,
                                            ignore_installed=True,
                                            isolated=False,
                                            wheel_cache=self.wheel_cache,
                                            use_user_site=False,
                                            ignore_compatibility=False)
                self.resolver.resolve(reqset)
                result = set(reqset.requirements.values())

            # HACK: Sometimes the InstallRequirement doesn't properly get
            # these values set on it during the resolution process. It's
            # difficult to pin down what is going wrong. This fixes things.
            if not getattr(ireq, 'version', None):
                try:
                    dist = ireq.get_dist() if not dist else None
                    ireq.version = ireq.get_dist().version
                except (ValueError, OSError, TypeError, AttributeError) as e:
                    pass
            if not getattr(ireq, 'project_name', None):
                try:
                    ireq.project_name = dist.project_name if dist else None
                except (ValueError, TypeError) as e:
                    pass
            if not getattr(ireq, 'req', None):
                try:
                    ireq.req = dist.as_requirement() if dist else None
                except (ValueError, TypeError) as e:
                    pass

            # Convert setup_requires dict into a somewhat usable form.
            if setup_requires:
                for section in setup_requires:
                    python_version = section
                    not_python = not (section.startswith('[')
                                      and ':' in section)

                    # This is for cleaning up :extras: formatted markers
                    # by adding them to the results of the resolver
                    # since any such extra would have been returned as a result anyway
                    for value in setup_requires[section]:
                        # This is a marker.
                        if value.startswith('[') and ':' in value:
                            python_version = value[1:-1]
                            not_python = False
                        # Strip out other extras.
                        if value.startswith('[') and ':' not in value:
                            not_python = True

                        if ':' not in value:
                            try:
                                if not not_python:
                                    result = result + [
                                        InstallRequirement.from_line(
                                            "{0}{1}".format(
                                                value, python_version).replace(
                                                    ':', ';'))
                                    ]
                            # Anything could go wrong here -- can't be too careful.
                            except Exception:
                                pass

            # this section properly creates 'python_version' markers for cross-python
            # virtualenv creation and for multi-python compatibility.
            requires_python = reqset.requires_python if hasattr(
                reqset, 'requires_python') else self.resolver.requires_python
            if requires_python:
                marker_str = ''
                # This corrects a logic error from the previous code which said that if
                # we Encountered any 'requires_python' attributes, basically only create a
                # single result no matter how many we resolved.  This should fix
                # a majority of the remaining non-deterministic resolution issues.
                if any(
                        requires_python.startswith(op)
                        for op in Specifier._operators.keys()):
                    # We are checking first if we have  leading specifier operator
                    # if not, we can assume we should be doing a == comparison
                    specifierset = list(SpecifierSet(requires_python))
                    # for multiple specifiers, the correct way to represent that in
                    # a specifierset is `Requirement('fakepkg; python_version<"3.0,>=2.6"')`
                    marker_key = Variable('python_version')
                    markers = []
                    for spec in specifierset:
                        operator, val = spec._spec
                        operator = Op(operator)
                        val = Value(val)
                        markers.append(''.join([
                            marker_key.serialize(),
                            operator.serialize(),
                            val.serialize()
                        ]))
                    marker_str = ' and '.join(markers)
                # The best way to add markers to a requirement is to make a separate requirement
                # with only markers on it, and then to transfer the object istelf
                marker_to_add = Requirement(
                    'fakepkg; {0}'.format(marker_str)).marker
                result.remove(ireq)
                ireq.req.marker = marker_to_add
                result.add(ireq)

            self._dependencies_cache[ireq] = result
            reqset.cleanup_files()

        return set(self._dependencies_cache[ireq])
Пример #3
0
    def get_legacy_dependencies(self, ireq):
        """
        Given a pinned or an editable InstallRequirement, returns a set of
        dependencies (also InstallRequirements, but not necessarily pinned).
        They indicate the secondary dependencies for the given requirement.
        """
        if not (ireq.editable or is_pinned_requirement(ireq)):
            raise TypeError(
                'Expected pinned or editable InstallRequirement, got {}'.
                format(ireq))

        if ireq not in self._dependencies_cache:
            if ireq.editable and (ireq.source_dir
                                  and os.path.exists(ireq.source_dir)):
                # No download_dir for locally available editable requirements.
                # If a download_dir is passed, pip will  unnecessarely
                # archive the entire source directory
                download_dir = None
            elif ireq.link and not ireq.link.is_artifact:
                # No download_dir for VCS sources.  This also works around pip
                # using git-checkout-index, which gets rid of the .git dir.
                download_dir = None
            else:
                download_dir = self._download_dir
                if not os.path.isdir(download_dir):
                    os.makedirs(download_dir)
            if not os.path.isdir(self._wheel_download_dir):
                os.makedirs(self._wheel_download_dir)

            try:
                # Pip < 9 and below
                reqset = RequirementSet(
                    self.build_dir,
                    self.source_dir,
                    download_dir=download_dir,
                    wheel_download_dir=self._wheel_download_dir,
                    session=self.session,
                    ignore_installed=True,
                    ignore_compatibility=False,
                    wheel_cache=self.wheel_cache,
                )
                result = reqset._prepare_file(self.finder,
                                              ireq,
                                              ignore_requires_python=True)
            except TypeError:
                # Pip >= 10 (new resolver!)
                preparer = RequirementPreparer(
                    build_dir=self.build_dir,
                    src_dir=self.source_dir,
                    download_dir=download_dir,
                    wheel_download_dir=self._wheel_download_dir,
                    progress_bar='off',
                    build_isolation=False)
                reqset = RequirementSet()
                ireq.is_direct = True
                reqset.add_requirement(ireq)
                self.resolver = PipResolver(preparer=preparer,
                                            finder=self.finder,
                                            session=self.session,
                                            upgrade_strategy="to-satisfy-only",
                                            force_reinstall=False,
                                            ignore_dependencies=False,
                                            ignore_requires_python=True,
                                            ignore_installed=True,
                                            isolated=False,
                                            wheel_cache=self.wheel_cache,
                                            use_user_site=False,
                                            ignore_compatibility=False)
                self.resolver.resolve(reqset)
                result = reqset.requirements.values()

            # Collect setup_requires info from local eggs.
            # Do this after we call the preparer on these reqs to make sure their
            # egg info has been created
            setup_requires = {}
            if ireq.editable:
                try:
                    dist = ireq.get_dist()
                    if dist.has_metadata('requires.txt'):
                        setup_requires = self.finder.get_extras_links(
                            dist.get_metadata_lines('requires.txt'))
                    # HACK: Sometimes the InstallRequirement doesn't properly get
                    # these values set on it during the resolution process. It's
                    # difficult to pin down what is going wrong. This fixes things.
                    ireq.version = dist.version
                    ireq.project_name = dist.project_name
                    ireq.req = dist.as_requirement()
                except (TypeError, ValueError):
                    pass
            # Convert setup_requires dict into a somewhat usable form.
            if setup_requires:
                for section in setup_requires:
                    python_version = section
                    not_python = not (section.startswith('[')
                                      and ':' in section)

                    for value in setup_requires[section]:
                        # This is a marker.
                        if value.startswith('[') and ':' in value:
                            python_version = value[1:-1]
                            not_python = False
                        # Strip out other extras.
                        if value.startswith('[') and ':' not in value:
                            not_python = True

                        if ':' not in value:
                            try:
                                if not not_python:
                                    result = result + [
                                        InstallRequirement.from_line(
                                            "{0}{1}".format(
                                                value, python_version).replace(
                                                    ':', ';'))
                                    ]
                            # Anything could go wrong here — can't be too careful.
                            except Exception:
                                pass
            requires_python = reqset.requires_python if hasattr(
                reqset, 'requires_python') else self.resolver.requires_python
            if requires_python:
                marker = 'python_version=="{0}"'.format(
                    requires_python.replace(' ', ''))
                new_req = InstallRequirement.from_line('{0}; {1}'.format(
                    str(ireq.req), marker))
                result = [new_req]

            self._dependencies_cache[ireq] = result
            reqset.cleanup_files()
        return set(self._dependencies_cache[ireq])