Skip to content

Instantly share code, notes, and snippets.

@Ivoz
Last active October 19, 2020 11:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ivoz/6838728 to your computer and use it in GitHub Desktop.
Save Ivoz/6838728 to your computer and use it in GitHub Desktop.
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