Repository: pex-tool/pex

Issue:
The interpreter we run Pex with affects the resolve
```
python3.6 -m pex.cli lock create --style=universal --interpreter-constraint 'CPython<3.9,>=3.8' 'aioconsole' 
```

Fails with `ERROR: Package 'aioconsole' requires a different Python: 3.6.6 not in '>=3.7'` . 

Running with python3.7 succeeds.

Removing `--style=universal` succeeds.

Note: `aioconsole` only publishes an sdist. 


Discussion:
Putting debugging/learning notes here, even though they are likely obvious to @jsirois, or plain wrong.
So this `aioconsole` is sdist-only, and we run its `setup.py` in the python 3.6 we use to run pex itself, rather than in an interpreter compatible with the explicit `--interpreter-constraint`.
Presumably, with verbosity turned up, it will be revealed this happens in the resolve post-processing phase where sdists are built into wheels to get `Requires-*` metadata for the lock. If so, this was just an oversight and, when an IC is present in a universal lock Pex should pick (demand) a local interpreter that fits the IC to do the post-processing with.
This is the full output:

```
$ python3.6 -m pex.cli lock create -vvvvvvvvv   --style=universal --interpreter-constraint 'CPython<3.9,>=3.8' 'aiomonitor<0.5.0,>=0.4.5' 
pex: Resolving for:
pex: Spawning a maximum of 8 parallel jobs to process:
  /Users/benjyw/src/pex/venv/bin/python3.6
pex: Hashing pex: 70.6ms
pex: Isolating pex: 0.1ms
pex: Calculating compatible python versions for ('<3.9,>=3.8',): 11.9ms
    Running command python setup.py egg_info
    running egg_info
    creating /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info
    writing /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info/PKG-INFO
    writing dependency_links to /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info/dependency_links.txt
    writing entry points to /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info/entry_points.txt
    writing top-level names to /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info/top_level.txt
    writing manifest file '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info/SOURCES.txt'
    reading manifest file '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info/SOURCES.txt'
    writing manifest file '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-4jkpcfae/aioconsole.egg-info/SOURCES.txt'
pex: Resolving for:
pex: Resolving for:/pex/venv/bin/python3.6 :: Building 1 source distribution to gather metadata for lock.
  /Users/benjyw/src/pex/venv/bin/python3.6 :: Building 1 source distribution to gather metadata for lock. :: Building distributions for:
  BuildRequest(target=LocalInterpreter(id='Users.benjyw.src.pex.venv.bin.python3.6', platform=Platform(platform='macosx_10_16_x86_64', impl='cp', version='3.6.6', version_info=(3, 6, 6), abi='cp36m'), marker_environment=MarkerEnvironment(implementation_name='cpython', implementation_version='3.6.6', os_name='posix', platform_machine='x86_64', platform_python_implementation='CPython', platform_release='21.4.0', platform_system='Darwin', platform_version='Darwin Kernel Version 21.4.0: Fri Mar 18 00:45:05 PDT 2022; root:xnu-8020.101.4~15/RELEASE_X86_64', python_full_version='3.6.6', python_version='3.6', sys_platform='darwin'), interpreter=PythonInterpreter('/Users/benjyw/src/pex/venv/bin/python3.6', PythonIdentity('/Users/benjyw/src/pex/venv/bin/python3.6', 'cp36', 'cp36m', 'macosx_10_16_x86_64', (3, 6, 6)))), source_path='/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz', fingerprint='0c0acb66b4e72d6606cpex: Building /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz to /Users/benjyw/.pex/built_wheels/sdists/aioconsole-0.4.1.tar.gz/0c0acb66b4e72d6606c9fa14ac9eb001a222c37c885b8fbdf65f41824cfa855f/cp36-cp36m                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
pex: Spawning a maximum of 8 parallel jobs to process:
  BuildRequest(target=LocalInterpreter(id='Users.benjyw.src.pex.venv.bin.python3.6', platform=Platform(platform='macosx_10_16_x86_64', impl='cp', version='3.6.6', version_info=(3, 6, 6), abi='cp36m'), marker_environment=MarkerEnvironment(implementation_name='cpython', implementation_version='3.6.6', os_name='posix', platform_machine='x86_64', platform_python_implementation='CPython', platform_release='21.4.0', platform_system='Darwin', platform_version='Darwin Kernel Version 21.4.0: Fri Mar 18 00:45:05 PDT 2022; root:xnu-8020.101.4~15/RELEASE_X86_64', python_full_version='3.6.6', python_version='3.6', sys_platform='darwin'), interpreter=PythonInterpreter('/Users/benjyw/src/pex/venv/bin/python3.6', PythonIdentity('/Users/benjyw/src/pex/venv/bin/python3.6', 'cp36', 'cp36m', 'macosx_10_16_x86_64', (3, 6, 6)))), source_path='/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz', fingerprint='0c0acb66b4e72d6606c9fa14ac9eb001a222c37c885b8fbdf65f41824cfa855f')
Created temporary directory: /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-ephem-wheel-cache-e8uljkdl
Created temporary directory: /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-tracker-nd10d19v
Initialized build tracking at /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-tracker-nd10d19v
Created build tracker: /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-tracker-nd10d19v
Entered build tracker: /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-tracker-nd10d19v
Created temporary directory: /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-wheel-33xx7m3h
Processing /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz
  Created temporary directory: /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-build-n_2udc6a
  Added file:///private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz to build tracker '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-tracker-nd10d19v'
    Running setup.py (path:/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-build-n_2udc6a/setup.py) egg_info for package from file:///private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz
    Created temporary directory: /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k
    Running command python setup.py egg_info
    running egg_info
    creating /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info
    writing /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info/PKG-INFO
    writing dependency_links to /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info/dependency_links.txt
    writing entry points to /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info/entry_points.txt
    writing top-level names to /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info/top_level.txt
    writing manifest file '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info/SOURCES.txt'
    reading manifest file '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info/SOURCES.txt'
    writing manifest file '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-pip-egg-info-niz5a_2k/aioconsole.egg-info/SOURCES.txt'
  Source in /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-build-n_2udc6a has version 0.4.1, which satisfies requirement aioconsole==0.4.1 from file:///private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz
  Removed aioconsole==0.4.1 from file:///private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz from build tracker '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-tracker-nd10d19v'
ERROR: Package 'aioconsole' requires a different Python: 3.6.6 not in '>=3.7'
Exception information:
Traceback (most recent call last):
  File "/Users/benjyw/.pex/venvs/s/a1a3f642/venv/lib/python3.6/site-packages/pip/_internal/cli/base_command.py", line 223, in _main
    status = self.run(options, args)
  File "/Users/benjyw/.pex/venvs/s/a1a3f642/venv/lib/python3.6/site-packages/pip/_internal/cli/req_command.py", line 180, in wrapper
    return func(self, options, args)
  File "/Users/benjyw/.pex/venvs/s/a1a3f642/venv/lib/python3.6/site-packages/pip/_internal/commands/wheel.py", line 163, in run
    reqs, check_supported_wheels=True
  File "/Users/benjyw/.pex/venvs/s/a1a3f642/venv/lib/python3.6/site-packages/pip/_internal/resolution/legacy/resolver.py", line 180, in resolve
    discovered_reqs.extend(self._resolve_one(requirement_set, req))
  File "/Users/benjyw/.pex/venvs/s/a1a3f642/venv/lib/python3.6/site-packages/pip/_internal/resolution/legacy/resolver.py", line 390, in _resolve_one
    ignore_requires_python=self.ignore_requires_python,
  File "/Users/benjyw/.pex/venvs/s/a1a3f642/venv/lib/python3.6/site-packages/pip/_internal/resolution/legacy/resolver.py", line 101, in _check_dist_requires_python
    dist.project_name, version, requires_python,
pip._internal.exceptions.UnsupportedPythonVersion: Package 'aioconsole' requires a different Python: 3.6.6 not in '>=3.7'
Removed build tracker: '/private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/pip-req-tracker-nd10d19v'
pid 91261 -> /Users/benjyw/.pex/venvs/a79216b84ff96b998dbc88a7f69324653f7b73b2/ca86241134ff9c9261cc49ffd61bf96e7844a4a8/pex --disable-pip-version-check --no-python-version-warning --exists-action a --use-deprecated legacy-resolver --isolated -vvv --cache-dir /Users/benjyw/.pex wheel --no-deps --wheel-dir /Users/benjyw/.pex/built_wheels/sdists/aioconsole-0.4.1.tar.gz/0c0acb66b4e72d6606c9fa14ac9eb001a222c37c885b8fbdf65f41824cfa855f/cp36-cp36m.09e668179bdd49b29524ebaf4a0cbe8c /private/var/folders/q4/pv4jnnm944b_ywr3tnp_b1300000gn/T/tmpwrrepd09/Users.benjyw.src.pex.venv.bin.python3.6/aioconsole-0.4.1.tar.gz --index-url https://pypi.org/simple --retries 5 --timeout 15 exited with 1 and STDERR:
None
```
So yeah, this is happening when processing the BuildRequest.

Resolving patch:
diff --git a/pex/cli/commands/lock.py b/pex/cli/commands/lock.py
--- a/pex/cli/commands/lock.py
+++ b/pex/cli/commands/lock.py
@@ -19,6 +19,7 @@
 from pex.resolve.lockfile import Lockfile, create, json_codec
 from pex.resolve.lockfile.updater import LockUpdater, ResolveUpdateRequest
 from pex.resolve.resolver_options import parse_lockfile
+from pex.resolve.target_configuration import InterpreterConstraintsNotSatisfied
 from pex.result import Error, Ok, Result, try_
 from pex.sorted_tuple import SortedTuple
 from pex.targets import Target, Targets
@@ -244,7 +245,20 @@ def _create(self):
                     for interpreter_constraint in target_configuration.interpreter_constraints
                 ),
             )
-            targets = Targets()
+            if target_configuration.interpreter_constraints:
+                try:
+                    interpreter = next(
+                        target_configuration.interpreter_configuration.iter_interpreters()
+                    )
+                except InterpreterConstraintsNotSatisfied as e:
+                    return Error(
+                        "When creating a universal lock with an --interpreter-constraint, an "
+                        "interpreter matching the constraint must be found on the local system but "
+                        "none was: {err}".format(err=e)
+                    )
+                targets = Targets(interpreters=(interpreter,))
+            else:
+                targets = Targets()
         else:
             lock_configuration = LockConfiguration(style=self.options.style)
             targets = target_configuration.resolve_targets()
diff --git a/pex/resolve/target_configuration.py b/pex/resolve/target_configuration.py
--- a/pex/resolve/target_configuration.py
+++ b/pex/resolve/target_configuration.py
@@ -18,7 +18,7 @@
 from pex.variables import ENV
 
 if TYPE_CHECKING:
-    from typing import Optional, Tuple
+    from typing import Iterator, Optional, Tuple
 
     import attr  # vendor:skip
 else:
@@ -37,16 +37,8 @@ def python_path(self):
         # TODO(#1075): stop looking at PEX_PYTHON_PATH and solely consult the `--python-path` flag.
         return self._python_path or ENV.PEX_PYTHON_PATH
 
-    def resolve_interpreters(self):
-        # type: () -> OrderedSet[PythonInterpreter]
-        """Resolves the interpreters satisfying the interpreter configuration.
-
-        :raise: :class:`InterpreterNotFound` specific --python interpreters were requested but could
-            not be found.
-        :raise: :class:`InterpreterConstraintsNotSatisfied` if --interpreter-constraint were
-            specified but no conforming interpreters could be found.
-        """
-        interpreters = OrderedSet()  # type: OrderedSet[PythonInterpreter]
+    def iter_interpreters(self):
+        # type: () -> Iterator[PythonInterpreter]
 
         if self.pythons:
             with TRACER.timed("Resolving interpreters", V=2):
@@ -55,32 +47,41 @@ def to_python_interpreter(full_path_or_basename):
                     if os.path.isfile(full_path_or_basename):
                         return PythonInterpreter.from_binary(full_path_or_basename)
                     else:
-                        interp = PythonInterpreter.from_env(
+                        interpreter = PythonInterpreter.from_env(
                             full_path_or_basename, paths=parse_path(self.python_path)
                         )
-                        if interp is None:
+                        if interpreter is None:
                             raise InterpreterNotFound(
                                 "Failed to find interpreter: {}".format(full_path_or_basename)
                             )
-                        return interp
+                        return interpreter
 
-                interpreters.update(to_python_interpreter(interp) for interp in self.pythons)
+                for python in self.pythons:
+                    yield to_python_interpreter(python)
 
         if self.interpreter_constraints:
             with TRACER.timed("Resolving interpreters", V=2):
                 try:
-                    interpreters.update(
-                        iter_compatible_interpreters(
-                            path=self.python_path,
-                            interpreter_constraints=self.interpreter_constraints,
-                        )
-                    )
+                    for interp in iter_compatible_interpreters(
+                        path=self.python_path,
+                        interpreter_constraints=self.interpreter_constraints,
+                    ):
+                        yield interp
                 except UnsatisfiableInterpreterConstraintsError as e:
                     raise InterpreterConstraintsNotSatisfied(
                         e.create_message("Could not find a compatible interpreter.")
                     )
 
-        return interpreters
+    def resolve_interpreters(self):
+        # type: () -> OrderedSet[PythonInterpreter]
+        """Resolves the interpreters satisfying the interpreter configuration.
+
+        :raise: :class:`InterpreterNotFound` specific --python interpreters were requested but could
+            not be found.
+        :raise: :class:`InterpreterConstraintsNotSatisfied` if --interpreter-constraint were
+            specified but no conforming interpreters could be found.
+        """
+        return OrderedSet(self.iter_interpreters())
 
 
 class TargetConfigurationError(Exception):
@@ -125,9 +126,7 @@ def resolve_targets(self):
         :raise: :class:`InterpreterConstraintsNotSatisfied` if --interpreter-constraint were
             specified but no conforming interpreters could be found.
         """
-        interpreters = OrderedSet(
-            self.interpreter_configuration.resolve_interpreters()
-        )  # type: OrderedSet[PythonInterpreter]
+        interpreters = self.interpreter_configuration.resolve_interpreters()
 
         all_platforms = (
             OrderedDict()


Test patch:
diff --git a/tests/integration/cli/commands/test_issue_1667.py b/tests/integration/cli/commands/test_issue_1667.py
--- a/tests/integration/cli/commands/test_issue_1667.py
+++ b/tests/integration/cli/commands/test_issue_1667.py
@@ -44,6 +44,8 @@ def test_interpreter_constraints_range_coverage(
         "pip-2020-resolver",
         "--interpreter-constraint",
         ">=3.7,<3.11",
+        "--python-path",
+        py37.binary,
         "ipython",
         "-o",
         lock,
diff --git a/tests/integration/cli/commands/test_issue_1711.py b/tests/integration/cli/commands/test_issue_1711.py
--- a/tests/integration/cli/commands/test_issue_1711.py
+++ b/tests/integration/cli/commands/test_issue_1711.py
@@ -5,6 +5,7 @@
 
 from pex.cli.testing import run_pex3
 from pex.compatibility import PY3
+from pex.interpreter import PythonInterpreter
 from pex.pep_440 import Version
 from pex.pep_503 import ProjectName
 from pex.resolve import lockfile
@@ -28,8 +29,11 @@ def pypi_artifact(
     )
 
 
-def test_backtrack_links_preserved(tmpdir):
-    # type: (Any) -> None
+def test_backtrack_links_preserved(
+    tmpdir,  # type: Any
+    py37,  # type: PythonInterpreter
+):
+    # type: (...) -> None
 
     lock = os.path.join(str(tmpdir), "lock")
     create_lock_args = [
@@ -41,6 +45,8 @@ def test_backtrack_links_preserved(tmpdir):
         "universal",
         "--interpreter-constraint",
         ">=3.7,<3.10",
+        "--python-path",
+        py37.binary,
         "psutil",
         "psutil<5.5",  # force a back-track
         "-o",
diff --git a/tests/integration/cli/commands/test_issue_1734.py b/tests/integration/cli/commands/test_issue_1734.py
new file mode 100644
--- /dev/null
+++ b/tests/integration/cli/commands/test_issue_1734.py
@@ -0,0 +1,107 @@
+# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
+# Licensed under the Apache License, Version 2.0 (see LICENSE).
+
+import os
+import subprocess
+
+from pex.cli.testing import run_pex3
+from pex.interpreter import PythonInterpreter
+from pex.testing import run_pex_command
+from pex.typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Any
+
+
+def test_lock_create_sdist_requires_python_different_from_current(
+    tmpdir,  # type: Any
+    py27,  # type: PythonInterpreter
+    py37,  # type: PythonInterpreter
+    py310,  # type: PythonInterpreter
+):
+    # type: (...) -> None
+
+    lock = os.path.join(str(tmpdir), "lock")
+    create_lock_args = [
+        "lock",
+        "create",
+        "--resolver-version",
+        "pip-2020-resolver",
+        "--style",
+        "universal",
+        "--interpreter-constraint",
+        "CPython<3.11,>=3.8",
+        "--python-path",
+        ":".join(interp.binary for interp in (py27, py37, py310)),
+        "aioconsole==0.4.1",
+        "-o",
+        lock,
+        "--indent",
+        "2",
+    ]
+
+    # 1st prove this does the wrong thing on prior broken versions of Pex.
+    result = run_pex_command(
+        args=["pex==2.1.82", "-c", "pex3", "--"] + create_lock_args,
+        python=py27.binary,
+        quiet=True,
+    )
+    result.assert_failure()
+    assert (
+        "ERROR: Package 'aioconsole' requires a different Python: {pyver} not in '>=3.7'".format(
+            pyver=py27.identity.version_str
+        )
+        == result.error.splitlines()[0]
+    )
+
+    # Now show it currently works.
+    subprocess.check_call(args=[py27.binary, "-m", "pex.cli"] + create_lock_args)
+    run_pex_command(
+        args=["--lock", lock, "--", "-c", "import aioconsole"],
+        python=py310.binary,
+    ).assert_success()
+
+
+def test_lock_create_universal_interpreter_constraint_unsatisfiable(
+    tmpdir,  # type: Any
+    py27,  # type: PythonInterpreter
+    py37,  # type: PythonInterpreter
+):
+    # type: (...) -> None
+
+    lock = os.path.join(str(tmpdir), "lock")
+    result = run_pex3(
+        "lock",
+        "create",
+        "--resolver-version",
+        "pip-2020-resolver",
+        "--style",
+        "universal",
+        "--interpreter-constraint",
+        "CPython<3.11,>=3.8",
+        "--python-path",
+        ":".join(interp.binary for interp in (py27, py37)),
+        "aioconsole==0.4.1",
+        "-o",
+        lock,
+        "--indent",
+        "2",
+    )
+    result.assert_failure()
+    assert (
+        "When creating a universal lock with an --interpreter-constraint, an interpreter matching "
+        "the constraint must be found on the local system but none was: Could not find a "
+        "compatible interpreter.\n"
+        "\n"
+        "Examined the following interpreters:\n"
+        "1.) {py27_path} {py27_req}\n"
+        "2.) {py37_path} {py37_req}\n"
+        "\n"
+        "No interpreter compatible with the requested constraints was found:\n"
+        "  Version matches CPython<3.11,>=3.8\n".format(
+            py27_path=py27.binary,
+            py27_req=py27.identity.requirement,
+            py37_path=py37.binary,
+            py37_req=py37.identity.requirement,
+        )
+    ) == result.error
diff --git a/tests/integration/cli/commands/test_lock.py b/tests/integration/cli/commands/test_lock.py
--- a/tests/integration/cli/commands/test_lock.py
+++ b/tests/integration/cli/commands/test_lock.py
@@ -84,18 +84,21 @@ def test_create(tmpdir):
     )
 
 
-def test_create_style(tmpdir):
-    # type: (Any) -> None
+def test_create_style(
+    tmpdir,  # type: Any
+    py310,  # type: str
+):
+    # type: (...) -> None
 
     pex_root = os.path.join(str(tmpdir), "pex_root")
 
     def create_lock(
         style,  # type: str
-        interpreter_constraint=None,  # type: Optional[str]
+        *additional_args  # type: str
     ):
         # type: (...) -> LockedRequirement
         lock_file = os.path.join(str(tmpdir), "{}.lock".format(style))
-        args = [
+        args = (
             "lock",
             "create",
             "psutil==5.9.0",
@@ -105,10 +108,8 @@ def create_lock(
             style,
             "--pex-root",
             pex_root,
-        ]
-        if interpreter_constraint:
-            args.extend(["--interpreter-constraint", interpreter_constraint])
-        run_pex3(*args).assert_success()
+        )
+        run_pex3(*(args + additional_args)).assert_success()
         lock = lockfile.load(lock_file)
         assert 1 == len(lock.locked_resolves)
         locked_resolve = lock.locked_resolves[0]
@@ -155,7 +156,11 @@ def create_lock(
 
     # We should have 6 total artifacts for a constrained universal lock since we know psutil 5.9.0
     # provides an sdist and 5 Python 3.10 wheels.
-    assert 5 == len(create_lock("universal", interpreter_constraint="~=3.10").additional_artifacts)
+    assert 5 == len(
+        create_lock(
+            "universal", "--interpreter-constraint", "~=3.10", "--python-path", py310
+        ).additional_artifacts
+    )
 
 
 def test_create_local_unsupported(pex_project_dir):
@@ -1387,10 +1392,6 @@ def test_excludes_pep517_build_requirements_issue_1565(tmpdir):
 }
 
 
-@pytest.mark.skipif(
-    PY_VER < (3, 6),
-    reason="Some sdists in this lock use f-strings in their builds which requires >=3.6",
-)
 @pytest.mark.parametrize(
     ["resolver_version", "expected_lockfile"],
     [
@@ -1407,6 +1408,16 @@ def test_universal_lock(
 ):
     # type: (...) -> None
 
+    py39 = None
+    for interp in PythonInterpreter.iter():
+        if (3, 9) == interp.version[:2]:
+            py39 = interp
+            break
+
+    if py39 is None:
+        pytest.skip("A Python 3.9 interpreter must be discoverable for this test.")
+        return
+
     constraints_file = os.path.join(str(tmpdir), "constraints.txt")
     with open(constraints_file, "w") as fp:
         fp.write(
@@ -1439,7 +1450,7 @@ def test_universal_lock(
     result.assert_success()
     lock = lockfile.loads(result.output)
 
-    platform_tag = PythonInterpreter.get().identity.supported_tags[0]
+    platform_tag = py39.identity.supported_tags[0]
     assert (
         attr.evolve(
             expected_lockfile,