Skip to content

Commit b1f5d4a

Browse files
committed
Plumb honoring editable builds as needed.
1 parent 49667e6 commit b1f5d4a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+494
-217
lines changed

pex/artifact_url.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ def from_hashing_fingerprint(cls, fingerprint):
129129
algorithm = attr.ib() # type: str
130130
hash = attr.ib() # type: str
131131

132+
def __str__(self):
133+
# type: () -> str
134+
return "{algorithm}:{hash}".format(algorithm=self.algorithm, hash=self.hash)
135+
132136

133137
# These ranks prefer the highest digest size and then use alphabetic order for a tie-break.
134138
RANKED_ALGORITHMS = tuple(
@@ -268,3 +272,7 @@ def is_wheel(self):
268272
def fingerprint(self):
269273
# type: () -> Optional[Fingerprint]
270274
return self.fingerprints[0] if self.fingerprints else None
275+
276+
def __str__(self):
277+
# type: () -> str
278+
return self.raw_url

pex/bin/pex.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from pex.pex_bootstrapper import ensure_venv
4343
from pex.pex_builder import Check, PEXBuilder
4444
from pex.pex_info import PexInfo
45+
from pex.requirements import as_parsed_requirement
4546
from pex.resolve import (
4647
project,
4748
requirement_options,
@@ -862,7 +863,7 @@ def configure_clp():
862863
)
863864

864865
configure_clp_sources(parser)
865-
requirement_options.register(parser, include_short_editable_switch=False)
866+
requirement_options.register(parser, include_editable_requirements=False)
866867
dependency_configuration.register(parser)
867868

868869
parser.add_argument(
@@ -1056,7 +1057,7 @@ def build_pex(
10561057
group_requirements = project.get_group_requirements(options)
10571058
if group_requirements:
10581059
requirements = OrderedSet(requirement_configuration.requirements)
1059-
requirements.update(str(req) for req in group_requirements)
1060+
requirements.update(as_parsed_requirement(req) for req in group_requirements)
10601061
requirement_configuration = attr.evolve(
10611062
requirement_configuration, requirements=requirements
10621063
)
@@ -1086,7 +1087,7 @@ def build_pex(
10861087
project_dependencies.update(built_project.iter_requirements())
10871088

10881089
requirements = OrderedSet(requirement_configuration.requirements)
1089-
requirements.update(str(req) for req in project_dependencies)
1090+
requirements.update(as_parsed_requirement(req) for req in project_dependencies)
10901091
requirement_configuration = attr.evolve(
10911092
requirement_configuration, requirements=requirements
10921093
)
@@ -1096,7 +1097,7 @@ def build_pex(
10961097
" ".join(
10971098
itertools.chain.from_iterable(
10981099
(
1099-
requirement_configuration.requirements or (),
1100+
map(str, requirement_configuration.requirements or ()),
11001101
requirement_configuration.requirement_files or (),
11011102
)
11021103
)
@@ -1290,7 +1291,10 @@ def main(args=None):
12901291
with global_environment(options) as env:
12911292
try:
12921293
resolver_configuration = resolver_options.configure(
1293-
options, use_system_time=options.use_system_time
1294+
options,
1295+
use_system_time=options.use_system_time,
1296+
# N.B.: Since a PEX freezes in whls, there is no point to using editable whls.
1297+
honor_editable=False,
12941298
)
12951299
except resolver_options.InvalidConfigurationError as e:
12961300
die(str(e))

pex/build_system/pep_517.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from pex.dist_metadata import DistMetadata, Distribution, MetadataType
1616
from pex.jobs import Job, SpawnedJob
1717
from pex.pip.version import PipVersion, PipVersionValue
18+
from pex.requirements import as_parsed_requirement, parse_requirement_string
1819
from pex.resolve.resolvers import Resolver
1920
from pex.result import Error, try_
2021
from pex.targets import Target, Targets
@@ -24,6 +25,8 @@
2425
if TYPE_CHECKING:
2526
from typing import Any, Dict, Iterable, List, Mapping, Optional, Set, Union
2627

28+
from pex.requirements import ParsedRequirement
29+
2730
_DEFAULT_BUILD_SYSTEMS = {} # type: Dict[PipVersionValue, BuildSystem]
2831

2932

@@ -41,22 +44,26 @@ def _default_build_system(
4144
"Building {build_backend} build_backend PEX".format(build_backend=DEFAULT_BUILD_BACKEND)
4245
):
4346
extra_env = {} # type: Dict[str, str]
44-
resolved_reqs = set() # type: Set[str]
47+
resolved_reqs = set() # type: Set[ParsedRequirement]
4548
resolved_dists = [] # type: List[Distribution]
4649
if selected_pip_version is PipVersion.VENDORED:
47-
requires = ["setuptools", str(selected_pip_version.wheel_requirement)]
50+
setuptools_req = parse_requirement_string("setuptools")
51+
requires = [
52+
setuptools_req,
53+
as_parsed_requirement(selected_pip_version.wheel_requirement),
54+
]
4855
resolved_dists.extend(
4956
Distribution.load(dist_location)
5057
for dist_location in third_party.expose_installed_wheels(
5158
["setuptools"], interpreter=target.get_interpreter()
5259
)
5360
)
54-
resolved_reqs.add("setuptools")
61+
resolved_reqs.add(setuptools_req)
5562
extra_env.update(__PEX_UNVENDORED__="setuptools")
5663
else:
5764
requires = [
58-
str(selected_pip_version.setuptools_requirement),
59-
str(selected_pip_version.wheel_requirement),
65+
as_parsed_requirement(selected_pip_version.setuptools_requirement),
66+
as_parsed_requirement(selected_pip_version.wheel_requirement),
6067
]
6168
unresolved = [
6269
requirement for requirement in requires if requirement not in resolved_reqs
@@ -71,7 +78,7 @@ def _default_build_system(
7178
build_system = try_(
7279
BuildSystem.create(
7380
interpreter=target.get_interpreter(),
74-
requires=requires,
81+
requires=map(str, requires),
7582
resolved=resolved_dists,
7683
build_backend=DEFAULT_BUILD_BACKEND,
7784
backend_path=(),

pex/build_system/pep_518.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from pex.pex import PEX
1515
from pex.pex_bootstrapper import VenvPex, ensure_venv
1616
from pex.pex_builder import PEXBuilder
17+
from pex.requirements import parse_requirement_strings
1718
from pex.resolve.resolvers import Resolver
1819
from pex.result import Error
1920
from pex.targets import LocalInterpreter, Target, Targets
@@ -184,7 +185,7 @@ def load_build_system(
184185
):
185186
result = resolver.resolve_requirements(
186187
targets=Targets.from_target(LocalInterpreter.create(target.get_interpreter())),
187-
requirements=build_system_table.requires,
188+
requirements=tuple(parse_requirement_strings(build_system_table.requires)),
188189
)
189190
return BuildSystem.create(
190191
interpreter=target.get_interpreter(),

pex/cli/commands/lock.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
from pex.pep_440 import Version
4242
from pex.pep_503 import ProjectName
4343
from pex.pip.version import PipVersionValue
44-
from pex.requirements import LocalProjectRequirement
44+
from pex.requirements import LocalProjectRequirement, as_parsed_requirement
4545
from pex.resolve import project, requirement_options, resolver_options, target_options
4646
from pex.resolve.config import finalize as finalize_resolve_config
4747
from pex.resolve.configured_resolver import ConfiguredResolver
@@ -1179,15 +1179,15 @@ def _merge_project_requirements(
11791179
return requirement_configuration
11801180

11811181
requirements = OrderedSet(requirement_configuration.requirements)
1182-
requirements.update(str(req) for req in group_requirements)
1182+
requirements.update(as_parsed_requirement(req) for req in group_requirements)
11831183
if projects:
11841184
with TRACER.timed(
11851185
"Collecting requirements from {count} local {projects}".format(
11861186
count=len(projects), projects=pluralize(projects, "project")
11871187
)
11881188
):
11891189
requirements.update(
1190-
str(req)
1190+
as_parsed_requirement(req)
11911191
for req in projects.collect_requirements(
11921192
resolver=ConfiguredResolver(pip_configuration),
11931193
interpreter=targets.interpreter,
@@ -1357,7 +1357,7 @@ def _export(self, requirement_configuration=RequirementConfiguration()):
13571357
requirement_configuration
13581358
if requirement_configuration.has_requirements
13591359
else RequirementConfiguration(
1360-
requirements=map(str, lock_file.requirements)
1360+
requirements=map(as_parsed_requirement, lock_file.requirements)
13611361
)
13621362
),
13631363
)
@@ -2212,10 +2212,7 @@ def _update(self):
22122212
def _sync(self):
22132213
# type: () -> Result
22142214

2215-
resolver_configuration = cast(
2216-
LockRepositoryConfiguration,
2217-
resolver_options.configure(self.options, use_system_time=False),
2218-
)
2215+
resolver_configuration = resolver_options.configure(self.options, use_system_time=False)
22192216
production_assert(isinstance(resolver_configuration, LockRepositoryConfiguration))
22202217
pip_configuration = resolver_configuration.pip_configuration
22212218
locking_configuration = try_(self._locking_configuration(pip_configuration))

pex/cli/commands/run.py

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@
4040
from pex.orderedset import OrderedSet
4141
from pex.os import safe_execv
4242
from pex.pip.version import PipVersionValue
43-
from pex.requirements import LocalProjectRequirement, ParseError, parse_requirement_string
43+
from pex.requirements import (
44+
LocalProjectRequirement,
45+
ParseError,
46+
as_parsed_requirement,
47+
parse_requirement_string,
48+
)
4449
from pex.resolve import lock_resolver, requirement_options, resolver_options, target_options
4550
from pex.resolve.configured_resolver import ConfiguredResolver
4651
from pex.resolve.locked_resolve import FileArtifact, UnFingerprintedLocalProjectArtifact
@@ -54,6 +59,7 @@
5459
from pex.targets import LocalInterpreter, Targets
5560
from pex.tracer import TRACER
5661
from pex.typing import TYPE_CHECKING
62+
from pex.util import CacheHelper
5763
from pex.variables import ENV, venv_dir
5864
from pex.venv import installer
5965
from pex.venv.installer import Provenance
@@ -115,7 +121,7 @@ class RunSpec(object):
115121
entry_point = attr.ib() # type: str
116122
is_script = attr.ib() # type: bool
117123
pip_configuration = attr.ib() # type: PipConfiguration
118-
run_requirement = attr.ib(default=None) # type: Optional[Requirement]
124+
run_requirement = attr.ib(default=None) # type: Optional[ParsedRequirement]
119125
all_requirements = attr.ib(default=RequirementConfiguration()) # type: RequirementConfiguration
120126
args = attr.ib(default=()) # type: Tuple[str, ...]
121127
locks = attr.ib(default=()) # type: Tuple[str, ...]
@@ -263,8 +269,8 @@ def resolve_run_spec(
263269
):
264270
# type: (...) -> RunSpec
265271

266-
requirement = None # type: Optional[Requirement]
267-
extra_requirements = OrderedSet() # type: OrderedSet[Requirement]
272+
requirement = None # type: Optional[ParsedRequirement]
273+
extra_requirements = OrderedSet() # type: OrderedSet[ParsedRequirement]
268274
local_projects = OrderedSet() # type: OrderedSet[LocalProjectRequirement]
269275

270276
entry_point = None # type: Optional[str]
@@ -289,7 +295,7 @@ def resolve_run_spec(
289295
if isinstance(self.requirement, LocalProjectRequirement):
290296
local_projects.add(self.requirement)
291297
elif self.requirement:
292-
requirement = self.requirement.requirement
298+
requirement = self.requirement
293299

294300
local_project_to_dist = dict(
295301
_create_dists(
@@ -301,8 +307,13 @@ def resolve_run_spec(
301307
)
302308
for local_project, dist in local_project_to_dist.items():
303309
project_name = DistMetadata.load(dist).project_name
304-
local_project_req = Requirement.local(
305-
project_name=project_name, path=dist, editable=local_project.editable
310+
local_project_req = as_parsed_requirement(
311+
Requirement.local(
312+
project_name=project_name,
313+
path=dist,
314+
editable=local_project.editable,
315+
fragment_parameters=[("sha256", CacheHelper.hash(dist, hasher=hashlib.sha256))],
316+
)
306317
)
307318
if self.entry_point == local_project:
308319
entry_point = project_name.raw
@@ -326,10 +337,10 @@ def resolve_run_spec(
326337
locks.append("pylock.{name}.toml".format(name=name))
327338
locks.append("pylock.toml")
328339

329-
requirements = OrderedSet() # type: OrderedSet[str]
340+
requirements = OrderedSet() # type: OrderedSet[ParsedRequirement]
330341
if requirement:
331-
requirements.add(str(requirement))
332-
requirements.update(map(str, extra_requirements))
342+
requirements.add(requirement)
343+
requirements.update(extra_requirements)
333344
if self.extra_requirements.requirements:
334345
requirements.update(self.extra_requirements.requirements)
335346

@@ -424,7 +435,7 @@ def resolve(
424435
refresh=False, # type: bool
425436
locked_choice=LockedChoice.AUTO, # type: LockedChoice.Value
426437
):
427-
# type: (...) -> Union[Tuple[str, Iterable[Requirement], LocalInterpreter], Error]
438+
# type: (...) -> Union[Tuple[str, Iterable[ParsedRequirement], LocalInterpreter], Error]
428439

429440
script = try_(
430441
self._resolve_script(pip_configuration, refresh=refresh, locked_choice=locked_choice)
@@ -438,14 +449,11 @@ def resolve(
438449
except Unsatisfiable as e:
439450
return Error(str(e))
440451

441-
requirements = OrderedSet() # type: OrderedSet[Requirement]
452+
requirements = OrderedSet() # type: OrderedSet[ParsedRequirement]
442453
if script_metadata_application.target_does_not_apply(target):
443454
target = try_(_resolve_local_interpreter(target_configuration, script))
444455
if script_metadata_application.requirement_configuration.requirements:
445-
requirements.update(
446-
Requirement.parse(req)
447-
for req in script_metadata_application.requirement_configuration.requirements
448-
)
456+
requirements.update(script_metadata_application.requirement_configuration.requirements)
449457

450458
return script, requirements, target
451459

@@ -626,7 +634,7 @@ def _resolve_pylock(self, run_spec):
626634

627635
downloaded = pip_resolver.download(
628636
targets=targets,
629-
requirements=[str(requirement)],
637+
requirements=[requirement],
630638
constraint_files=run_spec.all_requirements.constraint_files,
631639
allow_prereleases=pip_configuration.allow_prereleases,
632640
transitive=False,
@@ -658,7 +666,11 @@ def _resolve_pylock(self, run_spec):
658666
index=-1,
659667
project_name=dist_metadata.project_name,
660668
artifact=FileArtifact(
661-
url=ArtifactURL.parse("file://{path}".format(path=distribution.path)),
669+
url=ArtifactURL.parse(
670+
"file://{path}#sha256={hash}".format(
671+
path=distribution.path, hash=distribution.fingerprint
672+
)
673+
),
662674
verified=True,
663675
fingerprint=Fingerprint(algorithm="sha256", hash=distribution.fingerprint),
664676
filename=os.path.basename(distribution.path),

pex/cli/commands/scie.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,12 @@ def _create(self):
263263
if not scie_options:
264264
return Error("You must specify `--style {eager,lazy}`.")
265265

266-
resolver_configuration = resolver_options.configure(self.options)
266+
resolver_configuration = resolver_options.configure(
267+
self.options,
268+
# N.B.: Since a scie freezes in whls via freezing in a PEX, there is no point to using
269+
# editable whls.
270+
honor_editable=False,
271+
)
267272
if os.path.exists(self.options.pex[0]):
268273
pex_file, pex_info = try_(_extract_pex_info(self.options.pex[0]))
269274
if self.options.dest_dir and os.path.realpath(

pex/dist_metadata.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,10 +902,22 @@ def local(
902902
project_name, # type: ProjectName
903903
path, # type: Text
904904
editable=False, # type: bool
905+
fragment_parameters=(), # type: Iterable[Tuple[str, str]]
905906
):
906907
# type: (...) -> Requirement
907908
return cls.parse(
908-
"{project_name} @ file://{path}".format(project_name=project_name, path=path),
909+
"{project_name} @ file://{path}{fragment_parameters}".format(
910+
project_name=project_name,
911+
path=path,
912+
fragment_parameters="#{params}".format(
913+
params="&".join(
914+
"{key}={value}".format(key=key, value=value)
915+
for key, value in fragment_parameters
916+
)
917+
)
918+
if fragment_parameters
919+
else "",
920+
),
909921
editable=editable,
910922
)
911923

0 commit comments

Comments
 (0)