pex 2.60.1__py2.py3-none-any.whl → 2.61.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 (55) hide show
  1. pex/bin/pex.py +12 -1
  2. pex/cache/dirs.py +4 -4
  3. pex/docs/html/_pagefind/fragment/{en_cb99877.pf_fragment → en_5c93d32.pf_fragment} +0 -0
  4. pex/docs/html/_pagefind/fragment/{en_c350870.pf_fragment → en_6262b88.pf_fragment} +0 -0
  5. pex/docs/html/_pagefind/fragment/{en_52292af.pf_fragment → en_7f63cbe.pf_fragment} +0 -0
  6. pex/docs/html/_pagefind/fragment/{en_df34874.pf_fragment → en_9ce19f0.pf_fragment} +0 -0
  7. pex/docs/html/_pagefind/fragment/{en_8d14bba.pf_fragment → en_cd3f4ce.pf_fragment} +0 -0
  8. pex/docs/html/_pagefind/fragment/en_d1987a6.pf_fragment +0 -0
  9. pex/docs/html/_pagefind/fragment/{en_6190e2d.pf_fragment → en_d7a44fe.pf_fragment} +0 -0
  10. pex/docs/html/_pagefind/fragment/{en_9ba8f7b.pf_fragment → en_f6e4117.pf_fragment} +0 -0
  11. pex/docs/html/_pagefind/index/en_3ad4a26.pf_index +0 -0
  12. pex/docs/html/_pagefind/pagefind-entry.json +1 -1
  13. pex/docs/html/_pagefind/pagefind.en_50edc69c3c.pf_meta +0 -0
  14. pex/docs/html/_static/documentation_options.js +1 -1
  15. pex/docs/html/api/vars.html +5 -5
  16. pex/docs/html/buildingpex.html +5 -5
  17. pex/docs/html/genindex.html +5 -5
  18. pex/docs/html/index.html +5 -5
  19. pex/docs/html/recipes.html +5 -5
  20. pex/docs/html/scie.html +5 -5
  21. pex/docs/html/search.html +5 -5
  22. pex/docs/html/whatispex.html +5 -5
  23. pex/environment.py +22 -18
  24. pex/installed_wheel.py +15 -1
  25. pex/interpreter_constraints.py +1 -1
  26. pex/pep_427.py +70 -37
  27. pex/pip/version.py +1 -1
  28. pex/resolve/venv_resolver.py +4 -2
  29. pex/scie/science.py +1 -1
  30. pex/sh_boot.py +8 -4
  31. pex/tools/commands/repository.py +2 -2
  32. pex/vendor/__main__.py +3 -2
  33. pex/vendor/_vendored/ansicolors/.layout.json +1 -1
  34. pex/vendor/_vendored/appdirs/.layout.json +1 -1
  35. pex/vendor/_vendored/attrs/.layout.json +1 -1
  36. pex/vendor/_vendored/packaging_20_9/.layout.json +1 -1
  37. pex/vendor/_vendored/packaging_21_3/.layout.json +1 -1
  38. pex/vendor/_vendored/packaging_24_0/.layout.json +1 -1
  39. pex/vendor/_vendored/packaging_25_0/.layout.json +1 -1
  40. pex/vendor/_vendored/pip/.layout.json +1 -1
  41. pex/vendor/_vendored/setuptools/.layout.json +1 -1
  42. pex/vendor/_vendored/toml/.layout.json +1 -1
  43. pex/vendor/_vendored/tomli/.layout.json +1 -1
  44. pex/version.py +1 -1
  45. pex/wheel.py +13 -4
  46. {pex-2.60.1.dist-info → pex-2.61.0.dist-info}/METADATA +6 -5
  47. {pex-2.60.1.dist-info → pex-2.61.0.dist-info}/RECORD +52 -52
  48. {pex-2.60.1.dist-info → pex-2.61.0.dist-info}/pylock/pylock.toml +1 -1
  49. pex/docs/html/_pagefind/fragment/en_cf3d25b.pf_fragment +0 -0
  50. pex/docs/html/_pagefind/index/en_853e43e.pf_index +0 -0
  51. pex/docs/html/_pagefind/pagefind.en_71c76562fd.pf_meta +0 -0
  52. {pex-2.60.1.dist-info → pex-2.61.0.dist-info}/WHEEL +0 -0
  53. {pex-2.60.1.dist-info → pex-2.61.0.dist-info}/entry_points.txt +0 -0
  54. {pex-2.60.1.dist-info → pex-2.61.0.dist-info}/licenses/LICENSE +0 -0
  55. {pex-2.60.1.dist-info → pex-2.61.0.dist-info}/top_level.txt +0 -0
pex/pep_427.py CHANGED
@@ -25,6 +25,7 @@ from pex.common import (
25
25
  safe_mkdtemp,
26
26
  safe_open,
27
27
  safe_relative_symlink,
28
+ safe_rmtree,
28
29
  touch,
29
30
  )
30
31
  from pex.compatibility import commonpath, string
@@ -134,15 +135,25 @@ class InstallPaths(object):
134
135
  wheel, # type: Wheel
135
136
  ):
136
137
  # type: (...) -> InstallPaths
138
+
137
139
  base = os.path.join(destination, cls.CHROOT_STASH)
138
140
 
141
+ if wheel.root_is_purelib:
142
+ purelib = destination
143
+ platlib = os.path.join(base, "platlib")
144
+ path_names = ("headers", "scripts", "platlib", "data", "purelib")
145
+ else:
146
+ purelib = os.path.join(base, "purelib")
147
+ platlib = destination
148
+ path_names = ("headers", "scripts", "purelib", "data", "platlib")
149
+
139
150
  return cls(
140
- purelib=destination,
141
- platlib=destination,
151
+ purelib=purelib,
152
+ platlib=platlib,
142
153
  headers=_headers_install_path_for_wheel(base, wheel),
143
154
  scripts=os.path.join(base, SCRIPT_DIR),
144
- data=base,
145
- path_names=("headers", "scripts", "data", "purelib", "platlib"),
155
+ data=os.path.join(base, "data"),
156
+ path_names=path_names,
146
157
  )
147
158
 
148
159
  @classmethod
@@ -150,9 +161,17 @@ class InstallPaths(object):
150
161
  cls,
151
162
  interpreter, # type: PythonInterpreter
152
163
  project_name, # type: ProjectName
164
+ root_is_purelib, # type: bool
153
165
  ):
154
166
  # type: (...) -> InstallPaths
167
+
155
168
  sysconfig_paths = interpreter.identity.paths
169
+
170
+ if root_is_purelib:
171
+ path_names = ("purelib", "platlib", "headers", "scripts", "data")
172
+ else:
173
+ path_names = ("platlib", "purelib", "headers", "scripts", "data")
174
+
156
175
  return cls(
157
176
  purelib=sysconfig_paths["purelib"],
158
177
  platlib=sysconfig_paths["platlib"],
@@ -163,7 +182,7 @@ class InstallPaths(object):
163
182
  ),
164
183
  scripts=sysconfig_paths["scripts"],
165
184
  data=sysconfig_paths["data"],
166
- path_names=("purelib", "platlib", "headers", "scripts", "data"),
185
+ path_names=path_names,
167
186
  )
168
187
 
169
188
  @classmethod
@@ -186,27 +205,30 @@ class InstallPaths(object):
186
205
  def wheel(
187
206
  cls,
188
207
  destination, # type: str
189
- project_name, # type: ProjectName
190
- version, # type: Version
208
+ wheel, # type: Union[Wheel, InstallableWheel]
191
209
  ):
192
210
  # type: (...) -> InstallPaths
193
211
 
194
212
  data = os.path.join(
195
- destination,
196
- "{project_name}-{version}.data".format(
197
- # N.B.: We don't use the canonical form since it goes to lowercase.
198
- project_name=re.sub(r"[-_.]+", "_", project_name.raw),
199
- # N.B.: We don't use the canonical form since it drop trailing zero segments.
200
- version=version.raw.replace("-", "_"),
201
- ),
213
+ destination, "{wheel_prefix}.data".format(wheel_prefix=wheel.wheel_prefix)
202
214
  )
215
+
216
+ if wheel.root_is_purelib:
217
+ purelib = destination
218
+ platlib = os.path.join(data, "platlib")
219
+ path_names = ("headers", "scripts", "platlib", "data", "purelib")
220
+ else:
221
+ purelib = os.path.join(data, "purelib")
222
+ platlib = destination
223
+ path_names = ("headers", "scripts", "purelib", "data", "platlib")
224
+
203
225
  return cls(
204
- purelib=destination,
205
- platlib=destination,
226
+ purelib=purelib,
227
+ platlib=platlib,
206
228
  headers=os.path.join(data, "headers"),
207
229
  scripts=os.path.join(data, "scripts"),
208
230
  data=os.path.join(data, "data"),
209
- path_names=("headers", "scripts", "data", "purelib", "platlib"),
231
+ path_names=path_names,
210
232
  )
211
233
 
212
234
  purelib = attr.ib() # type: str
@@ -481,16 +503,10 @@ class InstallableWheel(object):
481
503
 
482
504
  object.__setattr__(self, "is_whl", is_whl)
483
505
 
484
- def iter_applicable_install_paths(self):
506
+ def iter_install_paths_by_name(self):
485
507
  # type: () -> Iterator[Tuple[str, str]]
486
508
  if self.install_paths:
487
509
  for path_name, path in self.install_paths:
488
- if path_name == "purelib":
489
- if not self.root_is_purelib:
490
- continue
491
- elif path_name == "platlib":
492
- if self.root_is_purelib:
493
- continue
494
510
  yield path_name, path
495
511
 
496
512
  @property
@@ -518,6 +534,11 @@ class InstallableWheel(object):
518
534
  # type: () -> str
519
535
  return self.wheel.data_dir
520
536
 
537
+ @property
538
+ def wheel_prefix(self):
539
+ # type: () -> str
540
+ return self.wheel.wheel_prefix
541
+
521
542
  @property
522
543
  def wheel_file_name(self):
523
544
  # type: () -> str
@@ -623,9 +644,10 @@ def install_wheel_chroot(
623
644
  wheel_to_install = (
624
645
  wheel if isinstance(wheel, InstallableWheel) else InstallableWheel.from_whl(wheel)
625
646
  )
647
+ chroot_install_paths = InstallPaths.chroot(destination, wheel=wheel_to_install.wheel)
626
648
  install_wheel(
627
649
  wheel_to_install,
628
- InstallPaths.chroot(destination, wheel=wheel_to_install.wheel),
650
+ chroot_install_paths,
629
651
  record_entry_info=True,
630
652
  normalize_file_stat=normalize_file_stat,
631
653
  )
@@ -635,11 +657,21 @@ def install_wheel_chroot(
635
657
  record_relpath is not None
636
658
  ), "The {module}.install_wheel function should always create a RECORD.".format(module=__name__)
637
659
 
660
+ root_is_purelib = wheel_to_install.root_is_purelib
661
+
662
+ entry_names = ("purelib", "platlib") if root_is_purelib else ("platlib", "purelib")
663
+ sys_path_entries = [] # type: List[str]
664
+ for entry_name in entry_names:
665
+ entry = chroot_install_paths[entry_name]
666
+ if os.path.isdir(entry):
667
+ sys_path_entries.append(os.path.relpath(entry, destination))
668
+
638
669
  return InstalledWheel.save(
639
670
  prefix_dir=destination,
640
671
  stash_dir=InstallPaths.CHROOT_STASH,
641
672
  record_relpath=record_relpath,
642
- root_is_purelib=wheel_to_install.root_is_purelib,
673
+ root_is_purelib=root_is_purelib,
674
+ sys_path_entries=tuple(sys_path_entries),
643
675
  )
644
676
 
645
677
 
@@ -659,7 +691,9 @@ def install_wheel_interpreter(
659
691
  return install_wheel(
660
692
  wheel_to_install,
661
693
  InstallPaths.interpreter(
662
- interpreter, project_name=wheel_to_install.metadata_files.metadata.project_name
694
+ interpreter,
695
+ project_name=wheel_to_install.project_name,
696
+ root_is_purelib=wheel_to_install.root_is_purelib,
663
697
  ),
664
698
  copy_mode=copy_mode,
665
699
  interpreter=interpreter,
@@ -710,11 +744,7 @@ def create_whl(
710
744
  whl_chroot = os.path.join(safe_mkdtemp(prefix="pex_create_whl."), whl_file_name)
711
745
  install_wheel(
712
746
  wheel_to_create,
713
- InstallPaths.wheel(
714
- destination=whl_chroot,
715
- project_name=wheel_to_create.project_name,
716
- version=wheel_to_create.version,
717
- ),
747
+ InstallPaths.wheel(destination=whl_chroot, wheel=wheel_to_create),
718
748
  compile=compile,
719
749
  install_entry_point_scripts=False,
720
750
  )
@@ -797,12 +827,14 @@ def install_wheel(
797
827
  else:
798
828
  install_paths = attr.evolve(install_paths, platlib=dest)
799
829
 
830
+ data_dir = None # type: Optional[str]
800
831
  if wheel.is_whl:
801
832
  whl = wheel.location
802
833
  zip_metadata = None # type: Optional[ZipMetadata]
803
834
  with open_zip(whl) as zf:
804
835
  # 1. Unpack
805
836
  zf.extractall(dest)
837
+ data_dir = os.path.join(dest, wheel.data_dir)
806
838
  if record_entry_info:
807
839
  zip_metadata = ZipMetadata.from_zip(
808
840
  filename=whl, info_list=zf.infolist(), normalize_file_stat=normalize_file_stat
@@ -813,11 +845,10 @@ def install_wheel(
813
845
  # poked on a per-entry basis allowing forging a RECORD entry and its associated file.
814
846
  # Only an outer fingerprint of the whole wheel really solves this sort of tampering.
815
847
 
848
+ unpacked_wheel = Wheel.load(dest, project_name=wheel.project_name)
816
849
  wheel = InstallableWheel(
817
- wheel=Wheel.load(dest, project_name=wheel.project_name),
818
- install_paths=InstallPaths.wheel(
819
- dest, project_name=wheel.project_name, version=wheel.version
820
- ),
850
+ wheel=unpacked_wheel,
851
+ install_paths=InstallPaths.wheel(dest, wheel=unpacked_wheel),
821
852
  zip_metadata=zip_metadata,
822
853
  )
823
854
 
@@ -919,7 +950,7 @@ def install_wheel(
919
950
 
920
951
  src_file = os.path.realpath(os.path.join(wheel.location, installed_file.path))
921
952
  dst_components = None # type: Optional[Tuple[Text, Text, bool]]
922
- for path_name, installed_path in wheel.iter_applicable_install_paths():
953
+ for path_name, installed_path in wheel.iter_install_paths_by_name():
923
954
  installed_path = os.path.realpath(installed_path)
924
955
  if installed_path == commonpath((installed_path, src_file)):
925
956
  rewrite_script = False
@@ -986,6 +1017,8 @@ def install_wheel(
986
1017
  shutil.copy(src_file, dst_file)
987
1018
  installed_files.append(create_installed_file(path=dst_file, dest_dir=dest))
988
1019
  provenance.append((src_file, dst_file))
1020
+ if data_dir:
1021
+ safe_rmtree(data_dir)
989
1022
 
990
1023
  if compile:
991
1024
  args = [
pex/pip/version.py CHANGED
@@ -366,7 +366,7 @@ class PipVersion(Enum["PipVersionValue"]):
366
366
  version="25.2",
367
367
  setuptools_version="80.9.0",
368
368
  wheel_version="0.45.1",
369
- requires_python=">=3.9,<3.15",
369
+ requires_python=">=3.9,<3.16",
370
370
  )
371
371
 
372
372
  VENDORED = v20_3_4_patched
@@ -43,7 +43,7 @@ from pex.sysconfig import script_name
43
43
  from pex.targets import LocalInterpreter, Target, Targets
44
44
  from pex.typing import TYPE_CHECKING
45
45
  from pex.venv.virtualenv import Virtualenv
46
- from pex.wheel import Wheel
46
+ from pex.wheel import WHEEL, Wheel
47
47
  from pex.whl import repacked_whl
48
48
 
49
49
  if TYPE_CHECKING:
@@ -107,7 +107,9 @@ def _install_distribution(
107
107
  production_assert(distribution.metadata.files.metadata.type is MetadataType.DIST_INFO)
108
108
 
109
109
  venv_install_paths = InstallPaths.interpreter(
110
- interpreter, project_name=distribution.metadata.project_name
110
+ interpreter,
111
+ project_name=distribution.metadata.project_name,
112
+ root_is_purelib=WHEEL.from_distribution(distribution).root_is_purelib,
111
113
  )
112
114
  wheel = InstallableWheel.from_whl(
113
115
  whl=Wheel.from_distribution(distribution), install_paths=venv_install_paths
pex/scie/science.py CHANGED
@@ -66,7 +66,7 @@ class Manifest(object):
66
66
 
67
67
 
68
68
  SCIENCE_RELEASES_URL = "https://github.com/a-scie/lift/releases"
69
- MIN_SCIENCE_VERSION = Version("0.13.0")
69
+ MIN_SCIENCE_VERSION = Version("0.14.0")
70
70
  SCIENCE_REQUIREMENT = SpecifierSet("~={min_version}".format(min_version=MIN_SCIENCE_VERSION))
71
71
 
72
72
 
pex/sh_boot.py CHANGED
@@ -87,10 +87,14 @@ def _calculate_applicable_binary_names(
87
87
  # more sophisticated detection and re-direction from these during its own bootstrap. When doing
88
88
  # so, select these interpreters from newest to oldest since it more likely any given machine
89
89
  # will have Python 3 at this point than it will Python 2.
90
- pex_requires_python = SpecifierSet(os.environ.get("_PEX_REQUIRES_PYTHON", ">=2.7"))
91
- dist = dist_metadata.find_distribution("pex") # type: Optional[Distribution]
92
- if dist and dist.metadata.version == Version(__version__):
93
- pex_requires_python = dist.metadata.requires_python
90
+ pex_requires_python_override = os.environ.get("_PEX_REQUIRES_PYTHON", None)
91
+ if pex_requires_python_override:
92
+ pex_requires_python = SpecifierSet(pex_requires_python_override)
93
+ else:
94
+ pex_requires_python = SpecifierSet(">=2.7")
95
+ dist = dist_metadata.find_distribution("pex") # type: Optional[Distribution]
96
+ if dist and dist.metadata.version == Version(__version__):
97
+ pex_requires_python = dist.metadata.requires_python
94
98
  pex_supported_python_versions = tuple(
95
99
  reversed(list(iter_compatible_versions(requires_python=[pex_requires_python])))
96
100
  )
@@ -1,7 +1,7 @@
1
1
  # Copyright 2021 Pex project contributors.
2
2
  # Licensed under the Apache License, Version 2.0 (see LICENSE).
3
3
 
4
- from __future__ import absolute_import
4
+ from __future__ import absolute_import, print_function
5
5
 
6
6
  import functools
7
7
  import logging
@@ -311,7 +311,7 @@ class Repository(JsonMixin, OutputMixin, PEXCommand):
311
311
  )
312
312
  )
313
313
  else:
314
- output.write(str(result))
314
+ print(result, file=output)
315
315
  if errors:
316
316
  return Error(
317
317
  "Failed to build wheels for {count} {distributions}.".format(
pex/vendor/__main__.py CHANGED
@@ -544,11 +544,12 @@ def vendorize(root_dir, vendor_specs, prefix, update):
544
544
  for project_name, version, wheel_chroot, wheel_file in wheels_chroots_to_install:
545
545
  with closing(zipfile.ZipFile(wheel_file)) as zf:
546
546
  zip_metadata = ZipMetadata.from_zip(filename=wheel_file, info_list=zf.infolist())
547
+ vendored_wheel = Wheel.load(wheel_chroot)
547
548
  install_wheel_chroot(
548
549
  wheel=InstallableWheel(
549
- wheel=Wheel.load(wheel_chroot),
550
+ wheel=vendored_wheel,
550
551
  install_paths=InstallPaths.wheel(
551
- destination=wheel_chroot, project_name=project_name, version=version
552
+ destination=wheel_chroot, wheel=vendored_wheel
552
553
  ),
553
554
  zip_metadata=zip_metadata,
554
555
  ),
@@ -1 +1 @@
1
- {"fingerprint":"93bbf4f9990c23d7f074400fbc7b72699025043cff2ba03c34196ad876cc265c","record_relpath":"ansicolors-1.1.8.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"93bbf4f9990c23d7f074400fbc7b72699025043cff2ba03c34196ad876cc265c","record_relpath":"ansicolors-1.1.8.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"24fd20ba81e67b247f15013f7f14f1932d342923d2f07d3a2cc73f264d01ca28","record_relpath":"appdirs-1.4.4.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"24fd20ba81e67b247f15013f7f14f1932d342923d2f07d3a2cc73f264d01ca28","record_relpath":"appdirs-1.4.4.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"60e0467569716898b2972fe5a3d4c9949a86cabb361124271abdc4fda2aabc8c","record_relpath":"attrs-21.5.0.dev0.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"60e0467569716898b2972fe5a3d4c9949a86cabb361124271abdc4fda2aabc8c","record_relpath":"attrs-21.5.0.dev0.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"e781ec09b3aa335b5436874df6b22577ddce0818a227be1c81ccc86aff78e850","record_relpath":"packaging-20.9.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"fb91f8df1ae86fdd0ebd7287158df23cf6d56791475d93841e7d3a76ec4eb23f","record_relpath":"packaging-20.9.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"17df8d37531246cbaf3690d78527842b5679ffc7cd4361d0c4bfceb5bf395346","record_relpath":"packaging-21.3.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"cb292a10d66bc05830548f9ae6da7d06b33cda7955eccb68a065436b119fefac","record_relpath":"packaging-21.3.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"2688e613bb54c0b61a1c101acb2aa489d06d2c524bfc9502c56768eedeb2f6eb","record_relpath":"packaging-24.0.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"2688e613bb54c0b61a1c101acb2aa489d06d2c524bfc9502c56768eedeb2f6eb","record_relpath":"packaging-24.0.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"c042647020954d0559e1bc7ae62bb4c2e5d6c586504b564a397a16b1fabd5f96","record_relpath":"packaging-25.0.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"c042647020954d0559e1bc7ae62bb4c2e5d6c586504b564a397a16b1fabd5f96","record_relpath":"packaging-25.0.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"93065fed46b0a0db8737c4a33aa24819d527ace9c84e9cdb8f9e41e9e2bd926a","record_relpath":"pip-20.3.4.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"93065fed46b0a0db8737c4a33aa24819d527ace9c84e9cdb8f9e41e9e2bd926a","record_relpath":"pip-20.3.4.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"b9e945a694f66bcb00f8366aadeb01b88e6b042b6c49b44b98c4bb814d8460e3","record_relpath":"setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"b9e945a694f66bcb00f8366aadeb01b88e6b042b6c49b44b98c4bb814d8460e3","record_relpath":"setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"e022215e30b009ca1018a9255f6812d150469e3f6ff12687dd93459dd5a5274d","record_relpath":"toml-0.10.2.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"e022215e30b009ca1018a9255f6812d150469e3f6ff12687dd93459dd5a5274d","record_relpath":"toml-0.10.2.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
@@ -1 +1 @@
1
- {"fingerprint":"bbe9219bfe424168417563a7c481eeed73fbb39ef7458e0e8ba636276afb2822","record_relpath":"tomli-2.0.1.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix"}
1
+ {"fingerprint":"bbe9219bfe424168417563a7c481eeed73fbb39ef7458e0e8ba636276afb2822","record_relpath":"tomli-2.0.1.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
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.60.1"
4
+ __version__ = "2.61.0"
pex/wheel.py CHANGED
@@ -225,6 +225,18 @@ class Wheel(object):
225
225
  # type: () -> Version
226
226
  return self.metadata_files.metadata.version
227
227
 
228
+ @property
229
+ def wheel_prefix(self):
230
+ # type: () -> str
231
+
232
+ # N.B.: We don't use the canonical form since it goes to lowercase.
233
+ project_name = re.sub(r"[-_.]+", "_", self.project_name.raw)
234
+
235
+ # N.B.: We don't use the canonical form since it drop trailing zero segments.
236
+ version = self.version.raw.replace("-", "_")
237
+
238
+ return "{project_name}-{version}".format(project_name=project_name, version=version)
239
+
228
240
  @property
229
241
  def wheel_file_name(self):
230
242
  # type: () -> str
@@ -239,10 +251,7 @@ class Wheel(object):
239
251
  tag = "{interpreters}-{abis}-{platforms}".format(
240
252
  interpreters=".".join(interpreters), abis=".".join(abis), platforms=".".join(platforms)
241
253
  )
242
-
243
- return "{project_name}-{version}-{tag}.whl".format(
244
- project_name=self.project_name.raw, version=self.version.raw, tag=tag
245
- )
254
+ return "{wheel_prefix}-{tag}.whl".format(wheel_prefix=self.wheel_prefix, tag=tag)
246
255
 
247
256
  def iter_compatible_python_versions(self):
248
257
  # type: () -> Iterator[Tuple[int, ...]]
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pex
3
- Version: 2.60.1
3
+ Version: 2.61.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.60.1/pex
6
+ Download-URL: https://github.com/pex-tool/pex/releases/download/v2.61.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.60.1/CHANGES.md
10
+ Project-URL: Changelog, https://github.com/pex-tool/pex/blob/v2.61.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.60.1
12
+ Project-URL: Source, https://github.com/pex-tool/pex/tree/v2.61.0
13
13
  Keywords: package,executable,virtualenv,lock,freeze
14
14
  Classifier: Development Status :: 5 - Production/Stable
15
15
  Classifier: Intended Audience :: Developers
@@ -30,13 +30,14 @@ Classifier: Programming Language :: Python :: 3.11
30
30
  Classifier: Programming Language :: Python :: 3.12
31
31
  Classifier: Programming Language :: Python :: 3.13
32
32
  Classifier: Programming Language :: Python :: 3.14
33
+ Classifier: Programming Language :: Python :: 3.15
33
34
  Classifier: Programming Language :: Python :: Implementation :: CPython
34
35
  Classifier: Programming Language :: Python :: Implementation :: PyPy
35
36
  Classifier: Topic :: Software Development :: Build Tools
36
37
  Classifier: Topic :: System :: Archiving :: Packaging
37
38
  Classifier: Topic :: System :: Software Distribution
38
39
  Classifier: Topic :: Utilities
39
- Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<3.15,>=2.7
40
+ Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,<3.16,>=2.7
40
41
  Description-Content-Type: text/x-rst
41
42
  License-File: LICENSE
42
43
  Provides-Extra: subprocess