Как разобрать PyCodeObject с помощью PyO3?

Я читаю файлы .pyc, и мне нужно иметь возможность демаршалировать объекты кода. Когда я пытаюсь преобразовать неупорядоченный PyAny в PyCodeObject, я получаю следующее сообщение об ошибке:

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`

Каков правильный способ сделать это?

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());
}

Чтобы создать тестовый файл:

  1. Создайте файл .py
  2. Импортируйте модуль в Python (например, python(3) -c 'import ...')
  3. В папке __pycache__ должен быть файл .pyc
  4. Замените путь в коде вызова include_bytes! на фактический путь

Информация о версии

  • Ржавчина 2018
  • rustc 1.43.0-ночная (564758c4c 08.03.2020)
  • грузовая 1.43.0-ночная (bda50510d 2020-03-02)
  • CPython 3.7.3
  • РуО3 0.9.1

person Solomon Ucko    schedule 22.03.2020    source источник
comment
Комментарии не для расширенного обсуждения; этот разговор был перешел в чат.   -  person Samuel Liew♦    schedule 24.03.2020


Ответы (1)


Кажется, я понял, как это сделать:

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 };
person Solomon Ucko    schedule 23.03.2020
comment
@user4815162342 user4815162342 Ни extract, ни as_ref недействительны. Я думаю, проблема в том, что PyCodeObject не реализовать любую из необходимых черт... - person Solomon Ucko; 23.03.2020