Last active
October 19, 2020 11:17
-
-
Save Ivoz/6838728 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctypes | |
# Create a function prototype for a 3-arg function | |
ternaryfunc = ctypes.CFUNCTYPE(ctypes.py_object, ctypes.py_object, | |
ctypes.py_object, ctypes.c_void_p) | |
# Define a new python type that's callable, via a ternaryfunc | |
class PyTypeObject(ctypes.Structure): | |
_fields_ = ( | |
("ob_refcnt", ctypes.c_ssize_t), | |
("ob_type", ctypes.c_void_p), | |
("ob_size", ctypes.c_ssize_t), | |
("tp_name", ctypes.c_char_p), | |
("tp_basicsize", ctypes.c_ssize_t), | |
("tp_itemsize", ctypes.c_ssize_t), | |
("tp_dealloc", ctypes.c_void_p), | |
("tp_print", ctypes.c_void_p), | |
("tp_getattr", ctypes.c_void_p), | |
("tp_setattr", ctypes.c_void_p), | |
("tp_reserved", ctypes.c_void_p), | |
("tp_repr", ctypes.c_void_p), | |
("tp_as_number", ctypes.c_void_p), | |
("tp_as_sequence", ctypes.c_void_p), | |
("tp_as_wrapping", ctypes.c_void_p), | |
("tp_hash", ctypes.c_void_p), | |
("tp_call", ternaryfunc), | |
("tp_str", ctypes.c_void_p), | |
) | |
# And define a python object whose type is the one above | |
class PyObject(ctypes.Structure): | |
_fields_ = ( | |
("ob_refcnt", ctypes.c_ssize_t), | |
("ob_type", ctypes.POINTER(PyTypeObject)), | |
) | |
@ternaryfunc | |
def module_call(obj, args, kwargs): | |
if kwargs: | |
kwargs = ctypes.cast(kwargs, ctypes.py_object).value | |
else: | |
kwargs = {} | |
# See if module contains an class named Module, instantiate it | |
if hasattr(obj, obj.__name__.title()): | |
prop = getattr(obj, obj.__name__.title()) | |
# or see if it similarly has a class named module | |
elif hasattr(obj, obj.__name__): | |
prop = getattr(obj, obj.__name__) | |
else: | |
return | |
try: | |
return prop(*args, **kwargs) | |
except TypeError as e: | |
## Well this doesn't work either. | |
raise e | |
# Load a module object into our new PyObject | |
ctypes_mod = PyObject.from_address(id(ctypes)) | |
# Grab its type's contents | |
ctypes_mod_ob_type = ctypes_mod.ob_type.contents | |
# Assign its callable to our module_call function | |
ctypes_mod_ob_type.tp_call = module_call | |
# Your modules can now be called! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment