python-undef 0.1.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of python-undef might be problematic. Click here for more details.

@@ -0,0 +1,252 @@
1
+ import os
2
+ import re
3
+ import datetime
4
+ import sys
5
+
6
+ def is_valid_macro_name(macro_name):
7
+ """
8
+ Determine whether a macro name is valid using Python's standard library methods.
9
+
10
+ Args:
11
+ macro_name: The macro name to check.
12
+
13
+ Returns:
14
+ bool: True if it's a valid Python identifier, False otherwise.
15
+ """
16
+ # Empty string is invalid
17
+ if not macro_name:
18
+ return False
19
+
20
+ # Use str.isidentifier() to check for valid identifier syntax
21
+ return macro_name.isidentifier()
22
+
23
+ def extract_macro_name(line):
24
+ """Extract the macro name from a #define line (handles spaces between # and define)."""
25
+ line = line.strip()
26
+
27
+ # Match '#', optional spaces, 'define', spaces, and the macro name
28
+ match = re.match(r'^#\s*define\s+([A-Za-z_][A-Za-z0-9_]*)', line)
29
+ if not match:
30
+ return None
31
+
32
+ candidate = match.group(1)
33
+
34
+ # Validate with standard identifier rules
35
+ if candidate and is_valid_macro_name(candidate):
36
+ return candidate
37
+ return None
38
+
39
+ def is_standard_python_macro(macro_name):
40
+ """
41
+ Check whether a macro follows Python's standard naming conventions.
42
+ Rules: Starts with Py, PY, _Py, _PY, or ends with _H.
43
+ """
44
+ standard_prefixes = ('Py', 'PY', '_Py', '_PY')
45
+ return macro_name.startswith(standard_prefixes) or macro_name.endswith('_H')
46
+
47
+ def generate_undef_code(macro_name):
48
+ """Generate the code to undefine a macro."""
49
+ return f"""#ifndef DONOTUNDEF_{macro_name}
50
+ #ifdef {macro_name}
51
+ #undef {macro_name}
52
+ #endif
53
+ #endif
54
+
55
+ """
56
+
57
+ def generate_python_undef_header(pyconfig_path, output_path=None):
58
+ """
59
+ Generate the Python_undef.h header file.
60
+
61
+ Args:
62
+ pyconfig_path: Path to pyconfig.h
63
+ output_path: Output file path, defaults to Python_undef.h in the current directory.
64
+ """
65
+ if output_path is None:
66
+ file_dir = os.path.dirname(os.path.abspath(__file__))
67
+ output_path = f'{file_dir}/include/Python_undef.h'
68
+ if not os.path.exists(f'{file_dir}/include'):
69
+ os.makedirs(f'{file_dir}/include')
70
+
71
+ # Read pyconfig.h
72
+ try:
73
+ with open(pyconfig_path, 'r', encoding='utf-8') as f:
74
+ lines = f.readlines()
75
+ except FileNotFoundError:
76
+ print(f"Error: File not found {pyconfig_path}")
77
+ return False
78
+ except Exception as e:
79
+ print(f"Error reading file: {e}")
80
+ return False
81
+
82
+ # Collect macros
83
+ macros_to_undef = []
84
+ all_macros = []
85
+ invalid_macros = []
86
+
87
+ print("Analyzing pyconfig.h...")
88
+
89
+ for i, line in enumerate(lines, 1):
90
+ macro_name = extract_macro_name(line)
91
+ if macro_name:
92
+ all_macros.append(macro_name)
93
+
94
+ # New rule: any macro not starting with Py/PY/_Py/_PY and not ending with _H is considered non-standard
95
+ if not is_standard_python_macro(macro_name):
96
+ macros_to_undef.append(macro_name)
97
+ print(f"Line {i:4d}: Found non-standard macro '{macro_name}'")
98
+ else:
99
+ # Check if line looks like a define but has invalid name
100
+ line = line.strip()
101
+ if line.startswith('#'):
102
+ m = re.match(r'^#\s*define\s+(\S+)', line)
103
+ if m:
104
+ candidate = m.group(1)
105
+ if candidate and not is_valid_macro_name(candidate):
106
+ invalid_macros.append((i, candidate))
107
+
108
+ # Deduplicate and sort
109
+ macros_to_undef = sorted(set(macros_to_undef))
110
+
111
+ # Header section
112
+ header = f"""/*
113
+ * Python_undef.h - Automatically generated macro undefinition header
114
+ *
115
+ * This file is automatically generated from {os.path.basename(pyconfig_path)}
116
+ * Contains macros that may need to be undefined to avoid conflicts with other libraries.
117
+ *
118
+ * WARNING: This is an automatically generated file. Do not edit manually.
119
+ *
120
+ * Usage:
121
+ * #include <Python.h>
122
+ * #include <Python_undef.h>
123
+ * #include <other_library_headers.h>
124
+ *
125
+ * To preserve specific macros, define before including this header:
126
+ * #define DONOTUNDEF_MACRO_NAME
127
+ *
128
+ * Generation rules:
129
+ * - Macros starting with Py_, PY_, _Py, _PY are preserved (Python standard)
130
+ * - Macros ending with _H are preserved (header guards)
131
+ * - All other macros are undefined
132
+ * - Macro name validation uses Python's standard identifier checking
133
+ *
134
+ * Generated from: {os.path.abspath(pyconfig_path)}
135
+ * Generated at: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
136
+ * Total valid macros found: {len(all_macros)}
137
+ * Macros to undef: {len(macros_to_undef)}
138
+ * Invalid macro names skipped: {len(invalid_macros)}
139
+ */
140
+
141
+ #ifndef PYTHON_UNDEF_H
142
+ #define PYTHON_UNDEF_H
143
+
144
+ #ifndef Py_PYTHON_H
145
+ # error "Python_undef.h must be included *after* Python.h"
146
+ #endif
147
+
148
+ /*
149
+ * Platform Note:
150
+ * - The COMPILER macro is primarily defined in pyconfig.h on Windows
151
+ * - Other platforms define compiler info in Python/getcompiler.c
152
+ * - This macro and others can conflict with libraries such as V8
153
+ */
154
+
155
+ """
156
+
157
+ # Generate undef code sections
158
+ undef_sections = []
159
+ for macro_name in macros_to_undef:
160
+ undef_sections.append(generate_undef_code(macro_name))
161
+
162
+ # Footer
163
+ footer = """#endif /* PYTHON_UNDEF_H */
164
+ """
165
+
166
+ # Write output
167
+ try:
168
+ with open(output_path, 'w', encoding='utf-8', newline='\n') as f:
169
+ f.write(header)
170
+ f.writelines(undef_sections)
171
+ f.write(footer)
172
+
173
+ print(f"\n{'='*60}")
174
+ print(f"Successfully generated: {output_path}")
175
+ print(f"{'='*60}")
176
+ print("Summary:")
177
+ print(f" - Total valid macro definitions: {len(all_macros)}")
178
+ print(f" - Macros to undefine: {len(macros_to_undef)}")
179
+ print(f" - Preserved standard macros: {len(all_macros) - len(macros_to_undef)}")
180
+ print(f" - Invalid macro names skipped: {len(invalid_macros)}")
181
+
182
+ if invalid_macros:
183
+ print(f"\nSkipped invalid macro names:")
184
+ for line_num, invalid_macro in invalid_macros[:10]: # show only first 10
185
+ print(f" Line {line_num:4d}: '{invalid_macro}'")
186
+ if len(invalid_macros) > 10:
187
+ print(f" ... and {len(invalid_macros) - 10} more")
188
+
189
+ if macros_to_undef:
190
+ print(f"\nMacros to undefine (first 50):")
191
+ for i, macro in enumerate(macros_to_undef[:50], 1):
192
+ print(f" {i:3d}. {macro}")
193
+ if len(macros_to_undef) > 50:
194
+ print(f" ... and {len(macros_to_undef) - 50} more")
195
+
196
+ print(f"\nUsage Notes:")
197
+ print(f" 1. Include this file before including other library headers.")
198
+ print(f" 2. Use DONOTUNDEF_XXX to protect macros that must be kept.")
199
+ print(f" 3. Regenerate this file whenever rebuilding Python.")
200
+
201
+ return True
202
+
203
+ except Exception as e:
204
+ print(f"Error writing file: {e}")
205
+ return False
206
+
207
+ def main():
208
+ import sysconfig
209
+ from pathlib import Path
210
+ if sys.argv[1:]:
211
+ if sys.argv[1] in ('-h', '--help'):
212
+ print("""Usage:
213
+ python -m python_undef --generate
214
+ Generate Python_undef.h based on the system's pyconfig.h.
215
+ python -m python_undef --include
216
+ Print the include path where Python_undef.h is located.""")
217
+ elif sys.argv[1] == '--generate':
218
+ include_dir = Path(sysconfig.get_path('include'))
219
+ print(f"\n{'='*60}")
220
+ print("Note: Python keywords are not excluded since they are valid macro names in C/C++.")
221
+ print(f"{'='*60}")
222
+
223
+ pyconfig_path = include_dir / "pyconfig.h"
224
+
225
+ if os.path.exists(pyconfig_path):
226
+ success = generate_python_undef_header(pyconfig_path)
227
+
228
+ if success:
229
+ print(f"\n✅ Generation complete!")
230
+ print(f"💡 Tip: Place Python_undef.h inside Python include search path.")
231
+ else:
232
+ print(f"\n❌ Generation failed!")
233
+
234
+ else:
235
+ print(f"File {pyconfig_path} not found.")
236
+ print("Please update the pyconfig_path variable to the actual pyconfig.h path.")
237
+ print("\nTypical paths on Windows:")
238
+ print(" C:\\\\Python3x\\\\include\\\\pyconfig.h")
239
+ print("\nTypical paths on Unix/Linux:")
240
+ print(" /usr/include/python3.x/pyconfig.h")
241
+ print(" /usr/local/include/python3.x/pyconfig.h")
242
+ elif sys.argv[1] == "--include":
243
+ file_dir = os.path.dirname(os.path.abspath(__file__))
244
+ if not Path(file_dir).exists():
245
+ print("File not found. Use 'python -m python_undef --generate' to generate the header first.")
246
+ return
247
+ include_path = os.path.abspath(os.path.join(file_dir, 'include'))
248
+ print(include_path)
249
+ else:
250
+ print("Unknown argument. Use --help for usage information.")
251
+ else:
252
+ print("No arguments provided. Use --help for usage information.")
@@ -0,0 +1,4 @@
1
+ from . import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,8 @@
1
+ Metadata-Version: 2.4
2
+ Name: python_undef
3
+ Version: 0.1.0
4
+ Summary: Python undefined header in pyconfig.h
5
+ Project-URL: homepage, https://github.com/Locked-chess-official/python_undef
6
+ Author-email: Locked-chess-official <13140752715@163.com>
7
+ License: MIT
8
+ License-File: LICENSE
@@ -0,0 +1,6 @@
1
+ python_undef/__init__.py,sha256=OSSRLqTFB7lDghJ70BkgI4LYdkj_D-YTs0XcKDYhKtg,9361
2
+ python_undef/__main__.py,sha256=_P5nfB_sOJcMhh75oVFs_0I6mHNXSw8EYgR6N8KDA-0,60
3
+ python_undef-0.1.0.dist-info/METADATA,sha256=CPkAaC8yJULZz-JmHiYP2lMWxhlF_fd-qnpHjWFvAWk,273
4
+ python_undef-0.1.0.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
5
+ python_undef-0.1.0.dist-info/licenses/LICENSE,sha256=EKyJBXvuO6DHzy9gUe1HC37yV521nbbAFFWTsPWflm4,1099
6
+ python_undef-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Locked-chess-official
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.