1

I am reading .pyc files, and need to be able to unmarshal code objects. When I try to downcast the unmarshalled PyAny to PyCodeObject, I get the following error message:

error[E0277]: the trait bound `pyo3::ffi::code::PyCodeObject: pyo3::type_object::PyTypeInfo` is not satisfied
   --> src/lib.rs:179:47
    |
179 |         let code = *(loads(py, &code_buffer)?.downcast::<PyCodeObject>()?);
    |                                               ^^^^^^^^ the trait `pyo3::type_object::PyTypeInfo` is not implemented for `pyo3::ffi::code::PyCodeObject`
    |
    = note: required because of the requirements on the impl of `for<'py> pyo3::conversion::PyTryFrom<'py>` for `pyo3::ffi::code::PyCodeObject`

error[E0277]: the trait bound `pyo3::ffi::code::PyCodeObject: pyo3::instance::PyNativeType` is not satisfied
   --> src/lib.rs:179:47
    |
179 |         let code = *(loads(py, &code_buffer)?.downcast::<PyCodeObject>()?);
    |                                               ^^^^^^^^ the trait `pyo3::instance::PyNativeType` is not implemented for `pyo3::ffi::code::PyCodeObject`
    |
    = note: required because of the requirements on the impl of `for<'py> pyo3::conversion::PyTryFrom<'py>` for `pyo3::ffi::code::PyCodeObject`

What is the proper way to do this?

MCVE

use pyo3::{ffi::PyCodeObject, marshal::loads, Python};

fn main() {
    let gil_guard = Python::acquire_gil();
    let py = gil_guard.python();
    let code_buffer = &include_bytes!("__pycache__/test.cpython-37.pyc")[16..];
    let code = *(loads(py, &code_buffer)
        .unwrap()
        .downcast::<PyCodeObject>()
        .unwrap());
}

To create the test file:

  1. Create a .py file
  2. Import the module in Python (e.g. python(3) -c 'import ...')
  3. There should be a .pyc file in the __pycache__ folder
  4. Replace the path in the code in the call to include_bytes! with the actual path

Version info

  • Rust 2018
  • rustc 1.43.0-nightly (564758c4c 2020-03-08)
  • cargo 1.43.0-nightly (bda50510d 2020-03-02)
  • CPython 3.7.3
  • PyO3 0.9.1
Solomon Ucko
  • 5,724
  • 3
  • 24
  • 45
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/210200/discussion-on-question-by-solomon-ucko-how-do-i-unmarshal-a-pycodeobject-using-p). – Samuel Liew Mar 24 '20 at 03:27

1 Answers1

1

I think I have figured out how to do this:

let code_ptr = loads(py, &code_buffer)?.as_ptr() as *mut PyCodeObject;
// This should be valid, since PyCodeObject is Copy, as long as the refcount is positive
let code = unsafe { *code_ptr };
Solomon Ucko
  • 5,724
  • 3
  • 24
  • 45
  • @user4815162342 Neither `extract` nor `as_ref` are valid. I think the issue is that [PyCodeObject](https://docs.rs/pyo3/0.9.1/pyo3/ffi/struct.PyCodeObject.html) doesn't implement any of the necessary traits... – Solomon Ucko Mar 23 '20 at 15:14