Conversation
Add "make check-capi-macros". Ignore existing macros which don't start with "Py", only prevent adding new names which don't respect this convention. Run "make check-capi-macros" in the GitHub Action "Check if generated files are up to date" job.
ZeroIntensity
left a comment
There was a problem hiding this comment.
I think this is a great idea. For clarity, do we already run similar checks for actual symbols? (For example, it should be impossible to add a new function to our headers that isn't prefixed with Py.)
We do already have So I'm not sure that it's useful to parse the public C API to check if PyAPI_FUNC() and PyAPI_DATA() use the Last year, I found exported symbols which doesn't with |
Yeah, as long as we have something, then I'm happy. |
|
I wrote a quick patch to test "make smelly": diff --git a/Include/pyerrors.h b/Include/pyerrors.h
index cfabbc5fe8d..f74534da7e6 100644
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -326,6 +326,8 @@ PyAPI_FUNC(int) PyOS_snprintf(char *str, size_t size, const char *format, ...)
PyAPI_FUNC(int) PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
Py_GCC_ATTRIBUTE((format(printf, 3, 0)));
+PyAPI_FUNC(int) test_dummy_func(void);
+
#ifndef Py_LIMITED_API
# define Py_CPYTHON_ERRORS_H
# include "cpython/pyerrors.h"
diff --git a/Python/errors.c b/Python/errors.c
index eb148998fc4..df7d3241dcc 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -2091,3 +2091,9 @@ PyErr_ProgramTextObject(PyObject *filename, int lineno)
{
return _PyErr_ProgramDecodedTextObject(filename, lineno, NULL);
}
+
+int
+test_dummy_func(void)
+{
+ return 4;
+}With this change, "make smelly" fails as expected with: |
| print('ERROR: the Python C API defines the following macros ' | ||
| 'with a name not starting with "Py":') | ||
| print() |
There was a problem hiding this comment.
Up to you, but it'd be nice to have colorful output with _colorize (the C API docs check script does this).
There was a problem hiding this comment.
I'm not sure that it's needed to add colors to this script.
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
|
Is our |
Some recently added "HAVE" macros start with a On the other hand, high-level functions like Python 3.16 adds the following macros to
|
hugovk
left a comment
There was a problem hiding this comment.
We have two other scripts with somewhat similar functionality to check things against ignore lists, and they both also verify the opposite: that the ignore file has no stale entries.
If a stale entry is found, the script also fails. This makes sure we keep it clean and relevant.
Let's add a similar check here, it would find the unnecessary FVC_ALT_REPR. And can also identify the generated ones from opcode_ids.h.
For reference:
cpython/Doc/tools/check-warnings.py
Lines 237 to 251 in 659e262
cpython/Tools/build/check_warnings.py
Lines 195 to 225 in 659e262
Fix UNDEF_REGEX macro: replace fullmatch() with match()
|
Ok, I made multiple changes to address reviews:
I also added a check to make sure that the ignore list is sorted. Is it overkill? I'm aware of Python 3.15 re.prefixprefix(), but my system Python is Python 3.14 and it's convenient for me to be able to use it :-) |
I wrote PR gh-157752 to rename HAVE_FLOAT16 macro to _Py_HAVE_FLOAT16. |
|
I added the following header to the ignore list: # Old C API macros with a name which doesn't start with "Py". If a macro
# is removed from the C API, it should be removed from this list as well.
#
# Adding a new macro to this ignore list requires the approval of the C API
# Working Group. Open an issue at:
# https://github.com/capi-workgroup/decisions/issues/"Adding a new macro to this ignore list requires approval" is a bold rule. Do we need exceptions? Or can we decide what are these exceptions later? AC_CHECK_FUNCS(), AC_CHECK_HEADERS() and PY_CHECK_FUNC() always define Or should we already add new functions defining |
hugovk
left a comment
There was a problem hiding this comment.
I also added a check to make sure that the ignore list is sorted. Is it overkill?
I think it's worth it, it's easier to manually search a sorted list, and it's a simple check.
(prek/pre-commit have a built-in sorter lint (file-contents-sorter) but that would require moving the ignore file's header into the .py)
|
|
||
| # Parse header files | ||
| include_dir = os.path.join(SRC_DIR, 'Include') | ||
| files = glob.glob(os.path.join(include_dir, '*.h')) |
There was a problem hiding this comment.
(Forgot to post this yesterday)
Include/opcode_ids.h contains generated opcodes, we could exclude these:
| files = glob.glob(os.path.join(include_dir, '*.h')) | |
| files = glob.glob(os.path.join(include_dir, '*.h')) | |
| files.remove(os.path.join(include_dir, 'opcode_ids.h')) |
And then remove the 245 generated names from check_capi_macros_ignored.txt. This will make maintenance easier so we don't need to add/remove future ones.
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Even if it's generated, it's part of the public Python C API and so we should care about these macros. Ignoring them only because they are generated doesn't look correct to me. |
|
I updated the PR to address @hugovk's latest review. |
Hum. I didn't take in account that opcode.h is not included by Python.h. Maybe we should/can ignore the following Include/ header files which are not included by Python.h:
I don't know. I'm now confused :-) See details in my comment on the issue. |
|
Ok, I changed my mind. I excluded 7 header files which are not included by Python.h:
They define multiple macros without The following header files are still parsed by the script even if they are not included by Python.h:
I wrote this script to list header files not included by Python.h: import re, glob, sys, os
INCLUDE = re.compile(r'\s*#\s*include\s+["<]([a-z0-9_./]+)[">]')
os.chdir("Include")
headers = set(glob.glob("*.h"))
headers.discard("Python.h")
os.chdir("..")
with open("Include/Python.h") as fp:
for line in fp:
match = INCLUDE.match(line)
if match:
name = match.group(1)
headers.discard(name)
elif line.startswith("// "):
continue
elif "include" in line:
print(f"failed to parse: {line!r}")
sys.exit(1)
print("Not included by Python.h:")
for name in sorted(headers):
print(f"- {name}") |
|
I also wrote PR gh-157821 to rename HAVE_ICONV macro to _Py_HAVE_ICONV. |
hugovk
left a comment
There was a problem hiding this comment.
Thanks! Looks good, can always exclude generated ones later if we decide to do so.
Add "make check-capi-macros". Ignore existing macros which don't start with "Py", only prevent adding new names which don't respect this convention.
Run "make check-capi-macros" in the GitHub Action "Check if generated files are up to date" job.
Py#157695