Skip to main content

A Python package for reference counting and interop with native pointers

Project description

A Python package for reference counting native pointers

license status Build status

This package has facilities primarily for managing from Python resources from native libraries written for instance in C++. While it boils down to simply maintaining a set of counters, it is practically complicated to properly do so and not end up with memory leak or crashes. This package aims to offer structured options for managing external native resources. Other use cases requiring reference counting may benefit from reusing and extending classes in refcount.

License

MIT-derived (see License.txt)

Installation

pip install -r requirements.txt
python setup.py install

Hopefully soon:

pip install refcount

Documentation

[Placeholder for a set of tutorials and examples]

Example

A canonical illustration of the use of this package, 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 from the end in mind, we want a python user experience like so, hiding the low level details close to the C API:

dog = Dog()
owner = DogOwner(dog)
owner.say_walk()
print(dog.position)
dog = None
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):
        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()

    def say_walk(self):
        ut_dll.say_walk(self.get_handle())

    def _release_handle(self):
        super(DogOwner, self)._release_handle()
        # super(DogOwner, self)._release_handle()
        self.dog.release()
        return True

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

refcount-0.5.1.zip (18.2 kB view hashes)

Uploaded Source

Built Distribution

refcount-0.5.1-py2.py3-none-any.whl (9.4 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page