Last active
June 19, 2026 12:22
-
-
Save qlrd/cac09c083e80b9b0174a1be31a7cc9f3 to your computer and use it in GitHub Desktop.
Verify decorators behaviour both on Cpython an Micropython
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # | |
| # Usage: | |
| # uv run python3 verify-decorators.py | |
| # uv run micropython verify-decorators.py | |
| import sys | |
| TITLE = "verify __new__ decorators" | |
| CASES = [ | |
| { | |
| "id": "1", | |
| "name": "bare __new__(cls)", | |
| "src": """ | |
| class T(object): | |
| _i = None | |
| def __new__(cls): | |
| if T._i is None: | |
| T._i = object.__new__(cls) | |
| return T._i | |
| def __init__(self): | |
| if getattr(self, '_built', False): | |
| return | |
| self._built = True | |
| """, | |
| "call": "obj = T()\nobj2 = T()\n", | |
| }, | |
| { | |
| "id": "2", | |
| "name": "@classmethod __new__(cls)", | |
| "src": """ | |
| class T(object): | |
| _i = None | |
| @classmethod | |
| def __new__(cls): | |
| if T._i is None: | |
| T._i = object.__new__(cls) | |
| return T._i | |
| def __init__(self): | |
| if getattr(self, '_built', False): | |
| return | |
| self._built = True | |
| """, | |
| "call": "obj = T()\nobj2 = T()\n", | |
| }, | |
| { | |
| "id": "3", | |
| "name": "@classmethod __new__(cls, *args, **kwargs)", | |
| "src": """ | |
| class T(object): | |
| @classmethod | |
| def __new__(cls, *args, **kwargs): | |
| return object.__new__(cls) | |
| """, | |
| "call": "obj = T()\nobj2 = T()\n", | |
| }, | |
| ] | |
| def is_micropython(): | |
| impl = getattr(sys, "implementation", None) | |
| return impl is not None and getattr(impl, "name", "") == "micropython" | |
| def runtime_label(): | |
| if is_micropython(): | |
| return sys.version.split(";")[0].strip() | |
| return sys.version.split("\n", 1)[0] | |
| def build_case_code(src, call_src): | |
| return src.strip() + "\n" + call_src.strip() | |
| def run_case_exec(src, call_src): | |
| ns = {} | |
| exec(build_case_code(src, call_src), ns) | |
| return "PASS", None | |
| def format_child_error(stderr, stdout, returncode): | |
| text = stderr or stdout or ("exit %d" % returncode) | |
| lines = [line.strip() for line in text.splitlines() if line.strip()] | |
| if not lines: | |
| return "exit %d" % returncode | |
| for line in reversed(lines): | |
| if line.startswith("TypeError:") or line.startswith("AttributeError:"): | |
| return line | |
| if ": " in line and not line.startswith("File "): | |
| return line | |
| return lines[-1] | |
| def run_case_popen(exe, src, call_src): | |
| import subprocess | |
| proc = subprocess.Popen( | |
| [exe, "-c", build_case_code(src, call_src)], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| ) | |
| out, err = proc.communicate() | |
| stderr = err.decode("utf-8", "replace").strip() | |
| stdout = out.decode("utf-8", "replace").strip() | |
| if proc.returncode == 0: | |
| return "PASS", None | |
| return "FAIL", format_child_error(stderr, stdout, proc.returncode) | |
| def run_case(src, call_src): | |
| if is_micropython(): | |
| try: | |
| return run_case_exec(src, call_src) | |
| except Exception as exc: | |
| return "FAIL", "%s: %s" % (type(exc).__name__, exc) | |
| return run_case_popen(sys.executable, src, call_src) | |
| def print_row(num, name, status, detail): | |
| if status == "PASS": | |
| print("[%s] %s PASS" % (num, name)) | |
| return | |
| print("[%s] %s" % (num, name)) | |
| print(" FAIL %s" % detail) | |
| def main(): | |
| print(TITLE) | |
| print("Runtime: %s" % runtime_label()) | |
| print("") | |
| pass_n = 0 | |
| fail_n = 0 | |
| for case in CASES: | |
| status, detail = run_case(case["src"], case["call"]) | |
| if status == "PASS": | |
| pass_n += 1 | |
| else: | |
| fail_n += 1 | |
| print_row(case["id"], case["name"], status, detail) | |
| print("") | |
| print("-" * 60) | |
| print("Summary: %d PASS, %d FAIL" % (pass_n, fail_n)) | |
| return 0 | |
| if __name__ == "__main__": | |
| try: | |
| sys.exit(main()) | |
| except Exception as exc: | |
| print("INTERNAL ERROR: %s: %s" % (type(exc).__name__, exc)) | |
| sys.exit(2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment