Package: cexi
Cee EXtensions InterpolationRationalecexi aims to facilitate developing ofC extensionforCPython. In particular interfacing between python and C. In general building C extensions is a tedious process, especially when it comes to interfacing between two languages. cexi aims to make it easier by providing a simple interface to write C extensions in a pythonic way. It's not a replacement forCython,CFFI,SWIG,Boost.PythonorPyBind11, but rather a tool to make writing C extensions easier. It's main features are:pythonic interface to write C extensionsautomatic re/compilation of C extensionsautomatic loading of C extensionsCode examplefromcexiimportModule,sclassFoo(Module):classoptions:flags=['-O3']"""#include "stdio.h""""@s.ceedeffoo(x:int)->int:"""return x + 1;"""@s.sharedefbar(self,x:int)->int:returnx**2@s.pydefbaz(x:int,y:int)->(int,int):"""printf("baz\\n");int ret = x + y;bar(ret, &ret);return(foo(x + y), ret);"""defwrapped_baz(self,x,y):print(f'calling{self.baz}')returnself.baz(x,y)Foo().foo(1)# => 2ret=Foo().wrapped_baz(3,4)# => prints# calling <cexi.proxy.Proxy object at 0x7f4bae56cf10># bazprint(ret)# => prints (8, 49)classFoo(Module,near=__file__):passclassFoo(Module):directory=Path('/some/path')BreakdownEach extension begins with a class definition that inherits fromcexi.Module. User can define flags
that will be passed to compiler viaoptionsclass attribute.classFoo(Module):classoptions:flags=['-O3']Module docstring is directly inserted at the beginning of cee extension. It's useful to include headers
that will be used in extension's code.classFoo(Module):"""#include "stdio.h""""Then user can define functions that will be compiled as extension's functions. There are three types of functions:@s.cee- plain cee function, it's useful to organize plain cee routines..ceefunctions aren't available for use in python, they're simply excluded from final class namespace@s.share-  .share is a plain python function that is added to module to be used in cee code it's signature is transformed as such:func([input parameters]) -> <output parameters>=>int func([input parameters], [pointers to output parameters])e.g. bar here becomesint bar(int x, int *a), it returns non-zero value on failure & modify pointer to the return value@s.py- .py is a cee extension function. it's available from python & can use both .cee & .share functions at will
Untagged functions are left untouched, i.e. they're just instance's methods.
cexi.Module children act as singletones - on instantiation they're get loaded/compiled by default they are built inside temporaty directories, but users are able to make modules persistent. There are two ways to do it:nearparameter - if it's set to__file__module will be built in directory at__file__/../<module name>_cexi_moduledirectoryclass attribute - if it's set module will be built in specified directoryPersistent extensions compiled on-demand. If extension is persistent cexi first loads it's module.
Then it compares revisions, which are hashed module's contents. Thus if class definition is changed
since last compilation it will be re-compiled and re-loaded.You can also compile persistent extensions with commandpython-mcexi<modulepath>:<classname>Installationpipinstallcexi