-
Notifications
You must be signed in to change notification settings - Fork 807
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementation of 'com_record' as a subclassable Python type. #2437
base: main
Are you sure you want to change the base?
Conversation
This PR addresses issue #2361 and will allow to create subclasses of It does enable typing of interface methods that expect a particular structure as a parameter. To define a particular subclass of
As an example with the following Type Library IDL:
the record class definitions for
The metaclass in the above code is only used to avoid retyping the The subclasses provide valuable information for type hints.
With the above class definitions, new instances of a particular record type can simply be created with e.g.
This PR does not break any existing code because the On the other hand, COM records returned by a call to a COM interface method will receive the proper subclass type, if their RecordInfo does match the GUID of a |
A 'tp_new' method was added to the 'PyTypeObject' slots of 'com_record'. Replacement new is now used to create an instance of a 'com_record' type, i.e. in 'tp_new' as well as in the factory functions. The 'tp_dealloc' method explicitely calls the destructor before finally calling 'tp_free'. Records returned from a call to a COM method do get the subclass type according to the GUID in the COM RecordInfo. If no subclass with that GUID is found, the generic 'com_record' base class is used. The algorithm that retrieves the list of subclasses of 'com_record' only uses methods and data structures of the public Python API. This is important because in Python 3.12 the type of the 'tp_subclasses' slot of a 'PyTypeObject' was changed to 'void*' to indicate that for some types it does not hold a valid 'PyObject*'. The 'PyRecord_Check' function was modified to test if the object is an instance of 'com_record' or a derived type. The implementation does not break existing code. It is not required to define 'com_record' subclasses, i.e. it is possible to work with the generic 'com_record' type as before using the factory function.
0c591f8
to
ebfaa62
Compare
A 'tp_new' method was added to the 'PyTypeObject' slots of 'com_record'. Replacement new is now used to create an instance of a 'com_record' type, i.e. in 'tp_new' as well as in the factory functions. The 'tp_dealloc' method explicitely calls the destructor before finally calling 'tp_free'.
Records returned from a call to a COM method do get the subclass type according to the GUID in the COM RecordInfo. If no subclass with that GUID is found, the generic 'com_record' base class is used.
The algorithm that retrieves the list of subclasses of 'com_record' only uses methods and data structures of the public Python API. This is important because in Python 3.12 the type of the 'tp_subclasses' slot of a 'PyTypeObject' was changed to 'void*' to indicate that for some types it does not hold a valid 'PyObject*'.
The 'PyRecord_Check' function was modified to test if the object is an instance of 'com_record' or a derived type.
The implementation does not break existing code.
It is not required to define 'com_record' subclasses, i.e. it is possible to work with the generic 'com_record' type as before using the factory function.
Resolves #2361