From e6f2c188db89fee0ecbd712af1559e152131c1ba Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 16 Nov 2024 20:12:17 +0000 Subject: [PATCH] generate type stubs which are sufficiently self-consistent to run mypy on all the examples --- create_define_consts.py | 4 ++-- create_stub_pyray.py | 31 ++++++++++++++++++++++++++----- create_stub_static.py | 33 ++++++++++++++++++++++++--------- make_docs.sh | 5 ++--- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/create_define_consts.py b/create_define_consts.py index 6817e4c..117981a 100644 --- a/create_define_consts.py +++ b/create_define_consts.py @@ -45,8 +45,8 @@ def process(filename): strval = str(e['value']).strip() if strval.startswith("__"): continue - if strval in known_enum: - print(e['name'] + " = raylib." + strval) + # if strval in known_enum: + # print(e['name'] + " = raylib." + strval) elif strval in known_define: print(e['name'] + " = " + strval) else: diff --git a/create_stub_pyray.py b/create_stub_pyray.py index c96d2c0..a5030bc 100644 --- a/create_stub_pyray.py +++ b/create_stub_pyray.py @@ -29,6 +29,12 @@ for filename in (Path("raylib.json"), Path("raymath.json"), Path("rlgl.json"), P for st in js["structs"]: if st["name"] not in known_structs: known_structs[st["name"]] = st + for e in js['enums']: + if e['name'] and e['values']: + print ("class "+e['name']+"(int):") + for value in e['values']: + print(" "+value['name']+" = "+str(value['value'])) + print("") def ctype_to_python_type(t): @@ -42,29 +48,39 @@ def ctype_to_python_type(t): return "int" elif t == "uint64_t": return "int" + elif t == "short": + return "int" + elif t == "unsigned short": + return "int" elif t == "double": return "float" elif "char * *" in t: return "list[str]" elif "char *" in t: return "str" - elif "char" in t: + elif t == "char": return "str" # not sure about this one + elif t == "unsigned char": + return "int" elif "*" in t: return "Any" + elif "[" in t: + return "list" # TODO FIXME type of items in the list elif t.startswith("struct"): return t.replace("struct ", "") elif t.startswith("unsigned"): return t.replace("unsigned ", "") + elif t.startswith("enum"): + return t.replace("enum ", "") else: return t print("""from typing import Any +import _cffi_backend # type: ignore -def pointer(struct): - ... +ffi: _cffi_backend.FFI """) # These words can be used for c arg names, but not in python @@ -90,6 +106,8 @@ for name, attr in getmembers(rl): if param_name in reserved_words: param_name = param_name + "_" + str(i) param_type = ctype_to_python_type(arg.cname) + if "struct" in arg.cname: + param_type += "|list|tuple" sig += f"{param_name}: {param_type}," return_type = ffi.typeof(attr).result.cname @@ -128,11 +146,14 @@ for struct in ffi.list_types()[0]: print(f' """ struct """') sig = "" for arg in ffi.typeof(struct).fields: - sig += ", " + arg[0] + ptype = ctype_to_python_type(arg[1].type.cname) + if arg[1].type.kind == "struct": + ptype += "|list|tuple" + sig += f", {arg[0]}: {ptype}|None = None" print(f" def __init__(self{sig}):") for arg in ffi.typeof(struct).fields: - print(f" self.{arg[0]}={arg[0]}") + print(f" self.{arg[0]}:{ctype_to_python_type(arg[1].type.cname)} = {arg[0]} # type: ignore") # elif ffi.typeof(struct).kind == "enum": # print(f"{struct}: int") diff --git a/create_stub_static.py b/create_stub_static.py index 7f4915e..4ad45d0 100644 --- a/create_stub_static.py +++ b/create_stub_static.py @@ -42,27 +42,35 @@ def ctype_to_python_type(t): return "int" elif t == "uint64_t": return "int" + elif t == "short": + return "int" + elif t == "unsigned short": + return "int" elif t == "double": return "float" elif "char * *" in t: - return "list[str]" + return "list[bytes]" elif "char *" in t: - return "str" + return "bytes" elif "char" in t: - return "str" # not sure about this one + return "bytes" # not sure about this one elif "*" in t: return "Any" + elif "[" in t: + return "list" # TODO FIXME type of items in the list elif t.startswith("struct"): return t.replace("struct ", "") elif t.startswith("unsigned"): return t.replace("unsigned ", "") + elif t.startswith("enum"): + return t.replace("enum ", "") else: return t print("""from typing import Any -import _cffi_backend +import _cffi_backend # type: ignore ffi: _cffi_backend.FFI rl: _cffi_backend.Lib @@ -96,6 +104,8 @@ for name, attr in getmembers(rl): if param_name in reserved_words: param_name = param_name + "_" + str(i) param_type = ctype_to_python_type(arg.cname) + if "struct" in arg.cname: + param_type += "|list|tuple" sig += f"{param_name}: {param_type}," return_type = ffi.typeof(attr).result.cname @@ -121,17 +131,22 @@ for struct in ffi.list_types()[0]: # if ffi.typeof(struct).fields is None: # print("weird empty struct, skipping", file=sys.stderr) # continue - print(f"{struct}: struct") + print(f"class {struct}:") # sig = "" - # for arg in ffi.typeof(struct).fields: - # sig += ", " + arg[0] + fields = ffi.typeof(struct).fields + if fields is not None: + #print(ffi.typeof(struct).fields) + #print(f" {arg}: {arg}") # print(f" def __init__(self{sig}):") # - # for arg in ffi.typeof(struct).fields: + for arg in ffi.typeof(struct).fields: + print(f" {arg[0]}: {ctype_to_python_type(arg[1].type.cname)}") + else: + print(" ...") # print(f" self.{arg[0]}={arg[0]}") elif ffi.typeof(struct).kind == "enum": - print(f"{struct}: int") + print(f"{struct} = int") else: print("ERROR UNKNOWN TYPE", ffi.typeof(struct), file=sys.stderr) diff --git a/make_docs.sh b/make_docs.sh index d8e4e64..5d13231 100755 --- a/make_docs.sh +++ b/make_docs.sh @@ -42,14 +42,13 @@ python3 create_enums.py > dynamic/raylib/enums.py echo "creating defines.py" -python3 create_define_consts.py > raylib/defines.py -python3 create_define_consts.py > dynamic/raylib/defines.py +python3 create_define_consts.py | awk '!seen[$0]++' > raylib/defines.py +python3 create_define_consts.py | awk '!seen[$0]++' > dynamic/raylib/defines.py echo "creating pyi files" python3 create_stub_pyray.py > pyray/__init__.pyi -python3 create_enums.py >> pyray/__init__.pyi python3 create_stub_static.py >raylib/__init__.pyi