Skip to content

Draft unpack implementation#5902

Draft
kaathewisegit wants to merge 1 commit intoPyO3:mainfrom
kaathewisegit:unpack
Draft

Draft unpack implementation#5902
kaathewisegit wants to merge 1 commit intoPyO3:mainfrom
kaathewisegit:unpack

Conversation

@kaathewisegit
Copy link
Copy Markdown

As per #5623, an implementation of Rust-side unpacking of Python objects.

This is a draft PR, because the API turned out to be trickier than I thought it would be. We have two types: the source (Python object) and the destination (the Rust type). The current trait is only generic over the destination:

trait Unpackable<'py>: Sized {
    fn unpack(obj: Borrowed<'_, 'py, PyAny>) -> PyResult<Self>;
}

The problem with this approach, as I discovered while writing the tests, is that calling it becomes a mouthful:

let unpacked: (i32, i32, i32) = Unpackable::unpack(py_tuple.as_any().as_borrowed()).unwrap();
// to get the error
let try_unpack = <(i32, i32, i32) as Unpackable>::unpack(py_tuple.as_any().as_borrowed()).unwrap_err();

Which means that ideally the trait should also be generic over the python type. This is also important because different types have different error messages. Arbitrary iterators (thanks to OutSquareCapital, I didn't know they unpackable) don't specify how many items we got because they are pulled lazily:

>>> a, b = II()
Traceback (most recent call last):
  File "<python-input-6>", line 1, in <module>
    a, b = II()
    ^^^^
ValueError: too many values to unpack (expected 2)

And sequences with a defined length do:

>>> a, b = [1, 2, 3]
Traceback (most recent call last):
  File "<python-input-7>", line 1, in <module>
    a, b = [1, 2, 3]
    ^^^^
ValueError: too many values to unpack (expected 2, got 3)

It might make sense to define the trait as Unpackable<T> where the implementer is the source and T is the destination. But that'd mean there would be n x m implementations (for 12 tuples for PySequence, PyAny, and PyIterator), which might lead to bloat.

@kaathewisegit kaathewisegit marked this pull request as draft March 22, 2026 09:58
@OutSquareCapital
Copy link
Copy Markdown

OutSquareCapital commented Mar 24, 2026

FYI, i made some work about unpacking of *args and **kwargs here
This may or may not be pertinent to consider,idk, but this is somewhat related.

Once used, this gives some performance gains (see Performance Improvements Details section),
and I'm pretty sure this could be improved further, as my Rust knowledge is beginner level still.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants