Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to exclude dependencies from pex file #2097

Closed
JoostvDoorn opened this issue Mar 15, 2023 · 13 comments · Fixed by #2409
Closed

Option to exclude dependencies from pex file #2097

JoostvDoorn opened this issue Mar 15, 2023 · 13 comments · Fixed by #2409

Comments

@JoostvDoorn
Copy link

Pex currently relies on Pip to resolve dependencies and build the PEX file. However, there are cases where users may want to exclude certain packages, either because they are already available on the target environment or because they are too large to include in the PEX file.

The proposed solution is to add an exclude flag to Pex, which would allow users to specify a list of packages to exclude from the PEX file. During the assembly phase, Pex would exclude these packages and their transitive dependencies, resulting in a smaller PEX file.

I believe this would be a useful feature for many users. We would want to use it with Pants to exclude dependencies such as pyspark for an environment that includes pyspark already.

This issue follows up on the comment here: #2082 (comment)

Other related issues have been filed previously in pants and pex as well. #1146 pantsbuild/pants#11324

@kaos
Copy link
Collaborator

kaos commented Mar 15, 2023

You'd have to find a way to ensure the version already present in the target env is compatible with the version janked from the pex or you might find yourself with hard to debug issues.

@jsirois
Copy link
Member

jsirois commented Mar 16, 2023

Yeah, as @kaos points out this is definitely buyer beware. It at least requires the --ignore-errors PEX build time option or the PEX_IGNORE_ERRORS=1 runtime env var option in combination with --inherit-path / PEX_INHERIT_PATH or PEX_EXTRA_SYS_PATH or PEX_PATH to make the elided distributions available. An advanced implementation could expand the current PEX boot resolve process:
https://github.com/pantsbuild/pex/blob/ecf9b95544c53970628e982b7132a345bbc931cd/pex/environment.py#L506-L509

Such that iter_distributions looks at more than the PEX internal distribution cache:
https://github.com/pantsbuild/pex/blob/ecf9b95544c53970628e982b7132a345bbc931cd/pex/environment.py#L266-L275

This would allow not using --ignore-errors / PEX_IGNORE_ERRORS=1 and still validating the boot resolve, but now via a mixed sys.path. This would only work though if the mixed-in sys.path elements had the distributions installed with dist-info metadata. For some systems, system packages are not installed this way. A quick check of Ubuntu 22.04 shows the system Python packages use egg-info metadata.

@jsirois
Copy link
Member

jsirois commented Sep 1, 2023

Ok, I've spent some time prototyping this (the advanced implementation described above). This works great but its also very sensitive. It turns out two installs of the same wheel can lead to a different hash due to ~inconsequential differences. For example:

$ diff -r ~/.pex/installed_wheels/354ecba855271d10b4901bcfb95ac3aa2bd1969cb6dd3a04c61ccf717f62fa61/cowsay-5.0-py2.py3-none-any.whl /tmp/tmpqwwi_ljs/cowsay-5.0-py2.py3-none-any.whl
diff -r /home/jsirois/.pex/installed_wheels/354ecba855271d10b4901bcfb95ac3aa2bd1969cb6dd3a04c61ccf717f62fa61/cowsay-5.0-py2.py3-none-any.whl/cowsay-5.0.dist-info/entry_points.txt /tmp/tmpqwwi_ljs/cowsay-5.0-py2.py3-none-any.whl/cowsay-5.0.dist-info/entry_points.txt
3d2
<
diff -r /home/jsirois/.pex/installed_wheels/354ecba855271d10b4901bcfb95ac3aa2bd1969cb6dd3a04c61ccf717f62fa61/cowsay-5.0-py2.py3-none-any.whl/cowsay-5.0.dist-info/METADATA /tmp/tmpqwwi_ljs/cowsay-5.0-py2.py3-none-any.whl/cowsay-5.0.dist-info/METADATA
9d8
< Platform: UNKNOWN
16a16
> License-File: LICENSE.txt
201,202d200
<
<
diff -r /home/jsirois/.pex/installed_wheels/354ecba855271d10b4901bcfb95ac3aa2bd1969cb6dd3a04c61ccf717f62fa61/cowsay-5.0-py2.py3-none-any.whl/cowsay-5.0.dist-info/WHEEL /tmp/tmpqwwi_ljs/cowsay-5.0-py2.py3-none-any.whl/cowsay-5.0.dist-info/WHEEL
2c2
< Generator: bdist_wheel (0.37.1)
---
> Generator: bdist_wheel (0.40.0)

So, in this case the cowsay installed in a venv was installed by a Pip that used a newer version of wheel to do the install work than Pex did and that version of wheel both leaves its version in metadata files as well as handling some (~inconsequential) metadata differently.

My experiment looks like so when this happens:

  1. The cowsay pex with cowsay excluded looks like:
$ zipinfo cowsay.pex
Archive:  cowsay.pex
Zip file size: 656033 bytes, number of entries: 170
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/
-rw-r--r--  2.0 unx      401 b- defN 80-Jan-01 00:00 .bootstrap/pex/__init__.py
-rw-r--r--  2.0 unx      235 b- defN 80-Jan-01 00:00 .bootstrap/pex/__main__.py
-rw-r--r--  2.0 unx      601 b- defN 80-Jan-01 00:00 .bootstrap/pex/argparse.py
-rw-r--r--  2.0 unx    12943 b- defN 80-Jan-01 00:00 .bootstrap/pex/atomic_directory.py
-rw-r--r--  2.0 unx      483 b- defN 80-Jan-01 00:00 .bootstrap/pex/attrs.py
-rw-r--r--  2.0 unx     5898 b- defN 80-Jan-01 00:00 .bootstrap/pex/auth.py
-rw-r--r--  2.0 unx     5092 b- defN 80-Jan-01 00:00 .bootstrap/pex/bootstrap.py
-rw-r--r--  2.0 unx    24035 b- defN 80-Jan-01 00:00 .bootstrap/pex/common.py
-rw-r--r--  2.0 unx     8218 b- defN 80-Jan-01 00:00 .bootstrap/pex/compatibility.py
-rw-r--r--  2.0 unx     3592 b- defN 80-Jan-01 00:00 .bootstrap/pex/compiler.py
-rw-r--r--  2.0 unx    30760 b- defN 80-Jan-01 00:00 .bootstrap/pex/dist_metadata.py
-rw-r--r--  2.0 unx     3896 b- defN 80-Jan-01 00:00 .bootstrap/pex/enum.py
-rw-r--r--  2.0 unx    34939 b- defN 80-Jan-01 00:00 .bootstrap/pex/environment.py
-rw-r--r--  2.0 unx     4151 b- defN 80-Jan-01 00:00 .bootstrap/pex/executor.py
-rw-r--r--  2.0 unx     5397 b- defN 80-Jan-01 00:00 .bootstrap/pex/fetcher.py
-rw-r--r--  2.0 unx     3457 b- defN 80-Jan-01 00:00 .bootstrap/pex/finders.py
-rw-r--r--  2.0 unx      776 b- defN 80-Jan-01 00:00 .bootstrap/pex/fingerprinted_distribution.py
-rw-r--r--  2.0 unx     7375 b- defN 80-Jan-01 00:00 .bootstrap/pex/hashing.py
-rw-r--r--  2.0 unx     1007 b- defN 80-Jan-01 00:00 .bootstrap/pex/inherit_path.py
-rw-r--r--  2.0 unx    54774 b- defN 80-Jan-01 00:00 .bootstrap/pex/interpreter.py
-rw-r--r--  2.0 unx    12280 b- defN 80-Jan-01 00:00 .bootstrap/pex/interpreter_constraints.py
-rw-r--r--  2.0 unx    20393 b- defN 80-Jan-01 00:00 .bootstrap/pex/jobs.py
-rw-r--r--  2.0 unx    11852 b- defN 80-Jan-01 00:00 .bootstrap/pex/layout.py
-rw-r--r--  2.0 unx     1710 b- defN 80-Jan-01 00:00 .bootstrap/pex/network_configuration.py
-rw-r--r--  2.0 unx     3747 b- defN 80-Jan-01 00:00 .bootstrap/pex/orderedset.py
-rw-r--r--  2.0 unx    28277 b- defN 80-Jan-01 00:00 .bootstrap/pex/pep_376.py
-rw-r--r--  2.0 unx     5719 b- defN 80-Jan-01 00:00 .bootstrap/pex/pep_425.py
-rw-r--r--  2.0 unx     2652 b- defN 80-Jan-01 00:00 .bootstrap/pex/pep_440.py
-rw-r--r--  2.0 unx     1120 b- defN 80-Jan-01 00:00 .bootstrap/pex/pep_503.py
-rw-r--r--  2.0 unx     5515 b- defN 80-Jan-01 00:00 .bootstrap/pex/pep_508.py
-rw-r--r--  2.0 unx    32708 b- defN 80-Jan-01 00:00 .bootstrap/pex/pex.py
-rw-r--r--  2.0 unx    29551 b- defN 80-Jan-01 00:00 .bootstrap/pex/pex_bootstrapper.py
-rw-r--r--  2.0 unx    33287 b- defN 80-Jan-01 00:00 .bootstrap/pex/pex_builder.py
-rw-r--r--  2.0 unx    20274 b- defN 80-Jan-01 00:00 .bootstrap/pex/pex_info.py
-rw-r--r--  2.0 unx     1137 b- defN 80-Jan-01 00:00 .bootstrap/pex/pex_warnings.py
-rw-r--r--  2.0 unx    13857 b- defN 80-Jan-01 00:00 .bootstrap/pex/platforms.py
-rw-r--r--  2.0 unx     3426 b- defN 80-Jan-01 00:00 .bootstrap/pex/pth.py
-rw-r--r--  2.0 unx     8432 b- defN 80-Jan-01 00:00 .bootstrap/pex/pyenv.py
-rw-r--r--  2.0 unx     3925 b- defN 80-Jan-01 00:00 .bootstrap/pex/rank.py
-rw-r--r--  2.0 unx    25101 b- defN 80-Jan-01 00:00 .bootstrap/pex/requirements.py
-rw-r--r--  2.0 unx    58037 b- defN 80-Jan-01 00:00 .bootstrap/pex/resolver.py
-rw-r--r--  2.0 unx     3114 b- defN 80-Jan-01 00:00 .bootstrap/pex/result.py
-rw-r--r--  2.0 unx    10441 b- defN 80-Jan-01 00:00 .bootstrap/pex/sh_boot.py
-rw-r--r--  2.0 unx     2091 b- defN 80-Jan-01 00:00 .bootstrap/pex/sorted_tuple.py
-rw-r--r--  2.0 unx    14206 b- defN 80-Jan-01 00:00 .bootstrap/pex/targets.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/third_party/
-rw-r--r--  2.0 unx    24952 b- defN 80-Jan-01 00:00 .bootstrap/pex/third_party/__init__.py
-rw-r--r--  2.0 unx     4614 b- defN 80-Jan-01 00:00 .bootstrap/pex/tracer.py
-rw-r--r--  2.0 unx     2538 b- defN 80-Jan-01 00:00 .bootstrap/pex/typing.py
-rw-r--r--  2.0 unx     5088 b- defN 80-Jan-01 00:00 .bootstrap/pex/util.py
-rw-r--r--  2.0 unx    32633 b- defN 80-Jan-01 00:00 .bootstrap/pex/variables.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/
-rw-r--r--  2.0 unx    14437 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/
-rw-r--r--  2.0 unx     1672 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/__init__.py
-rw-r--r--  2.0 unx    15100 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/__init__.pyi
-rw-r--r--  2.0 unx     4165 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_cmp.py
-rw-r--r--  2.0 unx      317 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_cmp.pyi
-rw-r--r--  2.0 unx     8396 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_compat.py
-rw-r--r--  2.0 unx      892 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_config.py
-rw-r--r--  2.0 unx    14753 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_funcs.py
-rw-r--r--  2.0 unx   102691 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_make.py
-rw-r--r--  2.0 unx     5728 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_next_gen.py
-rw-r--r--  2.0 unx     2194 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_version_info.py
-rw-r--r--  2.0 unx      209 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/_version_info.pyi
-rw-r--r--  2.0 unx     4078 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/converters.py
-rw-r--r--  2.0 unx      416 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/converters.pyi
-rw-r--r--  2.0 unx     1981 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/exceptions.py
-rw-r--r--  2.0 unx      539 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/exceptions.pyi
-rw-r--r--  2.0 unx     1124 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/filters.py
-rw-r--r--  2.0 unx      215 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/filters.pyi
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/py.typed
-rw-r--r--  2.0 unx     1466 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/setters.py
-rw-r--r--  2.0 unx      573 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/setters.pyi
-rw-r--r--  2.0 unx    15966 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/validators.py
-rw-r--r--  2.0 unx     2268 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/attrs/attr/validators.pyi
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/
-rw-r--r--  2.0 unx      726 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/__about__.py
-rw-r--r--  2.0 unx      562 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/__init__.py
-rw-r--r--  2.0 unx     1128 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/_compat.py
-rw-r--r--  2.0 unx     2022 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/_structures.py
-rw-r--r--  2.0 unx     1812 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/_typing.py
-rw-r--r--  2.0 unx     9741 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/markers.py
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/py.typed
-rw-r--r--  2.0 unx     5388 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/requirements.py
-rw-r--r--  2.0 unx    32208 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/specifiers.py
-rw-r--r--  2.0 unx    29561 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/tags.py
-rw-r--r--  2.0 unx     4385 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/utils.py
-rw-r--r--  2.0 unx    15974 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/packaging/version.py
-rw-r--r--  2.0 unx   273365 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_20_9/pyparsing.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/
-rw-r--r--  2.0 unx      661 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/__about__.py
-rw-r--r--  2.0 unx      497 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/__init__.py
-rw-r--r--  2.0 unx    11488 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/_manylinux.py
-rw-r--r--  2.0 unx     4378 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/_musllinux.py
-rw-r--r--  2.0 unx     1431 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/_structures.py
-rw-r--r--  2.0 unx     8756 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/markers.py
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/py.typed
-rw-r--r--  2.0 unx     4948 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/requirements.py
-rw-r--r--  2.0 unx    30110 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/specifiers.py
-rw-r--r--  2.0 unx    15699 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/tags.py
-rw-r--r--  2.0 unx     4200 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/utils.py
-rw-r--r--  2.0 unx    14665 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/packaging/version.py
-rw-r--r--  2.0 unx   273365 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_21_3/pyparsing.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/
-rw-r--r--  2.0 unx      501 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/__init__.py
-rw-r--r--  2.0 unx     3266 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/_elffile.py
-rw-r--r--  2.0 unx     8926 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/_manylinux.py
-rw-r--r--  2.0 unx     2524 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/_musllinux.py
-rw-r--r--  2.0 unx    10194 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/_parser.py
-rw-r--r--  2.0 unx     1431 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/_structures.py
-rw-r--r--  2.0 unx     5292 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/_tokenizer.py
-rw-r--r--  2.0 unx     8208 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/markers.py
-rw-r--r--  2.0 unx    16397 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/metadata.py
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/py.typed
-rw-r--r--  2.0 unx     3287 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/requirements.py
-rw-r--r--  2.0 unx    39206 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/specifiers.py
-rw-r--r--  2.0 unx    18106 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/tags.py
-rw-r--r--  2.0 unx     4355 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/utils.py
-rw-r--r--  2.0 unx    16326 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/packaging_23_1/packaging/version.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/
-rw-r--r--  2.0 unx   109513 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/__init__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/
-rw-r--r--  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/__init__.py
-rw-r--r--  2.0 unx    24701 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/appdirs.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/
-rw-r--r--  2.0 unx      720 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/__about__.py
-rw-r--r--  2.0 unx      513 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/__init__.py
-rw-r--r--  2.0 unx      860 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/_compat.py
-rw-r--r--  2.0 unx     1416 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/_structures.py
-rw-r--r--  2.0 unx     8769 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/markers.py
-rw-r--r--  2.0 unx     5044 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/requirements.py
-rw-r--r--  2.0 unx    28025 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/specifiers.py
-rw-r--r--  2.0 unx      421 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/utils.py
-rw-r--r--  2.0 unx    11556 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/packaging/version.py
-rw-r--r--  2.0 unx   232055 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/pyparsing.py
-rw-r--r--  2.0 unx    30098 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/_vendor/six.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/extern/
-rw-r--r--  2.0 unx     2498 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/extern/__init__.py
-rw-r--r--  2.0 unx      558 b- defN 80-Jan-01 00:00 .bootstrap/pex/vendor/_vendored/setuptools/pkg_resources/py31compat.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/
-rw-r--r--  2.0 unx      430 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/README.md
-rw-r--r--  2.0 unx      131 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/__init__.py
-rw-r--r--  2.0 unx      368 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/bin_path.py
-rw-r--r--  2.0 unx      376 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/install_scope.py
-rw-r--r--  2.0 unx    37100 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/installer.py
-rw-r--r--  2.0 unx      997 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/installer_configuration.py
-rw-r--r--  2.0 unx     3977 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/installer_options.py
-rw-r--r--  2.0 unx    17074 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/virtualenv.py
-rw-r--r--  2.0 unx   106996 b- defN 80-Jan-01 00:00 .bootstrap/pex/venv/virtualenv_16.7.12_py
-rw-r--r--  2.0 unx      156 b- defN 80-Jan-01 00:00 .bootstrap/pex/version.py
-rw-r--r--  2.0 unx     9643 b- defN 80-Jan-01 00:00 .bootstrap/pex/ziputils.py
-rw-r--r--  2.0 unx      758 b- defN 80-Jan-01 00:00 PEX-INFO
-rwxr-xr-x  2.0 unx     3774 b- defN 80-Jan-01 00:00 __main__.py
drwxr-xr-x  2.0 unx        0 b- defN 80-Jan-01 00:00 __pex__/
-rw-r--r--  2.0 unx     3747 b- defN 80-Jan-01 00:00 __pex__/__init__.py
170 files, 2357250 bytes uncompressed, 626649 bytes compressed:  73.4%
$ pex-tools cowsay.pex info -i2
{
  "bootstrap_hash": "a4d46434b329c38d5c4f9c98b08ec8ce9caf4fef",
  "build_properties": {
    "pex_version": "2.1.145"
  },
  "code_hash": "71a251766eb9b4ecb0da5ea67e0db028243c4ac4",
  "distributions": {
    "cowsay-5.0-py2.py3-none-any.whl": "9d9be34e631f7691e63cfbeb4b0f9add9b480da561e2b6d7421fc4e192a6d320"
  },
  "emit_warnings": true,
  "entry_point": "cowsay.main:cli",
  "ignore_errors": false,
  "includes_tools": false,
  "inherit_path": "false",
  "inject_args": [],
  "inject_env": {},
  "interpreter_constraints": [],
  "pex_hash": "9eda944200e43963fc910d18983232893448e5e1",
  "pex_path": "",
  "pex_paths": [],
  "requirements": [
    "cowsay"
  ],
  "strip_pex_env": true,
  "venv": false,
  "venv_bin_path": "false",
  "venv_copies": false,
  "venv_hermetic_scripts": true,
  "venv_site_packages_copies": false,
  "pex_root": "/home/jsirois/.pex"
}

