pex 2.66.0__py2.py3-none-any.whl → 2.67.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pex might be problematic. Click here for more details.

Files changed (45) hide show
  1. pex/docs/html/_pagefind/fragment/en_4dc5d41.pf_fragment +0 -0
  2. pex/docs/html/_pagefind/fragment/en_5ff234a.pf_fragment +0 -0
  3. pex/docs/html/_pagefind/fragment/en_7faba29.pf_fragment +0 -0
  4. pex/docs/html/_pagefind/fragment/en_8531963.pf_fragment +0 -0
  5. pex/docs/html/_pagefind/fragment/en_8d197bb.pf_fragment +0 -0
  6. pex/docs/html/_pagefind/fragment/en_e195b46.pf_fragment +0 -0
  7. pex/docs/html/_pagefind/fragment/{en_af1fb65.pf_fragment → en_f384da1.pf_fragment} +0 -0
  8. pex/docs/html/_pagefind/fragment/en_fbb9204.pf_fragment +0 -0
  9. pex/docs/html/_pagefind/index/{en_f48c2e4.pf_index → en_c236b81.pf_index} +0 -0
  10. pex/docs/html/_pagefind/pagefind-entry.json +1 -1
  11. pex/docs/html/_pagefind/pagefind.en_849a96a3e6.pf_meta +0 -0
  12. pex/docs/html/_static/documentation_options.js +1 -1
  13. pex/docs/html/api/vars.html +5 -5
  14. pex/docs/html/buildingpex.html +5 -5
  15. pex/docs/html/genindex.html +5 -5
  16. pex/docs/html/index.html +5 -5
  17. pex/docs/html/recipes.html +5 -5
  18. pex/docs/html/scie.html +5 -5
  19. pex/docs/html/search.html +5 -5
  20. pex/docs/html/whatispex.html +5 -5
  21. pex/jobs.py +13 -6
  22. pex/resolve/configured_resolve.py +13 -5
  23. pex/resolve/locker.py +17 -12
  24. pex/resolve/lockfile/create.py +1 -6
  25. pex/resolve/pre_resolved_resolver.py +1 -7
  26. pex/resolve/resolver_configuration.py +1 -1
  27. pex/resolve/resolver_options.py +14 -9
  28. pex/resolve/venv_resolver.py +189 -55
  29. pex/resolver.py +40 -35
  30. pex/version.py +1 -1
  31. {pex-2.66.0.dist-info → pex-2.67.0.dist-info}/METADATA +4 -4
  32. {pex-2.66.0.dist-info → pex-2.67.0.dist-info}/RECORD +37 -37
  33. pex/docs/html/_pagefind/fragment/en_1caf19d.pf_fragment +0 -0
  34. pex/docs/html/_pagefind/fragment/en_2268ed8.pf_fragment +0 -0
  35. pex/docs/html/_pagefind/fragment/en_469c87d.pf_fragment +0 -0
  36. pex/docs/html/_pagefind/fragment/en_4a75d8d.pf_fragment +0 -0
  37. pex/docs/html/_pagefind/fragment/en_9fe4bcc.pf_fragment +0 -0
  38. pex/docs/html/_pagefind/fragment/en_a951443.pf_fragment +0 -0
  39. pex/docs/html/_pagefind/fragment/en_e0b014e.pf_fragment +0 -0
  40. pex/docs/html/_pagefind/pagefind.en_4eb6e6f279.pf_meta +0 -0
  41. {pex-2.66.0.dist-info → pex-2.67.0.dist-info}/WHEEL +0 -0
  42. {pex-2.66.0.dist-info → pex-2.67.0.dist-info}/entry_points.txt +0 -0
  43. {pex-2.66.0.dist-info → pex-2.67.0.dist-info}/licenses/LICENSE +0 -0
  44. {pex-2.66.0.dist-info → pex-2.67.0.dist-info}/pylock/pylock.toml +0 -0
  45. {pex-2.66.0.dist-info → pex-2.67.0.dist-info}/top_level.txt +0 -0
@@ -56,9 +56,10 @@ class _HandleTransitiveAction(Action):
56
56
  class _ResolveVenvAction(Action):
