Repository: pex-tool/pex

Issue:
PEX builds broken on Big Sur after recent update 
I recently got a new work laptop with Big Sur installed, and I'm seeing a new error when building PEX files locally:

```
$ /Users/jlewis/nerdwallet/indy/build/venv/indy_macosx-11-x86-64_cp3.7/bin/python /Users/jlewis/nerdwallet/indy/build/venv/indy_macosx-11-x86-64_cp3.7/bin/pex --disable-cache --no-pypi --index=https://artifactory.nerdwallet.io/artifactory/api/pypi/pypi/simple/ --no-transitive --output-file=/Users/jlewis/nerdwallet/indy/build/dist/indy/1.1.119/pex/indy.pex --pre --preamble-file=/Users/jlewis/nerdwallet/indy/build/pex_preamble.py --python=/Users/jlewis/nerdwallet/indy/build/venv/indy_macosx-11-x86-64_cp3.7/bin/python --requirement=/Users/jlewis/nerdwallet/indy/requirements.txt --resolver-version=pip-2020-resolver --platform=linux-x86_64-cp-37-cp37m --platform=macosx-10.13-x86_64-cp-37-cp37m --no-emit-warnings --venv --script=indy /Users/jlewis/nerdwallet/indy/build/dist/indy/1.1.119/wheel/indy-1.1.119-py3-none-any.whl
Failed to spawn a job for DistributionTarget(platform=Platform(platform='linux_x86_64', impl='cp', version='37', abi='cp37m')): 'int' object has no attribute 'split'
```

I dug into the PEX code, and the underlying issue is a mistaken assumption about the possible values of `sysconfig.get_config_var("MACOSX_DEPLOYMENT_TARGET")`. Currently, `create_isolated_cmd` assumes that is a string: https://github.com/pantsbuild/pex/blob/3a5f1ecd486ba049b58954d2b9ec48dd7e6d1a5c/pex/interpreter.py#L1089

However, I've verified locally that `sysconfig.get_config_var("MACOSX_DEPLOYMENT_TARGET")` can return an int:
```
Python 3.7.10 (default, Feb 27 2021, 02:19:57) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.20.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import sysconfig

In [2]: sysconfig.get_config_var("MACOSX_DEPLOYMENT_TARGET")
Out[2]: 11
```

You can see a similar issue reported to `numpy`: [Mac OS X Big Sur: sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') can return an int, but a str is required](https://github.com/numpy/numpy/issues/18093)

The fix _should_ be as simple as coercing to string after this line: https://github.com/pantsbuild/pex/blob/3a5f1ecd486ba049b58954d2b9ec48dd7e6d1a5c/pex/interpreter.py#L94
```
        configured_macosx_deployment_target = configured_macosx_deployment_target and str(configured_macosx_deployment_target)
```


Discussion:
@luislew I think you've fully sussed this all out. Thanks for digging.

Are you up for contributing the fix? I don't have access to macOS for experimentation and repro on things like this, so it's ideal to get a fix from someone who can prove the fix works directly.

Resolving patch:
diff --git a/pex/interpreter.py b/pex/interpreter.py
--- a/pex/interpreter.py
+++ b/pex/interpreter.py
@@ -75,6 +75,16 @@ class UnknownRequirement(Error):
         "cp": "CPython",
     }
 
+    @staticmethod
+    def _normalize_macosx_deployment_target(value):
+        # type: (Any) -> Optional[str]
+
+        # N.B.: Sometimes MACOSX_DEPLOYMENT_TARGET can be configured as a float.
+        # See: https://github.com/pantsbuild/pex/issues/1337
+        if value is None:
+            return None
+        return str(value)
+
     @classmethod
     def get(cls, binary=None):
         # type: (Optional[str]) -> PythonIdentity
@@ -91,7 +101,10 @@ def get(cls, binary=None):
 
         supported_tags = tuple(tags.sys_tags())
         preferred_tag = supported_tags[0]
-        configured_macosx_deployment_target = sysconfig.get_config_var("MACOSX_DEPLOYMENT_TARGET")
+
+        configured_macosx_deployment_target = cls._normalize_macosx_deployment_target(
+            sysconfig.get_config_var("MACOSX_DEPLOYMENT_TARGET")
+        )
 
         return cls(
             binary=binary or sys.executable,
@@ -109,7 +122,7 @@ def get(cls, binary=None):
             version=sys.version_info[:3],
             supported_tags=supported_tags,
             env_markers=markers.default_environment(),
-            configured_macosx_deployment_target=configured_macosx_deployment_target or None,
+            configured_macosx_deployment_target=configured_macosx_deployment_target,
         )
 
     @classmethod
@@ -125,7 +138,17 @@ def iter_tags():
             for (interpreter, abi, platform) in supported_tags:
                 yield tags.Tag(interpreter=interpreter, abi=abi, platform=platform)
 
-        return cls(supported_tags=iter_tags(), **values)
+        # N.B.: Old encoded identities may have numeric values; so we support these and convert
+        # back to strings here as needed. See: https://github.com/pantsbuild/pex/issues/1337
+        configured_macosx_deployment_target = cls._normalize_macosx_deployment_target(
+            values.pop("configured_macosx_deployment_target")
+        )
+
+        return cls(
+            supported_tags=iter_tags(),
+            configured_macosx_deployment_target=configured_macosx_deployment_target,
+            **values
+        )
 
     @classmethod
     def _find_interpreter_name(cls, python_tag):


Test patch: