Package: refcount
refcount - Python classes for reference countingmaster:testing:This package is primarily for managing resources in native libraries, written for instance in C++, from Python. While it boils down to "simply" maintaining a set of counters,it is deceptively complicated to do so properlyand not end up with memory leaks or crashes. This package offers structured options for reliably managing external native resources. Surprisingly I could not locate an existing package doing just what I needed. Other use cases requiring reference counting, aside from native library resources, may benefit from reusing and extending classes inrefcount.refcount( >=0.7) includes classes usingcffi. Other low-level interoperability mechanisms may well be added in the future.LicenseMIT (seeLicense.txt)DocumentationHosted atrefcount via readthedocs.ioSource codeThe code repository is onGitHub.Installationconda-forgeUsingcondaormamba:mambainstall-cconda-forgerefcountpypipipinstallrefcountFrom source (development)pipinstall-rrequirements.txt
pipinstall-e.Sample useThe following example is based on one of the unit tests.Say we have a C++ library with objects and a C API:#define TEST_DOG_PTR  testnative::dog*#define TEST_OWNER_PTR  testnative::owner*#define TEST_COUNTED_PTR  testnative::reference_counter*testnative::dog*create_dog();testnative::owner*create_owner(testnative::dog*d);voidsay_walk(testnative::owner*owner);voidrelease(testnative::reference_counter*obj);// etc.From the outside of the library the API is exported with opaque pointersvoid*(C structs pointers and native C99 types could be handled too).void*create_dog();void*create_owner(void*d);voidsay_walk(void*owner);voidrelease(void*obj);// etc.Starting with the end in mind, from Python we want an API hiding the low level details close to the C API, in particular avoiding managing native memory viareleaseC API calls, piggybacking the python GC instead.dog=Dog()owner=DogOwner(dog)owner.say_walk()print(dog.position)dog=None# the "native dog" is still alive though, as the owner incremented the ref countowner=NoneThis is doable withrefcountand thecffipackage. One possible design is:ut_ffi=cffi.FFI()ut_ffi.cdef('extern void* create_dog();')ut_ffi.cdef('extern void* create_owner( void* d);')ut_ffi.cdef('extern void say_walk( void* owner);')ut_ffi.cdef('extern void release( void* obj);')# etc.ut_dll=ut_ffi.dlopen('c:/path/to/test_native_library.dll',1)# Lazy loadingclassCustomCffiNativeHandle(CffiNativeHandle):def__init__(self,pointer,prior_ref_count=0):super(CustomCffiNativeHandle,self).__init__(pointer,type_id='',prior_ref_count=prior_ref_count)def_release_handle(self)->bool:ut_dll.release(self.get_handle())returnTrueclassDog(CustomCffiNativeHandle):def__init__(self,pointer=None):ifpointerisNone:pointer=ut_dll.create_dog()super(Dog,self).__init__(pointer)# etc.classDogOwner(CustomCffiNativeHandle):def__init__(self,dog):super(DogOwner,self).__init__(None)self._set_handle(ut_dll.create_owner(dog.get_handle()))self.dog=dogself.dog.add_ref()# Do note this important reference incrementdefsay_walk(self):ut_dll.say_walk(self.get_handle())def_release_handle(self)->bool:super(DogOwner,self)._release_handle()# super(DogOwner, self)._release_handle()self.dog.release()returnTrueRelated workAncestry, acknowledgementsThis python packagerefcountactually spawned from prior work for interoperability between C++, R and .NET (R.NET)refcountfeatures usingcffiwere also significantly informed by Kevin Plastow'sworkwhile he was at the Australian Bureau of Meteorology; this contribution is gratefully acknowledged.In you have native interop needs you may also want to look at:the nuget packagedynamic-interop-dllfor .NET/native interop.a set of mostly c++ softwaretools for interop with C/C++a C# library forgenerating interop glue code on top of C API glue code.Other python packagesrefcountwas created in part because no existing prior (Python) work could quite fit the need. There are however packages that may better address your particular need:infi.pyutilscontains a reference counting class.