57
57
  def __init__(self, *args, **kwargs):
58
58
  kwargs["nargs"] = "?"
59
- super(_ResolveVenvAction, self).__init__(*args, **kwargs)
59
+ super(_ResolveVenvAction, self).__init__(*args, default=[], **kwargs)
60
60
 
61
61
  def __call__(self, parser, namespace, value, option_str=None):
62
+ venvs = getattr(namespace, self.dest)
62
63
  if value:
63
64
  if not os.path.exists(value):
64
65
  raise ArgumentError(
@@ -86,7 +87,7 @@ class _ResolveVenvAction(Action):
86
87
  "path.".format(option=option_str, value=value)
87
88
  ),
88
89
  )
89
- setattr(namespace, self.dest, venv)
90
+ venvs.append(venv)
90
91
  else:
91
92
  current_venv = Virtualenv.enclosing(python=sys.executable)
92
93
  if not current_venv:
@@ -105,7 +106,7 @@ class _ResolveVenvAction(Action):
105
106
  )
106
107
  ),
107
108
  )
108
- setattr(namespace, self.dest, current_venv)
109
+ venvs.append(current_venv)
109
110
 
110
111
 
111
112
  def register(
@@ -320,14 +321,18 @@ def register(
320
321
  if include_venv_repository:
321
322
  repository_choice.add_argument(
322
323
  "--venv-repository",
323
- dest="venv_repository",
324
+ dest="venv_repositories",
324
325
  action=_ResolveVenvAction,
325
- type=str,
326
326
  help=(
327
327
  "Resolve requirements from the given virtual environment instead of from "
328
328
  "--index servers, --find-links repos or a --lock file. The virtual environment to "
329
329
  "resolve from can be specified as the path to the venv or the path of its"
330
- "interpreter. If no value is specified, the current active venv is used."
330
+ "interpreter. If no value is specified, the current active venv is used. Multiple "
331
+ "virtual environments may be specified via multiple --venv-repository options and "
332
+ "the resolve will be the combined results. Each virtual environment will be "
333
+ "resolved from individually and must contain the full transitive closure of "
334
+ "requirements. This allows for creating a multi-platform PEX by specifying "
335
+ "multiple virtual environments; say one for Python 3.12 and one for Python 3.13."
331
336
  ),
332
337
  )
333
338
 
@@ -803,9 +808,9 @@ def configure(
803
808
  sdists=tuple(sdists), wheels=tuple(wheels), pip_configuration=pip_configuration
804
809
  )
805
810
 
806
- venv = getattr(options, "venv_repository", None)
807
- if venv:
808
- return VenvRepositoryConfiguration(venv=venv, pip_configuration=pip_configuration)
811
+ venvs = getattr(options, "venv_repositories", None)
812
+ if venvs:
813
+ return VenvRepositoryConfiguration(venvs=tuple(venvs), pip_configuration=pip_configuration)
809
814
 
810
815
  if pylock:
811
816
  return PylockRepositoryConfiguration(
@@ -5,14 +5,13 @@ from __future__ import absolute_import
5
5
 
6
6
  import functools
7
7
  import hashlib
8
- import itertools
9
8
  import os
10
9
  from collections import defaultdict, deque
11
10
 
12
11
  from pex import pex_warnings
13
12
  from pex.atomic_directory import atomic_directory
14
13
  from pex.cache.dirs import CacheDir, InstalledWheelDir
15
- from pex.common import safe_relative_symlink
14
+ from pex.common import pluralize, safe_relative_symlink
16
15
  from pex.compatibility import commonpath
17
16
  from pex.dependency_configuration import DependencyConfiguration
18
17
  from pex.dist_metadata import (
@@ -26,7 +25,6 @@ from pex.dist_metadata import (
26
25
  from pex.exceptions import production_assert, reportable_unexpected_error_msg
27
26
  from pex.fingerprinted_distribution import FingerprintedDistribution
28
27
  from pex.installed_wheel import InstalledWheel
29
- from pex.interpreter import PythonInterpreter
30
28
  from pex.jobs import DEFAULT_MAX_JOBS, iter_map_parallel
31
29
  from pex.orderedset import OrderedSet
32
30
  from pex.pep_376 import Record
@@ -47,7 +45,18 @@ from pex.wheel import WHEEL, Wheel
47
45
  from pex.whl import repacked_whl
48
46
 
49
47
  if TYPE_CHECKING:
50
- from typing import DefaultDict, Deque, FrozenSet, Iterable, Iterator, List, Mapping, Set, Union
48
+ from typing import (
49
+ DefaultDict,
50
+ Deque,
51
+ FrozenSet,
52
+ Iterable,
53
+ Iterator,
54
+ List,
55
+ Mapping,
56
+ Set,
57
+ Tuple,
58
+ Union,
59
+ )
51
60
 
52
61
  import attr # vendor:skip
53
62
  else:
@@ -96,12 +105,14 @@ def _normalize_record(
96
105
 
97
106
 
98
107
  def _install_distribution(
99
- interpreter, # type: PythonInterpreter
108
+ venv_distribution, # type: VenvDistribution
100
109
  result_type, # type: InstallableType.Value
101
110
  use_system_time, # type: bool
102
- distribution, # type: Distribution
103
111
  ):
104
- # type: (...) -> FingerprintedDistribution
112
+ # type: (...) -> ResolvedDistribution
113
+
114
+ interpreter = venv_distribution.target.interpreter
115
+ distribution = venv_distribution.distribution
105
116
 
106
117
  production_assert(distribution.type is DistributionType.INSTALLED)
107
118
  production_assert(distribution.metadata.files.metadata.type is MetadataType.DIST_INFO)
@@ -160,31 +171,86 @@ def _install_distribution(
160
171
  raise AssertionError(reportable_unexpected_error_msg())
161
172
 
162
173
  if result_type is InstallableType.INSTALLED_WHEEL_CHROOT:
163
- return FingerprintedDistribution(
164
- distribution=Distribution.load(installed_wheel.prefix_dir),
165
- fingerprint=installed_wheel.fingerprint,
174
+ return ResolvedDistribution(
175
+ target=venv_distribution.target,
176
+ fingerprinted_distribution=FingerprintedDistribution(
177
+ distribution=Distribution.load(installed_wheel.prefix_dir),
178
+ fingerprint=installed_wheel.fingerprint,
179
+ ),
180
+ direct_requirements=venv_distribution.direct_requirements,
166
181
  )
167
- return repacked_whl(
168
- installed_wheel, fingerprint=installed_wheel.fingerprint, use_system_time=use_system_time
182
+
183
+ return ResolvedDistribution(
184
+ target=venv_distribution.target,
185
+ fingerprinted_distribution=repacked_whl(
186
+ installed_wheel,
187
+ fingerprint=installed_wheel.fingerprint,
188
+ use_system_time=use_system_time,
189
+ ),
190
+ direct_requirements=venv_distribution.direct_requirements,
169
191
  )
170
192
 
171
193
 
194
+ @attr.s(frozen=True)
195
+ class VenvDistribution(object):
196
+ target = attr.ib() # type: LocalInterpreter
197
+ distribution = attr.ib() # type: Distribution
198
+ direct_requirements = attr.ib() # type: Iterable[Requirement]
199
+
200
+
172
201
  def _install_venv_distributions(
173
- venv, # type: Virtualenv
174
- distributions, # type: Iterable[Distribution]
202
+ venv_resolve_results, # type: Iterable[VenvResolveResult]
175
203
  max_install_jobs=DEFAULT_MAX_JOBS, # type: int
176
204
  result_type=InstallableType.INSTALLED_WHEEL_CHROOT, # type: InstallableType.Value
177
205
  use_system_time=False, # type: bool
178
206
  ):
179
- # type: (...) -> Iterator[FingerprintedDistribution]
207
+ # type: (...) -> Iterator[ResolvedDistribution]
208
+
209
+ seen = set() # type: Set[str]
210
+
211
+ venv_distributions = [] # type: List[VenvDistribution]
212
+ for venv_resolve_result in venv_resolve_results:
213
+ target = venv_resolve_result.target
214
+ direct_requirements = venv_resolve_result.direct_requirements_by_project_name
215
+ for re_resolved_distribution in venv_resolve_result.re_resolved_distributions:
216
+ wheel_file_name = Wheel.from_distribution(
217
+ re_resolved_distribution.distribution
218
+ ).wheel_file_name
219
+ if wheel_file_name in seen:
220
+ continue
221
+
222
+ seen.add(wheel_file_name)
223
+ yield ResolvedDistribution(
224
+ target=target,
225
+ fingerprinted_distribution=re_resolved_distribution,
226
+ direct_requirements=direct_requirements.get(
227
+ re_resolved_distribution.project_name, ()
228
+ ),
229
+ )
230
+ for venv_distribution in venv_resolve_result.venv_distributions:
231
+ wheel_file_name = Wheel.from_distribution(venv_distribution).wheel_file_name
232
+ if wheel_file_name in seen:
233
+ continue
234
+
235
+ seen.add(wheel_file_name)
236
+ venv_distributions.append(
237
+ VenvDistribution(
238
+ target=target,
239
+ distribution=venv_distribution,
240
+ direct_requirements=direct_requirements.get(
241
+ venv_distribution.metadata.project_name, ()
242
+ ),
243
+ )
244
+ )
180
245
 
181
- return iter_map_parallel(
182
- inputs=distributions,
246
+ for resolved_distribution in iter_map_parallel(
247
+ inputs=venv_distributions,
183
248
  function=functools.partial(
184
- _install_distribution, venv.interpreter, result_type, use_system_time
249
+ _install_distribution, result_type=result_type, use_system_time=use_system_time
185
250
  ),
186
251
  max_jobs=max_install_jobs,
187
- )
252
+ ):
253
+ yield resolved_distribution
188
254
 
189
255
 
190
256
  @attr.s(frozen=True)
@@ -359,27 +425,32 @@ def _resolve_distributions(
359
425
  )
360
426
 
361
427
 
362
- def resolve_from_venv(
363
- targets, # type: Targets
428
+ @attr.s(frozen=True)
429
+ class VenvResolveResult(object):
430
+ venv = attr.ib() # type: Virtualenv
431
+ venv_distributions = attr.ib() # type: Tuple[Distribution, ...]
432
+ re_resolved_distributions = attr.ib() # type: Tuple[FingerprintedDistribution, ...]
433
+ direct_requirements_by_project_name = attr.ib(
434
+ eq=False
435
+ ) # type: Mapping[ProjectName, Iterable[Requirement]]
436
+
437
+ @property
438
+ def target(self):
439
+ # type: () -> LocalInterpreter
440
+ return LocalInterpreter.create(self.venv.interpreter)
441
+
442
+
443
+ def _resolve_from_venv(
364
444
  venv, # type: Virtualenv
365
- requirement_configuration=RequirementConfiguration(), # type: RequirementConfiguration
366
- pip_configuration=PipConfiguration(), # type: PipConfiguration
367
- compile=False, # type: bool
368
- ignore_errors=False, # type: bool
369
- result_type=InstallableType.INSTALLED_WHEEL_CHROOT, # type: InstallableType.Value
370
- dependency_configuration=DependencyConfiguration(), # type: DependencyConfiguration
445
+ requirement_configuration, # type: RequirementConfiguration
446
+ pip_configuration, # type: PipConfiguration
447
+ compile, # type: bool
448
+ ignore_errors, # type: bool
449
+ result_type, # type: InstallableType.Value
450
+ dependency_configuration, # type: DependencyConfiguration
371
451
  ):
372
- # type: (...) -> Union[ResolveResult, Error]
373
-
452
+ # type: (...) -> Union[VenvResolveResult, Error]
374
453
  target = LocalInterpreter.create(venv.interpreter)
375
- if not targets.is_empty:
376
- return Error(
377
- "You configured custom targets via --python, --interpreter-constraint, --platform or "
378
- "--complete-platform but custom targets are not allowed when resolving from a virtual "
379
- "environment.\n"
380
- "For such resolves, the supported target is implicitly the one matching the venv "
381
- "interpreter; in this case: {target}.".format(target=target.render_description())
382
- )
383
454
 
384
455
  if pip_configuration.version:
385
456
  compatible_pip_version = (
@@ -487,27 +558,90 @@ def resolve_from_venv(
487
558
  dist.fingerprinted_distribution for dist in result.distributions
488
559
  )
489
560
 
561
+ return VenvResolveResult(
562
+ venv=venv,
563
+ venv_distributions=tuple(venv_distributions),
564
+ re_resolved_distributions=tuple(fingerprinted_distributions),
565
+ direct_requirements_by_project_name=direct_requirements_by_project_name,
566
+ )
567
+
568
+
569
+ def resolve_from_venvs(
570
+ targets, # type: Targets
571
+ venvs, # type: Tuple[Virtualenv, ...]
572
+ requirement_configuration=RequirementConfiguration(), # type: RequirementConfiguration
573
+ pip_configuration=PipConfiguration(), # type: PipConfiguration
574
+ compile=False, # type: bool
575
+ ignore_errors=False, # type: bool
576
+ result_type=InstallableType.INSTALLED_WHEEL_CHROOT, # type: InstallableType.Value
577
+ dependency_configuration=DependencyConfiguration(), # type: DependencyConfiguration
578
+ ):
579
+ # type: (...) -> Union[ResolveResult, Error]
580
+
581
+ if not targets.is_empty:
582
+ return Error(
583
+ "You configured custom targets via --python, --interpreter-constraint, --platform or "
584
+ "--complete-platform but custom targets are not allowed when resolving from {venvs}.\n"
585
+ "For such resolves, the supported target is implicitly the one matching the venv "
586
+ "{interpreters}; in this case:{targets}.".format(
587
+ venvs="a virtual environment" if len(venvs) == 1 else "virtual environments",
588
+ interpreters=pluralize(venvs, "interpreter"),
589
+ targets=(
590
+ " {target}".format(
591
+ target=LocalInterpreter.create(venvs[0].interpreter).render_description()
592
+ )
593
+ if len(venvs) == 1
594
+ else "\n {targets}".format(
595
+ targets="\n ".join(
596
+ LocalInterpreter.create(venv.interpreter).render_description()
597
+ for venv in venvs
598
+ )
599
+ )
600
+ ),
601
+ )
602
+ )
603
+
604
+ errors = [] # type: List[Error]
605
+ venv_resolve_results = [] # type: List[VenvResolveResult]
606
+ for result in iter_map_parallel(
607
+ venvs,
608
+ functools.partial(
609
+ _resolve_from_venv,
610
+ requirement_configuration=requirement_configuration,
611
+ pip_configuration=pip_configuration,
612
+ compile=compile,
613
+ ignore_errors=ignore_errors,
614
+ result_type=result_type,
615
+ dependency_configuration=dependency_configuration,
616
+ ),
617
+ ):
618
+ if isinstance(result, Error):
619
+ errors.append(result)
620
+ else:
621
+ venv_resolve_results.append(result)
622
+
623
+ if len(errors) == 1:
624
+ return errors[0]
625
+ elif errors:
626
+ return Error(
627
+ "Failed to resolve from {count} of {total} virtual environments:\n{failures}".format(
628
+ count=len(errors),
629
+ total=len(venvs),
630
+ failures="\n".join(
631
+ "{index}. {error}".format(index=index, error=error)
632
+ for index, error in enumerate(errors, start=1)
633
+ ),
634
+ )
635
+ )
636
+
490
637
  return ResolveResult(
491
638
  dependency_configuration=dependency_configuration,
492
639
  distributions=tuple(
493
- ResolvedDistribution(
494
- target=target,
495
- fingerprinted_distribution=fingerprinted_distribution,
496
- direct_requirements=direct_requirements_by_project_name[
497
- fingerprinted_distribution.project_name
498
- ],
499
- )
500
- for fingerprinted_distribution in itertools.chain(
501
- list(
502
- _install_venv_distributions(
503
- venv=venv,
504
- distributions=venv_distributions,
505
- max_install_jobs=pip_configuration.max_jobs,
506
- result_type=result_type,
507
- use_system_time=True,
508
- )
509
- ),
510
- fingerprinted_distributions,
640
+ _install_venv_distributions(
641
+ venv_resolve_results,
642
+ max_install_jobs=pip_configuration.max_jobs,
643
+ result_type=result_type,
644
+ use_system_time=True,
511
645
  )
512
646
  ),
513
647
  type=result_type,
pex/resolver.py CHANGED
@@ -65,6 +65,7 @@ from pex.resolve.resolvers import (
65
65
  check_resolve,
66
66
  )
67
67
  from pex.resolve.target_system import TargetSystem, UniversalTarget
68
+ from pex.result import Error
68
69
  from pex.targets import AbbreviatedPlatform, CompletePlatform, LocalInterpreter, Target, Targets
69
70
  from pex.third_party.packaging.specifiers import SpecifierSet
70
71
  from pex.third_party.packaging.tags import Tag
@@ -309,10 +310,7 @@ class _PipSession(object):
309
310
  if isinstance(requirement, LocalProjectRequirement):
310
311
  for request in self.requests:
311
312
  yield BuildRequest.for_directory(
312
- target=request.target,
313
- source_path=requirement.path,
314
- resolver=self.resolver,
315
- pip_version=self.pip_version,
313
+ target=request.target, source_path=requirement.path
316
314
  )
317
315
 
318
316
  def generate_reports(self, max_parallel_jobs=None):
@@ -594,12 +592,17 @@ def _fingerprint_directory(path):
594
592
  return CacheHelper.dir_hash(path, digest=_hasher())
595
593
 
596
594
 
595
+ class BuildError(Exception):
596
+ pass
597
+
598
+
597
599
  def _fingerprint_local_project(
598
600
  path, # type: str
599
601
  target, # type: Target
600
602
  resolver=None, # type: Optional[Resolver]
601
603
  pip_version=None, # type: Optional[PipVersionValue]
602
604
  ):
605
+ # type: (...) -> str
603
606
  if resolver:
604
607
  build_system_resolver = resolver
605
608
  else:
@@ -607,17 +610,20 @@ def _fingerprint_local_project(
607
610
 
608
611
  build_system_resolver = ConfiguredResolver.default()
609
612
 
610
- return digest_local_project(
613
+ hasher = _hasher()
614
+ result = digest_local_project(
611
615
  directory=path,
612
- digest=_hasher(),
616
+ digest=hasher,
613
617
  target=target,
614
618
  resolver=build_system_resolver,
615
619
  pip_version=pip_version,
616
620
  )
617
-
618
-
619
- class BuildError(Exception):
620
- pass
621
+ if isinstance(result, Error):
622
+ raise BuildError(
623
+ "Failed to create an sdist for hashing from the local project at {path}: "
624
+ "{err}".format(path=path, err=result)
625
+ )
626
+ return hasher.hexdigest()
621
627
 
622
628
 
623
629
  def _as_download_target(target):
@@ -649,27 +655,19 @@ class BuildRequest(object):
649
655
  target, # type: Union[DownloadTarget, Target]
650
656
  source_path, # type: str
651
657
  subdirectory=None, # type: Optional[str]
652
- resolver=None, # type: Optional[Resolver]
653
- pip_version=None, # type: Optional[PipVersionValue]
654
658
  ):
655
659
  # type: (...) -> BuildRequest
656
660
  download_target = _as_download_target(target)
657
- fingerprint = _fingerprint_local_project(
658
- path=source_path,
659
- target=download_target.target,
660
- resolver=resolver,
661
- pip_version=pip_version,
662
- )
663
661
  return cls(
664
662
  download_target=download_target,
665
663
  source_path=source_path,
666
- fingerprint=fingerprint,
664
+ fingerprint=None,
667
665
  subdirectory=subdirectory,
668
666
  )
669
667
 
670
668
  download_target = attr.ib(converter=_as_download_target) # type: DownloadTarget
671
669
  source_path = attr.ib() # type: str
672
- fingerprint = attr.ib() # type: str
670
+ fingerprint = attr.ib() # type: Optional[str]
673
671
  subdirectory = attr.ib() # type: Optional[str]
674
672
 
675
673
  @property
@@ -724,12 +722,16 @@ class BuildResult(object):
724
722
  source_path=None, # type: Optional[str]
725
723
  ):
726
724
  # type: (...) -> BuildResult
727
- built_wheel = BuiltWheelDir.create(
728
- sdist=source_path or build_request.source_path,
729
- fingerprint=build_request.fingerprint,
730
- target=build_request.target,
731
- )
732
- return cls(request=build_request, atomic_dir=AtomicDirectory(built_wheel.dist_dir))
725
+ if build_request.fingerprint:
726
+ built_wheel = BuiltWheelDir.create(
727
+ sdist=source_path or build_request.source_path,
728
+ fingerprint=build_request.fingerprint,
729
+ target=build_request.target,
730
+ )
731
+ target_dir = built_wheel.dist_dir
732
+ else:
733
+ target_dir = os.path.join(safe_mkdtemp(), "build")
734
+ return cls(request=build_request, atomic_dir=AtomicDirectory(target_dir))
733
735
 
734
736
  request = attr.ib() # type: BuildRequest
735
737
  _atomic_dir = attr.ib() # type: AtomicDirectory
@@ -1290,14 +1292,7 @@ class BuildAndInstallRequest(object):
1290
1292
  if is_wheel(dist_path):
1291
1293
  to_install.add(InstallRequest.create(install_request.target, dist_path))
1292
1294
  elif os.path.isdir(dist_path):
1293
- to_build.add(
1294
- BuildRequest.for_directory(
1295
- install_request.target,
1296
- dist_path,
1297
- resolver=self._resolver,
1298
- pip_version=self._pip_version,
1299
- )
1300
- )
1295
+ to_build.add(BuildRequest.for_directory(install_request.target, dist_path))
1301
1296
  else:
1302
1297
  to_build.add(BuildRequest.for_file(install_request.target, dist_path))
1303
1298
  already_analyzed.add(metadata.project_name)
@@ -1907,11 +1902,21 @@ def download_requests(
1907
1902
  def add_build_requests(requests):
1908
1903
  # type: (Iterable[BuildRequest]) -> None
1909
1904
  for request in requests:
1905
+ if request.fingerprint:
1906
+ fingerprint = request.fingerprint
1907
+ else:
1908
+ production_assert(os.path.isdir(request.source_path))
1909
+ fingerprint = _fingerprint_local_project(
1910
+ path=request.source_path,
1911
+ target=request.target,
1912
+ resolver=resolver,
1913
+ pip_version=pip_version,
1914
+ )
1910
1915
  local_distributions.append(
1911
1916
  LocalDistribution(
1912
1917
  download_target=request.download_target,
1913
1918
  path=request.source_path,
1914
- fingerprint=request.fingerprint,
1919
+ fingerprint=fingerprint,
1915
1920
  subdirectory=request.subdirectory,
1916
1921
  )
1917
1922
  )
pex/version.py CHANGED
@@ -1,4 +1,4 @@
1
1
  # Copyright 2015 Pex project contributors.
2
2
  # Licensed under the Apache License, Version 2.0 (see LICENSE).
3
3
 
4
- __version__ = "2.66.0"
4
+ __version__ = "2.67.0"
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pex
3
- Version: 2.66.0
3
+ Version: 2.67.0
4
4
  Summary: The PEX packaging toolchain.
5
5
  Home-page: https://github.com/pex-tool/pex
6
- Download-URL: https://github.com/pex-tool/pex/releases/download/v2.66.0/pex
6
+ Download-URL: https://github.com/pex-tool/pex/releases/download/v2.67.0/pex
7
7
  Author: The PEX developers
8
8
  Author-email: developers@pex-tool.org
9
9
  License-Expression: Apache-2.0
10
- Project-URL: Changelog, https://github.com/pex-tool/pex/blob/v2.66.0/CHANGES.md
10
+ Project-URL: Changelog, https://github.com/pex-tool/pex/blob/v2.67.0/CHANGES.md
11
11
  Project-URL: Documentation, https://docs.pex-tool.org/
12
- Project-URL: Source, https://github.com/pex-tool/pex/tree/v2.66.0
12
+ Project-URL: Source, https://github.com/pex-tool/pex/tree/v2.67.0
13
13
  Keywords: package,executable,virtualenv,lock,freeze
14
14
  Classifier: Development Status :: 5 - Production/Stable
15
15
  Classifier: Intended Audience :: Developers