Repository navigation
gh-157695: Check that C API macros start with "Py" #157696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
e48804c
0d6621d
714f1f5
44eb795
819558a
c6af62b
998dd34
fa62aac
6188980
8c09a6c
7c8c77d
80a2e2f
d2347d9
a63e018
86514dc
dec9c88
d326d3f
d7a9559
dd15660
4e78617
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,106 @@ | ||||||||
| """ | ||||||||
| Check that all macros defined by the Python C API have a name starting with | ||||||||
| "Py". Ignore names listed by check_capi_macros_ignored.txt: macros with an | ||||||||
| invalid name, added before this script was created. | ||||||||
|
|
||||||||
| Python C API: | ||||||||
|
|
||||||||
| * Include/*.h | ||||||||
| * Include/cpython/*.h | ||||||||
| * pyconfig.h.in | ||||||||
| """ | ||||||||
|
|
||||||||
| import glob | ||||||||
| import os.path | ||||||||
| import re | ||||||||
| import sys | ||||||||
|
|
||||||||
| TOOLS_BUILD_DIR = os.path.abspath(os.path.dirname(__file__)) | ||||||||
| SRC_DIR = os.path.dirname(os.path.dirname(TOOLS_BUILD_DIR)) | ||||||||
|
ZeroIntensity marked this conversation as resolved.
Resolved
|
||||||||
|
|
||||||||
| DEFINE_REGEX = re.compile(r'^\s*# *define\s+(.*)') | ||||||||
| PYTHON_PREFIX = re.compile(r'^(Py|PY|_Py|_PY)') | ||||||||
| DEFINE_NAME_REGEX = re.compile(r'^([A-Za-z_][A-Za-z0-9_]*)\b') | ||||||||
| UNDEF_REGEX = re.compile(r'#undef (.*)$') | ||||||||
|
vstinner marked this conversation as resolved.
Resolved
|
||||||||
|
|
||||||||
|
|
||||||||
| def parse_file(filename, names, ignored): | ||||||||
| with open(filename, encoding='utf8') as fp: | ||||||||
| for line in fp: | ||||||||
| match = DEFINE_REGEX.match(line) | ||||||||
|
vstinner marked this conversation as resolved.
Resolved
|
||||||||
| if not match: | ||||||||
| continue | ||||||||
| macro = match.group(1) | ||||||||
|
|
||||||||
| if PYTHON_PREFIX.match(macro): | ||||||||
|
vstinner marked this conversation as resolved.
Resolved
|
||||||||
| continue | ||||||||
|
|
||||||||
| match = DEFINE_NAME_REGEX.search(macro) | ||||||||
| if not match: | ||||||||
| print(f"ERROR: {filename}: Unable to parse {line!r}") | ||||||||
| sys.exit(1) | ||||||||
| name = match.group(1) | ||||||||
| if name in ignored: | ||||||||
| continue | ||||||||
|
|
||||||||
| names.append((name, filename)) | ||||||||
|
|
||||||||
|
|
||||||||
| def parse_pyconfig_in(filename, names, ignored): | ||||||||
| with open(filename, encoding='utf8') as fp: | ||||||||
| for line in fp: | ||||||||
| match = UNDEF_REGEX.match(line) | ||||||||
| if not match: | ||||||||
| continue | ||||||||
| name = match.group(1) | ||||||||
| if name in ignored: | ||||||||
| continue | ||||||||
| names.append((name, filename)) | ||||||||
|
|
||||||||
|
|
||||||||
| def get_ignored_names(): | ||||||||
| filename = os.path.join(TOOLS_BUILD_DIR, 'check_capi_macros_ignored.txt') | ||||||||
| ignored = set() | ||||||||
| with open(filename, encoding='utf8') as fp: | ||||||||
| for line in fp: | ||||||||
| name = line.strip() | ||||||||
| if name.startswith('#'): | ||||||||
| # Ignore comment | ||||||||
| continue | ||||||||
| if name: | ||||||||
| ignored.add(name) | ||||||||
| return ignored | ||||||||
|
|
||||||||
|
|
||||||||
| def main(): | ||||||||
| ignored = get_ignored_names() | ||||||||
|
|
||||||||
| include_dir = os.path.join(SRC_DIR, 'Include') | ||||||||
| files = glob.glob(os.path.join(include_dir, '*.h')) | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Forgot to post this yesterday)
Suggested change
And then remove the 245 generated names from |
||||||||
| files.extend(glob.glob(os.path.join(include_dir, 'cpython', '*.h'))) | ||||||||
| names = [] | ||||||||
| for filename in files: | ||||||||
| parse_file(filename, names, ignored) | ||||||||
|
ZeroIntensity marked this conversation as resolved.
Resolved
|
||||||||
|
|
||||||||
| filename = os.path.join(SRC_DIR, 'pyconfig.h.in') | ||||||||
| parse_file(filename, names, ignored) | ||||||||
| parse_pyconfig_in(filename, names, ignored) | ||||||||
| names.sort() | ||||||||
|
|
||||||||
| if not names: | ||||||||
| print("OK: the Python C API only defines macros with names " | ||||||||
| f"starting with Py (ignoring {len(ignored)} macros)") | ||||||||
| sys.exit(0) | ||||||||
|
|
||||||||
| print('ERROR: the Python C API defines the following macros ' | ||||||||
| 'with a name not starting with "Py":') | ||||||||
| print() | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Up to you, but it'd be nice to have colorful output with
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that it's needed to add colors to this script. |
||||||||
| for name, filename in names: | ||||||||
| print(f"- {name} defined by {filename}") | ||||||||
| print() | ||||||||
| print(f"Total: {len(names)} macros") | ||||||||
| sys.exit(1) | ||||||||
|
|
||||||||
|
|
||||||||
| if __name__ == "__main__": | ||||||||
| main() | ||||||||
Uh oh!
There was an error while loading. Please reload this page.