pex 2.60.0__py2.py3-none-any.whl → 2.60.2__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/cache/dirs.py +4 -4
  2. pex/docs/html/_pagefind/fragment/{en_c5d35a7.pf_fragment → en_2cb42bd.pf_fragment} +0 -0
  3. pex/docs/html/_pagefind/fragment/en_47f6d3d.pf_fragment +0 -0
  4. pex/docs/html/_pagefind/fragment/en_56ed862.pf_fragment +0 -0
  5. pex/docs/html/_pagefind/fragment/en_6496f1a.pf_fragment +0 -0
  6. pex/docs/html/_pagefind/fragment/en_6dbe51b.pf_fragment +0 -0
  7. pex/docs/html/_pagefind/fragment/en_9e24e3a.pf_fragment +0 -0
  8. pex/docs/html/_pagefind/fragment/en_bd88b48.pf_fragment +0 -0
  9. pex/docs/html/_pagefind/fragment/{en_b16e3bd.pf_fragment → en_f6b9ae5.pf_fragment} +0 -0
  10. pex/docs/html/_pagefind/index/{en_b211695.pf_index → en_e1fb5a4.pf_index} +0 -0
  11. pex/docs/html/_pagefind/pagefind-entry.json +1 -1
  12. pex/docs/html/_pagefind/pagefind.en_bfea5ad292.pf_meta +0 -0
  13. pex/docs/html/_static/documentation_options.js +1 -1
  14. pex/docs/html/api/vars.html +5 -5
  15. pex/docs/html/buildingpex.html +5 -5
  16. pex/docs/html/genindex.html +5 -5
  17. pex/docs/html/index.html +5 -5
  18. pex/docs/html/recipes.html +5 -5
  19. pex/docs/html/scie.html +5 -5
  20. pex/docs/html/search.html +5 -5
  21. pex/docs/html/whatispex.html +5 -5
  22. pex/environment.py +22 -18
  23. pex/installed_wheel.py +15 -1
  24. pex/pep_376.py +17 -0
  25. pex/pep_427.py +102 -46
  26. pex/resolve/venv_resolver.py +6 -13
  27. pex/tools/commands/repository.py +2 -2
  28. pex/vendor/__main__.py +3 -2
  29. pex/vendor/_vendored/ansicolors/.layout.json +1 -1
  30. pex/vendor/_vendored/appdirs/.layout.json +1 -1
  31. pex/vendor/_vendored/attrs/.layout.json +1 -1
  32. pex/vendor/_vendored/packaging_20_9/.layout.json +1 -1
  33. pex/vendor/_vendored/packaging_21_3/.layout.json +1 -1
  34. pex/vendor/_vendored/packaging_24_0/.layout.json +1 -1
  35. pex/vendor/_vendored/packaging_25_0/.layout.json +1 -1
  36. pex/vendor/_vendored/pip/.layout.json +1 -1
  37. pex/vendor/_vendored/setuptools/.layout.json +1 -1
  38. pex/vendor/_vendored/toml/.layout.json +1 -1
  39. pex/vendor/_vendored/tomli/.layout.json +1 -1
  40. pex/version.py +1 -1
  41. pex/wheel.py +13 -4
  42. {pex-2.60.0.dist-info → pex-2.60.2.dist-info}/METADATA +4 -4
  43. {pex-2.60.0.dist-info → pex-2.60.2.dist-info}/RECORD +48 -48
  44. pex/docs/html/_pagefind/fragment/en_39c0488.pf_fragment +0 -0
  45. pex/docs/html/_pagefind/fragment/en_3eeaaf4.pf_fragment +0 -0
  46. pex/docs/html/_pagefind/fragment/en_a1dde36.pf_fragment +0 -0
  47. pex/docs/html/_pagefind/fragment/en_a755644.pf_fragment +0 -0
  48. pex/docs/html/_pagefind/fragment/en_ec62bd2.pf_fragment +0 -0
  49. pex/docs/html/_pagefind/fragment/en_f32628f.pf_fragment +0 -0
  50. pex/docs/html/_pagefind/pagefind.en_e8a49380e5.pf_meta +0 -0
  51. {pex-2.60.0.dist-info → pex-2.60.2.dist-info}/WHEEL +0 -0
  52. {pex-2.60.0.dist-info → pex-2.60.2.dist-info}/entry_points.txt +0 -0
  53. {pex-2.60.0.dist-info → pex-2.60.2.dist-info}/licenses/LICENSE +0 -0
  54. {pex-2.60.0.dist-info → pex-2.60.2.dist-info}/pylock/pylock.toml +0 -0
  55. {pex-2.60.0.dist-info → pex-2.60.2.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
  )
@@ -759,6 +789,20 @@ def _detect_record_eol(path):
759
789
  return "\r\n" if line.endswith(b"\r\n") else "\n"
760
790
 
761
791
 
792
+ def _iter_installed_files(
793
+ chroot, # type: str
794
+ exclude_rel_paths=(), # type: Iterable[str]
795
+ ):
796
+ # type: (...) -> Iterator[InstalledFile]
797
+ exclude = frozenset(exclude_rel_paths)
798
+ for root, _, files in deterministic_walk(chroot):
799
+ for path in files:
800
+ rel_path = os.path.relpath(os.path.join(root, path), chroot)
801
+ if rel_path in exclude:
802
+ continue
803
+ yield InstalledFile(rel_path)
804
+
805
+
762
806
  def install_wheel(
763
807
  wheel, # type: InstallableWheel
764
808
  install_paths, # type: InstallPaths
@@ -783,12 +827,14 @@ def install_wheel(
783
827
  else:
784
828
  install_paths = attr.evolve(install_paths, platlib=dest)
785
829
 
830
+ data_dir = None # type: Optional[str]
786
831
  if wheel.is_whl:
787
832
  whl = wheel.location
788
833
  zip_metadata = None # type: Optional[ZipMetadata]
789
834
  with open_zip(whl) as zf:
790
835
  # 1. Unpack
791
836
  zf.extractall(dest)
837
+ data_dir = os.path.join(dest, wheel.data_dir)
792
838
  if record_entry_info:
793
839
  zip_metadata = ZipMetadata.from_zip(
794
840
  filename=whl, info_list=zf.infolist(), normalize_file_stat=normalize_file_stat
@@ -799,11 +845,10 @@ def install_wheel(
799
845
  # poked on a per-entry basis allowing forging a RECORD entry and its associated file.
800
846
  # Only an outer fingerprint of the whole wheel really solves this sort of tampering.
801
847
 
848
+ unpacked_wheel = Wheel.load(dest, project_name=wheel.project_name)
802
849
  wheel = InstallableWheel(
803
- wheel=Wheel.load(dest, project_name=wheel.project_name),
804
- install_paths=InstallPaths.wheel(
805
- dest, project_name=wheel.project_name, version=wheel.version
806
- ),
850
+ wheel=unpacked_wheel,
851
+ install_paths=InstallPaths.wheel(dest, wheel=unpacked_wheel),
807
852
  zip_metadata=zip_metadata,
808
853
  )
809
854
 
@@ -838,11 +883,7 @@ def install_wheel(
838
883
  # Write a minimal repaired record to drive the spread operation below.
839
884
  Record.write(
840
885
  dst=os.path.join(dest, wheel.metadata_path("RECORD")),
841
- installed_files=[
842
- InstalledFile(os.path.relpath(os.path.join(root, path), dest))
843
- for root, _, files in deterministic_walk(dest)
844
- for path in files
845
- ],
886
+ installed_files=list(_iter_installed_files(dest)),
846
887
  eol=eol,
847
888
  )
848
889
 
@@ -851,10 +892,23 @@ def install_wheel(
851
892
 
852
893
  record_data = wheel.metadata_files.read("RECORD")
853
894
  if not record_data:
854
- raise WheelInstallError(
855
- "Cannot re-install installed wheel for {source} because it has no installation "
856
- "RECORD metadata.".format(source=wheel.source)
857
- )
895
+ try:
896
+ installed_wheel = InstalledWheel.load(wheel.location)
897
+ except InstalledWheel.LoadError:
898
+ raise WheelInstallError(
899
+ "Cannot re-install wheel for {source} because it has no installation RECORD "
900
+ "metadata.".format(source=wheel.source)
901
+ )
902
+ else:
903
+ # This is a legacy installed wheel layout with no RECORD; so we concoct one
904
+ layout_file_rel_path = os.path.relpath(
905
+ installed_wheel.layout_file(wheel.location), wheel.location
906
+ )
907
+ record_data = Record.write_bytes(
908
+ installed_files=_iter_installed_files(
909
+ chroot=wheel.location, exclude_rel_paths=[layout_file_rel_path]
910
+ )
911
+ )
858
912
 
859
913
  # 2. Spread
860
914
  entry_points = wheel.distribution().get_entry_map()
@@ -896,7 +950,7 @@ def install_wheel(
896
950
 
897
951
  src_file = os.path.realpath(os.path.join(wheel.location, installed_file.path))
898
952
  dst_components = None # type: Optional[Tuple[Text, Text, bool]]
899
- for path_name, installed_path in wheel.iter_applicable_install_paths():
953
+ for path_name, installed_path in wheel.iter_install_paths_by_name():
900
954
  installed_path = os.path.realpath(installed_path)
901
955
  if installed_path == commonpath((installed_path, src_file)):
902
956
  rewrite_script = False
@@ -963,6 +1017,8 @@ def install_wheel(
963
1017
  shutil.copy(src_file, dst_file)
964
1018
  installed_files.append(create_installed_file(path=dst_file, dest_dir=dest))
965
1019
  provenance.append((src_file, dst_file))
1020
+ if data_dir:
1021
+ safe_rmtree(data_dir)
966
1022
 
967
1023
  if compile:
968
1024
  args = [
@@ -5,7 +5,6 @@ from __future__ import absolute_import
5
5
 
6
6
  import functools
7
7
  import hashlib
8
- import io
9
8
  import itertools
10
9
  import os
11
10
  from collections import defaultdict, deque
@@ -14,7 +13,7 @@ from pex import pex_warnings
14
13
  from pex.atomic_directory import atomic_directory
15
14
  from pex.cache.dirs import CacheDir, InstalledWheelDir
16
15
  from pex.common import safe_relative_symlink
17
- from pex.compatibility import PY2, commonpath
16
+ from pex.compatibility import commonpath
18
17
  from pex.dependency_configuration import DependencyConfiguration
19
18
  from pex.dist_metadata import (
20
19
  Constraint,
@@ -44,7 +43,7 @@ from pex.sysconfig import script_name
44
43
  from pex.targets import LocalInterpreter, Target, Targets
45
44
  from pex.typing import TYPE_CHECKING
46
45
  from pex.venv.virtualenv import Virtualenv
47
- from pex.wheel import Wheel
46
+ from pex.wheel import WHEEL, Wheel
48
47
  from pex.whl import repacked_whl
49
48
 
50
49
  if TYPE_CHECKING:
@@ -93,15 +92,7 @@ def _normalize_record(
93
92
  )
94
93
  )
95
94
  ]
96
-
97
- if PY2:
98
- record_fp = io.BytesIO()
99
- Record.write_fp(fp=record_fp, installed_files=installed_files, eol=eol)
100
- return record_fp.getvalue()
101
- else:
102
- record_fp = io.StringIO()
103
- Record.write_fp(fp=record_fp, installed_files=installed_files, eol=eol)
104
- return record_fp.getvalue().encode("utf-8")
95
+ return Record.write_bytes(installed_files=installed_files, eol=eol)
105
96
 
106
97
 
107
98
  def _install_distribution(
@@ -116,7 +107,9 @@ def _install_distribution(
116
107
  production_assert(distribution.metadata.files.metadata.type is MetadataType.DIST_INFO)
117
108
 
118
109
  venv_install_paths = InstallPaths.interpreter(
119
- 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,
120
113
  )
121
114
  wheel = InstallableWheel.from_whl(
122
115
  whl=Wheel.from_distribution(distribution), install_paths=venv_install_paths
@@ -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.0"
4
+ __version__ = "2.60.2"
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.0
3
+ Version: 2.60.2
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.0/pex
6
+ Download-URL: https://github.com/pex-tool/pex/releases/download/v2.60.2/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.0/CHANGES.md
10
+ Project-URL: Changelog, https://github.com/pex-tool/pex/blob/v2.60.2/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.0
12
+ Project-URL: Source, https://github.com/pex-tool/pex/tree/v2.60.2
13
13
  Keywords: package,executable,virtualenv,lock,freeze
14
14
  Classifier: Development Status :: 5 - Production/Stable
15
15
  Classifier: Intended Audience :: Developers