Skip to main content

Python classes for reference counting

Project description

refcount - Python classes for reference counting

license status Documentation Status codecovPython package

pypi versionConda VersionConda Downloads

Reference counted native handles

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:

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:

Development branch

Python package

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-1.2.5.tar.gz (15.4 kB view details)

Uploaded Source

Built Distribution

refcount-1.2.5-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

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

Hashes for refcount-1.2.5.tar.gz
Algorithm Hash digest
SHA256 c72ddcb3d4c327f77869a2544a7ba93d94651fca9b22c803aea34ee7b55164f0
MD5 0d8ad5a380682ed0c1237ad38a7c4cb9
BLAKE2b-256 91df8c9d5f02ecee75180319088ebbdc2906260d6a1bb12564044e6830e61cf3

See more details on using hashes here.

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

Hashes for refcount-1.2.5-py3-none-any.whl
Algorithm Hash digest
SHA256 ef31568e8bdc7b1db06d85c60bb3fd3a0b9b1bb3d8d33133fdc064612c65df55
MD5 e9ac59a7e48801cff9d483c4db3e95b0
BLAKE2b-256 66c43b7f74f1da2e932a2695346e5501731ee7d140c8bd8e7d5ebccdea65cbdb

See more details on using hashes here.

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