From 3744686f7ba16fa006c70d5e98b0f12eb4e18c3f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sun, 3 Mar 2024 11:48:09 +0000 Subject: [PATCH] throw helpful errors when params supplied are not ctype pointers (#122) --- create_stub_pyray.py | 2 ++ pyray/__init__.py | 45 ++++++++++++++++++++++---------------- tests/xtest_raygui2.py | 49 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 19 deletions(-) create mode 100644 tests/xtest_raygui2.py diff --git a/create_stub_pyray.py b/create_stub_pyray.py index ffe6a86..6cbd5e3 100644 --- a/create_stub_pyray.py +++ b/create_stub_pyray.py @@ -41,6 +41,8 @@ def ctype_to_python_type(t): return "int" elif t == "double": return "float" + elif "char * *" in t: + return "list[str]" elif "char *" in t: return "str" elif "char" in t: diff --git a/pyray/__init__.py b/pyray/__init__.py index e721b1b..192ce46 100644 --- a/pyray/__init__.py +++ b/pyray/__init__.py @@ -47,32 +47,43 @@ def makefunc(a): for (c_arg, arg) in zip(ffi.typeof(a).args, args): # print("arg:",str(arg), "c_arg.kind:", c_arg.kind, "c_arg:", c_arg, "type(arg):",str(type(arg))) if c_arg.kind == 'pointer': - if type(arg) == str: + if type(arg) is str: arg = arg.encode('utf-8') - elif type(arg) is bool: - arg = ffi.new("bool *", arg) - elif type(arg) is int: - arg = ffi.new("int *", arg) - elif type(arg) is float: - arg = ffi.new("float *", arg) + # if c_arg is a 'char *' not a 'const char *' then we ought to raise here because its an out + # parameter and user should supply a ctype pointer, but cffi cant detect const + # so we would have to get the info from raylib.json elif type(arg) is list and str(c_arg) == "": arg = [ffi.new("char[]", x.encode('utf-8')) for x in arg] - elif str(type(arg)) == "" and "*" not in str(arg): # CPython - arg = ffi.addressof(arg) - elif str(type(arg)) == "" and "*" not in str(arg): # Pypy + elif is_cdata(arg) and "*" not in str(arg): arg = ffi.addressof(arg) elif arg is None: arg = ffi.NULL + elif not is_cdata(arg): + if str(c_arg) == "": + raise TypeError( + "Argument must be a ctype bool, please create one with: pyray.ffi.new('bool *', True)") + elif str(c_arg) == "": + raise TypeError( + "Argument must be a ctype int, please create one with: pyray.ffi.new('int *', 1)") + elif str(c_arg) == "": + raise TypeError( + "Argument must be a ctype float, please create one with: pyray.ffi.new('float *', 1.0)") modified_args.append(arg) result = a(*modified_args) if result is None: return - if str(type(result)) == "" and str(result).startswith("": - result = "" + return "" else: - result = ffi.string(result).decode('utf-8') - return result + return ffi.string(result).decode('utf-8') + else: + return result + + # apparently pypy and cpython produce different types so check for both + def is_cdata(arg): + return str(type(arg)) == "" or str( + type(arg)) == "" return func @@ -99,20 +110,16 @@ def makeStructHelper(struct): for name, attr in getmembers(rl): - # print(name, attr) + #print(name, dir(attr)) uname = inflection.underscore(name).replace('3_d', '_3d').replace('2_d', '_2d') if isbuiltin(attr) or str(type(attr)) == "" or str( type(attr)) == "": # print(attr.__call__) # print(attr.__doc__) - # print(attr.__text_signature__) # print(dir(attr)) # print(dir(attr.__repr__)) f = makefunc(attr) setattr(current_module, uname, f) - # def wrap(*args): - # print("call to ",attr) - # setattr(PyRay, uname, lambda *args: print("call to ",attr)) else: setattr(current_module, name, attr) diff --git a/tests/xtest_raygui2.py b/tests/xtest_raygui2.py new file mode 100644 index 0000000..49c2f01 --- /dev/null +++ b/tests/xtest_raygui2.py @@ -0,0 +1,49 @@ +import pyray +from pyray import * +import pytest + +SCREEN_WIDTH = 640 +SCREEN_HEIGHT = 480 + + +def main(): + init_window(SCREEN_WIDTH, SCREEN_HEIGHT, "raygui") + set_exit_key(KeyboardKey.KEY_ESCAPE) + set_target_fps(30) + + _bool_pointer = pyray.ffi.new("bool *", True) + _bool = True + _float = 5.5 + _float_pointer = pyray.ffi.new("float *", 5.2) + color = RED + color_pointer = Color() + _int=0 + _int_pointer = pyray.ffi.new("int *", 0) + _string ="cant edit this string" + _string_pointer = pyray.ffi.new("char []", b"0123456789") + + while not window_should_close(): + begin_drawing() + clear_background(WHITE) + + gui_check_box((40, 40, 30, 30), "checkbox", _bool_pointer) + with pytest.raises(TypeError): + gui_check_box(Rectangle(40, 40, 100, 100), "checkbox", _bool) + + gui_color_bar_alpha((40, 80, 100, 20), "bar", _float_pointer) + with pytest.raises(TypeError): + gui_color_bar_alpha((40, 80, 100, 20), "bar", _float) + + gui_color_picker((40,120, 100, 100), "color", color_pointer) + with pytest.raises(TypeError): + gui_color_picker((40,120, 100, 100), "color", color) + + gui_text_box((40,230, 100, 30), _string_pointer, 10, True) + gui_text_box((200,230, 100, 30), _string, 10, True) + + gui_tab_bar((40,300, 100, 30), ["foo", "boo"], 2, _int_pointer) + with pytest.raises(TypeError): + gui_tab_bar((40,300, 100, 30), ["foo", "boo"], 2, _int) + + end_drawing() +main() \ No newline at end of file