Interop module¶
Reference counting classes using
cffi
(C Foreign Function Interface for Python) for interoperability.
Implementation of reference counting classes for external resources accessed via interoperability software such as cffi
CffiData: TypeAlias = Any
module-attribute
¶
A dummy type to use in type hints for limited documentation purposes
FFI.CData is a type, but it seems it cannot be used in type hinting.
CffiNativeHandle
¶
Bases: NativeHandle
Reference counting wrapper class for CFFI pointers
This class is originally inspired from a class with a similar purpose in C#. See https://github.com/rdotnet/dynamic-interop-dll
Say you have a C API as follows:
void* create_some_object();
dispose_of_some_object(void* obj);
and accessing it using Python and CFFI.
Users would use the calllib
function:
from cffi import FFI
ffi = FFI()
# cdef() expects a single string declaring the C types, functions and
# globals needed to use the shared object. It must be in valid C syntax.
ffi.cdef('''
void* create_some_object();
dispose_of_some_object(void* obj);
''')
mydll_so = ffi.dlopen('/path/to/mydll.so')
cffi_void_ptr = mydll_so.create_some_object()
at some point when done you need to dispose of it to clear native memory:
In practice in real systems one quickly ends up with cases
where it is unclear when to dispose of the object.
If you call the dispose_of_some_object
function more
than once, or too soon, you quickly crash the program, or possibly worse outcomes with numeric non-sense.
CffiNativeHandle
is designed to alleviate this headache by
using native reference counting of handle
classes to reliably dispose of objects.
Attributes:
Name | Type | Description |
---|---|---|
_handle |
object
|
The handle (e.g. cffi pointer) to the native resource. |
_type_id |
Optional[str]
|
An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. |
_finalizing |
bool
|
a flag telling whether this object is in its deletion phase. This has a use in some advanced cases with reverse callback, possibly not relevant in Python. |
Source code in refcount/interop.py
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
|
disposed: bool
property
¶
Has the native object and memory already been disposed of.
Returns:
Type | Description |
---|---|
bool
|
The underlying native handle has been disposed of from this wrapper |
is_invalid: bool
property
¶
Is the underlying handle valid? In practice synonym with the disposed attribute.
Returns:
Type | Description |
---|---|
bool
|
True if this handle is valid |
obj: Any
property
¶
Return the object pointed to (cffi object)
ptr: CffiData
property
¶
Return the pointer (cffi object)
type_id: Optional[str]
property
¶
Return an optional type identifier for the underlying native type.
This can be in practice useful to be more transparent about the underlying type obtained via a C API with opaque pointers (i.e. void*)
Returns:
Name | Type | Description |
---|---|---|
str |
Optional[str]
|
optional type identifier |
__del__()
¶
destructor, triggering the release of the underlying handled resource if the reference count is 0
Source code in refcount/interop.py
__dispose_impl(decrement)
¶
An implementation of the dispose method in a 'Dispose' software pattern. Avoids cyclic method calls.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
decrement |
bool
|
indicating whether the reference count should be decreased. It should almost always be True except in very unusual use cases (argument is for possible future use). |
required |
Source code in refcount/interop.py
__init__(handle, type_id=None, prior_ref_count=0)
¶
Initialize a reference counter for a resource handle, with an initial reference count.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
handle |
object
|
The handle (e.g. cffi pointer) to the native resource. |
required |
type_id |
Optional[str]
|
An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. |
None
|
prior_ref_count |
int
|
the initial reference count. Default 0 if this NativeHandle is sole responsible for the lifecycle of the resource. |
0
|
Source code in refcount/interop.py
__repr__()
¶
__str__()
¶
string representation
Source code in refcount/interop.py
dispose()
¶
Disposing of the object pointed to by the CFFI pointer (handle) if the reference counts allows it.
get_handle()
¶
Gets the underlying low-level CFFI handle this object wraps
Returns:
Type | Description |
---|---|
Union[CffiData, None]
|
CFFI handle or None |
release()
¶
CffiWrapperFactory
¶
A class that creates custom python wrappers based on the type identifier of the external pointer being wrapped
Source code in refcount/interop.py
__init__(api_type_wrapper, strict_wrapping=False)
¶
summary
Parameters:
Name | Type | Description | Default |
---|---|---|---|
api_type_wrapper |
Dict[str, Any]
|
dictionary, mapping from type identifiers to callables, class constructors |
required |
strict_wrapping |
bool
|
If true, type identifiers passed at wrapper creation time |
False
|
Source code in refcount/interop.py
create_wrapper(obj, type_id, release_native)
¶
summary
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
Union[CffiData, Any]
|
An object, which will be wrapped if this is a CFFI pointer, i.e. an instance of |
required |
type_id |
Optional[str]
|
An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. |
required |
release_native |
Callable[[CffiData], None]
|
function to call on deleting this wrapper. The function should have one argument accepting the object handle. |
required |
Raises:
Type | Description |
---|---|
ValueError
|
Missing type_id |
ValueError
|
If this object is in strict mode, and |
NotImplementedError
|
|
TypeError
|
The function to create the wrapper does not accept any argument. |
Returns:
Name | Type | Description |
---|---|---|
CffiNativeHandle |
CffiNativeHandle
|
cffi wrapper |
Source code in refcount/interop.py
DeletableCffiNativeHandle
¶
Bases: CffiNativeHandle
Reference counting wrapper class for CFFI pointers
Attributes:
Name | Type | Description |
---|---|---|
_handle |
object
|
The handle (e.g. cffi pointer) to the native resource. |
_type_id |
Optional[str]
|
An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. |
_finalizing |
bool
|
a flag telling whether this object is in its deletion phase. This has a use in some advanced cases with reverse callback, possibly not relevant in Python. |
_release_native |
Callable[[CffiData], None]
|
function to call on deleting this wrapper. The function should have one argument accepting the object _handle. |
Source code in refcount/interop.py
__init__(handle, release_native, type_id=None, prior_ref_count=0)
¶
New reference counter for a CFFI resource handle.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
handle |
CffiData
|
The handle (expected cffi pointer) to the native resource. |
required |
release_native |
Callable[[CffiData], None]
|
function to call on deleting this wrapper. The function should have one argument accepting the object handle. |
required |
type_id |
str
|
[description]. An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. Defaults to None. |
None
|
prior_ref_count |
int
|
[description]. The initial reference count. Defaults to 0 if this NativeHandle is sole responsible for the lifecycle of the resource. |
0
|
Source code in refcount/interop.py
GenericWrapper
¶
A pass-through wrapper for python objects that are ready for C interop. "bytes" can be passed as C 'char*'
This is mostly a facility to generate glue code more easily
Source code in refcount/interop.py
OwningCffiNativeHandle
¶
Bases: CffiNativeHandle
Reference counting wrapper class for CFFI pointers that own and already manage the native memory
Attributes:
Name | Type | Description |
---|---|---|
_handle |
object
|
The handle (e.g. cffi pointer) to the native resource. |
_type_id |
Optional[str]
|
An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. |
_finalizing |
bool
|
a flag telling whether this object is in its deletion phase. This has a use in some advanced cases with reverse callback, possibly not relevant in Python. |
Source code in refcount/interop.py
__init__(handle, type_id=None, prior_ref_count=0)
¶
Reference counting wrapper class for CFFI pointers that own and already manage the native memory
Parameters:
Name | Type | Description | Default |
---|---|---|---|
handle |
CffiData
|
The handle (expected cffi pointer) to the native resource. |
required |
type_id |
str
|
[description]. An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. Defaults to None. |
None
|
prior_ref_count |
int
|
[description]. The initial reference count. Defaults to 0 if this NativeHandle is sole responsible for the lifecycle of the resource. |
0
|
Source code in refcount/interop.py
cffi_arg_error_external_obj_type(x, expected_type_id)
¶
Build an error message that an unexpected object is in lieu of an expected refcount external ref object.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x |
object
|
object passed as an argument to a function but with an unexpected type or type id. |
required |
expected_type_id |
Optional[str]
|
Expected identifier for the type of underlying resource being wrapped. |
required |
Returns (str): the error message
Source code in refcount/interop.py
is_cffi_native_handle(x, type_id='')
¶
Checks whether an object is a ref counting wrapper around a CFFI pointer
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x |
object
|
object to test, presumed to be an instance of |
required |
type_id |
Optional[str]
|
Optional identifier for the type of underlying resource being wrapped. |
''
|
Source code in refcount/interop.py
type_error_cffi(x, expected_type)
¶
DEPRECATED Build an error message for situations where a cffi pointer handler is not that, or not of the expected type
Parameters:
Name | Type | Description | Default |
---|---|---|---|
x |
Union[CffiNativeHandle, Any]
|
actual object that is not of the expected type or underlying type for the external pointer. |
required |
expected_type |
str
|
underlying type expected for the CFFI pointer handler |
required |
Returns:
Name | Type | Description |
---|---|---|
str |
str
|
error message that the caller can use to report the issue |
Source code in refcount/interop.py
unwrap_cffi_native_handle(obj_wrapper, stringent=False)
¶
Unwrap a reference counting wrapper and returns its CFFI pointer if it is found (wrapped or 'raw')
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj_wrapper |
Any
|
An object, which will be unwrapped if this is a CFFI pointer, i.e. an instance of |
required |
stringent |
bool
|
[description]. if True an error is raised if obj_wrapper is neither None, a CffiNativeHandle nor an CffiData. Defaults to False. |
False
|
Raises:
Type | Description |
---|---|
Exception
|
A CFFI pointer could not be found in the object. |
Returns:
Type | Description |
---|---|
Union[CffiData, Any, None]
|
Union[CffiData,Any,None]: A CFFI pointer if it was found. Returns None or unchanged if not found, and stringent is equal to False. Exception otherwise. |
Source code in refcount/interop.py
wrap_as_pointer_handle(obj_wrapper, stringent=False)
¶
Wrap an object, if need be, so that its C API pointer appears accessible via a 'ptr' property
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj_wrapper |
Any
|
Object to wrap, if necessary |
required |
stringent |
bool
|
Throws an exception if the input type is unhandled. Defaults to False. |
False
|
Raises:
Type | Description |
---|---|
TypeError
|
neither a CffiNativeHandle nor a CFFI external pointer, nor bytes |
Returns:
Type | Description |
---|---|
Union[CffiNativeHandle, OwningCffiNativeHandle, GenericWrapper]
|
Union[CffiNativeHandle, OwningCffiNativeHandle, GenericWrapper, None]: wrapped object or None |
Source code in refcount/interop.py
wrap_cffi_native_handle(obj, type_id='', release_native=None)
¶
Create a reference counting wrapper around an object if this object is a CFFI pointer
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
Union[CffiData, Any]
|
An object, which will be wrapped if this is a CFFI pointer, i.e. an instance of |
required |
release_native |
Callable[[CffiData], None]
|
function to call on deleting this wrapper. The function should have one argument accepting the object handle. |
None
|
type_id |
Optional[str]
|
An optional identifier for the type of underlying resource. This can be used to usefully maintain type information about the pointer/handle across an otherwise opaque C API. See package documentation. |
''
|