https://github.com/python/cpython/commit/978a8befa5ec9b28b161a56b16d326330aef4733
commit: 978a8befa5ec9b28b161a56b16d326330aef4733
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-06T19:15:14Z
summary:
gh-157695: Parse also _Py_HAVE_xxx variables in sysconfig (#158926)
Add parse_config_h() tests to test_sysconfig.
files:
M Lib/sysconfig/__init__.py
M Lib/test/test_sysconfig.py
diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py
index fe55f48647e9a86..0657e458806e9b6 100644
--- a/Lib/sysconfig/__init__.py
+++ b/Lib/sysconfig/__init__.py
@@ -437,9 +437,10 @@ def parse_config_h(fp, vars=None):
if vars is None:
vars = {}
import re
- define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
- undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
- quoted_re = re.compile('^"(.*)"$')
+ name_rx = '(?:[A-Z]|_Py_)[A-Za-z0-9_]+'
+ define_rx = re.compile(fr"#define ({name_rx}) (.*)\n")
+ undef_rx = re.compile(fr"/[*] #undef ({name_rx}) [*]/\n")
+ quoted_re = re.compile(r'"(.*)"')
while True:
line = fp.readline()
@@ -448,7 +449,7 @@ def parse_config_h(fp, vars=None):
m = define_rx.match(line)
if m:
n, v = m.group(1, 2)
- if mq := quoted_re.match(v):
+ if mq := quoted_re.fullmatch(v):
v = mq.group(1)
try:
if n in _ALWAYS_STR:
diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
index 126e314db149165..6b90f2960672b69 100644
--- a/Lib/test/test_sysconfig.py
+++ b/Lib/test/test_sysconfig.py
@@ -29,7 +29,7 @@
get_path, get_path_names, _INSTALL_SCHEMES,
get_default_scheme, get_scheme_names, get_config_var,
_expand_vars, _get_preferred_schemes,
- is_python_build, _PROJECT_BASE)
+ is_python_build, _PROJECT_BASE, parse_config_h)
from sysconfig.__main__ import _main, _parse_makefile, _get_pybuilddir,
_get_json_data_name
import _imp
import _osx_support
@@ -767,6 +767,72 @@ def test_sysconfig_config_vars_no_prefix_cache(self):
self.assertEqual(config_vars['exec_prefix'], sys.exec_prefix)
self.assertEqual(config_vars['platbase'], sys.exec_prefix)
+ def test_parse_config_h(self):
+ config = textwrap.dedent('''
+ #ifndef Py_PYCONFIG_H
+ #define Py_PYCONFIG_H
+
+ /* C comment */
+
+ #define ALIGNOF_LONG 8
+ #define HAVE_ACCEPT 1
+ #define _Py_HAVE_COSPI 1
+ #define INVALID_NUMBER abc
+ #define ALT_SOABI "cpython-316t-x86_64-linux-gnu"
+
+ // Undef macros must be written as "/* #undef NAME */":
+ // name must be valid and there is not value.
+ /* #undef ANDROID_API_LEVEL */
+ #undef IGNORE_UNDEF
+ /* #undef IGNORE_VALUE 1 */
+
+ # _ALWAYS_STR: don't convert values to an integer,
+ # but quotes are removed
+ #define IPHONEOS_DEPLOYMENT_TARGET "13.0"
+ #define MACOSX_DEPLOYMENT_TARGET 10
+
+ // Spaces are tolerated after the name, not before
+ #define SPACES_AFTER 1
+ #define IGNORED_SPACES_BEFORE 1
+
+ // Ignore macro without value
+ #define IGNORE_NO_VALUE
+
+ // Ignore macros with an invalid name
+ #define _PRIVATE_IGNORED 1
+ #define aLOWER_IGNORED 1
+ #define 123IGNORED 1
+ #define INVALID-NAME 1
+ #define INVALID#NAME 1
+ #define NONASCII_NAME_é 1
+
+ // Ignore single letter names
+ #define A 1
+ /* #undef A */
+
+ #endif /*Py_PYCONFIG_H*/
+ ''')
+
+ filename = TESTFN
+ self.addCleanup(unlink, filename)
+ with open(filename, "w", encoding="utf-8") as fp:
+ fp.write(config)
+ vars = {}
+ with open(filename, encoding="utf-8") as fp:
+ parse_config_h(fp, vars)
+ expected = {
+ 'ALIGNOF_LONG': 8,
+ 'HAVE_ACCEPT': 1,
+ '_Py_HAVE_COSPI': 1,
+ 'INVALID_NUMBER': 'abc',
+ 'ALT_SOABI': 'cpython-316t-x86_64-linux-gnu',
+ 'ANDROID_API_LEVEL': 0,
+ 'IPHONEOS_DEPLOYMENT_TARGET': '13.0',
+ 'MACOSX_DEPLOYMENT_TARGET': '10', # str, not int
+ 'SPACES_AFTER': 1,
+ }
+ self.assertEqual(vars, expected)
+
class MakefileTests(unittest.TestCase):
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]