Running it yields a failure since the cowsay wheel is excluded:

$ ./cowsay.pex Moo
Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/__main__.py", line 108, in <module>
    bootstrap_pex(__entry_point__, execute=__execute__, venv_dir=__venv_dir__)
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/pex_bootstrapper.py", line 627, in bootstrap_pex
    pex.PEX(entry_point).execute()
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/pex.py", line 560, in execute
    sys.exit(self._wrap_coverage(self._wrap_profiling, self._execute))
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/pex.py", line 467, in _wrap_coverage
    return runner(*args)
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/pex.py", line 498, in _wrap_profiling
    return runner(*args)
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/pex.py", line 603, in _execute
    return self.execute_entry(
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/pex.py", line 769, in execute_entry
    return self.execute_entry_point(entry_point)
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/pex.py", line 786, in execute_entry_point
    runner = entry_point.resolve()
  File "/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/dist_metadata.py", line 772, in resolve
    module = importlib.import_module(self.module)
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'cowsay'

But letting the PEX get cowsay from another venv works with warning:

$ PEX_EXTRA_SYS_PATH=/home/jsirois/3.10.venv/lib/python3.10/site-packages ./cowsay.pex Moo
/home/jsirois/.pex/unzipped_pexes/9eda944200e43963fc910d18983232893448e5e1/.bootstrap/pex/environment.py:570: PEXWarning: Found cowsay 5.0 at /home/jsirois/3.10.venv/lib/python3.10/site-packages with unexpected contents. Continuing...
Expected sha256 dir hash of:
  9d9be34e631f7691e63cfbeb4b0f9add9b480da561e2b6d7421fc4e192a6d320
Found:
  be484262b504788cddd888a18e73d5e5a2f099e793ce6ccc83a664884b73157e
  pex_warnings.warn(str(e))
  ___
| Moo |
  ===
   \
    \
      ^__^
      (oo)\_______
      (__)\       )\/\
          ||----w |
          ||     ||

