From bb6600ba9db998c5b5f532ca4bc7845f9686744b Mon Sep 17 00:00:00 2001 From: alexion Date: Mon, 7 Sep 2026 19:53:14 -0400 Subject: [PATCH] feat(clew): serialize Python callables in AST output --- src/clew/extract_renpy_ast.py | 48 +++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/clew/extract_renpy_ast.py b/src/clew/extract_renpy_ast.py index 35ac9a5..f95cd2f 100644 --- a/src/clew/extract_renpy_ast.py +++ b/src/clew/extract_renpy_ast.py @@ -5,6 +5,7 @@ import json import os import struct import sys +import types import zlib try: @@ -110,6 +111,41 @@ def is_primitive(value): return value is None or isinstance(value, (bool, int, long, float, basestring)) +def serialize_function(value): + code = getattr(value, "func_code", None) or getattr(value, "__code__", None) + result = { + "type": "function", + "name": safe_text(getattr(value, "func_name", None) or getattr(value, "__name__", None)), + "module": safe_text(getattr(value, "__module__", None)), + } + if code is not None: + result["filename"] = safe_text(getattr(code, "co_filename", None)) + result["firstlineno"] = getattr(code, "co_firstlineno", None) + return result + + +def serialize_method(value): + function = getattr(value, "im_func", None) or getattr(value, "__func__", None) + receiver = getattr(value, "im_self", None) or getattr(value, "__self__", None) + result = serialize_function(function) if function is not None else { + "type": "function", + "name": safe_text(getattr(value, "__name__", None)), + "module": safe_text(getattr(value, "__module__", None)), + } + result["type"] = "method" + if receiver is not None: + result["receiver_class"] = class_name(receiver) + return result + + +def serialize_type(value): + return { + "type": "python-type", + "name": safe_text(getattr(value, "__name__", None)), + "module": safe_text(getattr(value, "__module__", None)), + } + + class Serializer(object): def __init__(self, max_depth): self.max_depth = max_depth @@ -148,12 +184,14 @@ class Serializer(object): self.active_containers.remove(object_id) return {"type": "dict", "items": items} + if isinstance(value, types.FunctionType) or isinstance(value, types.BuiltinFunctionType): + return serialize_function(value) + + if isinstance(value, types.MethodType): + return serialize_method(value) + if isinstance(value, type): - return { - "type": "repr", - "class": class_name(value), - "repr": repr(value), - } + return serialize_type(value) identity = id(value) if identity in self.seen: