Repository: pypa/build
Pull request #149 (2020-10-20 00:33:11)

main: run isolation build with the environment python interpreter

FFY00: @gaborbernat please do not merge yet.
gaborbernat: https://github.com/FFY00/python-build/pull/1 adds the fix

Patch:
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 15e93f1..5eb3704 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -78,13 +78,13 @@ jobs:
         run: tox -e ${{env.BASE}} --skip-pkg-install
 
       - name: Run test suite via path
-        run: tox -e ${{env.BASE}}-path --skip-pkg-install
+        run: tox -e ${{env.BASE}}-path --skip-pkg-install -- --run-integration
 
       - name: Run test suite via sdist
-        run: tox -e ${{env.BASE}}-sdist --skip-pkg-install
+        run: tox -e ${{env.BASE}}-sdist --skip-pkg-install -- --run-integration
 
       - name: Run test suite via wheel
-        run: tox -e ${{env.BASE}}-wheel --skip-pkg-install
+        run: tox -e ${{env.BASE}}-wheel --skip-pkg-install -- --run-integration
 
       - name: Rename coverage report file
         run: |
diff --git a/setup.cfg b/setup.cfg
index 02cfdb2..89727bd 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -26,7 +26,7 @@ project_urls =
 packages = find:
 install_requires =
     packaging
-    pep517>=0.9.1
+    pep517>=0.9
     toml
     importlib-metadata;python_version < "3.8"
     typing;python_version<"3"
diff --git a/src/build/__init__.py b/src/build/__init__.py
index d6d3455..82c8a7d 100644
--- a/src/build/__init__.py
+++ b/src/build/__init__.py
@@ -10,7 +10,8 @@ import difflib
 import os
 import sys
 import warnings
-from typing import Dict, Iterator, List, Mapping, Optional, Set, Union
+
+from typing import Dict, Iterator, List, Mapping, Optional, Set, Union, Text
 
 import pep517.wrappers
 import toml
@@ -117,7 +118,7 @@ def _working_directory(path):  # type: (str) -> Iterator[None]
 
 class ProjectBuilder(object):
     def __init__(self, srcdir='.', config_settings=None, python_executable=sys.executable):
-        # type: (str, Optional[ConfigSettings], str) -> None
+        # type: (str, Optional[ConfigSettings], Union[bytes, Text]) -> None
         """
         Create a project builder.
 
@@ -161,6 +162,16 @@ class ProjectBuilder(object):
             python_executable=python_executable,
         )
 
+    @property
+    def python_executable(self):  # type: () -> Union[bytes, Text]
+        # make mypy happy
+        exe = self.hook.python_executable  # type: Union[bytes, Text]
+        return exe
+
+    @python_executable.setter
+    def python_executable(self, value):  # type: (Union[bytes, Text]) -> None
+        self.hook.python_executable = value
+
     @property
     def build_dependencies(self):  # type: () -> Set[str]
         return set(self._build_system['requires'])
diff --git a/src/build/__main__.py b/src/build/__main__.py
index a353f9d..24fe371 100644
--- a/src/build/__main__.py
+++ b/src/build/__main__.py
@@ -42,7 +42,7 @@ def _error(msg, code=1):  # type: (str, int) -> None  # pragma: no cover
 def _build_in_isolated_env(builder, outdir, distributions):
     # type: (ProjectBuilder, str, List[str]) -> None
     with IsolatedEnvBuilder() as env:
-        builder.hook.python_executable = env.executable
+        builder.python_executable = env.executable
         env.install(builder.build_dependencies)
         for distribution in distributions:
             builder.build(distribution, outdir)
diff --git a/src/build/_compat.py b/src/build/_compat.py
index 3a5da79..cb5fd17 100644
--- a/src/build/_compat.py
+++ b/src/build/_compat.py
@@ -1,6 +1,6 @@
 import abc
 import sys
-from typing import Callable, TypeVar
+from typing import Callable, TypeVar, TYPE_CHECKING
 
 _T = TypeVar('_T')
 
@@ -28,12 +28,12 @@ def add_metaclass(metaclass):  # type: (type) -> Callable[[_T], _T]
 if sys.version_info[0] == 2:
     abstractproperty = abc.abstractproperty
 else:
-    from typing import Any, cast
+    if TYPE_CHECKING:  # pragma: no cover
+        abstractproperty = property  # pragma: no cover
+    else:
 
-    F = TypeVar('F', bound=Callable[..., Any])
-
-    def abstractproperty(func):  # type: (F) -> F
-        return cast(F, property(abc.abstractmethod(func)))
+        def abstractproperty(func):
+            return property(abc.abstractmethod(func))
 
 
 __all__ = (
diff --git a/tox.ini b/tox.ini
index 31dff1b..91a3d4b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -35,7 +35,7 @@ commands =
     pytest -rsx --cov --cov-config setup.cfg \
       --cov-report=html:{envdir}/htmlcov --cov-context=test \
       --cov-report=xml:{toxworkdir}/coverage.{envname}.xml \
-      tests {posargs:--run-integration}
+      tests {posargs}
 
 [testenv:fix]
 description = run static analysis and style checks


Test patch:
diff --git a/tests/test_projectbuilder.py b/tests/test_projectbuilder.py
index 0c0a036..3304e06 100644
--- a/tests/test_projectbuilder.py
+++ b/tests/test_projectbuilder.py
@@ -5,6 +5,7 @@ from __future__ import unicode_literals
 import copy
 import os
 import sys
+import typing
 
 import pep517.wrappers
 import pytest
@@ -88,17 +89,35 @@ def test_init(mocker, test_flit_path, legacy_path, test_no_permission, test_bad_
         'setuptools.build_meta:__legacy__': None,
     }
     mocker.patch('importlib.import_module', modules.get)
-    caller = mocker.patch('pep517.wrappers.Pep517HookCaller')
+    mocker.patch('pep517.wrappers.Pep517HookCaller')
 
     # correct flit pyproject.toml
     build.ProjectBuilder(test_flit_path)
-    caller.assert_called_with(test_flit_path, 'flit_core.buildapi', backend_path=None, python_executable=sys.executable)
-    caller.reset_mock()
+    pep517.wrappers.Pep517HookCaller.assert_called_with(
+        test_flit_path,
+        'flit_core.buildapi',
+        backend_path=None,
+        python_executable=sys.executable,
+    )
+    pep517.wrappers.Pep517HookCaller.reset_mock()
+
+    # custom python
+    build.ProjectBuilder(test_flit_path, python_executable='some-python')
+    pep517.wrappers.Pep517HookCaller.assert_called_with(
+        test_flit_path,
+        'flit_core.buildapi',
+        backend_path=None,
+        python_executable='some-python',
+    )
+    pep517.wrappers.Pep517HookCaller.reset_mock()
 
     # FileNotFoundError
     build.ProjectBuilder(legacy_path)
-    caller.assert_called_with(
-        legacy_path, 'setuptools.build_meta:__legacy__', backend_path=None, python_executable=sys.executable
+    pep517.wrappers.Pep517HookCaller.assert_called_with(
+        legacy_path,
+        'setuptools.build_meta:__legacy__',
+        backend_path=None,
+        python_executable=sys.executable,
     )
 
     # PermissionError
@@ -111,6 +130,15 @@ def test_init(mocker, test_flit_path, legacy_path, test_no_permission, test_bad_
         build.ProjectBuilder(test_bad_syntax_path)
 
 
+@pytest.mark.parametrize('value', [b'something', typing.Text('something_else')])
+def test_python_executable(test_flit_path, value):
+    builder = build.ProjectBuilder(test_flit_path)
+
+    builder.python_executable = value
+    assert builder.python_executable == value
+    assert builder.hook.python_executable == value
+
+
 @pytest.mark.parametrize('distribution', ['wheel', 'sdist'])
 def test_get_dependencies_missing_backend(packages_path, distribution):
     bad_backend_path = os.path.join(packages_path, 'test-bad-backend')