Example #1
0
    def cached_wheel(self, link, package_name):
        not_cached = (not self._cache_dir or not link or link.is_wheel
                      or not link.is_artifact or not package_name)

        if not_cached:
            return link

        canonical_name = canonicalize_name(package_name)
        formats = pip.index.fmt_ctl_formats(self._format_control,
                                            canonical_name)
        if "binary" not in formats:
            return link
        root = self.get_cache_path_for_link(link)
        try:
            wheel_names = os.listdir(root)
        except OSError as err:
            if err.errno in {errno.ENOENT, errno.ENOTDIR}:
                return link
            raise
        candidates = []
        for wheel_name in wheel_names:
            try:
                wheel = Wheel(wheel_name)
            except InvalidWheelFilename:
                continue
            if not wheel.supported():
                # Built for a different python/arch/etc
                continue
            candidates.append((wheel.support_index_min(), wheel_name))
        if not candidates:
            return link
        candidates.sort()
        path = os.path.join(root, candidates[0][1])
        return pip.index.Link(path_to_url(path))
Example #2
0
def faster_find_requirement(self, req, upgrade):
    """see faster_pip_packagefinder"""
    from pip.index import BestVersionAlreadyInstalled
    if req_is_absolute(req.req):
        # if the version is pinned-down by a ==
        # first try to use any installed package that satisfies the req
        if req.satisfied_by:
            if upgrade:
                # as a matter of api, find_requirement() only raises during upgrade -- shrug
                raise BestVersionAlreadyInstalled
            else:
                return None

        # then try an optimistic search for a .whl file:
        from os.path import join
        from glob import glob
        from pip.wheel import Wheel
        from pip.index import Link
        for findlink in self.find_links:
            if findlink.startswith('file://'):
                findlink = findlink[7:]
            else:
                continue
            # this matches the name-munging done in pip.wheel:
            reqname = req.name.replace('-', '_')
            for link in glob(join(findlink, reqname + '-*.whl')):
                link = Link('file://' + link)
                wheel = Wheel(link.filename)
                if wheel.version in req.req and wheel.supported():
                    return link

    # otherwise, do the full network search
    return self.unpatched['find_requirement'](self, req, upgrade)
Example #3
0
 def _link_sort_key(self, link_tuple):
     """
     Function used to generate link sort key for link tuples.
     The greater the return value, the more preferred it is.
     If not finding wheels, then sorted by version only.
     If finding wheels, then the sort order is by version, then:
       1. existing installs
       2. wheels ordered via Wheel.support_index_min()
       3. source archives
     Note: it was considered to embed this logic into the Link
           comparison operators, but then different sdist links
           with the same version, would have to be considered equal
     """
     parsed_version, link, _ = link_tuple
     if self.use_wheel:
         support_num = len(supported_tags)
         if link == INSTALLED_VERSION:
             pri = 1
         elif link.ext == wheel_ext:
             wheel = Wheel(link.filename)  # can raise InvalidWheelFilename
             if not wheel.supported():
                 raise UnsupportedWheel(
                     "%s is not a supported wheel for this platform. It "
                     "can't be sorted." % wheel.filename
                 )
             pri = -(wheel.support_index_min())
         else:  # sdist
             pri = -(support_num)
         return (parsed_version, pri)
     else:
         return parsed_version
Example #4
0
 def _candidate_sort_key(self, candidate):
     """
     Function used to generate link sort key for link tuples.
     The greater the return value, the more preferred it is.
     If not finding wheels, then sorted by version only.
     If finding wheels, then the sort order is by version, then:
       1. existing installs
       2. wheels ordered via Wheel.support_index_min()
       3. source archives
     Note: it was considered to embed this logic into the Link
           comparison operators, but then different sdist links
           with the same version, would have to be considered equal
     """
     support_num = len(supported_tags)
     if candidate.location.is_wheel:
         # can raise InvalidWheelFilename
         wheel = Wheel(candidate.location.filename)
         if not wheel.supported():
             raise UnsupportedWheel(
                 "%s is not a supported wheel for this platform. It "
                 "can't be sorted." % wheel.filename
             )
         pri = -(wheel.support_index_min())
     else:  # sdist
         pri = -(support_num)
     return (candidate.version, pri)
Example #5
0
 def _link_sort_key(self, link_tuple):
     """
     Function used to generate link sort key for link tuples.
     The greater the return value, the more preferred it is.
     If not finding wheels, then sorted by version only.
     If finding wheels, then the sort order is by version, then:
       1. existing installs
       2. wheels ordered via Wheel.support_index_min()
       3. source archives
     Note: it was considered to embed this logic into the Link
           comparison operators, but then different sdist links
           with the same version, would have to be considered equal
     """
     parsed_version, link, _ = link_tuple
     if self.use_wheel:
         support_num = len(supported_tags)
         if link == INSTALLED_VERSION:
             pri = 1
         elif link.ext == wheel_ext:
             wheel = Wheel(link.filename)  # can raise InvalidWheelFilename
             if not wheel.supported():
                 raise UnsupportedWheel(
                     "%s is not a supported wheel for this platform. It can't be sorted."
                     % wheel.filename)
             pri = -(wheel.support_index_min())
         else:  # sdist
             pri = -(support_num)
         return (parsed_version, pri)
     else:
         return parsed_version
Example #6
0
def faster_find_requirement(self, req, upgrade):
    """see faster_pip_packagefinder"""
    from pip.index import BestVersionAlreadyInstalled
    if req_is_absolute(req.req):
        # if the version is pinned-down by a ==
        # first try to use any installed package that satisfies the req
        if req.satisfied_by:
            if upgrade:
                # as a matter of api, find_requirement() only raises during upgrade -- shrug
                raise BestVersionAlreadyInstalled
            else:
                return None

        # then try an optimistic search for a .whl file:
        from os.path import join
        from glob import glob
        from pip.wheel import Wheel
        from pip.index import Link
        for findlink in self.find_links:
            if findlink.startswith('file://'):
                findlink = findlink[7:]
            else:
                continue
            # this matches the name-munging done in pip.wheel:
            reqname = req.name.replace('-', '_')
            for link in glob(join(findlink, reqname + '-*.whl')):
                link = Link('file://' + link)
                wheel = Wheel(link.filename)
                if wheel.version in req.req and wheel.supported():
                    return link

    # otherwise, do the full network search
    return self.unpatched['find_requirement'](self, req, upgrade)
Example #7
0
File: index.py Project: rwols/pip
 def _candidate_sort_key(self, candidate):
     """
     Function used to generate link sort key for link tuples.
     The greater the return value, the more preferred it is.
     If not finding wheels, then sorted by version only.
     If finding wheels, then the sort order is by version, then:
       1. existing installs
       2. wheels ordered via Wheel.support_index_min(self.valid_tags)
       3. source archives
     Note: it was considered to embed this logic into the Link
           comparison operators, but then different sdist links
           with the same version, would have to be considered equal
     """
     support_num = len(self.valid_tags)
     if candidate.location.is_wheel:
         # can raise InvalidWheelFilename
         wheel = Wheel(candidate.location.filename)
         if not wheel.supported(self.valid_tags):
             raise UnsupportedWheel(
                 "%s is not a supported wheel for this platform. It "
                 "can't be sorted." % wheel.filename)
         pri = -(wheel.support_index_min(self.valid_tags))
     else:  # sdist
         pri = -(support_num)
     return (candidate.version, pri)
Example #8
0
    def _link_package_versions(self, link, search):
        """Return an InstallationCandidate or None"""

        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
            ext = link.ext
        else:
            egg_info, ext = link.splitext()
            if not ext:
                self._log_skipped_link(link, "not a file")
                return
            if ext not in SUPPORTED_EXTENSIONS:
                self._log_skipped_link(link, "unsupported archive format: %s" % ext)
                return
            if "binary" not in search.formats and ext == wheel_ext:
                self._log_skipped_link(link, "No binaries permitted for %s" % search.supplied)
                return
            if "macosx10" in link.path and ext == ".zip":
                self._log_skipped_link(link, "macosx10 one")
                return
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    self._log_skipped_link(link, "invalid wheel filename")
                    return
                if canonicalize_name(wheel.name) != search.canonical:
                    self._log_skipped_link(link, "wrong project name (not %s)" % search.supplied)
                    return
                if not wheel.supported():
                    self._log_skipped_link(link, "it is not compatible with this Python")
                    return

                version = wheel.version

        # This should be up by the search.ok_binary check, but see issue 2700.
        if "source" not in search.formats and ext != wheel_ext:
            self._log_skipped_link(link, "No sources permitted for %s" % search.supplied)
            return

        if not version:
            version = egg_info_matches(egg_info, search.supplied, link)
        if version is None:
            self._log_skipped_link(link, "wrong project name (not %s)" % search.supplied)
            return

        match = self._py_version_re.search(version)
        if match:
            version = version[: match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                self._log_skipped_link(link, "Python version is incorrect")
                return
        logger.debug("Found link %s, version: %s", link, version)

        return InstallationCandidate(search.supplied, version, link)
Example #9
0
def optimistic_wheel_search(req, index_urls):
    name = req.name.replace('-', '_').lower()

    for index_url in index_urls:
        expected_location = os.path.join(
            CACHE.wheelhouse,
            index_url,
            ignorecase_glob(name) + '-*.whl',
        )
        for link in glob.glob(expected_location):
            link = Link('file:' + link)
            wheel = Wheel(link.filename)
            if req.specifier.contains(wheel.version) and wheel.supported():
                return link
Example #10
0
def it_doesnt_wheel_local_dirs(tmpdir):
    venv = tmpdir.join('venv')
    install_coverage(venv)

    pip = venv.join('bin/pip').strpath
    run(pip, 'install', 'venv-update==' + __version__)

    run(
        venv.join('bin/pip-faster').strpath,
        'install',
        TOP.join('tests/testing/packages/dependant_package').strpath,
    )

    frozen_requirements = pip_freeze(str(venv)).split('\n')
    assert set(frozen_requirements) == set([
        'coverage==4.0.3',
        'coverage-enable-subprocess==0',
        'dependant-package==1',
        'implicit-dependency==1',
        'many-versions-package==3',
        'pure-python-package==0.2.0',
        'venv-update==' + __version__,
        'wheel==0.29.0',
        '',
    ])

    wheelhouse = tmpdir.join('home', '.cache', 'pip-faster', 'wheelhouse')
    assert set(Wheel(f.basename).name for f in wheelhouse.listdir()) == set([
        'implicit-dependency',
        'many-versions-package',
        'pure-python-package',
    ])
Example #11
0
def it_installs_stuff_with_dash_e_without_wheeling(tmpdir):
    venv = tmpdir.join('venv')
    install_coverage(venv)

    pip = venv.join('bin/pip').strpath
    run(pip, 'install', 'venv-update==' + __version__)

    # Install a package from git with no extra dependencies in editable mode.
    #
    # We need to install a package from VCS instead of the filesystem because
    # otherwise we aren't testing that editable requirements aren't wheeled
    # (and instead might just be testing that local paths aren't wheeled).
    requirements(
        '-e git+git://github.com/Yelp/dumb-init.git@87545be699a13d0fd31f67199b7782ebd446437e#egg=dumb-init'
    )  # noqa

    run(str(venv.join('bin/pip-faster')), 'install', '-r', 'requirements.txt')

    frozen_requirements = pip_freeze(str(venv)).split('\n')
    assert set(frozen_requirements) == set([
        '-e git://github.com/Yelp/dumb-init.git@87545be699a13d0fd31f67199b7782ebd446437e#egg=dumb_init-dev',  # noqa
        'coverage-enable-subprocess==0',
        'coverage==4.0.3',
        'venv-update==' + __version__,
        'wheel==0.29.0',
        '',
    ])

    # we shouldn't wheel things installed editable
    wheelhouse = tmpdir.join('home', '.cache', 'pip-faster', 'wheelhouse')
    assert set(Wheel(f.basename).name for f in wheelhouse.listdir()) == set([])
Example #12
0
def cached_wheels(tmpdir):
    for _, _, filenames in os.walk(
            tmpdir.join('home', '.cache', 'pip-faster',
                        'wheelhouse').strpath, ):
        for filename in filenames:
            assert filename.endswith('.whl'), filename
            yield Wheel(filename)
Example #13
0
File: cache.py Project: rowhit/pip
    def get(self, link, package_name):
        candidates = []

        for wheel_name in self._get_candidates(link, package_name):
            try:
                wheel = Wheel(wheel_name)
            except InvalidWheelFilename:
                continue
            if not wheel.supported():
                # Built for a different python/arch/etc
                continue
            candidates.append((wheel.support_index_min(), wheel_name))

        if not candidates:
            return link

        return self._link_for_candidate(link, min(candidates)[1])
Example #14
0
    def get(self, link, package_name):
        candidates = []

        for wheel_name in self._get_candidates(link, package_name):
            try:
                wheel = Wheel(wheel_name)
            except InvalidWheelFilename:
                continue
            if not wheel.supported():
                # Built for a different python/arch/etc
                continue
            candidates.append((wheel.support_index_min(), wheel_name))

        if not candidates:
            return link

        return self._link_for_candidate(link, min(candidates)[1])
def get_platform_tags(wheel):
    # type (unicode) -> List[unicode]
    """
    Returns the python platform tags indicated by the file name.
    :param wheel: wheel file name (without directory)
    :return:
    """
    from pip.wheel import Wheel
    w = Wheel(wheel)
    return w.pyversions
Example #16
0
    def __init__(self, url, comes_from=None, internal=None, trusted=None):
        self.url = url
        self.comes_from = comes_from
        self.internal = internal
        self.trusted = trusted

        # Set whether it's a wheel
        self.wheel = None
        if url != Inf and self.splitext()[1] == wheel_ext:
            self.wheel = Wheel(self.filename)
    def from_line(cls, name, comes_from=None, prereleases=None):
        """Creates an InstallRequirement from a name, which might be a
        requirement, directory containing 'setup.py', filename, or URL.
        """
        url = None
        name = name.strip()
        req = None
        path = os.path.normpath(os.path.abspath(name))
        link = None

        if is_url(name):
            link = Link(name)
        elif (os.path.isdir(path)
                and (os.path.sep in name or name.startswith('.'))):
            if not is_installable_dir(path):
                raise InstallationError(
                    "Directory %r is not installable. File 'setup.py' not "
                    "found." % name
                )
            link = Link(path_to_url(name))
        elif is_archive_file(path):
            if not os.path.isfile(path):
                logger.warn(
                    'Requirement %r looks like a filename, but the file does '
                    'not exist',
                    name
                )
            link = Link(path_to_url(name))

        # If the line has an egg= definition, but isn't editable, pull the
        # requirement out. Otherwise, assume the name is the req for the non
        # URL/path/archive case.
        if link and req is None:
            url = link.url_without_fragment
            # when fragment is None, this will become an 'unnamed' requirement
            req = link.egg_fragment

            # Handle relative file URLs
            if link.scheme == 'file' and re.search(r'\.\./', url):
                url = path_to_url(os.path.normpath(os.path.abspath(link.path)))

            # fail early for invalid or unsupported wheels
            if link.ext == wheel_ext:
                wheel = Wheel(link.filename)  # can raise InvalidWheelFilename
                if not wheel.supported():
                    raise UnsupportedWheel(
                        "%s is not a supported wheel on this platform." %
                        wheel.filename
                    )

        else:
            req = name

        return cls(req, comes_from, url=url, prereleases=prereleases)
Example #18
0
def optimistic_wheel_search(req, find_links):
    assert req_is_pinned(req), req

    # this matches the name-munging done in pip.wheel:
    reqname = req.project_name.replace('-', '_')
    reqname = ignorecase_glob(reqname)
    reqname = reqname + '-*.whl'

    for findlink in find_links:
        if findlink.startswith('file:'):
            findlink = findlink[5:]
        from os.path import join
        findlink = join(findlink, reqname)
        logger.debug('wheel glob: %s', findlink)
        from glob import glob
        for link in glob(findlink):
            from pip.index import Link
            link = Link('file:' + link)
            from pip.wheel import Wheel
            wheel = Wheel(link.filename)
            logger.debug('Candidate wheel: %s', link.filename)
            if wheel.version in req and wheel.supported():
                return link
Example #19
0
def make_wheels():
    """Build wheels of all installed packages that don't already have one"""
    bootstrap()

    from pip import get_installed_distributions
    from pip.wheel import Wheel
    from wheel.install import WheelFile
    from wheel.util import matches_requirement

    supported_wheels = []
    for wheel_file in glob.glob('/tmp/wheelhouse/*.whl'):
        wheelobj = Wheel(wheel_file)
        if wheelobj.supported():
            supported_wheels.append(WheelFile(wheel_file))

    for dist in get_installed_distributions():
        if dist.project_name == 'kwarter':
            continue

        distid = '{0.project_name}=={0.version}'.format(dist)
        if not matches_requirement(distid, supported_wheels):
            call(
                ['pip', 'wheel', '-w', '/tmp/wheelhouse', '--no-deps', distid])
Example #20
0
def optimistic_wheel_search(req, find_links):
    from os.path import join, exists

    best_version = pkg_resources.parse_version('')
    best_link = None
    for findlink in find_links:
        if findlink.startswith('file:'):
            findlink = findlink[5:]
        elif not exists(findlink):
            assert False, 'findlink not file: coverage: %r' % findlink
            continue  # TODO: test coverage
        # this matches the name-munging done in pip.wheel:
        reqname = req.name.replace('-', '_')

        reqname = ignorecase_glob(reqname)
        reqname = join(findlink, reqname + '-*.whl')
        logger.debug('wheel glob: %s', reqname)
        from glob import glob
        for link in glob(reqname):
            from pip.index import Link
            link = Link('file://' + link)
            from pip.wheel import Wheel
            wheel = Wheel(link.filename)
            logger.debug('Candidate wheel: %s', link.filename)
            if wheel.version not in req.req:
                continue

            if not wheel.supported():
                continue

            version = pkg_resources.parse_version(wheel.version)
            if version > best_version:
                best_version = version
                best_link = link

    return best_link
Example #21
0
def optimistic_wheel_search(req, find_links):
    from os.path import join, exists

    best_version = pkg_resources.parse_version('')
    best_link = None
    for findlink in find_links:
        if findlink.startswith('file:'):
            findlink = findlink[5:]
        elif not exists(findlink):
            assert False, 'findlink not file: coverage: %r' % findlink
            continue  # TODO: test coverage
        # this matches the name-munging done in pip.wheel:
        reqname = req.name.replace('-', '_')

        reqname = ignorecase_glob(reqname)
        reqname = join(findlink, reqname + '-*.whl')
        logger.debug('wheel glob: %s', reqname)
        from glob import glob
        for link in glob(reqname):
            from pip.index import Link
            link = Link('file://' + link)
            from pip.wheel import Wheel
            wheel = Wheel(link.filename)
            logger.debug('Candidate wheel: %s', link.filename)
            if wheel.version not in req.req:
                continue

            if not wheel.supported():
                continue

            version = pkg_resources.parse_version(wheel.version)
            if version > best_version:
                best_version = version
                best_link = link

    return best_link
Example #22
0
def test_old_pip_and_setuptools(tmpdir, reqs):
    """We should be able to use pip-faster's wheel building even if we have
    ancient pip and setuptools.

    https://github.com/Yelp/pip-faster/issues/33
    """
    tmpdir.chdir()

    # 1. Create an empty virtualenv.
    # 2. Install old pip/setuptools that don't support wheel building.
    # 3. Install pip-faster.
    # 4. Install pure-python-package and assert it was wheeled during install.
    venv = tmpdir.join('venv')
    run('virtualenv', venv.strpath)

    # We need to add public PyPI as an extra URL since we're installing
    # packages (setuptools and pip) which aren't available from our PyPI fixture.
    from os import environ
    environ['PIP_EXTRA_INDEX_URL'] = 'https://pypi.python.org/simple/'
    try:
        pip = venv.join('bin/pip').strpath
        for req in reqs:
            run(pip, 'install', '--', req)
        # wheel needs argparse but it won't get installed
        if sys.version_info < (2, 7):
            run(pip, 'install', 'argparse')
        run(pip, 'install', 'pip-faster==' + __version__)
    finally:
        del environ['PIP_EXTRA_INDEX_URL']

    run(str(venv.join('bin/pip-faster')), 'install', 'pure_python_package')

    # it was installed
    assert 'pure-python-package==0.2.0' in pip_freeze(str(venv)).split('\n')

    # it was wheeled
    from pip.wheel import Wheel
    wheelhouse = tmpdir.join('home', '.cache', 'pip-faster', 'wheelhouse')
    assert 'pure-python-package' in [
        Wheel(f.basename).name for f in wheelhouse.listdir()
    ]
Example #23
0
    def _link_package_versions(self, link, search):
        """Return an InstallationCandidate or None"""
        platform = get_platform()

        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
            ext = link.ext
        else:
            egg_info, ext = link.splitext()
            if not ext:
                self._log_skipped_link(link, 'not a file')
                return
            if ext not in SUPPORTED_EXTENSIONS:
                self._log_skipped_link(
                    link, 'unsupported archive format: %s' % ext)
                return
            if "binary" not in search.formats and ext == wheel_ext:
                self._log_skipped_link(
                    link, 'No binaries permitted for %s' % search.supplied)
                return
            if "macosx10" in link.path and ext == '.zip':
                self._log_skipped_link(link, 'macosx10 one')
                return
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    self._log_skipped_link(link, 'invalid wheel filename')
                    return
                if (pkg_resources.safe_name(wheel.name).lower() !=
                        search.canonical):
                    self._log_skipped_link(
                        link, 'wrong project name (not %s)' % search.supplied)
                    return
                if not wheel.supported():
                    self._log_skipped_link(
                        link, 'it is not compatible with this Python')
                    return
                # This is a dirty hack to prevent installing Binary Wheels from
                # PyPI unless it is a Windows or Mac Binary Wheel. This is
                # paired with a change to PyPI disabling uploads for the
                # same. Once we have a mechanism for enabling support for
                # binary wheels on linux that deals with the inherent problems
                # of binary distribution this can be removed.
                comes_from = getattr(link, "comes_from", None)
                if (
                        (
                            not platform.startswith('win') and not
                            platform.startswith('macosx') and not
                            platform == 'cli'
                        ) and
                        comes_from is not None and
                        urllib_parse.urlparse(
                            comes_from.url
                        ).netloc.endswith(PyPI.netloc)):
                    if not wheel.supported(tags=supported_tags_noarch):
                        self._log_skipped_link(
                            link,
                            "it is a pypi-hosted binary "
                            "Wheel on an unsupported platform",
                        )
                        return
                version = wheel.version

        # This should be up by the search.ok_binary check, but see issue 2700.
        if "source" not in search.formats and ext != wheel_ext:
            self._log_skipped_link(
                link, 'No sources permitted for %s' % search.supplied)
            return

        if not version:
            version = egg_info_matches(egg_info, search.supplied, link)
        if version is None:
            self._log_skipped_link(
                link, 'wrong project name (not %s)' % search.supplied)
            return

        if (link.internal is not None and not
                link.internal and not
                normalize_name(search.supplied).lower()
                in self.allow_external and not
                self.allow_all_external):
            # We have a link that we are sure is external, so we should skip
            #   it unless we are allowing externals
            self._log_skipped_link(link, 'it is externally hosted')
            self.need_warn_external = True
            return

        if (link.verifiable is not None and not
                link.verifiable and not
                (normalize_name(search.supplied).lower()
                    in self.allow_unverified)):
            # We have a link that we are sure we cannot verify its integrity,
            #   so we should skip it unless we are allowing unsafe installs
            #   for this requirement.
            self._log_skipped_link(
                link, 'it is an insecure and unverifiable file')
            self.need_warn_unverified = True
            return

        match = self._py_version_re.search(version)
        if match:
            version = version[:match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                self._log_skipped_link(
                    link, 'Python version is incorrect')
                return
        logger.debug('Found link %s, version: %s', link, version)

        return InstallationCandidate(search.supplied, version, link)
Example #24
0
    def add_requirement(self, install_req, parent_req_name=None,
                        extras_requested=None):
        """Add install_req as a requirement to install.

        :param parent_req_name: The name of the requirement that needed this
            added. The name is used because when multiple unnamed requirements
            resolve to the same name, we could otherwise end up with dependency
            links that point outside the Requirements set. parent_req must
            already be added. Note that None implies that this is a user
            supplied requirement, vs an inferred one.
        :param extras_requested: an iterable of extras used to evaluate the
            environement markers.
        :return: Additional requirements to scan. That is either [] if
            the requirement is not applicable, or [install_req] if the
            requirement is applicable and has just been added.
        """
        name = install_req.name
        if not install_req.match_markers(extras_requested):
            logger.warning("Ignoring %s: markers '%s' don't match your "
                           "environment", install_req.name,
                           install_req.markers)
            return []

        # This check has to come after we filter requirements with the
        # environment markers.
        if install_req.link and install_req.link.is_wheel:
            wheel = Wheel(install_req.link.filename)
            if not wheel.supported():
                raise InstallationError(
                    "%s is not a supported wheel on this platform." %
                    wheel.filename
                )

        install_req.as_egg = self.as_egg
        install_req.use_user_site = self.use_user_site
        install_req.target_dir = self.target_dir
        install_req.pycompile = self.pycompile
        install_req.is_direct = (parent_req_name is None)

        if not name:
            # url or path requirement w/o an egg fragment
            self.unnamed_requirements.append(install_req)
            return [install_req]
        else:
            try:
                existing_req = self.get_requirement(name)
            except KeyError:
                existing_req = None
            if (parent_req_name is None and existing_req and not
                    existing_req.constraint and
                    existing_req.extras == install_req.extras and not
                    existing_req.req.specifier == install_req.req.specifier):
                raise InstallationError(
                    'Double requirement given: %s (already in %s, name=%r)'
                    % (install_req, existing_req, name))
            if not existing_req:
                # Add requirement
                self.requirements[name] = install_req
                # FIXME: what about other normalizations?  E.g., _ vs. -?
                if name.lower() != name:
                    self.requirement_aliases[name.lower()] = name
                result = [install_req]
            else:
                # Assume there's no need to scan, and that we've already
                # encountered this for scanning.
                result = []
                if not install_req.constraint and existing_req.constraint:
                    if (install_req.link and not (existing_req.link and
                       install_req.link.path == existing_req.link.path)):
                        self.reqs_to_cleanup.append(install_req)
                        raise InstallationError(
                            "Could not satisfy constraints for '%s': "
                            "installation from path or url cannot be "
                            "constrained to a version" % name)
                    # If we're now installing a constraint, mark the existing
                    # object for real installation.
                    existing_req.constraint = False
                    existing_req.extras = tuple(
                        sorted(set(existing_req.extras).union(
                               set(install_req.extras))))
                    logger.debug("Setting %s extras to: %s",
                                 existing_req, existing_req.extras)
                    # And now we need to scan this.
                    result = [existing_req]
                # Canonicalise to the already-added object for the backref
                # check below.
                install_req = existing_req
            if parent_req_name:
                parent_req = self.get_requirement(parent_req_name)
                self._dependencies[parent_req].append(install_req)
            return result
Example #25
0
    def from_line(cls,
                  name,
                  comes_from=None,
                  isolated=False,
                  options=None,
                  wheel_cache=None,
                  constraint=False):
        """Creates an InstallRequirement from a name, which might be a
        requirement, directory containing 'setup.py', filename, or URL.
        """
        from pip.index import Link

        if is_url(name):
            marker_sep = '; '
        else:
            marker_sep = ';'
        if marker_sep in name:
            name, markers = name.split(marker_sep, 1)
            markers = markers.strip()
            if not markers:
                markers = None
            else:
                markers = Marker(markers)
        else:
            markers = None
        name = name.strip()
        req = None
        path = os.path.normpath(os.path.abspath(name))
        link = None
        extras = None

        if is_url(name):
            link = Link(name)
        else:
            p, extras = _strip_extras(path)
            if (os.path.isdir(p)
                    and (os.path.sep in name or name.startswith('.'))):

                if not is_installable_dir(p):
                    raise InstallationError(
                        "Directory %r is not installable. File 'setup.py' "
                        "not found." % name)
                link = Link(path_to_url(p))
            elif is_archive_file(p):
                if not os.path.isfile(p):
                    logger.warning(
                        'Requirement %r looks like a filename, but the '
                        'file does not exist', name)
                link = Link(path_to_url(p))

        # it's a local file, dir, or url
        if link:
            # Handle relative file URLs
            if link.scheme == 'file' and re.search(r'\.\./', link.url):
                link = Link(
                    path_to_url(os.path.normpath(os.path.abspath(link.path))))
            # wheel file
            if link.is_wheel:
                wheel = Wheel(link.filename)  # can raise InvalidWheelFilename
                req = "%s==%s" % (wheel.name, wheel.version)
            else:
                # set the req to the egg fragment.  when it's not there, this
                # will become an 'unnamed' requirement
                req = link.egg_fragment

        # a requirement specifier
        else:
            req = name

        if extras:
            extras = Requirement("placeholder" + extras.lower()).extras
        else:
            extras = ()
        if req is not None:
            try:
                req = Requirement(req)
            except InvalidRequirement:
                if os.path.sep in req:
                    add_msg = "It looks like a path."
                    add_msg += deduce_helpful_msg(req)
                elif '=' in req and not any(op in req for op in operators):
                    add_msg = "= is not a valid operator. Did you mean == ?"
                else:
                    add_msg = traceback.format_exc()
                raise InstallationError("Invalid requirement: '%s'\n%s" %
                                        (req, add_msg))
        return cls(
            req,
            comes_from,
            link=link,
            markers=markers,
            isolated=isolated,
            options=options if options else {},
            wheel_cache=wheel_cache,
            constraint=constraint,
            extras=extras,
        )
Example #26
0
    def _link_package_versions(self, link, search_name):
        """
        Return an iterable of triples (pkg_resources_version_key,
        link, python_version) that can be extracted from the given
        link.

        Meant to be overridden by subclasses, not called by clients.
        """
        platform = get_platform()

        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
        else:
            egg_info, ext = link.splitext()
            if not ext:
                if link not in self.logged_links:
                    logger.debug('Skipping link %s; not a file' % link)
                    self.logged_links.add(link)
                return []
            if egg_info.endswith('.tar'):
                # Special double-extension case:
                egg_info = egg_info[:-4]
                ext = '.tar' + ext
            if ext not in self._known_extensions():
                if link not in self.logged_links:
                    logger.debug(
                        'Skipping link %s; unknown archive format: %s' %
                        (link, ext)
                    )
                    self.logged_links.add(link)
                return []
            if "macosx10" in link.path and ext == '.zip':
                if link not in self.logged_links:
                    logger.debug('Skipping link %s; macosx10 one' % (link))
                    self.logged_links.add(link)
                return []
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    logger.debug(
                        'Skipping %s because the wheel filename is invalid' %
                        link
                    )
                    return []
                if wheel.name.lower() != search_name.lower():
                    logger.debug(
                        'Skipping link %s; wrong project name (not %s)' %
                        (link, search_name)
                    )
                    return []
                if not wheel.supported():
                    logger.debug(
                        'Skipping %s because it is not compatible with this '
                        'Python' % link
                    )
                    return []
                # This is a dirty hack to prevent installing Binary Wheels from
                # PyPI unless it is a Windows or Mac Binary Wheel. This is
                # paired with a change to PyPI disabling uploads for the
                # same. Once we have a mechanism for enabling support for
                # binary wheels on linux that deals with the inherent problems
                # of binary distribution this can be removed.
                comes_from = getattr(link, "comes_from", None)
                if (
                        (
                            not platform.startswith('win')
                            and not platform.startswith('macosx')
                        )
                        and comes_from is not None
                        and urlparse.urlparse(
                            comes_from.url
                        ).netloc.endswith("pypi.python.org")):
                    if not wheel.supported(tags=supported_tags_noarch):
                        logger.debug(
                            "Skipping %s because it is a pypi-hosted binary "
                            "Wheel on an unsupported platform" % link
                        )
                        return []
                version = wheel.version

        if not version:
            version = self._egg_info_matches(egg_info, search_name, link)
        if version is None:
            logger.debug(
                'Skipping link %s; wrong project name (not %s)' %
                (link, search_name)
            )
            return []

        if (link.internal is not None
                and not link.internal
                and not normalize_name(search_name).lower()
                in self.allow_external
                and not self.allow_all_external):
            # We have a link that we are sure is external, so we should skip
            #   it unless we are allowing externals
            logger.debug("Skipping %s because it is externally hosted." % link)
            self.need_warn_external = True
            return []

        if (link.verifiable is not None
                and not link.verifiable
                and not (normalize_name(search_name).lower()
                         in self.allow_unverified)):
            # We have a link that we are sure we cannot verify its integrity,
            #   so we should skip it unless we are allowing unsafe installs
            #   for this requirement.
            logger.debug("Skipping %s because it is an insecure and "
                         "unverifiable file." % link)
            self.need_warn_unverified = True
            return []

        match = self._py_version_re.search(version)
        if match:
            version = version[:match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                logger.debug(
                    'Skipping %s because Python version is incorrect' % link
                )
                return []
        logger.debug('Found link %s, version: %s' % (link, version))
        return [(
            pkg_resources.parse_version(version),
            link,
            version,
        )]
Example #27
0
    def _link_package_versions(self, link, search_name):
        """
        Return an iterable of triples (pkg_resources_version_key,
        link, python_version) that can be extracted from the given
        link.

        Meant to be overridden by subclasses, not called by clients.
        """
        platform = get_platform()

        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
        else:
            egg_info, ext = link.splitext()
            if not ext:
                if link not in self.logged_links:
                    logger.debug('Skipping link %s; not a file' % link)
                    self.logged_links.add(link)
                return []
            if egg_info.endswith('.tar'):
                # Special double-extension case:
                egg_info = egg_info[:-4]
                ext = '.tar' + ext
            if ext not in self._known_extensions():
                if link not in self.logged_links:
                    logger.debug(
                        'Skipping link %s; unknown archive format: %s' %
                        (link, ext))
                    self.logged_links.add(link)
                return []
            if "macosx10" in link.path and ext == '.zip':
                if link not in self.logged_links:
                    logger.debug('Skipping link %s; macosx10 one' % (link))
                    self.logged_links.add(link)
                return []
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    logger.debug(
                        'Skipping %s because the wheel filename is invalid' %
                        link)
                    return []
                if wheel.name.lower() != search_name.lower():
                    logger.debug(
                        'Skipping link %s; wrong project name (not %s)' %
                        (link, search_name))
                    return []
                if not wheel.supported():
                    logger.debug(
                        'Skipping %s because it is not compatible with this Python'
                        % link)
                    return []
                # This is a dirty hack to prevent installing Binary Wheels from
                # PyPI unless it is a Windows or Mac Binary Wheel. This is
                # paired with a change to PyPI disabling uploads for the
                # same. Once we have a mechanism for enabling support for binary
                # wheels on linux that deals with the inherent problems of
                # binary distribution this can be removed.
                comes_from = getattr(link, "comes_from", None)
                if ((not platform.startswith('win')
                     and not platform.startswith('macosx'))
                        and comes_from is not None and urlparse.urlparse(
                            comes_from.url).netloc.endswith("pypi.python.org")
                    ):
                    if not wheel.supported(tags=supported_tags_noarch):
                        logger.debug(
                            "Skipping %s because it is a pypi-hosted binary "
                            "Wheel on an unsupported platform" % link)
                        return []
                version = wheel.version

        if not version:
            version = self._egg_info_matches(egg_info, search_name, link)
        if version is None:
            logger.debug('Skipping link %s; wrong project name (not %s)' %
                         (link, search_name))
            return []

        if (link.internal is not None and not link.internal and
                not normalize_name(search_name).lower() in self.allow_external
                and not self.allow_all_external):
            # We have a link that we are sure is external, so we should skip
            #   it unless we are allowing externals
            logger.debug("Skipping %s because it is externally hosted." % link)
            self.need_warn_external = True
            return []

        if (link.verifiable is not None and not link.verifiable
                and not (normalize_name(search_name).lower()
                         in self.allow_unverified)
                and not self.allow_all_unverified):
            # We have a link that we are sure we cannot verify it's integrity,
            #   so we should skip it unless we are allowing unsafe installs
            #   for this requirement.
            logger.debug("Skipping %s because it is an insecure and "
                         "unverifiable file." % link)
            self.need_warn_unverified = True
            return []

        match = self._py_version_re.search(version)
        if match:
            version = version[:match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                logger.debug(
                    'Skipping %s because Python version is incorrect' % link)
                return []
        logger.debug('Found link %s, version: %s' % (link, version))
        return [(pkg_resources.parse_version(version), link, version)]
Example #28
0
    def _link_package_versions(self, link, search_name):
        """Return an InstallationCandidate or None"""
        platform = get_platform()

        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
        else:
            egg_info, ext = link.splitext()
            if not ext:
                if link not in self.logged_links:
                    logger.debug("Skipping link %s; not a file", link)
                    self.logged_links.add(link)
                return
            if egg_info.endswith(".tar"):
                # Special double-extension case:
                egg_info = egg_info[:-4]
                ext = ".tar" + ext
            if ext not in self._known_extensions():
                if link not in self.logged_links:
                    logger.debug("Skipping link %s; unknown archive format: %s", link, ext)
                    self.logged_links.add(link)
                return
            if "macosx10" in link.path and ext == ".zip":
                if link not in self.logged_links:
                    logger.debug("Skipping link %s; macosx10 one", link)
                    self.logged_links.add(link)
                return
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    logger.debug("Skipping %s because the wheel filename is invalid", link)
                    return
                if pkg_resources.safe_name(wheel.name).lower() != pkg_resources.safe_name(search_name).lower():
                    logger.debug("Skipping link %s; wrong project name (not %s)", link, search_name)
                    return
                if not wheel.supported():
                    logger.debug("Skipping %s because it is not compatible with this " "Python", link)
                    return
                # This is a dirty hack to prevent installing Binary Wheels from
                # PyPI unless it is a Windows or Mac Binary Wheel. This is
                # paired with a change to PyPI disabling uploads for the
                # same. Once we have a mechanism for enabling support for
                # binary wheels on linux that deals with the inherent problems
                # of binary distribution this can be removed.
                comes_from = getattr(link, "comes_from", None)
                if (
                    (not platform.startswith("win") and not platform.startswith("macosx") and not platform == "cli")
                    and comes_from is not None
                    and urllib_parse.urlparse(comes_from.url).netloc.endswith(PyPI.netloc)
                ):
                    if not wheel.supported(tags=supported_tags_noarch):
                        logger.debug(
                            "Skipping %s because it is a pypi-hosted binary " "Wheel on an unsupported platform", link
                        )
                        return
                version = wheel.version

        if not version:
            version = self._egg_info_matches(egg_info, search_name, link)
        if version is None:
            logger.debug("Skipping link %s; wrong project name (not %s)", link, search_name)
            return

        if (
            link.internal is not None
            and not link.internal
            and not normalize_name(search_name).lower() in self.allow_external
            and not self.allow_all_external
        ):
            # We have a link that we are sure is external, so we should skip
            #   it unless we are allowing externals
            logger.debug("Skipping %s because it is externally hosted.", link)
            self.need_warn_external = True
            return

        if (
            link.verifiable is not None
            and not link.verifiable
            and not (normalize_name(search_name).lower() in self.allow_unverified)
        ):
            # We have a link that we are sure we cannot verify its integrity,
            #   so we should skip it unless we are allowing unsafe installs
            #   for this requirement.
            logger.debug("Skipping %s because it is an insecure and unverifiable file.", link)
            self.need_warn_unverified = True
            return

        match = self._py_version_re.search(version)
        if match:
            version = version[: match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                logger.debug("Skipping %s because Python version is incorrect", link)
                return
        logger.debug("Found link %s, version: %s", link, version)

        return InstallationCandidate(search_name, version, link)
Example #29
0
    def from_line(cls,
                  name,
                  comes_from=None,
                  isolated=False,
                  options=None,
                  wheel_cache=None,
                  constraint=False):
        """Creates an InstallRequirement from a name, which might be a
        requirement, directory containing 'setup.py', filename, or URL.
        """
        from pip.index import Link

        if is_url(name):
            marker_sep = '; '
        else:
            marker_sep = ';'
        if marker_sep in name:
            name, markers = name.split(marker_sep, 1)
            markers = markers.strip()
            if not markers:
                markers = None
        else:
            markers = None
        name = name.strip()
        req = None
        path = os.path.normpath(os.path.abspath(name))
        link = None
        extras = None

        if is_url(name):
            link = Link(name)
        else:
            p, extras = _strip_extras(path)
            if (os.path.isdir(p)
                    and (os.path.sep in name or name.startswith('.'))):

                if not is_installable_dir(p):
                    raise InstallationError(
                        "Directory %r is not installable. File 'setup.py' "
                        "not found." % name)
                link = Link(path_to_url(p))
            elif is_archive_file(p):
                if not os.path.isfile(p):
                    logger.warning(
                        'Requirement %r looks like a filename, but the '
                        'file does not exist', name)
                link = Link(path_to_url(p))

        # it's a local file, dir, or url
        if link:
            # Handle relative file URLs
            if link.scheme == 'file' and re.search(r'\.\./', link.url):
                link = Link(
                    path_to_url(os.path.normpath(os.path.abspath(link.path))))
            # wheel file
            if link.is_wheel:
                wheel = Wheel(link.filename)  # can raise InvalidWheelFilename
                if not wheel.supported():
                    raise UnsupportedWheel(
                        "%s is not a supported wheel on this platform." %
                        wheel.filename)
                req = "%s==%s" % (wheel.name, wheel.version)
            else:
                # set the req to the egg fragment.  when it's not there, this
                # will become an 'unnamed' requirement
                req = link.egg_fragment

        # a requirement specifier
        else:
            req = name

        options = options if options else {}
        res = cls(req,
                  comes_from,
                  link=link,
                  markers=markers,
                  isolated=isolated,
                  options=options,
                  wheel_cache=wheel_cache,
                  constraint=constraint)

        if extras:
            res.extras = pkg_resources.Requirement.parse('__placeholder__' +
                                                         extras).extras

        return res
Example #30
0
    def _link_package_versions(self, link, search):
        """Return an InstallationCandidate or None"""
        platform = get_platform()

        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
            ext = link.ext
        else:
            egg_info, ext = link.splitext()
            if not ext:
                self._log_skipped_link(link, 'not a file')
                return
            if ext not in SUPPORTED_EXTENSIONS:
                self._log_skipped_link(link,
                                       'unsupported archive format: %s' % ext)
                return
            if "binary" not in search.formats and ext == wheel_ext:
                self._log_skipped_link(
                    link, 'No binaries permitted for %s' % search.supplied)
                return
            if "macosx10" in link.path and ext == '.zip':
                self._log_skipped_link(link, 'macosx10 one')
                return
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    self._log_skipped_link(link, 'invalid wheel filename')
                    return
                if (pkg_resources.safe_name(wheel.name).lower() !=
                        search.canonical):
                    self._log_skipped_link(
                        link, 'wrong project name (not %s)' % search.supplied)
                    return
                if not wheel.supported():
                    self._log_skipped_link(
                        link, 'it is not compatible with this Python')
                    return
                # This is a dirty hack to prevent installing Binary Wheels from
                # PyPI unless it is a Windows or Mac Binary Wheel. This is
                # paired with a change to PyPI disabling uploads for the
                # same. Once we have a mechanism for enabling support for
                # binary wheels on linux that deals with the inherent problems
                # of binary distribution this can be removed.
                comes_from = getattr(link, "comes_from", None)
                if ((not platform.startswith('win')
                     and not platform.startswith('macosx')
                     and not platform == 'cli') and comes_from is not None
                        and urllib_parse.urlparse(
                            comes_from.url).netloc.endswith(PyPI.netloc)):
                    if not wheel.supported(tags=supported_tags_noarch):
                        self._log_skipped_link(
                            link,
                            "it is a pypi-hosted binary "
                            "Wheel on an unsupported platform",
                        )
                        return
                version = wheel.version

        # This should be up by the search.ok_binary check, but see issue 2700.
        if "source" not in search.formats and ext != wheel_ext:
            self._log_skipped_link(
                link, 'No sources permitted for %s' % search.supplied)
            return

        if not version:
            version = egg_info_matches(egg_info, search.supplied, link)
        if version is None:
            self._log_skipped_link(
                link, 'wrong project name (not %s)' % search.supplied)
            return

        if (link.internal is not None and not link.internal
                and not normalize_name(search.supplied).lower()
                in self.allow_external and not self.allow_all_external):
            # We have a link that we are sure is external, so we should skip
            #   it unless we are allowing externals
            self._log_skipped_link(link, 'it is externally hosted')
            self.need_warn_external = True
            return

        if (link.verifiable is not None and not link.verifiable
                and not (normalize_name(search.supplied).lower()
                         in self.allow_unverified)):
            # We have a link that we are sure we cannot verify its integrity,
            #   so we should skip it unless we are allowing unsafe installs
            #   for this requirement.
            self._log_skipped_link(link,
                                   'it is an insecure and unverifiable file')
            self.need_warn_unverified = True
            return

        match = self._py_version_re.search(version)
        if match:
            version = version[:match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                self._log_skipped_link(link, 'Python version is incorrect')
                return
        logger.debug('Found link %s, version: %s', link, version)

        return InstallationCandidate(search.supplied, version, link)
Example #31
0
File: index.py Project: rwols/pip
    def _link_package_versions(self, link, search):
        """Return an InstallationCandidate or None"""
        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
            ext = link.ext
        else:
            egg_info, ext = link.splitext()
            if not ext:
                self._log_skipped_link(link, 'not a file')
                return
            if ext not in SUPPORTED_EXTENSIONS:
                self._log_skipped_link(link,
                                       'unsupported archive format: %s' % ext)
                return
            if "binary" not in search.formats and ext == wheel_ext:
                self._log_skipped_link(
                    link, 'No binaries permitted for %s' % search.supplied)
                return
            if "macosx10" in link.path and ext == '.zip':
                self._log_skipped_link(link, 'macosx10 one')
                return
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    self._log_skipped_link(link, 'invalid wheel filename')
                    return
                if canonicalize_name(wheel.name) != search.canonical:
                    self._log_skipped_link(
                        link, 'wrong project name (not %s)' % search.supplied)
                    return

                if not wheel.supported(self.valid_tags):
                    self._log_skipped_link(
                        link, 'it is not compatible with this Python')
                    return

                version = wheel.version

        # This should be up by the search.ok_binary check, but see issue 2700.
        if "source" not in search.formats and ext != wheel_ext:
            self._log_skipped_link(
                link, 'No sources permitted for %s' % search.supplied)
            return

        if not version:
            version = egg_info_matches(egg_info, search.supplied, link)
        if version is None:
            self._log_skipped_link(
                link, 'wrong project name (not %s)' % search.supplied)
            return

        match = self._py_version_re.search(version)
        if match:
            version = version[:match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                self._log_skipped_link(link, 'Python version is incorrect')
                return
        try:
            support_this_python = check_requires_python(link.requires_python)
        except specifiers.InvalidSpecifier:
            logger.debug("Package %s has an invalid Requires-Python entry: %s",
                         link.filename, link.requires_python)
            support_this_python = True

        if not support_this_python:
            logger.debug(
                "The package %s is incompatible with the python"
                "version in use. Acceptable python versions are:%s", link,
                link.requires_python)
            return
        logger.debug('Found link %s, version: %s', link, version)

        return InstallationCandidate(search.supplied, version, link)
Example #32
0
    def _link_package_versions(self, link, search):
        """Return an InstallationCandidate or None"""
        version = None
        if link.egg_fragment:
            egg_info = link.egg_fragment
            ext = link.ext
        else:
            egg_info, ext = link.splitext()
            if not ext:
                self._log_skipped_link(link, 'not a file')
                return
            if ext not in SUPPORTED_EXTENSIONS:
                self._log_skipped_link(
                    link, 'unsupported archive format: %s' % ext)
                return
            if "binary" not in search.formats and ext == wheel_ext:
                self._log_skipped_link(
                    link, 'No binaries permitted for %s' % search.supplied)
                return
            if "macosx10" in link.path and ext == '.zip':
                self._log_skipped_link(link, 'macosx10 one')
                return
            if ext == wheel_ext:
                try:
                    wheel = Wheel(link.filename)
                except InvalidWheelFilename:
                    self._log_skipped_link(link, 'invalid wheel filename')
                    return
                if canonicalize_name(wheel.name) != search.canonical:
                    self._log_skipped_link(
                        link, 'wrong project name (not %s)' % search.supplied)
                    return

                if not wheel.supported(self.valid_tags):
                    self._log_skipped_link(
                        link, 'it is not compatible with this Python')
                    return

                version = wheel.version

        # This should be up by the search.ok_binary check, but see issue 2700.
        if "source" not in search.formats and ext != wheel_ext:
            self._log_skipped_link(
                link, 'No sources permitted for %s' % search.supplied)
            return

        if not version:
            version = egg_info_matches(egg_info, search.supplied, link)
        if version is None:
            self._log_skipped_link(
                link, 'wrong project name (not %s)' % search.supplied)
            return

        match = self._py_version_re.search(version)
        if match:
            version = version[:match.start()]
            py_version = match.group(1)
            if py_version != sys.version[:3]:
                self._log_skipped_link(
                    link, 'Python version is incorrect')
                return
        try:
            support_this_python = check_requires_python(link.requires_python)
        except specifiers.InvalidSpecifier:
            logger.debug("Package %s has an invalid Requires-Python entry: %s",
                         link.filename, link.requires_python)
            support_this_python = True

        if not support_this_python:
            logger.debug("The package %s is incompatible with the python"
                         "version in use. Acceptable python versions are:%s",
                         link, link.requires_python)
            return
        logger.debug('Found link %s, version: %s', link, version)

        return InstallationCandidate(search.supplied, version, link)