From df0fa1fc64f31744ec3d104bfaae04415b87bb4a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 10 May 2022 22:48:40 +0200 Subject: [PATCH] gh-92584: test_cppext uses setuptools Rewrite test_cppext to run in a virtual environment and to build the C++ extension with setuptools rather than distutils. --- Lib/test/setup_testcppext.py | 42 +++++++++++++++ Lib/test/test_cppext.py | 102 ++++++++++++----------------------- 2 files changed, 77 insertions(+), 67 deletions(-) create mode 100644 Lib/test/setup_testcppext.py diff --git a/Lib/test/setup_testcppext.py b/Lib/test/setup_testcppext.py new file mode 100644 index 00000000000000..780cb7b24a78c9 --- /dev/null +++ b/Lib/test/setup_testcppext.py @@ -0,0 +1,42 @@ +# gh-91321: Build a basic C++ test extension to check that the Python C API is +# compatible with C++ and does not emit C++ compiler warnings. +import sys +from test import support + +from setuptools import setup, Extension + + +MS_WINDOWS = (sys.platform == 'win32') + + +SOURCE = support.findfile('_testcppext.cpp') +if not MS_WINDOWS: + # C++ compiler flags for GCC and clang + CPPFLAGS = [ + # Python currently targets C++11 + '-std=c++11', + # gh-91321: The purpose of _testcppext extension is to check that building + # a C++ extension using the Python C API does not emit C++ compiler + # warnings + '-Werror', + # Warn on old-style cast (C cast) like: (PyObject*)op + '-Wold-style-cast', + # Warn when using NULL rather than _Py_NULL in static inline functions + '-Wzero-as-null-pointer-constant', + ] +else: + # Don't pass any compiler flag to MSVC + CPPFLAGS = [] + + +def main(): + cpp_ext = Extension( + '_testcppext', + sources=[SOURCE], + language='c++', + extra_compile_args=CPPFLAGS) + setup(name="_testcppext", ext_modules=[cpp_ext]) + + +if __name__ == "__main__": + main() diff --git a/Lib/test/test_cppext.py b/Lib/test/test_cppext.py index 337cb08f8c9d8c..8acf0f1b7c0dc3 100644 --- a/Lib/test/test_cppext.py +++ b/Lib/test/test_cppext.py @@ -1,91 +1,59 @@ # gh-91321: Build a basic C++ test extension to check that the Python C API is # compatible with C++ and does not emit C++ compiler warnings. -import contextlib -import os +import os.path import sys import unittest -import warnings +import subprocess from test import support from test.support import os_helper -with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - from distutils.core import setup, Extension - import distutils.sysconfig - MS_WINDOWS = (sys.platform == 'win32') -SOURCE = support.findfile('_testcppext.cpp') -if not MS_WINDOWS: - # C++ compiler flags for GCC and clang - CPPFLAGS = [ - # Python currently targets C++11 - '-std=c++11', - # gh-91321: The purpose of _testcppext extension is to check that building - # a C++ extension using the Python C API does not emit C++ compiler - # warnings - '-Werror', - # Warn on old-style cast (C cast) like: (PyObject*)op - '-Wold-style-cast', - # Warn when using NULL rather than _Py_NULL in static inline functions - '-Wzero-as-null-pointer-constant', - ] -else: - # Don't pass any compiler flag to MSVC - CPPFLAGS = [] +SETUP_TESTCPPEXT = support.findfile('setup_testcppext.py') @support.requires_subprocess() class TestCPPExt(unittest.TestCase): - def build(self): - cpp_ext = Extension( - '_testcppext', - sources=[SOURCE], - language='c++', - extra_compile_args=CPPFLAGS) - capture_stdout = (not support.verbose) - - try: - try: - if capture_stdout: - stdout = support.captured_stdout() - else: - print() - stdout = contextlib.nullcontext() - with (stdout, - support.swap_attr(sys, 'argv', ['setup.py', 'build_ext', '--verbose'])): - setup(name="_testcppext", ext_modules=[cpp_ext]) - return - except: - if capture_stdout: - # Show output on error - print() - print(stdout.getvalue()) - raise - except SystemExit: - self.fail("Build failed") - # With MSVC, the linker fails with: cannot open file 'python311.lib' # https://github.com/python/cpython/pull/32175#issuecomment-1111175897 @unittest.skipIf(MS_WINDOWS, 'test fails on Windows') def test_build(self): - # save/restore os.environ - def restore_env(old_env): - os.environ.clear() - os.environ.update(old_env) - self.addCleanup(restore_env, dict(os.environ)) - - def restore_sysconfig_vars(old_config_vars): - distutils.sysconfig._config_vars.clear() - distutils.sysconfig._config_vars.update(old_config_vars) - self.addCleanup(restore_sysconfig_vars, - dict(distutils.sysconfig._config_vars)) - # Build in a temporary directory with os_helper.temp_cwd(): - self.build() + self._test_build() + + def _test_build(self): + venv_dir = 'env' + + # Create virtual environment to get setuptools + cmd = [sys.executable, '-X', 'dev', '-m', 'venv', venv_dir] + if support.verbose: + print() + print('Run:', ' '.join(cmd)) + subprocess.run(cmd, check=True) + + # Get the Python executable of the venv + python_exe = 'python' + if sys.executable.endswith('.exe'): + python_exe += '.exe' + if MS_WINDOWS: + python = os.path.join(venv_dir, 'Scripts', python_exe) + else: + python = os.path.join(venv_dir, 'bin', python_exe) + + # Build the C++ extension + cmd = [python, '-X', 'dev', SETUP_TESTCPPEXT, 'build_ext', '--verbose'] + if support.verbose: + print('Run:', ' '.join(cmd)) + proc = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True) + if proc.returncode: + print(proc.stdout, end='') + self.fail(f"Build failed with exit code {proc.returncode}") if __name__ == "__main__": pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy