Example #1
0
def _get_url_from_path(path, name):
    # type: (str, str) -> Optional[str]
    """
    First, it checks whether a provided path is an installable directory
    (e.g. it has a setup.py). If it is, returns the path.

    If false, check if the path is an archive file (such as a .whl).
    The function checks if the path is a file. If false, if the path has
    an @, it will treat it as a PEP 440 URL requirement and return the path.
    """
    if _looks_like_path(name) and os.path.isdir(path):
        if is_installable_dir(path):
            return path_to_url(path)
        raise InstallationError(
            "Directory {name!r} is not installable. Neither 'setup.py' "
            "nor 'pyproject.toml' found.".format(**locals()))
    if not is_archive_file(path):
        return None
    if os.path.isfile(path):
        return path_to_url(path)
    urlreq_parts = name.split('@', 1)
    if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]):
        # If the path contains '@' and the part before it does not look
        # like a path, try to treat it as a PEP 440 URL req instead.
        return None
    logger.warning(
        'Requirement %r looks like a filename, but the '
        'file does not exist', name)
    return path_to_url(path)
Example #2
0
 def sort_path(path):
     # type: (str) -> None
     url = path_to_url(path)
     if mimetypes.guess_type(url, strict=False)[0] == 'text/html':
         urls.append(url)
     else:
         files.append(url)
Example #3
0
 def get_remote_url(cls, location):
     urls = cls.run_command(['info'], cwd=location)
     for line in urls.splitlines():
         line = line.strip()
         for x in ('checkout of branch: ', 'parent branch: '):
             if line.startswith(x):
                 repo = line.split(x)[1]
                 if cls._is_local_repository(repo):
                     return path_to_url(repo)
                 return repo
     return None
Example #4
0
def build(
        requirements,  # type: Iterable[InstallRequirement]
        wheel_cache,  # type: WheelCache
        build_options,  # type: List[str]
        global_options,  # type: List[str]
):
    # type: (...) -> BuildResult
    """Build wheels.

    :return: The list of InstallRequirement that succeeded to build and
        the list of InstallRequirement that failed to build.
    """
    if not requirements:
        return [], []

    # Build the wheels.
    logger.info(
        'Building wheels for collected packages: %s',
        ', '.join(req.name for req in requirements),  # type: ignore
    )

    with indent_log():
        build_successes, build_failures = [], []
        for req in requirements:
            cache_dir = _get_cache_dir(req, wheel_cache)
            wheel_file = _build_one(req, cache_dir, build_options,
                                    global_options)
            if wheel_file:
                # Update the link for this.
                req.link = Link(path_to_url(wheel_file))
                req.local_file_path = req.link.file_path
                assert req.link.is_wheel
                build_successes.append(req)
            else:
                build_failures.append(req)

    # notify success/failure
    if build_successes:
        logger.info(
            'Successfully built %s',
            ' '.join([req.name for req in build_successes]),  # type: ignore
        )
    if build_failures:
        logger.info(
            'Failed to build %s',
            ' '.join([req.name for req in build_failures]),  # type: ignore
        )
    # Return a list of requirements that failed to build
    return build_successes, build_failures
Example #5
0
    def __init__(
            self,
            url,  # type: str
            comes_from=None,  # type: Optional[Union[str, HTMLPage]]
            requires_python=None,  # type: Optional[str]
            yanked_reason=None,  # type: Optional[Text]
            cache_link_parsing=True,  # type: bool
    ):
        # type: (...) -> None
        """
        :param url: url of the resource pointed to (href of the link)
        :param comes_from: instance of HTMLPage where the link was found,
            or string.
        :param requires_python: String containing the `Requires-Python`
            metadata field, specified in PEP 345. This may be specified by
            a data-requires-python attribute in the HTML link tag, as
            described in PEP 503.
        :param yanked_reason: the reason the file has been yanked, if the
            file has been yanked, or None if the file hasn't been yanked.
            This is the value of the "data-yanked" attribute, if present, in
            a simple repository HTML link. If the file has been yanked but
            no reason was provided, this should be the empty string. See
            PEP 592 for more information and the specification.
        :param cache_link_parsing: A flag that is used elsewhere to determine
                                   whether resources retrieved from this link
                                   should be cached. PyPI index urls should
                                   generally have this set to False, for
                                   example.
        """

        # url can be a UNC windows share
        if url.startswith('\\\\'):
            url = path_to_url(url)

        self._parsed_url = urllib_parse.urlsplit(url)
        # Store the url as a private attribute to prevent accidentally
        # trying to set a new value.
        self._url = url

        self.comes_from = comes_from
        self.requires_python = requires_python if requires_python else None
        self.yanked_reason = yanked_reason

        super(Link, self).__init__(key=url, defining_class=Link)

        self.cache_link_parsing = cache_link_parsing
Example #6
0
def parse_editable(editable_req):
    # type: (str) -> Tuple[Optional[str], str, Set[str]]
    """Parses an editable requirement into:
        - a requirement name
        - an URL
        - extras
        - editable options
    Accepted requirements:
        svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir
        .[some_extra]
    """

    url = editable_req

    # If a file path is specified with extras, strip off the extras.
    url_no_extras, extras = _strip_extras(url)

    if os.path.isdir(url_no_extras):
        if not os.path.exists(os.path.join(url_no_extras, 'setup.py')):
            msg = ('File "setup.py" not found. Directory cannot be installed '
                   'in editable mode: {}'.format(
                       os.path.abspath(url_no_extras)))
            pyproject_path = make_pyproject_path(url_no_extras)
            if os.path.isfile(pyproject_path):
                msg += ('\n(A "pyproject.toml" file was found, but editable '
                        'mode currently requires a setup.py based build.)')
            raise InstallationError(msg)

        # Treating it as code that has already been checked out
        url_no_extras = path_to_url(url_no_extras)

    if url_no_extras.lower().startswith('file:'):
        package_name = Link(url_no_extras).egg_fragment
        if extras:
            return (
                package_name,
                url_no_extras,
                Requirement("placeholder" + extras.lower()).extras,
            )
        else:
            return package_name, url_no_extras, set()

    for version_control in vcs:
        if url.lower().startswith('{}:'.format(version_control)):
            url = '{}+{}'.format(version_control, url)
            break

    if '+' not in url:
        raise InstallationError(
            '{} is not a valid editable requirement. '
            'It should either be a path to a local project or a VCS URL '
            '(beginning with svn+, git+, hg+, or bzr+).'.format(editable_req))

    vc_type = url.split('+', 1)[0].lower()

    if not vcs.get_backend(vc_type):
        backends = ", ".join([bends.name + '+URL' for bends in vcs.backends])
        error_message = "For --editable={}, " \
                        "only {} are currently supported".format(
                            editable_req, backends)
        raise InstallationError(error_message)

    package_name = Link(url).egg_fragment
    if not package_name:
        raise InstallationError(
            "Could not detect requirement name for '{}', please specify one "
            "with #egg=your_package_name".format(editable_req))
    return package_name, url, set()
Example #7
0
def parse_req_from_line(name, line_source):
    # type: (str, Optional[str]) -> RequirementParts
    if is_url(name):
        marker_sep = '; '
    else:
        marker_sep = ';'
    if marker_sep in name:
        name, markers_as_string = name.split(marker_sep, 1)
        markers_as_string = markers_as_string.strip()
        if not markers_as_string:
            markers = None
        else:
            markers = Marker(markers_as_string)
    else:
        markers = None
    name = name.strip()
    req_as_string = None
    path = os.path.normpath(os.path.abspath(name))
    link = None
    extras_as_string = None

    if is_url(name):
        link = Link(name)
    else:
        p, extras_as_string = _strip_extras(path)
        url = _get_url_from_path(p, name)
        if url is not None:
            link = Link(url)

    # 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_as_string = "{wheel.name}=={wheel.version}".format(**locals())
        else:
            # set the req to the egg fragment.  when it's not there, this
            # will become an 'unnamed' requirement
            req_as_string = link.egg_fragment

    # a requirement specifier
    else:
        req_as_string = name

    extras = convert_extras(extras_as_string)

    def with_source(text):
        # type: (str) -> str
        if not line_source:
            return text
        return '{} (from {})'.format(text, line_source)

    if req_as_string is not None:
        try:
            req = Requirement(req_as_string)
        except InvalidRequirement:
            if os.path.sep in req_as_string:
                add_msg = "It looks like a path."
                add_msg += deduce_helpful_msg(req_as_string)
            elif ('=' in req_as_string
                  and not any(op in req_as_string for op in operators)):
                add_msg = "= is not a valid operator. Did you mean == ?"
            else:
                add_msg = ''
            msg = with_source(
                'Invalid requirement: {!r}'.format(req_as_string))
            if add_msg:
                msg += '\nHint: {}'.format(add_msg)
            raise InstallationError(msg)
        else:
            # Deprecate extras after specifiers: "name>=1.0[extras]"
            # This currently works by accident because _strip_extras() parses
            # any extras in the end of the string and those are saved in
            # RequirementParts
            for spec in req.specifier:
                spec_str = str(spec)
                if spec_str.endswith(']'):
                    msg = "Extras after version '{}'.".format(spec_str)
                    replace = "moving the extras before version specifiers"
                    deprecated(msg, replacement=replace, gone_in="21.0")
    else:
        req = None

    return RequirementParts(req, link, markers, extras)
Example #8
0
 def get_remote_url(cls, location):
     url = cls.run_command(['showconfig', 'paths.default'],
                           cwd=location).strip()
     if cls._is_local_repository(url):
         url = path_to_url(url)
     return url.strip()