I’m exposing a function that takes a Buffer as an argument. However, the Buffer type only exists in Python 3.12+.
I had considered using one of these “ponyfills” for it:
Code
Option 1: typing.Union
try:
# version_info >= (3, 12)
from collections.abc import Buffer as BufferLike
except ImportError:
# version_info < (3, 12)
import abc
import array
import collections.abc
import ctypes
import mmap
from typing import Union
BufferLike = Union[
collections.abc.ByteString,
array.array,
ctypes.Array,
memoryview,
mmap.mmap
]
# * CFFI:
try:
import cffi
except ImportError:
pass
else:
if hasattr(cffi.FFI, 'buffer') and isinstance(cffi.FFI.buffer, type):
BufferLike = Union[BufferLike, cffi.FFI.buffer]
else:
_ffi = cffi.FFI()
if isinstance(_ffi.buffer, type):
BufferLike = Union[BufferLike, _ffi.buffer]
else:
with _ffi.new('uint8_t[0]') as _cdata:
_cdata_buf = _ffi.buffer(_cdata)
_ffi_buffer = _cdata_buf.__class__
BufferLike = Union[BufferLike, _ffi_buffer]
# * NumPy:
try:
import numpy
except ImportError:
pass
else:
BufferLike = Union[BufferLike, numpy.ndarray]
# * bitarray
try:
import bitarray
except ImportError:
pass
else:
BufferLike = Union[BufferLike, bitarray.bitarray]
Option 2: collections.abc.ABC
try:
# version_info >= (3, 12)
from collections.abc import Buffer as BufferLike
except ImportError:
# version_info < (3, 12)
import abc
import array
import collections.abc
import ctypes
import mmap
class BufferLike(collections.abc.ByteString):
pass
BufferLike.register(array.array)
BufferLike.register(ctypes.Array)
BufferLike.register(memoryview)
BufferLike.register(mmap.mmap)
# Bonus Library Support:
# * CFFI:
try:
import cffi
except ImportError:
pass
else:
if hasattr(cffi.FFI, 'buffer') and isinstance(cffi.FFI.buffer, type):
BufferLike.register(cffi.FFI.buffer)
else:
_ffi = cffi.FFI()
if isinstance(_ffi.buffer, type):
BufferLike.register(_ffi.buffer)
else:
with _ffi.new('uint8_t[0]') as _cdata:
_cdata_buf = _ffi.buffer(_cdata)
_ffi_buffer = _cdata_buf.__class__
BufferLike.register(_ffi_buffer)
# * NumPy:
try:
import numpy
except ImportError:
pass
else:
BufferLike.register(numpy.ndarray)
# * bitarray
try:
import bitarray
except ImportError:
pass
else:
BufferLike.register(bitarray.bitarray)
But I’m unsure what the considerations are between these options. As far as I can tell, they both do “work”, as in function correctly (at least when the user isn’t sticking in Buffer
-like objects from 3rd-party libraries I don’t yet know about…)
The code does use isinstance(buffer_or_file, BufferLike)
internally to narrow typing on conditional codepaths in functions that take Union[BufferLike, BinaryIO]
.
Is this just a matter of personal preference, or am I missing something major?