Воркед
This commit is contained in:
1 parent
ac32c55ab9
commit
ee94d8e529
1138 files changed
+55771
-77901
No files matched your search
@@ -8,10 +8,12 @@ These are meant to be used elsewhere within pip to create instances of
|
||||
InstallRequirement.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from typing import Any, Dict, Optional, Set, Tuple, Union
|
||||
from dataclasses import dataclass
|
||||
from typing import Collection, Dict, List, Optional, Set, Tuple, Union
|
||||
|
||||
from pip._vendor.packaging.markers import Marker
|
||||
from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
|
||||
@@ -57,6 +59,31 @@ def convert_extras(extras: Optional[str]) -> Set[str]:
|
||||
return get_requirement("placeholder" + extras.lower()).extras
|
||||
|
||||
|
||||
def _set_requirement_extras(req: Requirement, new_extras: Set[str]) -> Requirement:
|
||||
"""
|
||||
Returns a new requirement based on the given one, with the supplied extras. If the
|
||||
given requirement already has extras those are replaced (or dropped if no new extras
|
||||
are given).
|
||||
"""
|
||||
match: Optional[re.Match[str]] = re.fullmatch(
|
||||
# see https://peps.python.org/pep-0508/#complete-grammar
|
||||
r"([\w\t .-]+)(\[[^\]]*\])?(.*)",
|
||||
str(req),
|
||||
flags=re.ASCII,
|
||||
)
|
||||
# ireq.req is a valid requirement so the regex should always match
|
||||
assert (
|
||||
match is not None
|
||||
), f"regex match on requirement {req} failed, this should never happen"
|
||||
pre: Optional[str] = match.group(1)
|
||||
post: Optional[str] = match.group(3)
|
||||
assert (
|
||||
pre is not None and post is not None
|
||||
), f"regex group selection for requirement {req} failed, this should never happen"
|
||||
extras: str = "[{}]".format(",".join(sorted(new_extras)) if new_extras else "")
|
||||
return get_requirement(f"{pre}{extras}{post}")
|
||||
|
||||
|
||||
def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]:
|
||||
"""Parses an editable requirement into:
|
||||
- a requirement name
|
||||
@@ -106,8 +133,8 @@ def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]:
|
||||
package_name = link.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)
|
||||
f"Could not detect requirement name for '{editable_req}', "
|
||||
"please specify one with #egg=your_package_name"
|
||||
)
|
||||
return package_name, url, set()
|
||||
|
||||
@@ -136,7 +163,7 @@ def check_first_requirement_in_file(filename: str) -> None:
|
||||
# If there is a line continuation, drop it, and append the next line.
|
||||
if line.endswith("\\"):
|
||||
line = line[:-2].strip() + next(lines, "")
|
||||
Requirement(line)
|
||||
get_requirement(line)
|
||||
return
|
||||
|
||||
|
||||
@@ -165,18 +192,12 @@ def deduce_helpful_msg(req: str) -> str:
|
||||
return msg
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RequirementParts:
|
||||
def __init__(
|
||||
self,
|
||||
requirement: Optional[Requirement],
|
||||
link: Optional[Link],
|
||||
markers: Optional[Marker],
|
||||
extras: Set[str],
|
||||
):
|
||||
self.requirement = requirement
|
||||
self.link = link
|
||||
self.markers = markers
|
||||
self.extras = extras
|
||||
requirement: Optional[Requirement]
|
||||
link: Optional[Link]
|
||||
markers: Optional[Marker]
|
||||
extras: Set[str]
|
||||
|
||||
|
||||
def parse_req_from_editable(editable_req: str) -> RequirementParts:
|
||||
@@ -184,9 +205,9 @@ def parse_req_from_editable(editable_req: str) -> RequirementParts:
|
||||
|
||||
if name is not None:
|
||||
try:
|
||||
req: Optional[Requirement] = Requirement(name)
|
||||
except InvalidRequirement:
|
||||
raise InstallationError(f"Invalid requirement: '{name}'")
|
||||
req: Optional[Requirement] = get_requirement(name)
|
||||
except InvalidRequirement as exc:
|
||||
raise InstallationError(f"Invalid requirement: {name!r}: {exc}")
|
||||
else:
|
||||
req = None
|
||||
|
||||
@@ -201,15 +222,16 @@ def parse_req_from_editable(editable_req: str) -> RequirementParts:
|
||||
def install_req_from_editable(
|
||||
editable_req: str,
|
||||
comes_from: Optional[Union[InstallRequirement, str]] = None,
|
||||
*,
|
||||
use_pep517: Optional[bool] = None,
|
||||
isolated: bool = False,
|
||||
options: Optional[Dict[str, Any]] = None,
|
||||
global_options: Optional[List[str]] = None,
|
||||
hash_options: Optional[Dict[str, List[str]]] = None,
|
||||
constraint: bool = False,
|
||||
user_supplied: bool = False,
|
||||
permit_editable_wheels: bool = False,
|
||||
config_settings: Optional[Dict[str, str]] = None,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
) -> InstallRequirement:
|
||||
|
||||
parts = parse_req_from_editable(editable_req)
|
||||
|
||||
return InstallRequirement(
|
||||
@@ -222,9 +244,8 @@ def install_req_from_editable(
|
||||
constraint=constraint,
|
||||
use_pep517=use_pep517,
|
||||
isolated=isolated,
|
||||
install_options=options.get("install_options", []) if options else [],
|
||||
global_options=options.get("global_options", []) if options else [],
|
||||
hash_options=options.get("hashes", {}) if options else {},
|
||||
global_options=global_options,
|
||||
hash_options=hash_options,
|
||||
config_settings=config_settings,
|
||||
extras=parts.extras,
|
||||
)
|
||||
@@ -338,8 +359,8 @@ def parse_req_from_line(name: str, line_source: Optional[str]) -> RequirementPar
|
||||
|
||||
def _parse_req_string(req_as_string: str) -> Requirement:
|
||||
try:
|
||||
req = get_requirement(req_as_string)
|
||||
except InvalidRequirement:
|
||||
return get_requirement(req_as_string)
|
||||
except InvalidRequirement as exc:
|
||||
if os.path.sep in req_as_string:
|
||||
add_msg = "It looks like a path."
|
||||
add_msg += deduce_helpful_msg(req_as_string)
|
||||
@@ -349,21 +370,10 @@ def parse_req_from_line(name: str, line_source: Optional[str]) -> RequirementPar
|
||||
add_msg = "= is not a valid operator. Did you mean == ?"
|
||||
else:
|
||||
add_msg = ""
|
||||
msg = with_source(f"Invalid requirement: {req_as_string!r}")
|
||||
msg = with_source(f"Invalid requirement: {req_as_string!r}: {exc}")
|
||||
if add_msg:
|
||||
msg += f"\nHint: {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 = f"Extras after version '{spec_str}'."
|
||||
raise InstallationError(msg)
|
||||
return req
|
||||
|
||||
if req_as_string is not None:
|
||||
req: Optional[Requirement] = _parse_req_string(req_as_string)
|
||||
@@ -376,13 +386,15 @@ def parse_req_from_line(name: str, line_source: Optional[str]) -> RequirementPar
|
||||
def install_req_from_line(
|
||||
name: str,
|
||||
comes_from: Optional[Union[str, InstallRequirement]] = None,
|
||||
*,
|
||||
use_pep517: Optional[bool] = None,
|
||||
isolated: bool = False,
|
||||
options: Optional[Dict[str, Any]] = None,
|
||||
global_options: Optional[List[str]] = None,
|
||||
hash_options: Optional[Dict[str, List[str]]] = None,
|
||||
constraint: bool = False,
|
||||
line_source: Optional[str] = None,
|
||||
user_supplied: bool = False,
|
||||
config_settings: Optional[Dict[str, str]] = None,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
) -> InstallRequirement:
|
||||
"""Creates an InstallRequirement from a name, which might be a
|
||||
requirement, directory containing 'setup.py', filename, or URL.
|
||||
@@ -399,9 +411,8 @@ def install_req_from_line(
|
||||
markers=parts.markers,
|
||||
use_pep517=use_pep517,
|
||||
isolated=isolated,
|
||||
install_options=options.get("install_options", []) if options else [],
|
||||
global_options=options.get("global_options", []) if options else [],
|
||||
hash_options=options.get("hashes", {}) if options else {},
|
||||
global_options=global_options,
|
||||
hash_options=hash_options,
|
||||
config_settings=config_settings,
|
||||
constraint=constraint,
|
||||
extras=parts.extras,
|
||||
@@ -415,12 +426,11 @@ def install_req_from_req_string(
|
||||
isolated: bool = False,
|
||||
use_pep517: Optional[bool] = None,
|
||||
user_supplied: bool = False,
|
||||
config_settings: Optional[Dict[str, str]] = None,
|
||||
) -> InstallRequirement:
|
||||
try:
|
||||
req = get_requirement(req_string)
|
||||
except InvalidRequirement:
|
||||
raise InstallationError(f"Invalid requirement: '{req_string}'")
|
||||
except InvalidRequirement as exc:
|
||||
raise InstallationError(f"Invalid requirement: {req_string!r}: {exc}")
|
||||
|
||||
domains_not_allowed = [
|
||||
PyPI.file_storage_domain,
|
||||
@@ -436,7 +446,7 @@ def install_req_from_req_string(
|
||||
raise InstallationError(
|
||||
"Packages installed from PyPI cannot depend on packages "
|
||||
"which are not also hosted on PyPI.\n"
|
||||
"{} depends on {} ".format(comes_from.name, req)
|
||||
f"{comes_from.name} depends on {req} "
|
||||
)
|
||||
|
||||
return InstallRequirement(
|
||||
@@ -445,7 +455,6 @@ def install_req_from_req_string(
|
||||
isolated=isolated,
|
||||
use_pep517=use_pep517,
|
||||
user_supplied=user_supplied,
|
||||
config_settings=config_settings,
|
||||
)
|
||||
|
||||
|
||||
@@ -454,7 +463,7 @@ def install_req_from_parsed_requirement(
|
||||
isolated: bool = False,
|
||||
use_pep517: Optional[bool] = None,
|
||||
user_supplied: bool = False,
|
||||
config_settings: Optional[Dict[str, str]] = None,
|
||||
config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
|
||||
) -> InstallRequirement:
|
||||
if parsed_req.is_editable:
|
||||
req = install_req_from_editable(
|
||||
@@ -473,7 +482,14 @@ def install_req_from_parsed_requirement(
|
||||
comes_from=parsed_req.comes_from,
|
||||
use_pep517=use_pep517,
|
||||
isolated=isolated,
|
||||
options=parsed_req.options,
|
||||
global_options=(
|
||||
parsed_req.options.get("global_options", [])
|
||||
if parsed_req.options
|
||||
else []
|
||||
),
|
||||
hash_options=(
|
||||
parsed_req.options.get("hashes", {}) if parsed_req.options else {}
|
||||
),
|
||||
constraint=parsed_req.constraint,
|
||||
line_source=parsed_req.line_source,
|
||||
user_supplied=user_supplied,
|
||||
@@ -493,9 +509,52 @@ def install_req_from_link_and_ireq(
|
||||
markers=ireq.markers,
|
||||
use_pep517=ireq.use_pep517,
|
||||
isolated=ireq.isolated,
|
||||
install_options=ireq.install_options,
|
||||
global_options=ireq.global_options,
|
||||
hash_options=ireq.hash_options,
|
||||
config_settings=ireq.config_settings,
|
||||
user_supplied=ireq.user_supplied,
|
||||
)
|
||||
|
||||
|
||||
def install_req_drop_extras(ireq: InstallRequirement) -> InstallRequirement:
|
||||
"""
|
||||
Creates a new InstallationRequirement using the given template but without
|
||||
any extras. Sets the original requirement as the new one's parent
|
||||
(comes_from).
|
||||
"""
|
||||
return InstallRequirement(
|
||||
req=(
|
||||
_set_requirement_extras(ireq.req, set()) if ireq.req is not None else None
|
||||
),
|
||||
comes_from=ireq,
|
||||
editable=ireq.editable,
|
||||
link=ireq.link,
|
||||
markers=ireq.markers,
|
||||
use_pep517=ireq.use_pep517,
|
||||
isolated=ireq.isolated,
|
||||
global_options=ireq.global_options,
|
||||
hash_options=ireq.hash_options,
|
||||
constraint=ireq.constraint,
|
||||
extras=[],
|
||||
config_settings=ireq.config_settings,
|
||||
user_supplied=ireq.user_supplied,
|
||||
permit_editable_wheels=ireq.permit_editable_wheels,
|
||||
)
|
||||
|
||||
|
||||
def install_req_extend_extras(
|
||||
ireq: InstallRequirement,
|
||||
extras: Collection[str],
|
||||
) -> InstallRequirement:
|
||||
"""
|
||||
Returns a copy of an installation requirement with some additional extras.
|
||||
Makes a shallow copy of the ireq object.
|
||||
"""
|
||||
result = copy.copy(ireq)
|
||||
result.extras = {*ireq.extras, *extras}
|
||||
result.req = (
|
||||
_set_requirement_extras(ireq.req, result.extras)
|
||||
if ireq.req is not None
|
||||
else None
|
||||
)
|
||||
return result
|
||||
Reference in new issue
Block a user