Python classes for reference counting
Project description
refcount - Python classes for reference counting
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 properly and 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 in refcount
.
refcount
( >=0.7) includes classes using cffi. Other low-level interoperability mechanisms may well be added in the future.
License
MIT (see License.txt)
Documentation
Hosted at refcount via readthedocs.io
Source code
The code repository is on GitHub.
Installation
conda-forge
Using conda
or mamba
:
mamba install -c conda-forge refcount
pypi
pip install refcount
From source (development)
pip install -r requirements.txt
pip install -e .
Sample use
The 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);
void say_walk(testnative::owner* owner);
void release(testnative::reference_counter* obj);
// etc.
From the outside of the library the API is exported with opaque pointers void*
(C structs pointers and native C99 types could be handled too).
void* create_dog();
void* create_owner(void* d);
void say_walk(void* owner);
void release(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 via release
C 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 count
owner = None
This is doable with refcount
and the cffi
package. 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 loading
class CustomCffiNativeHandle(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())
return True
class Dog(CustomCffiNativeHandle):
def __init__(self, pointer = None):
if pointer is None:
pointer = ut_dll.create_dog()
super(Dog, self).__init__(pointer)
# etc.
class DogOwner(CustomCffiNativeHandle):
def __init__(self, dog):
super(DogOwner, self).__init__(None)
self._set_handle(ut_dll.create_owner(dog.get_handle()))
self.dog = dog
self.dog.add_ref() # Do note this important reference increment
def say_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()
return True
Related work
Ancestry, acknowledgements
This python package refcount
actually spawned from prior work for interoperability between C++, R and .NET (R.NET)
refcount
features using cffi
were also significantly informed by Kevin Plastow's work while 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 package dynamic-interop-dll for .NET/native interop.
- a set of mostly c++ software tools for interop with C/C++
- a C# library for generating interop glue code on top of C API glue code.
Other python packages
refcount
was 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.pyutils contains a reference counting class.
Development branch
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file refcount-1.2.5.tar.gz
.
File metadata
- Download URL: refcount-1.2.5.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.9.6 readme-renderer/37.3 requests/2.31.0 requests-toolbelt/1.0.0 urllib3/2.0.7 tqdm/4.66.1 importlib-metadata/6.7.0 keyring/24.1.1 rfc3986/2.0.0 colorama/0.4.6 CPython/3.11.9
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c72ddcb3d4c327f77869a2544a7ba93d94651fca9b22c803aea34ee7b55164f0 |
|
MD5 | 0d8ad5a380682ed0c1237ad38a7c4cb9 |
|
BLAKE2b-256 | 91df8c9d5f02ecee75180319088ebbdc2906260d6a1bb12564044e6830e61cf3 |
File details
Details for the file refcount-1.2.5-py3-none-any.whl
.
File metadata
- Download URL: refcount-1.2.5-py3-none-any.whl
- Upload date:
- Size: 15.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.8.0 pkginfo/1.9.6 readme-renderer/37.3 requests/2.31.0 requests-toolbelt/1.0.0 urllib3/2.0.7 tqdm/4.66.1 importlib-metadata/6.7.0 keyring/24.1.1 rfc3986/2.0.0 colorama/0.4.6 CPython/3.11.9
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ef31568e8bdc7b1db06d85c60bb3fd3a0b9b1bb3d8d33133fdc064612c65df55 |
|
MD5 | e9ac59a7e48801cff9d483c4db3e95b0 |
|
BLAKE2b-256 | 66c43b7f74f1da2e932a2695346e5501731ee7d140c8bd8e7d5ebccdea65cbdb |