Skip to content

A zero-copy file-like wrapper for Python byte buffers, inspired by Rust's std::io::Cursor.

License

Notifications You must be signed in to change notification settings

althonos/iocursor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

06baa5c · Apr 4, 2023

History

54 Commits
Nov 9, 2022
Nov 9, 2022
Feb 5, 2021
Feb 2, 2021
Nov 9, 2022
Feb 10, 2021
Jan 23, 2022
Feb 10, 2021
Apr 4, 2023
Nov 9, 2022
Nov 9, 2022

Repository files navigation

io‸cursor

A zero-copy file-like wrapper for Python byte buffers, inspired by Rust's std::io::Cursor.

Actions Coverage PyPI Wheel Python Versions Python Implementations License Source GitHub issues Downloads Changelog

🗺️ Overview

iocursor.Cursor lets you wrap an allocated buffer (i.e. a Python object implementing the buffer protocol), and interfacing with it through the API of a file-like object. It shares some common points with io.BytesIO but with the following main differences:

  • zero-copy VS copy: Cursor will not copy the data you give it at initialisation, while BytesIO will. This makes Cursor more efficient when you are using it for read-only operations.
  • static VS growable: Cursor will only use the buffer you give it at static memory, while BytesIO will use its dedicated, growable buffer.

🔧 Installing

Install directly from PyPI, using pip:

$ pip install iocursor

Pre-built wheels are available on Linux and OSX for all supported Python3 versions. Otherwise, building from source only requires a working C compiler.

🧶 Thread-safety

iocursor.Cursor instances are not thread-safe. Using several Cursor instances with the same backend memory only for reading should be fine. Use a lock when interfacing otherwise.

💡 Examples

  • Use iocursor.Cursor when you have bytes you need to pass to an interface that only accepts file-like objects. For instance, pass a PNG image decoded from base64 to PIL, without copy:
    import base64
    from iocursor import Cursor
    from PIL import Image
    
    imgdata = base64.b64decode("iVBORw0KGgoAAAANSUhEU...")
    img = Image.open(Cursor(imgdata))
  • Use iocursor.Cursor when you want to use the file-like API to write to a buffer of known size. For instance, retrieve a file using the pysmb API, which only accepts file-like objects:
    from SMB.SMBConnection import SMBConnectSMBConnection
    
    smb = SMBConnection('guest', '', 'client', 'server')
    smb.connect("192.168.0.1")
    
    info = smb.getAttributes("Music", "The Clash/Rock the Casbah.mp3")
    cursor = Cursor(bytearray(shared_file.file_size))
    smb.retrieveFile("Music", "The Clash/Rock the Casbah.mp3", cursor)
    
    buffer = cursor.getvalue()
  • Use iocursor.Cursor when you want to do direct I/O on a type implementing the buffer protocol. For instance, initialize a numpy array by writing bytes to it:
    import numpy
    
    array = numpy.empty(4, dtype="int16")
    cursor = Cursor(array)
    cursor.write(b"\x01\x00\x02\x00\x03\x00\x04\x00")
    print(array)  # array([1, 2, 3, 4], dtype=int16)

💭 Feedback

⚠️ Issue Tracker

Found a bug ? Have an enhancement request ? Head over to the GitHub issue tracker if you need to report or ask something. If you are filing in on a bug, please include as much information as you can about the issue, and try to recreate the same bug in a simple, easily reproducible situation.

🏗️ Contributing

Contributions are more than welcome! See CONTRIBUTING.md for more details.

⚖️ License

This library is provided under the MIT License.

About

A zero-copy file-like wrapper for Python byte buffers, inspired by Rust's std::io::Cursor.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published