question on callback functions with ctypes
question on callback functions with ctypes I try to use GoVCL( https://github.com/ying32/govcl ) in python via ctypes. GoVCL supplies C header and simple C demo under https://github.com/ying32/govcl/tree/master/Tools/makeCHeader/test Now the simple python code can run on both win7 and win10 according to Eryk Sun's suggestion - thank you Eryk Sun. But I am still puzzled by 2 questions 1. the callback function does not been invoked, so there must be something wrong when I deal with it. However, I can't figure it out. 2. in the original main.c, there is no need to call `vcl.SetEventCallback(doEventCallbackProc)`. But I learn this in a python code that uses cffi to call GoVCL. How can I make the python code as simple as the C code? Thanks The following python code is a simplified version of the C code ```python import sys, os import ctypes # In Python 3.8+, ctypes no longer searches PATH or the # current working directory when loading DLLs. liblcl_path = os.path.join(os.path.split(os.path.realpath(__file__))[0], 'liblcl.dll') vcl = ctypes.CDLL(liblcl_path) def _doEventCallbackProc(f, args, argcount): print(f, args, argcount) if f == ctypes.addressof(onButton1Click): vcl.DShowMessage("Hello world!".encode('utf8')) elif f == ctypes.addressof(onFormKeyDown): fnOnFormKeyDown(f, args, argcount) elif f == ctypes.addressof(onFormKeyDown): fnOnFormKeyDown(f, args, argcount) doEventCallbackProc = ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long)(_doEventCallbackProc) def _onButton1Click(sender): vcl.ShowMessage("Hello world!"); onButton1Click = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(_onButton1Click) print(ctypes.addressof(onButton1Click)) Char = ctypes.c_uint16 TShiftState = ctypes.c_uint32 def _onFormKeyDown(sender, key, shift): print(key, shift); onFormKeyDown = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(Char), TShiftState)(_onFormKeyDown) print(ctypes.addressof(onFormKeyDown)) def _onEditChange(sender): print("%s\n", vcl.Edit_GetText(sender)); onEditChange = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(_onEditChange) print(ctypes.addressof(onEditChange)) def main(): vcl.SetEventCallback(doEventCallbackProc) vcl.Application_Instance.restype = ctypes.c_void_p Application = vcl.Application_Instance() vcl.Application_Initialize.argtypes = ctypes.c_void_p, vcl.Application_Initialize(Application) vcl.Application_CreateForm.argtypes = ctypes.c_void_p, ctypes.c_bool vcl.Application_CreateForm.restype = ctypes.c_void_p form = vcl.Application_CreateForm(Application, False); vcl.Form_SetCaption.argtypes = ctypes.c_void_p, ctypes.c_char_p vcl.Form_SetCaption(form, "LCL Form".encode('utf8')); vcl.Form_SetKeyPreview.argtypes = ctypes.c_void_p, ctypes.c_bool vcl.Form_SetKeyPreview(form, True); vcl.Form_SetOnKeyDown.argtypes = ctypes.c_void_p, ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(Char), TShiftState) vcl.Form_SetOnKeyDown(form, onFormKeyDown); vcl.Button_Create.argtypes = ctypes.c_void_p, vcl.Button_Create.restype = ctypes.c_void_p btn = vcl.Button_Create(form); vcl.Button_SetParent.argtypes = ctypes.c_void_p, ctypes.c_void_p vcl.Button_SetParent(btn, form); vcl.Button_SetOnClick.argtypes = ctypes.c_void_p, ctypes.CFUNCTYPE(None, ctypes.c_void_p) vcl.Button_SetOnClick(btn, onButton1Click); vcl.Button_SetCaption.argtypes = ctypes.c_void_p, ctypes.c_char_p vcl.Button_SetCaption(btn, "button1".encode('utf8')); vcl.Button_SetLeft.argtypes = ctypes.c_void_p, ctypes.c_uint32 vcl.Button_SetLeft(btn, 100); vcl.Button_SetTop.argtypes = ctypes.c_void_p, ctypes.c_uint32 vcl.Button_SetTop(btn, 100); vcl.Edit_Create.argtypes = ctypes.c_void_p, vcl.Edit_Create.restype = ctypes.c_void_p edit = vcl.Edit_Create(form); vcl.Edit_SetParent.argtypes = ctypes.c_void_p, ctypes.c_void_p vcl.Edit_SetParent(edit, form); vcl.Edit_SetOnChange.argtypes = ctypes.c_void_p, ctypes.CFUNCTYPE(None, ctypes.c_void_p) vcl.Edit_SetOnChange(edit, onEditChange); vcl.Application_Run.argtypes = ctypes.c_void_p, vcl.Application_Run(Application); main() ``` the C code ```C #include "liblcl.h" #ifdef _WIN32 char *UTF8Decode(char* str) { int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0); wchar_t* wCharBuffer = (wchar_t*)malloc(len * sizeof(wchar_t) + 1); MultiByteToWideChar(CP_UTF8, 0, str, -1, wCharBuffer, len); len = WideCharToMultiByte(CP_ACP, 0, wCharBuffer, -1, 0, 0, 0, NULL); char* aCharBuffer = (char*)malloc(len * sizeof(char) + 1); WideCharToMultiByte(CP_ACP, 0, wCharBuffer, -1, aCharBuffer, len, 0, NULL); free((void*)wCharBuffer); return aCharBuffer; } #endif void onButton1Click(TObject sender) { ShowMessage("Hello world!"); } void onOnDropFiles(TObject sender, void* aFileNames, intptr_t len) { printf("aFileNames: %p, len=%d\n", aFileN
Re: how to let argument be optional falling back to certain integer
On Sun, Jun 21, 2020 at 10:06 AM Boris Dorestand wrote: > > Chris Angelico writes: > > Zero being false shouldn't be a surprise. If None can count as false, > > then so should other "emptiness" values. (Remember, the canonical > > falseness value is False, not None.) > > This is true. I have written 0 as false in C so many times. But > clearly for me times have changed... I now look at numbers as a thing > in their own special class not to be confused as truth-values. (So much > so that I fell for this.) But I confess I still think of numbers as all > TRUE. (Even zero!) That's an interesting view. But fortunately you can have that too - just have to treat None as its own thing, instead of using a falsiness test. :) > Anyway, I kind of replied just to thank you all for the great group this > is. ChrisA, I don't know how can keep up with this newsgroup, but you > do. This is crazy. Years go by and when I come back, there you are > still. You're priceless. You're most welcome! I hang out here a lot because the people here are awesome. I've learned a lot, helped a lot of people, the language has shifted, it's been great. I like to think of myself as an empowerer - I help YOU to be able to do amazing things. It's you who are the awesome creative person who's making code do magic, and I'm just removing barriers from your way :) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
Re: how to let argument be optional falling back to certain integer
Chris Angelico writes: > On Sun, Jun 21, 2020 at 2:02 AM Boris Dorestand > wrote: >> >> I just wrote >> >> def f(y, N, k = None): >> k = k or (N - 1) >> return k >> >> I was surprised to find out that 0 == False, so f(7, 31, 0) produces 31. >> >> I'd like 0 to be a valid choice for k. >> >> How do you guys let k be an optional argument such that it defaults to >> N - 1? >> > > The easiest way is to explicitly check for None. > > if k is None: k = N - 1 Got it. That's clear code. > Zero being false shouldn't be a surprise. If None can count as false, > then so should other "emptiness" values. (Remember, the canonical > falseness value is False, not None.) This is true. I have written 0 as false in C so many times. But clearly for me times have changed... I now look at numbers as a thing in their own special class not to be confused as truth-values. (So much so that I fell for this.) But I confess I still think of numbers as all TRUE. (Even zero!) Anyway, I kind of replied just to thank you all for the great group this is. ChrisA, I don't know how can keep up with this newsgroup, but you do. This is crazy. Years go by and when I come back, there you are still. You're priceless. -- https://mail.python.org/mailman/listinfo/python-list
Re: how to let argument be optional falling back to certain integer
Le 20/06/2020 à 18:23, Stefan Ram a écrit : Boris Dorestand writes: def f(y, N, k = None): k = k or (N - 1) return k I was surprised to find out that 0 == False, so f(7, 31, 0) produces 31. bool is a subtype of int. I'd like 0 to be a valid choice for k. k = N-1 if k==None else k When comparing wih None "is" is preferred to == k = N - 1 if k is None else k -- https://mail.python.org/mailman/listinfo/python-list
Re: how to let argument be optional falling back to certain integer
On Sun, Jun 21, 2020 at 2:02 AM Boris Dorestand wrote: > > I just wrote > > def f(y, N, k = None): > k = k or (N - 1) > return k > > I was surprised to find out that 0 == False, so f(7, 31, 0) produces 31. > > I'd like 0 to be a valid choice for k. > > How do you guys let k be an optional argument such that it defaults to > N - 1? > The easiest way is to explicitly check for None. if k is None: k = N - 1 Zero being false shouldn't be a surprise. If None can count as false, then so should other "emptiness" values. (Remember, the canonical falseness value is False, not None.) ChrisA -- https://mail.python.org/mailman/listinfo/python-list
how to let argument be optional falling back to certain integer
I just wrote def f(y, N, k = None): k = k or (N - 1) return k I was surprised to find out that 0 == False, so f(7, 31, 0) produces 31. I'd like 0 to be a valid choice for k. How do you guys let k be an optional argument such that it defaults to N - 1? Thank you. -- https://mail.python.org/mailman/listinfo/python-list
Re: How to test?
On 5/1/20 2:34 PM, DL Neil via Python-list wrote: >>> Given your replies, 'now' might be a good time to take a look at >>> Pytest, and see how you could use it to help build better code - by >>> building tested units/functions which are assembled into ever-larger >>> tested-units... (there is a range of choice/other testing aids if >>> Pytest doesn't take your fancy) >> >> I have to admit I chose unittest. Simply because it is in the standard >> lbrary. As so many people seem to prefer pytest I should take a look at >> it. > > Not at all! This is a personal bias - I happen to have been using Pytest. it doesn't have to be either-or; pytest can deal with unittest tests, with some limitations. See here for some notes: https://docs.pytest.org/en/stable/unittest.html so you can try out what you have under pytest, and if liking it, can begin to transition to more native pytest - or just keep it as the test runner, or just stick with unittest. -- https://mail.python.org/mailman/listinfo/python-list
Re: How to test?
Worth noting: by assertTrue he probably meant assertEqual. But I'd recommend using assertIn [1] if you're using unittest to check output written to stdout/stderr. That way, your tests are slightly more robust to changes in the exact output. pytest may also be helpful for this (or any!) type of testing. Disclaimer/warning: pytest can be confusing even for experienced python programmers because it does some fancy things. But if you put in the time to learn it, it's very popular because of the way it structures testsuites and code reuse (i.e. fixtures). It can do a lot to help you, and provides output capturing out of the box [2] as well as some handy tools for building temporary testing directories [3]. [1] https://docs.python.org/3.6/library/unittest.html#unittest.TestCase.assertIn [2] https://docs.pytest.org/en/stable/capture.html [3] https://docs.pytest.org/en/stable/tmpdir.html On Fri, Jun 19, 2020 at 2:18 PM Terry Reedy wrote: > On 6/17/2020 12:34 PM, Tony Flury via Python-list wrote: > > > In a recent application that I wrote (where output to the console was > > important), I tested it using the 'unittest' framework, and by patching > > sys.stderr to be a StringIO - that way my test case could inspect what > > was being output. > > Tony's code with hard returns added so that code lines remain separated > instead of wrapping. > > with patch('sys.stderr', StringIO()) as stderr: >application.do_stuff() self.assertTrue(stderr.getvalue(), >'Woops - that didn\'t work') > This doc, worth reading more than once, is > https://docs.python.org/3/library/unittest.mock.html#the-patchers > > -- > Terry Jan Reedy > > -- > https://mail.python.org/mailman/listinfo/python-list > -- https://mail.python.org/mailman/listinfo/python-list