I'll think a bit on how to boild this all down into a sane set of defaults and options to control all this.

@jsirois jsirois self-assigned this Sep 1, 2023
@jsirois
Copy link
Member

jsirois commented Oct 2, 2023

Ok, a conversation over in Pants slack has re-awakened the possibility of bloated 3rdparty deps and the need to sometimes say: I know better, exclude this because I know this dep is not actually used. The case in that discussion was langchain which unconditionally includes SQLAlchemy. SQLAlchemy is not small, ~3MB and has its own small set of default transitive deps. And, crucially, apparantly langchain exposes useful functionality that does not, in fact, need SQLAlchemy.

So I think there are two types of excludes to support:

  1. --exclude: both exclude the dep and all its transitive deps not reachable from the root requirements and do not try to resolve that dep at runtime
  2. --provided: exclude the dep and all its transitive deps not reachable from the root requirements but still resolve that dep at runtime.

Basically, case 1 is where you know the code goes unused at runtime - you know better. Case 2 is where you need the code, but its a waste to ship in the PEX because you know the PEX will only run in environments that provide that code in pre-installed packages.

Implementing case 1 solves both use cases and could ship before implementing case 2. You have to be very careful with it under use case 2 though setting up PEX_IGNORE_ERRORS and PEX_INHERIT_PATH or PEX_EXTRA_SYS_PATH just so to ensure all the excluded deps are actually available on the sys.path at runtime. There will be no fail-fast error and the app may run a while before ever importing the missing code.

Implementing case 2 is what I explored above with nice fail-fast behavior and no need for PEX_IGNORE_ERRORS.

jsirois added a commit to jsirois/pex that referenced this issue Nov 6, 2023
When excluding a requirement from a PEX, any resolved distribution
matching that requirement, as well as any of its transitive dependencies
not also needed by non-excluded requirements, are elided from the PEX.

At runtime these missing dependencies will not trigger boot resolve
errors, but they will cause errors if the modules they would have
provided are attempted to be imported. If the intention is to load the
modules from the runtime environment, then `--pex-inherit-path` /
`PEX_INHERIT_PATH` or `PEX_EXTRA_SYS_PATH` knobs must be used to allow
the PEX to see distributions installed in the runtime environment.
Clearly, you must know what you're doing to use this option and not
encounter runtime errors due to import errors. Be ware!

A forthcoming `--provided` option, with similar effects on the PEX
contents, will both automatically inherit any needed missing
distributions from the runtime environment and require all missing
distributions are found; failing fast if they are not.

Work towards pex-tool#2097.
jsirois added a commit that referenced this issue Nov 7, 2023
When excluding a requirement from a PEX, any resolved distribution
matching that requirement, as well as any of its transitive dependencies
not also needed by non-excluded requirements, are elided from the PEX.

