pex 2.54.2__py2.py3-none-any.whl → 2.69.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.
- pex/auth.py +1 -1
- pex/bin/pex.py +15 -2
- pex/build_backend/configuration.py +5 -5
- pex/build_backend/wrap.py +27 -23
- pex/build_system/pep_517.py +4 -1
- pex/cache/dirs.py +17 -12
- pex/cli/commands/lock.py +302 -165
- pex/cli/commands/pip/core.py +4 -12
- pex/cli/commands/pip/wheel.py +1 -1
- pex/cli/commands/run.py +13 -20
- pex/cli/commands/venv.py +85 -16
- pex/cli/pex.py +11 -4
- pex/common.py +57 -7
- pex/compatibility.py +1 -1
- pex/dependency_configuration.py +87 -15
- pex/dist_metadata.py +143 -25
- pex/docs/html/_pagefind/fragment/en_4250138.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_7125dad.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_785d562.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_8e94bb8.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a0396bb.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_a8a3588.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_c07d988.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_d718411.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_a2e3c5e.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind-entry.json +1 -1
- pex/docs/html/_pagefind/pagefind.en_4ce1afa9e3.pf_meta +0 -0
- pex/docs/html/_static/documentation_options.js +1 -1
- pex/docs/html/_static/pygments.css +164 -146
- pex/docs/html/_static/styles/furo.css +1 -1
- pex/docs/html/_static/styles/furo.css.map +1 -1
- pex/docs/html/api/vars.html +25 -34
- pex/docs/html/buildingpex.html +25 -34
- pex/docs/html/genindex.html +24 -33
- pex/docs/html/index.html +25 -34
- pex/docs/html/recipes.html +25 -34
- pex/docs/html/scie.html +25 -34
- pex/docs/html/search.html +24 -33
- pex/docs/html/whatispex.html +25 -34
- pex/entry_points_txt.py +98 -0
- pex/environment.py +54 -33
- pex/finders.py +1 -1
- pex/hashing.py +71 -9
- pex/installed_wheel.py +141 -0
- pex/interpreter.py +41 -38
- pex/interpreter_constraints.py +25 -25
- pex/interpreter_implementation.py +40 -0
- pex/jobs.py +13 -6
- pex/pep_376.py +68 -384
- pex/pep_425.py +11 -2
- pex/pep_427.py +937 -205
- pex/pep_508.py +4 -5
- pex/pex_builder.py +5 -8
- pex/pex_info.py +14 -9
- pex/pip/dependencies/__init__.py +85 -13
- pex/pip/dependencies/requires.py +38 -3
- pex/pip/foreign_platform/__init__.py +4 -3
- pex/pip/installation.py +2 -2
- pex/pip/local_project.py +6 -14
- pex/pip/package_repositories/__init__.py +78 -0
- pex/pip/package_repositories/link_collector.py +96 -0
- pex/pip/tool.py +139 -33
- pex/pip/vcs.py +109 -43
- pex/pip/version.py +8 -1
- pex/requirements.py +121 -16
- pex/resolve/config.py +5 -1
- pex/resolve/configured_resolve.py +32 -10
- pex/resolve/configured_resolver.py +10 -39
- pex/resolve/downloads.py +4 -3
- pex/resolve/lock_downloader.py +16 -23
- pex/resolve/lock_resolver.py +41 -51
- pex/resolve/locked_resolve.py +89 -32
- pex/resolve/locker.py +145 -101
- pex/resolve/locker_patches.py +123 -197
- pex/resolve/lockfile/create.py +232 -87
- pex/resolve/lockfile/download_manager.py +5 -1
- pex/resolve/lockfile/json_codec.py +103 -28
- pex/resolve/lockfile/model.py +13 -35
- pex/resolve/lockfile/pep_751.py +117 -98
- pex/resolve/lockfile/requires_dist.py +17 -262
- pex/resolve/lockfile/subset.py +11 -0
- pex/resolve/lockfile/targets.py +445 -0
- pex/resolve/lockfile/updater.py +22 -10
- pex/resolve/package_repository.py +406 -0
- pex/resolve/pex_repository_resolver.py +1 -1
- pex/resolve/pre_resolved_resolver.py +19 -16
- pex/resolve/project.py +233 -47
- pex/resolve/requirement_configuration.py +28 -10
- pex/resolve/resolver_configuration.py +18 -32
- pex/resolve/resolver_options.py +234 -28
- pex/resolve/resolvers.py +3 -12
- pex/resolve/target_options.py +18 -2
- pex/resolve/target_system.py +908 -0
- pex/resolve/venv_resolver.py +670 -0
- pex/resolver.py +673 -209
- pex/scie/__init__.py +40 -1
- pex/scie/model.py +2 -0
- pex/scie/science.py +25 -3
- pex/sdist.py +219 -0
- pex/sh_boot.py +24 -21
- pex/sysconfig.py +5 -3
- pex/targets.py +31 -10
- pex/third_party/__init__.py +1 -1
- pex/tools/commands/repository.py +48 -25
- pex/vendor/__init__.py +4 -9
- pex/vendor/__main__.py +65 -41
- pex/vendor/_vendored/ansicolors/.layout.json +1 -1
- pex/vendor/_vendored/ansicolors/ansicolors-1.1.8.dist-info/RECORD +11 -0
- pex/vendor/_vendored/ansicolors/ansicolors-1.1.8.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/appdirs/.layout.json +1 -1
- pex/vendor/_vendored/appdirs/appdirs-1.4.4.dist-info/RECORD +7 -0
- pex/vendor/_vendored/appdirs/appdirs-1.4.4.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/attrs/.layout.json +1 -1
- pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/RECORD +37 -0
- pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_20_9/.layout.json +1 -1
- pex/vendor/_vendored/packaging_20_9/packaging-20.9.dist-info/RECORD +20 -0
- pex/vendor/_vendored/packaging_20_9/packaging-20.9.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_20_9/pyparsing-2.4.7.dist-info/RECORD +7 -0
- pex/vendor/_vendored/packaging_20_9/pyparsing-2.4.7.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_21_3/.layout.json +1 -1
- pex/vendor/_vendored/packaging_21_3/packaging-21.3.dist-info/RECORD +20 -0
- pex/vendor/_vendored/packaging_21_3/packaging-21.3.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_21_3/pyparsing-3.0.7.dist-info/RECORD +18 -0
- pex/vendor/_vendored/packaging_21_3/pyparsing-3.0.7.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_24_0/.layout.json +1 -1
- pex/vendor/_vendored/packaging_24_0/packaging-24.0.dist-info/RECORD +22 -0
- pex/vendor/_vendored/packaging_24_0/packaging-24.0.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/packaging_25_0/.layout.json +1 -1
- pex/vendor/_vendored/packaging_25_0/packaging-25.0.dist-info/RECORD +24 -0
- pex/vendor/_vendored/packaging_25_0/packaging-25.0.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/pip/.layout.json +1 -1
- pex/vendor/_vendored/pip/pip/_vendor/certifi/cacert.pem +63 -1
- pex/vendor/_vendored/pip/pip-20.3.4.dist-info/RECORD +388 -0
- pex/vendor/_vendored/pip/pip-20.3.4.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/setuptools/.layout.json +1 -1
- pex/vendor/_vendored/setuptools/setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/RECORD +107 -0
- pex/vendor/_vendored/setuptools/setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/toml/.layout.json +1 -1
- pex/vendor/_vendored/toml/toml-0.10.2.dist-info/RECORD +11 -0
- pex/vendor/_vendored/toml/toml-0.10.2.pex-info/original-whl-info.json +1 -0
- pex/vendor/_vendored/tomli/.layout.json +1 -1
- pex/vendor/_vendored/tomli/tomli-2.0.1.dist-info/RECORD +10 -0
- pex/vendor/_vendored/tomli/tomli-2.0.1.pex-info/original-whl-info.json +1 -0
- pex/venv/installer.py +46 -19
- pex/venv/venv_pex.py +6 -3
- pex/version.py +1 -1
- pex/wheel.py +188 -40
- pex/whl.py +67 -0
- pex/windows/__init__.py +14 -11
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/METADATA +6 -5
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/RECORD +157 -133
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/entry_points.txt +1 -0
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/pylock/pylock.toml +1 -1
- pex/docs/html/_pagefind/fragment/en_42c9d8c.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_45dd5a2.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_4ca74d2.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_77273d5.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_87a59c5.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_8dc89b5.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_9d1319b.pf_fragment +0 -0
- pex/docs/html/_pagefind/fragment/en_e55df9d.pf_fragment +0 -0
- pex/docs/html/_pagefind/index/en_1e98c6f.pf_index +0 -0
- pex/docs/html/_pagefind/pagefind.en_d1c488ecae.pf_meta +0 -0
- pex/vendor/_vendored/ansicolors/ansicolors-1.1.8.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/appdirs/appdirs-1.4.4.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/attrs/attrs-21.5.0.dev0.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_20_9/packaging-20.9.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_20_9/pyparsing-2.4.7.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_21_3/packaging-21.3.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_21_3/pyparsing-3.0.7.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_24_0/packaging-24.0.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/packaging_25_0/packaging-25.0.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/pip/pip-20.3.4.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/setuptools/setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/toml/toml-0.10.2.dist-info/INSTALLER +0 -1
- pex/vendor/_vendored/tomli/tomli-2.0.1.dist-info/INSTALLER +0 -1
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/WHEEL +0 -0
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/licenses/LICENSE +0 -0
- {pex-2.54.2.dist-info → pex-2.69.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
easy_install.py,sha256=KmUyF4ULoa4KKPBmNIgrhxSm6THkvc-0olDNVQ97dJs,308
|
|
2
|
+
pkg_resources/__init__.py,sha256=jC9RTTj6Z0a9J4xMMIxispKIDOxbSzG88Z5ehFVRTfw,109721
|
|
3
|
+
pkg_resources/py31compat.py,sha256=-WQ0e4c3RG_acdhwC3gLiXhP_lg4G5q7XYkZkQg0gxU,558
|
|
4
|
+
pkg_resources/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
pkg_resources/_vendor/appdirs.py,sha256=MievUEuv3l_mQISH5SF0shDk_BNhHHzYiAPrT3ITN4I,24701
|
|
6
|
+
pkg_resources/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055
|
|
7
|
+
pkg_resources/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098
|
|
8
|
+
pkg_resources/_vendor/packaging/__about__.py,sha256=zkcCPTN_6TcLW0Nrlg0176-R1QQ_WVPTm8sz1R4-HjM,720
|
|
9
|
+
pkg_resources/_vendor/packaging/__init__.py,sha256=_vNac5TrzwsrzbOFIbF-5cHqc_Y2aPT2D7zrIR06BOo,513
|
|
10
|
+
pkg_resources/_vendor/packaging/_compat.py,sha256=Vi_A0rAQeHbU-a9X0tt1yQm9RqkgQbDSxzRw8WlU9kA,860
|
|
11
|
+
pkg_resources/_vendor/packaging/_structures.py,sha256=RImECJ4c_wTlaTYYwZYLHEiebDMaAJmK1oPARhw1T5o,1416
|
|
12
|
+
pkg_resources/_vendor/packaging/markers.py,sha256=Hu2KTHSVDw5TouLFIAlTF8VJG6FB7edt82AEv3Y4U5A,8847
|
|
13
|
+
pkg_resources/_vendor/packaging/requirements.py,sha256=kW33jVL1licHp04f2mlX-WvYJerGIIpvwYB_UZ6t5tk,5148
|
|
14
|
+
pkg_resources/_vendor/packaging/specifiers.py,sha256=SAMRerzO3fK2IkFZCaZkuwZaL_EGqHNOz4pni4vhnN0,28025
|
|
15
|
+
pkg_resources/_vendor/packaging/utils.py,sha256=3m6WvPm6NNxE8rkTGmn0r75B_GZSGg7ikafxHsBN1WA,421
|
|
16
|
+
pkg_resources/_vendor/packaging/version.py,sha256=OwGnxYfr2ghNzYx59qWIBkrK3SnB6n-Zfd1XaLpnnM0,11556
|
|
17
|
+
pkg_resources/extern/__init__.py,sha256=cHiEfHuLmm6rs5Ve_ztBfMI7Lr31vss-D4wkqF5xzlI,2498
|
|
18
|
+
setuptools/__init__.py,sha256=Uuh_WcZ0TRLLCFViihlbT9Ua0Lux7z7Bp20LKTEDNYw,8289
|
|
19
|
+
setuptools/_deprecation_warning.py,sha256=jU9-dtfv6cKmtQJOXN8nP1mm7gONw5kKEtiPtbwnZyI,218
|
|
20
|
+
setuptools/_imp.py,sha256=jloslOkxrTKbobgemfP94YII0nhqiJzE1bRmCTZ1a5I,2223
|
|
21
|
+
setuptools/archive_util.py,sha256=XexyqeTFmMuHRY_xuQabc4Q6Wi6pO0lEJDg9vpQTYUk,6756
|
|
22
|
+
setuptools/build_meta.py,sha256=dfrceySHiu4U0aED-WU0NKP4ghCW7P7AVRpH_sBM5u4,10257
|
|
23
|
+
setuptools/cli-32.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536
|
|
24
|
+
setuptools/cli-64.exe,sha256=KLABu5pyrnokJCv6skjXZ6GsXeyYHGcqOUT3oHI3Xpo,74752
|
|
25
|
+
setuptools/cli.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536
|
|
26
|
+
setuptools/config.py,sha256=zRnI8kZPk18-1QgPyzab9Rwi7CtuBZMwQqLn5jltfqU,21727
|
|
27
|
+
setuptools/dep_util.py,sha256=fgixvC1R7sH3r13ktyf7N0FALoqEXL1cBarmNpSEoWg,935
|
|
28
|
+
setuptools/depends.py,sha256=qt2RWllArRvhnm8lxsyRpcthEZYp4GHQgREl1q0LkFw,5517
|
|
29
|
+
setuptools/dist.py,sha256=YcPMXMT6H4w1Z1R7JcsycT2mXTvgkhh5FCPNUWYjY_I,52087
|
|
30
|
+
setuptools/errors.py,sha256=MVOcv381HNSajDgEUWzOQ4J6B5BHCBMSjHfaWcEwA1o,524
|
|
31
|
+
setuptools/extension.py,sha256=0WXnVGwooazqD2LEs78uPNGzVWMIzaUatnRqmkRng2U,1894
|
|
32
|
+
setuptools/glob.py,sha256=o75cHrOxYsvn854thSxE0x9k8JrKDuhP_rRXlVB00Q4,5084
|
|
33
|
+
setuptools/gui-32.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536
|
|
34
|
+
setuptools/gui-64.exe,sha256=aYKMhX1IJLn4ULHgWX0sE0yREUt6B3TEHf_jOw6yNyE,75264
|
|
35
|
+
setuptools/gui.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536
|
|
36
|
+
setuptools/installer.py,sha256=1xI9rP5aEgdx1OaUZHvQj0zb6hc83AKgXTC85GPMxm0,5985
|
|
37
|
+
setuptools/launch.py,sha256=sd7ejwhBocCDx_wG9rIs0OaZ8HtmmFU8ZC6IR_S0Lvg,787
|
|
38
|
+
setuptools/lib2to3_ex.py,sha256=Io05v90REA2PxHwOHlPS9eJro51OFUWNXHEHcN5y3Jc,2166
|
|
39
|
+
setuptools/monkey.py,sha256=2QsnbSxUqVdzzAwGZ43Kp5-2Gb9wovE2-DLK_kNalM0,5572
|
|
40
|
+
setuptools/msvc.py,sha256=cMTBhLLMH0HW6nZgm3hwqoc5KpQJnajxuJ61KpYcDB4,47287
|
|
41
|
+
setuptools/namespaces.py,sha256=2noPXS--lCOyu502TtSo82IQfDO6Ay52ZyVxlUUrDZg,3364
|
|
42
|
+
setuptools/package_index.py,sha256=er2zuCiMV-rdJ2JkKTmGEByllSnhyK85nWZ86YFN8ew,42324
|
|
43
|
+
setuptools/py27compat.py,sha256=GNzhD1cFG0gPge9jtHyS7l8LJfQyi5MnfBLKPWPB71k,1651
|
|
44
|
+
setuptools/py31compat.py,sha256=h2rtZghOfwoGYd8sQ0-auaKiF3TcL3qX0bX3VessqcE,838
|
|
45
|
+
setuptools/py33compat.py,sha256=8Y5fKcoonFLZ2cE4xRVjA8txoBk40PLnWxH5OPVHqJs,1658
|
|
46
|
+
setuptools/py34compat.py,sha256=KYOd6ybRxjBW8NJmYD8t_UyyVmysppFXqHpFLdslGXU,245
|
|
47
|
+
setuptools/sandbox.py,sha256=gMAXGebq6f-0Iz2PbY8h0WSuXTQg5HZZ1LF870CMv7s,15606
|
|
48
|
+
setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218
|
|
49
|
+
setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138
|
|
50
|
+
setuptools/site-patch.py,sha256=OumkIHMuoSenRSW1382kKWI1VAwxNE86E5W8iDd34FY,2302
|
|
51
|
+
setuptools/ssl_support.py,sha256=FruiFl4qaRtN7MLcCbjvmvk9g6-q1F3IunTulwbbrYc,8867
|
|
52
|
+
setuptools/unicode_utils.py,sha256=43e8tF6LD0F7Pfs1RNtFEJ0VKYYiLpMi45C3MLNGPhI,1151
|
|
53
|
+
setuptools/version.py,sha256=VdCoXTpi0KtLcobgKjQ7oPgwHaLWbnQRyKo4Phc5tl4,303
|
|
54
|
+
setuptools/wheel.py,sha256=Kx7MtrWi7Muo3ZekSn6_l9fDxsxFvjSHdUS17RFZ9Rk,9627
|
|
55
|
+
setuptools/windows_support.py,sha256=5GrfqSP2-dLGJoZTq2g6dCKkyQxxa2n5IQiXlJCoYEE,714
|
|
56
|
+
setuptools/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
+
setuptools/_vendor/ordered_set.py,sha256=dbaCcs27dyN9gnMWGF5nA_BrVn6Q-NrjKYJpV9_fgBs,15130
|
|
58
|
+
setuptools/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055
|
|
59
|
+
setuptools/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098
|
|
60
|
+
setuptools/_vendor/packaging/__about__.py,sha256=CpuMSyh1V7adw8QMjWKkY3LtdqRUkRX4MgJ6nF4stM0,744
|
|
61
|
+
setuptools/_vendor/packaging/__init__.py,sha256=6enbp5XgRfjBjsI9-bn00HjHf5TH21PDMOKkJW8xw-w,562
|
|
62
|
+
setuptools/_vendor/packaging/_compat.py,sha256=Ugdm-qcneSchW25JrtMIKgUxfEEBcCAz6WrEeXeqz9o,865
|
|
63
|
+
setuptools/_vendor/packaging/_structures.py,sha256=pVd90XcXRGwpZRB_qdFuVEibhCHpX_bL5zYr9-N0mc8,1416
|
|
64
|
+
setuptools/_vendor/packaging/markers.py,sha256=dcGCz4lgFcrJ2gdAD9O9nxMu4bbpaPM7sDEyAbMjQHA,8858
|
|
65
|
+
setuptools/_vendor/packaging/requirements.py,sha256=3VNhQZIQJ5gp5yX2s5HQ5QIlnBxFLWhS1vjDTMtHdcA,5523
|
|
66
|
+
setuptools/_vendor/packaging/specifiers.py,sha256=0ZzQpcUnvrQ6LjR-mQRLzMr8G6hdRv-mY0VSf_amFtI,27778
|
|
67
|
+
setuptools/_vendor/packaging/tags.py,sha256=EPLXhO6GTD7_oiWEO1U0l0PkfR8R_xivpMDHXnsTlts,12933
|
|
68
|
+
setuptools/_vendor/packaging/utils.py,sha256=VaTC0Ei7zO2xl9ARiWmz2YFLFt89PuuhLbAlXMyAGms,1520
|
|
69
|
+
setuptools/_vendor/packaging/version.py,sha256=Npdwnb8OHedj_2L86yiUqscujb7w_i5gmSK1PhOAFzg,11978
|
|
70
|
+
setuptools/command/__init__.py,sha256=AKflHeDUOP4is4ei1qbHofQKcwRcSyfINONhZ033D48,736
|
|
71
|
+
setuptools/command/alias.py,sha256=pz07W_jSsI7IS_aL-jtTQ3L6RjCSP4CMuhGO9JpNL2E,2788
|
|
72
|
+
setuptools/command/bdist_egg.py,sha256=mfNDhWYfXk5LcNHJBuyMoNsEiWP9qs7NZDGZNZ_LN7o,19010
|
|
73
|
+
setuptools/command/bdist_rpm.py,sha256=B7l0TnzCGb-0nLlm6rS00jWLkojASwVmdhW2w5Qz_Ak,1508
|
|
74
|
+
setuptools/command/bdist_wininst.py,sha256=_6dz3lpB1tY200LxKPLM7qgwTCceOMgaWFF-jW2-pm0,637
|
|
75
|
+
setuptools/command/build_clib.py,sha256=c8E-1vI7D_Mj_d8vMTZZ_ELNiyL96z3Io62xnRjH5ws,4658
|
|
76
|
+
setuptools/command/build_ext.py,sha256=e0tiGPVj2uGY-7mcitC3wJy95fxlDcuXJu6NGJkvwMQ,13336
|
|
77
|
+
setuptools/command/build_py.py,sha256=GSt0nPHc49dAdYbvWOEqagd5WsIGd5KbynzppGiheu0,10114
|
|
78
|
+
setuptools/command/develop.py,sha256=xz2QxiSZpNreRBl83_7oJErT96Wf4TuKGQrPZbW2U6Y,8984
|
|
79
|
+
setuptools/command/dist_info.py,sha256=5t6kOfrdgALT-P3ogss6PF9k-Leyesueycuk3dUyZnI,960
|
|
80
|
+
setuptools/command/easy_install.py,sha256=EnGUyalpoTuvnGu9m-3ow5rwQzaCcjrKTEug_6JUsZs,90509
|
|
81
|
+
setuptools/command/egg_info.py,sha256=bwlBZr098bERbOyuoJ-Z3YK9b_Eo53NVTBlqHy7w1qY,27642
|
|
82
|
+
setuptools/command/install.py,sha256=9liesUQ1k4BEQSEhLqLENxvUo9rMEOu49TKy6qVpt98,4858
|
|
83
|
+
setuptools/command/install_egg_info.py,sha256=N8jEtbO-sbVgocH_UaxpXJr8hQHLJzlA6Wzket9K-xk,2841
|
|
84
|
+
setuptools/command/install_lib.py,sha256=6MtjU2yWIz_s9Nf0C2i_W5SzNzp-Osi1EC5_TvOrt3s,4060
|
|
85
|
+
setuptools/command/install_scripts.py,sha256=hQoU7y-avHBmMWIf7aItNwtOuD8BXpzNgYR7kwBNG_I,3183
|
|
86
|
+
setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628
|
|
87
|
+
setuptools/command/py36compat.py,sha256=qT-JswbG5zAwE2J8MjBLLul0dhPw3N0nJlX86Ohk7QE,5154
|
|
88
|
+
setuptools/command/register.py,sha256=gVnecx-SrrwluacsjTVBZdw4TMe3zG2NhlRr-O9p2ls,639
|
|
89
|
+
setuptools/command/rotate.py,sha256=mmrpsrTocbiWVSHqtR1cYkfL3vHwzoApCMeUPv60Wkg,2471
|
|
90
|
+
setuptools/command/saveopts.py,sha256=205RP_EjM2azFiW85SaZbVWMOnbdym4SmJxiY0symC4,842
|
|
91
|
+
setuptools/command/sdist.py,sha256=AV18vNYnPx789DEdrmZIgfO8hJp8b-WjamAsBOrvVi8,8415
|
|
92
|
+
setuptools/command/setopt.py,sha256=viOJ884FpXaVyV2ObW-7zm477elxO4yGG7Va7HHeDBk,5411
|
|
93
|
+
setuptools/command/test.py,sha256=KTtsCAupub1RUGbNgfIqOybLpgpPFJY3Ntle3TJpEpM,10432
|
|
94
|
+
setuptools/command/upload.py,sha256=ltCvw8pEG6uTsOVvm0JeJAuW3AsVlFFxnpYvbu2VK9A,633
|
|
95
|
+
setuptools/command/upload_docs.py,sha256=Zb1pqfPBqDrDDWXCmgBXe0Su8Ad4ucZhbIytJnTQpY4,7812
|
|
96
|
+
setuptools/extern/__init__.py,sha256=4q9gtShB1XFP6CisltsyPqtcfTO6ZM9Lu1QBl3l-qmo,2514
|
|
97
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/LICENSE,sha256=wyo6w5WvYyHv0ovnPQagDw22q4h9HCHU_sRhKNIFbVo,1078
|
|
98
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/METADATA,sha256=bCBVNmPt47gDwba_WAZOXBBpg-tCVPKptY8uN8GEljU,3745
|
|
99
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
|
|
100
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/dependency_links.txt,sha256=HlkCFkoK5TbZ5EMLbLKYhLcY_E31kBWD8TqW2EgmatQ,239
|
|
101
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/entry_points.txt,sha256=W9P2rmG1eAT0rV3ZZUgfE9wjmBgZ8ZAMAMxTB5ustPA,3206
|
|
102
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/top_level.txt,sha256=2HUXVVwA4Pff1xgTFr3GsTXXKaPaO6vlG6oNJ_4u4Tg,38
|
|
103
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
104
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/RECORD,,
|
|
105
|
+
.prefix/bin/easy_install,sha256=4mDn0ktXXNhpTn4bmLk-6hWTwdNNGKcVL3-STaSD7wo,470
|
|
106
|
+
.prefix/bin/easy_install-3.9,sha256=4mDn0ktXXNhpTn4bmLk-6hWTwdNNGKcVL3-STaSD7wo,470
|
|
107
|
+
setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.pex-info/original-whl-info.json,sha256=cjYUbQtgEMJQC9n_4TXC9xXCU2dW82EFb7w2JvZ2LtA,7000
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"entries":[["easy_install.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/__init__.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/py31compat.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/__init__.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/appdirs.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/pyparsing.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/six.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/__about__.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/__init__.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/_compat.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/_structures.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/markers.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/requirements.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/specifiers.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/utils.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/_vendor/packaging/version.py",[1980,1,1,0,0,0],2175008768],["pkg_resources/extern/__init__.py",[1980,1,1,0,0,0],2175008768],["setuptools/__init__.py",[1980,1,1,0,0,0],2175008768],["setuptools/_deprecation_warning.py",[1980,1,1,0,0,0],2175008768],["setuptools/_imp.py",[1980,1,1,0,0,0],2175008768],["setuptools/archive_util.py",[1980,1,1,0,0,0],2175008768],["setuptools/build_meta.py",[1980,1,1,0,0,0],2175008768],["setuptools/cli-32.exe",[1980,1,1,0,0,0],2175008768],["setuptools/cli-64.exe",[1980,1,1,0,0,0],2175008768],["setuptools/cli.exe",[1980,1,1,0,0,0],2175008768],["setuptools/config.py",[1980,1,1,0,0,0],2175008768],["setuptools/dep_util.py",[1980,1,1,0,0,0],2175008768],["setuptools/depends.py",[1980,1,1,0,0,0],2175008768],["setuptools/dist.py",[1980,1,1,0,0,0],2175008768],["setuptools/errors.py",[1980,1,1,0,0,0],2175008768],["setuptools/extension.py",[1980,1,1,0,0,0],2175008768],["setuptools/glob.py",[1980,1,1,0,0,0],2175008768],["setuptools/gui-32.exe",[1980,1,1,0,0,0],2175008768],["setuptools/gui-64.exe",[1980,1,1,0,0,0],2175008768],["setuptools/gui.exe",[1980,1,1,0,0,0],2175008768],["setuptools/installer.py",[1980,1,1,0,0,0],2175008768],["setuptools/launch.py",[1980,1,1,0,0,0],2175008768],["setuptools/lib2to3_ex.py",[1980,1,1,0,0,0],2175008768],["setuptools/monkey.py",[1980,1,1,0,0,0],2175008768],["setuptools/msvc.py",[1980,1,1,0,0,0],2175008768],["setuptools/namespaces.py",[1980,1,1,0,0,0],2175008768],["setuptools/package_index.py",[1980,1,1,0,0,0],2175008768],["setuptools/py27compat.py",[1980,1,1,0,0,0],2175008768],["setuptools/py31compat.py",[1980,1,1,0,0,0],2175008768],["setuptools/py33compat.py",[1980,1,1,0,0,0],2175008768],["setuptools/py34compat.py",[1980,1,1,0,0,0],2175008768],["setuptools/sandbox.py",[1980,1,1,0,0,0],2175008768],["setuptools/script (dev).tmpl",[1980,1,1,0,0,0],2175008768],["setuptools/script.tmpl",[1980,1,1,0,0,0],2175008768],["setuptools/site-patch.py",[1980,1,1,0,0,0],2175008768],["setuptools/ssl_support.py",[1980,1,1,0,0,0],2175008768],["setuptools/unicode_utils.py",[1980,1,1,0,0,0],2175008768],["setuptools/version.py",[1980,1,1,0,0,0],2175008768],["setuptools/wheel.py",[1980,1,1,0,0,0],2175008768],["setuptools/windows_support.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/__init__.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/ordered_set.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/pyparsing.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/six.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/__about__.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/__init__.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/_compat.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/_structures.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/markers.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/requirements.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/specifiers.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/tags.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/utils.py",[1980,1,1,0,0,0],2175008768],["setuptools/_vendor/packaging/version.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/__init__.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/alias.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/bdist_egg.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/bdist_rpm.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/bdist_wininst.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/build_clib.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/build_ext.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/build_py.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/develop.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/dist_info.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/easy_install.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/egg_info.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/install.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/install_egg_info.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/install_lib.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/install_scripts.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/launcher manifest.xml",[1980,1,1,0,0,0],2175008768],["setuptools/command/py36compat.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/register.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/rotate.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/saveopts.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/sdist.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/setopt.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/test.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/upload.py",[1980,1,1,0,0,0],2175008768],["setuptools/command/upload_docs.py",[1980,1,1,0,0,0],2175008768],["setuptools/extern/__init__.py",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/LICENSE",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/METADATA",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/WHEEL",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/dependency_links.txt",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/entry_points.txt",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/top_level.txt",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/zip-safe",[1980,1,1,0,0,0],2175008768],["setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863.dist-info/RECORD",[1980,1,1,0,0,0],28573696]],"filename":"setuptools-44.0.0+3acb925dd708430aeaf197ea53ac8a752f7c1863-py2.py3-none-any.whl"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"fingerprint":
|
|
1
|
+
{"fingerprint":"e022215e30b009ca1018a9255f6812d150469e3f6ff12687dd93459dd5a5274d","record_relpath":"toml-0.10.2.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
toml/__init__.py,sha256=OAi77F_oThE00nGyd1z7JgtG_PKq6XKQxLfThnETzcU,1003
|
|
2
|
+
toml/decoder.py,sha256=NT-RGTEh0vBksVd2WaYorMu5-K350_ymWiDggVUXefM,39084
|
|
3
|
+
toml/encoder.py,sha256=KWnqyK3VROUobm8d3dOKckXMEh4d_yOQGPWvPNCj5xI,10273
|
|
4
|
+
toml/ordered.py,sha256=-0iAss5NfnsyIjhzsyjtztFiCgVINlW7dGXmgdBcLvA,642
|
|
5
|
+
toml/tz.py,sha256=-5vg8wkg_atnVi2TnEveexIVE7T_FxBVr_-2WVfO1oA,701
|
|
6
|
+
toml-0.10.2.dist-info/LICENSE,sha256=LZKUgj32yJNXyL5JJ_znk2HWVh5e51MtWSbmOTmqpTY,1252
|
|
7
|
+
toml-0.10.2.dist-info/METADATA,sha256=n_YkspvEihd_QXLIZZ50WVSFz3rZ_k7jQP-OU1WUpWY,7142
|
|
8
|
+
toml-0.10.2.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
|
|
9
|
+
toml-0.10.2.dist-info/top_level.txt,sha256=2BO8ZRNnvJWgXyiQv66LBb_v87qBzcoUtEBefA75Ouk,5
|
|
10
|
+
toml-0.10.2.dist-info/RECORD,,
|
|
11
|
+
toml-0.10.2.pex-info/original-whl-info.json,sha256=63hjg_RvL2dX1x8O7tNS3P_oW9o1e5CHUfZ0MIyKehM,636
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"entries":[["toml/__init__.py",[2020,11,1,1,37,2],2175008768],["toml/decoder.py",[2020,10,31,3,20,8],2175008768],["toml/encoder.py",[2020,10,31,3,20,8],2175008768],["toml/ordered.py",[2018,4,1,16,33,32],2175008768],["toml/tz.py",[2020,10,31,3,20,8],2175008768],["toml-0.10.2.dist-info/LICENSE",[2020,11,1,1,37,14],2175008768],["toml-0.10.2.dist-info/METADATA",[2020,11,1,1,37,14],2175008768],["toml-0.10.2.dist-info/WHEEL",[2020,11,1,1,37,14],2175008768],["toml-0.10.2.dist-info/top_level.txt",[2020,11,1,1,37,14],2175008768],["toml-0.10.2.dist-info/RECORD",[2020,11,1,1,37,14],28573696]],"filename":"toml-0.10.2-py2.py3-none-any.whl"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"fingerprint":
|
|
1
|
+
{"fingerprint":"bbe9219bfe424168417563a7c481eeed73fbb39ef7458e0e8ba636276afb2822","record_relpath":"tomli-2.0.1.dist-info/RECORD","root_is_purelib":true,"stash_dir":".prefix","sys_path_entries":["."]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
tomli/__init__.py,sha256=JhUwV66DB1g4Hvt1UQCVMdfCu-IgAV8FXmvDU9onxd4,396
|
|
2
|
+
tomli/_parser.py,sha256=g9-ENaALS-B8dokYpCuzUFalWlog7T-SIYMjLZSWrtM,22633
|
|
3
|
+
tomli/_re.py,sha256=dbjg5ChZT23Ka9z9DHOXfdtSpPwUfdgMXnj8NOoly-w,2943
|
|
4
|
+
tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254
|
|
5
|
+
tomli/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
|
|
6
|
+
tomli-2.0.1.dist-info/LICENSE,sha256=uAgWsNUwuKzLTCIReDeQmEpuO2GSLCte6S8zcqsnQv4,1072
|
|
7
|
+
tomli-2.0.1.dist-info/WHEEL,sha256=jPMR_Dzkc4X4icQtmz81lnNY_kAsfog7ry7qoRvYLXw,81
|
|
8
|
+
tomli-2.0.1.dist-info/METADATA,sha256=zPDceKmPwJGLWtZykrHixL7WVXWmJGzZ1jyRT5lCoPI,8875
|
|
9
|
+
tomli-2.0.1.dist-info/RECORD,,
|
|
10
|
+
tomli-2.0.1.pex-info/original-whl-info.json,sha256=_Iy0aZfe20sZ7ZM6ou1a246HfctfLCZeq4YrNIc7k_I,552
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"entries":[["tomli/__init__.py",[2022,2,8,10,53,42],2175008768],["tomli/_parser.py",[2022,2,8,10,53,42],2175008768],["tomli/_re.py",[2022,2,8,10,53,42],2175008768],["tomli/_types.py",[2022,2,8,10,53,42],2175008768],["tomli/py.typed",[2022,2,8,10,53,42],2175008768],["tomli-2.0.1.dist-info/LICENSE",[2022,2,8,10,53,42],2175008768],["tomli-2.0.1.dist-info/WHEEL",[2016,1,1,0,0,0],27525120],["tomli-2.0.1.dist-info/METADATA",[2016,1,1,0,0,0],27525120],["tomli-2.0.1.dist-info/RECORD",[2016,1,1,0,0,0],27525120]],"filename":"tomli-2.0.1-py3-none-any.whl"}
|
pex/venv/installer.py
CHANGED
|
@@ -17,12 +17,14 @@ from pex.dist_metadata import Distribution
|
|
|
17
17
|
from pex.environment import PEXEnvironment
|
|
18
18
|
from pex.executables import chmod_plus_x
|
|
19
19
|
from pex.fs import safe_symlink
|
|
20
|
+
from pex.installed_wheel import InstalledWheel
|
|
20
21
|
from pex.orderedset import OrderedSet
|
|
21
22
|
from pex.os import WINDOWS
|
|
22
|
-
from pex.
|
|
23
|
+
from pex.pep_427 import reinstall_flat, reinstall_venv
|
|
23
24
|
from pex.pep_440 import Version
|
|
24
25
|
from pex.pep_503 import ProjectName
|
|
25
26
|
from pex.pex import PEX
|
|
27
|
+
from pex.pex_info import PexInfo
|
|
26
28
|
from pex.result import Error
|
|
27
29
|
from pex.sysconfig import SCRIPT_DIR
|
|
28
30
|
from pex.tracer import TRACER
|
|
@@ -43,6 +45,7 @@ if TYPE_CHECKING:
|
|
|
43
45
|
Iterator,
|
|
44
46
|
List,
|
|
45
47
|
Optional,
|
|
48
|
+
Sequence,
|
|
46
49
|
Text,
|
|
47
50
|
Tuple,
|
|
48
51
|
Union,
|
|
@@ -268,8 +271,8 @@ def _populate_flat_deps(
|
|
|
268
271
|
for dist in distributions:
|
|
269
272
|
try:
|
|
270
273
|
installed_wheel = InstalledWheel.load(dist.location)
|
|
271
|
-
for src, dst in
|
|
272
|
-
target_dir=dest_dir, copy_mode=copy_mode
|
|
274
|
+
for src, dst in reinstall_flat(
|
|
275
|
+
installed_wheel=installed_wheel, target_dir=dest_dir, copy_mode=copy_mode
|
|
273
276
|
):
|
|
274
277
|
yield src, dst
|
|
275
278
|
except InstalledWheel.LoadError:
|
|
@@ -482,8 +485,11 @@ def _populate_venv_deps(
|
|
|
482
485
|
|
|
483
486
|
try:
|
|
484
487
|
installed_wheel = InstalledWheel.load(dist.location)
|
|
485
|
-
for src, dst in
|
|
486
|
-
|
|
488
|
+
for src, dst in reinstall_venv(
|
|
489
|
+
installed_wheel=installed_wheel,
|
|
490
|
+
venv=venv,
|
|
491
|
+
copy_mode=copy_mode,
|
|
492
|
+
rel_extra_path=rel_extra_path,
|
|
487
493
|
):
|
|
488
494
|
yield src, dst
|
|
489
495
|
except InstalledWheel.LoadError:
|
|
@@ -570,24 +576,16 @@ def _populate_sources(
|
|
|
570
576
|
yield src, dest
|
|
571
577
|
|
|
572
578
|
|
|
573
|
-
def
|
|
579
|
+
def install_pex_main(
|
|
574
580
|
target_dir, # type: str
|
|
575
581
|
venv, # type: Virtualenv
|
|
576
|
-
|
|
582
|
+
pex_info, # type: PexInfo
|
|
583
|
+
activated_dists, # type: Sequence[Distribution]
|
|
577
584
|
shebang, # type: str
|
|
578
585
|
venv_python, # type: str
|
|
579
586
|
bin_path, # type: BinPath.Value
|
|
580
587
|
):
|
|
581
|
-
# type: (...) ->
|
|
582
|
-
|
|
583
|
-
# We want the venv at rest to reflect the PEX it was created from at rest; as such we use the
|
|
584
|
-
# PEX's at-rest PEX-INFO to perform the layout. The venv can then be executed with various PEX
|
|
585
|
-
# environment variables in-play that it respects (e.g.: PEX_EXTRA_SYS_PATH, PEX_INTERPRETER,
|
|
586
|
-
# PEX_MODULE, etc.).
|
|
587
|
-
pex_info = pex.pex_info(include_env_overrides=False)
|
|
588
|
-
|
|
589
|
-
for src, dst in _populate_sources(pex=pex, dst=venv.site_packages_dir):
|
|
590
|
-
yield src, dst
|
|
588
|
+
# type: (...) -> None
|
|
591
589
|
|
|
592
590
|
with open(os.path.join(venv.site_packages_dir, "PEX_EXTRA_SYS_PATH.pth"), "w") as fp:
|
|
593
591
|
# N.B.: .pth import lines must be single lines: https://docs.python.org/3/library/site.html
|
|
@@ -603,7 +601,7 @@ def _populate_first_party(
|
|
|
603
601
|
with open(os.path.join(venv.venv_dir, pex_info.PATH), "w") as fp:
|
|
604
602
|
fp.write(pex_info.dump())
|
|
605
603
|
|
|
606
|
-
#
|
|
604
|
+
# Add a __main__ to the root of the venv for running the venv dir like a loose PEX dir
|
|
607
605
|
# and a main.py for running as a script.
|
|
608
606
|
with open(venv.join_path("__main__.py"), "w") as fp:
|
|
609
607
|
fp.write(
|
|
@@ -656,9 +654,38 @@ def _populate_first_party(
|
|
|
656
654
|
repl.create_pex_repl_exe(
|
|
657
655
|
shebang=shebang,
|
|
658
656
|
pex_info=pex_info,
|
|
659
|
-
activated_dists=
|
|
657
|
+
activated_dists=activated_dists,
|
|
660
658
|
pex=os.path.join(target_dir, "pex"),
|
|
661
659
|
venv=True,
|
|
662
660
|
)
|
|
663
661
|
)
|
|
664
662
|
chmod_plus_x(fp.name)
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
def _populate_first_party(
|
|
666
|
+
target_dir, # type: str
|
|
667
|
+
venv, # type: Virtualenv
|
|
668
|
+
pex, # type: PEX
|
|
669
|
+
shebang, # type: str
|
|
670
|
+
venv_python, # type: str
|
|
671
|
+
bin_path, # type: BinPath.Value
|
|
672
|
+
):
|
|
673
|
+
# type: (...) -> Iterator[Tuple[Text, Text]]
|
|
674
|
+
|
|
675
|
+
for src, dst in _populate_sources(pex=pex, dst=venv.site_packages_dir):
|
|
676
|
+
yield src, dst
|
|
677
|
+
|
|
678
|
+
# We want the venv at rest to reflect the PEX it was created from at rest; as such we use the
|
|
679
|
+
# PEX's at-rest PEX-INFO to perform the layout. The venv can then be executed with various PEX
|
|
680
|
+
# environment variables in-play that it respects (e.g.: PEX_EXTRA_SYS_PATH, PEX_INTERPRETER,
|
|
681
|
+
# PEX_MODULE, etc.).
|
|
682
|
+
pex_info = pex.pex_info(include_env_overrides=False)
|
|
683
|
+
install_pex_main(
|
|
684
|
+
target_dir=target_dir,
|
|
685
|
+
venv=venv,
|
|
686
|
+
pex_info=pex_info,
|
|
687
|
+
activated_dists=tuple(pex.resolve()),
|
|
688
|
+
shebang=shebang,
|
|
689
|
+
venv_python=venv_python,
|
|
690
|
+
bin_path=bin_path,
|
|
691
|
+
)
|
pex/venv/venv_pex.py
CHANGED
|
@@ -179,15 +179,18 @@ def boot(
|
|
|
179
179
|
"_PEX_USE_PIP_CONFIG",
|
|
180
180
|
# This is used by Pex's Pip to inject runtime patches dynamically.
|
|
181
181
|
"_PEX_PIP_RUNTIME_PATCHES_PACKAGE",
|
|
182
|
-
# These are used by Pex's Pip venv to provide foreign platform support
|
|
183
|
-
# around https://github.com/pypa/pip/issues/10050.
|
|
182
|
+
# These are used by Pex's Pip venv to provide foreign platform support, universal lock
|
|
183
|
+
# support and work around https://github.com/pypa/pip/issues/10050.
|
|
184
|
+
"_PEX_INTERPRETER_IMPLEMENTATION",
|
|
184
185
|
"_PEX_PATCHED_MARKERS_FILE",
|
|
185
186
|
"_PEX_PATCHED_TAGS_FILE",
|
|
186
187
|
# These are used by Pex's Pip venv to implement universal locks.
|
|
187
188
|
"_PEX_PYTHON_VERSIONS_FILE",
|
|
188
|
-
"
|
|
189
|
+
"_PEX_UNIVERSAL_TARGET_FILE",
|
|
189
190
|
# This is used to implement Pex --exclude and --override support.
|
|
190
191
|
"_PEX_DEP_CONFIG_FILE",
|
|
192
|
+
# This is used to implement --source support.
|
|
193
|
+
"_PEX_REPOS_CONFIG_FILE",
|
|
191
194
|
# This is used as an experiment knob for atomic_directory locking.
|
|
192
195
|
"_PEX_FILE_LOCK_STYLE",
|
|
193
196
|
# This is used in the scie binding command for ZIPAPP PEXes.
|
pex/version.py
CHANGED
pex/wheel.py
CHANGED
|
@@ -10,24 +10,27 @@ from email.message import Message
|
|
|
10
10
|
|
|
11
11
|
from pex.dist_metadata import (
|
|
12
12
|
DistMetadata,
|
|
13
|
+
Distribution,
|
|
13
14
|
MetadataFiles,
|
|
14
15
|
MetadataType,
|
|
15
16
|
load_metadata,
|
|
16
17
|
parse_message,
|
|
17
18
|
)
|
|
18
19
|
from pex.orderedset import OrderedSet
|
|
20
|
+
from pex.pep_440 import Version
|
|
21
|
+
from pex.pep_503 import ProjectName
|
|
19
22
|
from pex.third_party.packaging import tags
|
|
20
23
|
from pex.typing import TYPE_CHECKING, cast
|
|
21
24
|
|
|
22
25
|
if TYPE_CHECKING:
|
|
23
|
-
from typing import Dict, Text, Tuple
|
|
26
|
+
from typing import Dict, Iterator, List, Optional, Text, Tuple
|
|
24
27
|
|
|
25
28
|
import attr # vendor:skip
|
|
26
29
|
else:
|
|
27
30
|
from pex.third_party import attr
|
|
28
31
|
|
|
29
32
|
|
|
30
|
-
class WheelMetadataLoadError(
|
|
33
|
+
class WheelMetadataLoadError(ValueError):
|
|
31
34
|
"""Indicates an error loading WHEEL metadata."""
|
|
32
35
|
|
|
33
36
|
|
|
@@ -38,27 +41,62 @@ class WHEEL(object):
|
|
|
38
41
|
See item 6 here for the WHEEL file contents: https://peps.python.org/pep-0427/#file-contents
|
|
39
42
|
"""
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
@classmethod
|
|
45
|
+
def from_metadata_files(cls, metadata_files):
|
|
46
|
+
# type: (MetadataFiles) -> WHEEL
|
|
47
|
+
|
|
48
|
+
metadata_bytes = metadata_files.read("WHEEL")
|
|
49
|
+
if not metadata_bytes:
|
|
50
|
+
raise WheelMetadataLoadError(
|
|
51
|
+
"Could not find WHEEL metadata in {wheel}.".format(
|
|
52
|
+
wheel=metadata_files.render_description(metadata_file_name="WHEEL")
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Some WHEEL metadata in the wild has blank lines in between headers when it should not.
|
|
57
|
+
# Since WHEEL metadata, unlike METADATA, does not use the message body to convey metadata,
|
|
58
|
+
# this should be safe.
|
|
59
|
+
#
|
|
60
|
+
# See here for initial discovery case:
|
|
61
|
+
# https://github.com/pex-tool/pex/issues/2998#issuecomment-3492998265
|
|
62
|
+
normalized_metadata = b"".join(
|
|
63
|
+
line for line in metadata_bytes.splitlines(True) if line.strip()
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
metadata = parse_message(normalized_metadata)
|
|
67
|
+
return cls(files=metadata_files, metadata=metadata)
|
|
68
|
+
|
|
69
|
+
_CACHE = {} # type: Dict[Tuple[Text, Optional[ProjectName]], WHEEL]
|
|
42
70
|
|
|
43
71
|
@classmethod
|
|
44
|
-
def load(
|
|
45
|
-
|
|
46
|
-
|
|
72
|
+
def load(
|
|
73
|
+
cls,
|
|
74
|
+
location, # type: Text
|
|
75
|
+
project_name=None, # type: Optional[ProjectName]
|
|
76
|
+
):
|
|
77
|
+
# type: (...) -> WHEEL
|
|
78
|
+
wheel = cls._CACHE.get((location, project_name))
|
|
47
79
|
if not wheel:
|
|
48
|
-
metadata_files = load_metadata(
|
|
80
|
+
metadata_files = load_metadata(
|
|
81
|
+
location, project_name=project_name, restrict_types_to=(MetadataType.DIST_INFO,)
|
|
82
|
+
)
|
|
49
83
|
if not metadata_files:
|
|
50
84
|
raise WheelMetadataLoadError(
|
|
51
85
|
"Could not find any metadata in {wheel}.".format(wheel=location)
|
|
52
86
|
)
|
|
87
|
+
wheel = cls.from_metadata_files(metadata_files)
|
|
88
|
+
cls._CACHE[(location, project_name)] = wheel
|
|
89
|
+
return wheel
|
|
53
90
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
91
|
+
@classmethod
|
|
92
|
+
def from_distribution(cls, distribution):
|
|
93
|
+
# type: (Distribution) -> WHEEL
|
|
94
|
+
location = distribution.metadata.files.metadata.path
|
|
95
|
+
project_name = distribution.metadata.project_name
|
|
96
|
+
wheel = cls._CACHE.get((location, project_name))
|
|
97
|
+
if not wheel:
|
|
98
|
+
wheel = cls.from_metadata_files(distribution.metadata.files)
|
|
99
|
+
cls._CACHE[(location, project_name)] = wheel
|
|
62
100
|
return wheel
|
|
63
101
|
|
|
64
102
|
files = attr.ib() # type: MetadataFiles
|
|
@@ -69,7 +107,16 @@ class WHEEL(object):
|
|
|
69
107
|
# type: () -> Tuple[tags.Tag, ...]
|
|
70
108
|
return tuple(
|
|
71
109
|
itertools.chain.from_iterable(
|
|
72
|
-
|
|
110
|
+
# N.B.: There should be just 1 tag per Tag entry per items 7 and 11 in
|
|
111
|
+
# https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-contents
|
|
112
|
+
# There are wheels in the wild though with WHEEL metadata Tag entries that contain
|
|
113
|
+
# compressed tags instead of having the tags expanded to 1 per Tag. Although
|
|
114
|
+
# `tags.parse_tag` handles expansion of the compressed tags, it collects them in
|
|
115
|
+
# a frozenset with unstable order which can cause issues when attempting to
|
|
116
|
+
# construct stable wheel names from these tags; as such, we do the sort here as a
|
|
117
|
+
# defense against this style of bad WHEEL Tag metadata.
|
|
118
|
+
sorted(tags.parse_tag(tag), key=lambda tag: str(tag))
|
|
119
|
+
for tag in self.metadata.get_all("Tag", ())
|
|
73
120
|
)
|
|
74
121
|
)
|
|
75
122
|
|
|
@@ -84,26 +131,42 @@ class WHEEL(object):
|
|
|
84
131
|
|
|
85
132
|
@attr.s(frozen=True)
|
|
86
133
|
class Wheel(object):
|
|
87
|
-
@
|
|
88
|
-
def
|
|
89
|
-
# type:
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
134
|
+
@staticmethod
|
|
135
|
+
def _source(
|
|
136
|
+
location, # type: str
|
|
137
|
+
metadata_files, # type: MetadataFiles
|
|
138
|
+
):
|
|
139
|
+
# type: (...) -> str
|
|
140
|
+
return "{project_name} {version} at {location}".format(
|
|
141
|
+
project_name=metadata_files.metadata.project_name,
|
|
142
|
+
version=metadata_files.metadata.version,
|
|
143
|
+
location=location,
|
|
144
|
+
)
|
|
98
145
|
|
|
99
|
-
|
|
146
|
+
@classmethod
|
|
147
|
+
def _from_metadata_files(
|
|
148
|
+
cls,
|
|
149
|
+
location, # type: str
|
|
150
|
+
metadata_files, # type: MetadataFiles
|
|
151
|
+
wheel=None, # type: Optional[WHEEL]
|
|
152
|
+
):
|
|
153
|
+
# type: (...) -> Wheel
|
|
154
|
+
|
|
155
|
+
if wheel:
|
|
156
|
+
metadata = wheel
|
|
157
|
+
else:
|
|
158
|
+
metadata = WHEEL.from_metadata_files(metadata_files)
|
|
159
|
+
|
|
160
|
+
wheel_metadata_dir = os.path.dirname(metadata_files.metadata.rel_path)
|
|
100
161
|
if not wheel_metadata_dir.endswith(".dist-info"):
|
|
101
162
|
raise WheelMetadataLoadError(
|
|
102
|
-
"Expected
|
|
103
|
-
"found at {wheel_metadata_path}.".format(
|
|
104
|
-
|
|
163
|
+
"Expected METADATA file for {source} to be housed in a .dist-info directory, but "
|
|
164
|
+
"was found at {wheel_metadata_path}.".format(
|
|
165
|
+
source=cls._source(location, metadata_files),
|
|
166
|
+
wheel_metadata_path=metadata_files.metadata.rel_path,
|
|
105
167
|
)
|
|
106
168
|
)
|
|
169
|
+
|
|
107
170
|
# Although not crisply defined, all PEPs lead to PEP-508 which restricts project names
|
|
108
171
|
# to ASCII: https://peps.python.org/pep-0508/#names. Likewise, version numbers are also
|
|
109
172
|
# restricted to ASCII: https://peps.python.org/pep-0440/. Since the `.dist-info` dir
|
|
@@ -113,13 +176,35 @@ class Wheel(object):
|
|
|
113
176
|
metadata_dir = str(wheel_metadata_dir)
|
|
114
177
|
|
|
115
178
|
data_dir = re.sub(r"\.dist-info$", ".data", metadata_dir)
|
|
179
|
+
pex_metadata_dir = re.sub(r"\.dist-info$", ".pex-info", metadata_dir)
|
|
116
180
|
|
|
117
181
|
return cls(
|
|
118
|
-
location=
|
|
182
|
+
location=location,
|
|
119
183
|
metadata_dir=metadata_dir,
|
|
120
|
-
metadata_files=
|
|
184
|
+
metadata_files=metadata_files,
|
|
121
185
|
metadata=metadata,
|
|
122
186
|
data_dir=data_dir,
|
|
187
|
+
pex_metadata_dir=pex_metadata_dir,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
@classmethod
|
|
191
|
+
def load(
|
|
192
|
+
cls,
|
|
193
|
+
wheel_path, # type: str
|
|
194
|
+
project_name=None, # type: Optional[ProjectName]
|
|
195
|
+
):
|
|
196
|
+
# type: (...) -> Wheel
|
|
197
|
+
|
|
198
|
+
wheel = WHEEL.load(wheel_path, project_name=project_name)
|
|
199
|
+
return cls._from_metadata_files(
|
|
200
|
+
location=wheel_path, metadata_files=wheel.files, wheel=wheel
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
@classmethod
|
|
204
|
+
def from_distribution(cls, distribution):
|
|
205
|
+
# type: (Distribution) -> Wheel
|
|
206
|
+
return cls._from_metadata_files(
|
|
207
|
+
location=distribution.location, metadata_files=distribution.metadata.files
|
|
123
208
|
)
|
|
124
209
|
|
|
125
210
|
location = attr.ib() # type: str
|
|
@@ -127,6 +212,34 @@ class Wheel(object):
|
|
|
127
212
|
metadata_files = attr.ib() # type: MetadataFiles
|
|
128
213
|
metadata = attr.ib() # type: WHEEL
|
|
129
214
|
data_dir = attr.ib() # type: str
|
|
215
|
+
pex_metadata_dir = attr.ib() # type: str
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def source(self):
|
|
219
|
+
# type: () -> str
|
|
220
|
+
return self._source(self.location, self.metadata_files)
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def project_name(self):
|
|
224
|
+
# type: () -> ProjectName
|
|
225
|
+
return self.metadata_files.metadata.project_name
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def version(self):
|
|
229
|
+
# type: () -> Version
|
|
230
|
+
return self.metadata_files.metadata.version
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
def wheel_prefix(self):
|
|
234
|
+
# type: () -> str
|
|
235
|
+
|
|
236
|
+
# N.B.: We don't use the canonical form since it goes to lowercase.
|
|
237
|
+
project_name = re.sub(r"[-_.]+", "_", self.project_name.raw)
|
|
238
|
+
|
|
239
|
+
# N.B.: We don't use the canonical form since it drop trailing zero segments.
|
|
240
|
+
version = self.version.raw.replace("-", "_")
|
|
241
|
+
|
|
242
|
+
return "{project_name}-{version}".format(project_name=project_name, version=version)
|
|
130
243
|
|
|
131
244
|
@property
|
|
132
245
|
def wheel_file_name(self):
|
|
@@ -142,12 +255,29 @@ class Wheel(object):
|
|
|
142
255
|
tag = "{interpreters}-{abis}-{platforms}".format(
|
|
143
256
|
interpreters=".".join(interpreters), abis=".".join(abis), platforms=".".join(platforms)
|
|
144
257
|
)
|
|
258
|
+
return "{wheel_prefix}-{tag}.whl".format(wheel_prefix=self.wheel_prefix, tag=tag)
|
|
145
259
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
260
|
+
def iter_compatible_python_versions(self):
|
|
261
|
+
# type: () -> Iterator[Tuple[int, ...]]
|
|
262
|
+
|
|
263
|
+
for tag in self.metadata.tags:
|
|
264
|
+
match = re.search(r"\d+(?:_\d+)*", tag.interpreter)
|
|
265
|
+
if not match:
|
|
266
|
+
raise WheelMetadataLoadError(
|
|
267
|
+
"Invalid interpreter tag for wheel {whl} at {location}: {tag}".format(
|
|
268
|
+
whl=self.wheel_file_name, location=self.location, tag=tag.interpreter
|
|
269
|
+
)
|
|
270
|
+
)
|
|
271
|
+
components = match.group().split("_")
|
|
272
|
+
version = [] # type: List[int]
|
|
273
|
+
if len(components) == 1:
|
|
274
|
+
py_version_nodot = components[0]
|
|
275
|
+
version.append(int(py_version_nodot[0]))
|
|
276
|
+
if len(py_version_nodot) > 1:
|
|
277
|
+
version.append(int(py_version_nodot[1:]))
|
|
278
|
+
else:
|
|
279
|
+
version.extend(int(component) for component in components)
|
|
280
|
+
yield tuple(version)
|
|
151
281
|
|
|
152
282
|
@property
|
|
153
283
|
def root_is_purelib(self):
|
|
@@ -159,9 +289,27 @@ class Wheel(object):
|
|
|
159
289
|
return DistMetadata.from_metadata_files(self.metadata_files)
|
|
160
290
|
|
|
161
291
|
def metadata_path(self, *components):
|
|
162
|
-
#
|
|
292
|
+
# type: (*str) -> str
|
|
293
|
+
if not components:
|
|
294
|
+
return self.metadata_dir
|
|
163
295
|
return os.path.join(self.metadata_dir, *components)
|
|
164
296
|
|
|
165
297
|
def data_path(self, *components):
|
|
166
|
-
#
|
|
298
|
+
# type: (*str) -> str
|
|
167
299
|
return os.path.join(self.data_dir, *components)
|
|
300
|
+
|
|
301
|
+
def pex_metadata_path(self, *components):
|
|
302
|
+
# type: (*str) -> str
|
|
303
|
+
if not components:
|
|
304
|
+
return self.pex_metadata_dir
|
|
305
|
+
return os.path.join(self.pex_metadata_dir, *components)
|
|
306
|
+
|
|
307
|
+
def read_pex_metadata(self, *components):
|
|
308
|
+
# type: (*str) -> Optional[bytes]
|
|
309
|
+
|
|
310
|
+
location = os.path.join(self.location, self.pex_metadata_path(*components))
|
|
311
|
+
if not os.path.exists(location):
|
|
312
|
+
return None
|
|
313
|
+
|
|
314
|
+
with open(location, "rb") as fp:
|
|
315
|
+
return fp.read()
|