At runtime these missing dependencies will not trigger boot resolve
errors, but they will cause errors if the modules they would have
provided are attempted to be imported. If the intention is to load the
modules from the runtime environment, then `--pex-inherit-path` /
`PEX_INHERIT_PATH` or `PEX_EXTRA_SYS_PATH` knobs must be used to allow
the PEX to see distributions installed in the runtime environment.
Clearly, you must know what you're doing to use this option and not
encounter runtime errors due to import errors. Be ware!

A forthcoming `--provided` option, with similar effects on the PEX
contents, will both automatically inherit any needed missing
distributions from the runtime environment and require all missing
distributions are found; failing fast if they are not.

Work towards #2097.
@jsirois
Copy link
Member

jsirois commented Nov 7, 2023

Ok, item 1. - --exclude is implemented and released in 2.1.151.
I'm keeping this open for the --provided bit.

@jsirois
Copy link
Member

jsirois commented May 14, 2024

I have not started work on --provided but I found a bug in --exclude over in #455 where excludes were being performed too late in the PEX build process, leading to spurious errors for valid use cases. In the course of fixing that, I found another bug in the current --exclude implementation, which accepts arbitrary --exclude requirements, like, say --exclude requests<2, but was not honoring the version specifier and instead excluding all versions of requests. That too is fixed. A PR is coming later today with these fixes which should allow #455 to be closed.

@AlexTereshenkov, I'm not sure if you took my advice here: #455 (comment), but, if not, you should be able to use exhaustive excludes if that is somehow easier for you.

@jsirois
Copy link
Member

jsirois commented May 15, 2024

Still some issues to work through on that PR #2409.

I may not get back to this until the 29th or so.

@TonySherman
Copy link

I'm commenting here since this is still open and you have #2409 in progress. I can open a new issue if preferred though. I tried using the --exclude flag and noticed that Pex throws an error for the missing dependency:

Failed to resolve requirements from PEX environment @ /private/var/folders/64/9_yprtsn1qxdw5ykxkxrfd840000gn/T/pants-sandbox-rNeYgQ/faas_repository.pex.
Needed cp39-cp39-manylinux_2_26_x86_64 compatible dependencies for:
 1: boto3<2.0.0,>=1.9.201
    Required by:
      redshift-connector 2.1.1
    But this pex had no ProjectName(raw='boto3', validated=False, normalized='boto3') distributions.

I can get around this by adding --ignore-errors but if I'm explicitly excluding a dep, it doesn't seem like that should be an error.

@jsirois
Copy link
Member

jsirois commented May 24, 2024

@TonySherman can you provide more context for your case? Notably, it seems to involve Pants and, fwict maybe involves Pants performing a subset of a PEX repository?

For example, creating a PEX using exclude works fine afaict:

# ~
:; pex redshift-connector==2.1.1 --exclude boto3 -o exclude.pex

# ~ took 5s
:; ./exclude.pex -c 'import redshift_connector; print(redshift_connector.__file__)'
/home/jsirois/.pex/installed_wheels/540c4674859bb2e9668abbcfb64d346cff9d11ed2707533efd28717dbff523c0/redshift_connector-2.1.1-py3-none-any.whl/redshift_connector/__init__.py

It's only when you try to use code that needs the excluded dep, that you hit issues - as you should:

# ~
:; ./exclude.pex -c 'from redshift_connector.iam_helper import IamHelper; IamHelper.get_boto3_redshift_client(None, None)'
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/__main__.py", line 106, in <module>
    bootstrap_pex(__entry_point__, execute=__execute__, venv_dir=__venv_dir__)
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex_bootstrapper.py", line 627, in bootstrap_pex
    pex.PEX(entry_point).execute()
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 562, in execute
    sys.exit(self._wrap_coverage(self._wrap_profiling, self._execute))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 469, in _wrap_coverage
    return runner(*args)
           ^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 500, in _wrap_profiling
    return runner(*args)
           ^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 586, in _execute
    return self.execute_interpreter()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 640, in execute_interpreter
    return self.execute_content("-c <cmd>", content, argv0="-c")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 784, in execute_content
    return cls.execute_ast(name, program, argv0=argv0)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 802, in execute_ast
    exec_function(program, globals_map)
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/compatibility.py", line 110, in exec_function
    exec (ast, globals_map, locals_map)
  File "-c <cmd>", line 1, in <module>
  File "/home/jsirois/.pex/installed_wheels/540c4674859bb2e9668abbcfb64d346cff9d11ed2707533efd28717dbff523c0/redshift_connector-2.1.1-py3-none-any.whl/redshift_connector/iam_helper.py", line 304, in get_boto3_redshift_client
    import boto3  # type: ignore
    ^^^^^^^^^^^^
ModuleNotFoundError: No module named 'boto3'

And, which you can correct by using either PEX_INHERIT_PATH / --inherit-path or PEX_EXTRA_SYS_PATH (N.B. still a failure since I provide bogus (None, None) parameters to the call, but further along after the boto3 import happens):

# ~
x=1 :; head -1 exclude.pex
#!/usr/bin/env python3.12

# ~
:; python3.12 -mvenv boto3.venv

# ~
:; boto3.venv/bin/pip install "boto3<2.0.0,>=1.9.201"
Collecting boto3<2.0.0,>=1.9.201
  Downloading boto3-1.34.112-py3-none-any.whl.metadata (6.6 kB)
Collecting botocore<1.35.0,>=1.34.112 (from boto3<2.0.0,>=1.9.201)
  Downloading botocore-1.34.112-py3-none-any.whl.metadata (5.7 kB)
Collecting jmespath<2.0.0,>=0.7.1 (from boto3<2.0.0,>=1.9.201)
  Downloading jmespath-1.0.1-py3-none-any.whl.metadata (7.6 kB)
Collecting s3transfer<0.11.0,>=0.10.0 (from boto3<2.0.0,>=1.9.201)
  Downloading s3transfer-0.10.1-py3-none-any.whl.metadata (1.7 kB)
Collecting python-dateutil<3.0.0,>=2.1 (from botocore<1.35.0,>=1.34.112->boto3<2.0.0,>=1.9.201)
  Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB)
Collecting urllib3!=2.2.0,<3,>=1.25.4 (from botocore<1.35.0,>=1.34.112->boto3<2.0.0,>=1.9.201)
  Using cached urllib3-2.2.1-py3-none-any.whl.metadata (6.4 kB)
Collecting six>=1.5 (from python-dateutil<3.0.0,>=2.1->botocore<1.35.0,>=1.34.112->boto3<2.0.0,>=1.9.201)
  Using cached six-1.16.0-py2.py3-none-any.whl.metadata (1.8 kB)
Downloading boto3-1.34.112-py3-none-any.whl (139 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 139.3/139.3 kB 1.3 MB/s eta 0:00:00
Downloading botocore-1.34.112-py3-none-any.whl (12.3 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.3/12.3 MB 765.7 kB/s eta 0:00:00
Downloading jmespath-1.0.1-py3-none-any.whl (20 kB)
Downloading s3transfer-0.10.1-py3-none-any.whl (82 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 82.2/82.2 kB 1.0 MB/s eta 0:00:00
Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 229.9/229.9 kB 1.0 MB/s eta 0:00:00
Using cached urllib3-2.2.1-py3-none-any.whl (121 kB)
Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: urllib3, six, jmespath, python-dateutil, botocore, s3transfer, boto3
Successfully installed boto3-1.34.112 botocore-1.34.112 jmespath-1.0.1 python-dateutil-2.9.0.post0 s3transfer-0.10.1 six-1.16.0 urllib3-2.2.1

# ~ took 20s
:; PEX_INHERIT_PATH=fallback boto3.venv/bin/python ./exclude.pex -c 'from redshift_connector.iam_helper import IamHelper; IamHelper.get_boto3_redshift_client(None, None)'
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/__main__.py", line 106, in <module>
    bootstrap_pex(__entry_point__, execute=__execute__, venv_dir=__venv_dir__)
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex_bootstrapper.py", line 627, in bootstrap_pex
    pex.PEX(entry_point).execute()
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 562, in execute
    sys.exit(self._wrap_coverage(self._wrap_profiling, self._execute))
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 469, in _wrap_coverage
    return runner(*args)
           ^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 500, in _wrap_profiling
    return runner(*args)
           ^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 586, in _execute
    return self.execute_interpreter()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 640, in execute_interpreter
    return self.execute_content("-c <cmd>", content, argv0="-c")
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 784, in execute_content
    return cls.execute_ast(name, program, argv0=argv0)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/pex.py", line 802, in execute_ast
    exec_function(program, globals_map)
  File "/home/jsirois/.pex/unzipped_pexes/d6b32f2dd03b2977da9d2671a0e6e0405500d356/.bootstrap/pex/compatibility.py", line 110, in exec_function
    exec (ast, globals_map, locals_map)
  File "-c <cmd>", line 1, in <module>
  File "/home/jsirois/.pex/installed_wheels/540c4674859bb2e9668abbcfb64d346cff9d11ed2707533efd28717dbff523c0/redshift_connector-2.1.1-py3-none-any.whl/redshift_connector/iam_helper.py", line 308, in get_boto3_redshift_client
    "service_name": "redshift-serverless" if info._is_serverless else "redshift"
                                             ^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute '_is_serverless'

@jsirois
Copy link
Member

jsirois commented May 24, 2024

@TonySherman actually a PEX repository subset works fine. Using the exclude.pex from above:

# ~
:; pex --pex-repository exclude.pex requests -o requests-subset.pex

# ~
:; ./requests-subset.pex -c 'import requests; print(requests.__file__)'
/home/jsirois/.pex/installed_wheels/fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c/requests-2.32.2-py3-none-any.whl/requests/__init__.py

# ~
:; pex-tools ./requests-subset.pex repository info
requests 2.32.2 /home/jsirois/.pex/installed_wheels/fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c/requests-2.32.2-py3-none-any.whl
charset-normalizer 3.3.2 /home/jsirois/.pex/installed_wheels/90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
idna 3.7 /home/jsirois/.pex/installed_wheels/82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0/idna-3.7-py3-none-any.whl
urllib3 2.2.1 /home/jsirois/.pex/installed_wheels/450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d/urllib3-2.2.1-py3-none-any.whl
certifi 2024.2.2 /home/jsirois/.pex/installed_wheels/dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1/certifi-2024.2.2-py3-none-any.whl

So I'll need very detailed information to flesh out your Pants error message. In particular the Pex command line it runs that leads to that error. The Pex version in use would be helpful too.

@TonySherman
Copy link

Sorry about the lack of information. I recently worked on pantsbuild/pants#20939 which passes additional arguments to the PexFromTargetsRequest in Pants. I will have to do some digging into the exact command that builds out and gets passed to pex.

My use case is building aws lambda function zips which don't need to have boto3/botocore in the package because they are in the runtime.

@jsirois
Copy link
Member

jsirois commented Jun 10, 2024

I'm going to let #2409 close this issue. I've broken out the --provided idea to #2426.

@jsirois
Copy link
Member

jsirois commented Jun 12, 2024

Alright. The now polished --exclude is available in 2.4.0: https://github.com/pex-tool/pex/releases/tag/v2.4.0

This was referenced Aug 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants