Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PyMarshal_* functions to ffi interface. #460

Merged
merged 7 commits into from
Apr 28, 2019

Conversation

de-vri-es
Copy link
Contributor

This PR adds the PyMarshal_* functions [1] to the ffi interface.

This can be used to serialize/deserialize a limited set of python objects. Most interestingly for me, it can serialize code objects. That makes it possible to split compiling and running of python code between different processes, which can be very useful.

I haven't added any tests, mainly because it looks like there are no tests for the ffi modules.

[1] https://docs.python.org/3/c-api/marshal.html

Copy link
Member

@pganssle pganssle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 2.7 is no longer supported, so I think the marshal.rs module can be added directly into the ffi/ folder, not the ffi3/ folder. The ffi3 folder exists for historical reasons, because originally Python 2 and 3 had their own completely separate implementations. The ffi folder was recently created for a few modules that just used conditional compile statements to support both, but I think new modules should go in ffi (and eventually the old modules should move there too).

@pganssle
Copy link
Member

@de-vri-es I think generally no tests are added because the ffi stuff is used by the safe rust layer, and that is tested.

I'm not sure what the policy is on expanding the ffi without a corresponding change in the safe Rust layer. I think it would be better to have a safe rust layer, but if it doesn't make sense to add one, then maybe just test the ffi layer.

@kngwyu
Copy link
Member

kngwyu commented Apr 24, 2019

Though I'm not against adding the marshal module, I have no idea what we can use it for 🤔

@codecov
Copy link

codecov bot commented Apr 24, 2019

Codecov Report

Merging #460 into master will increase coverage by 0.03%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #460      +/-   ##
==========================================
+ Coverage   87.83%   87.87%   +0.03%     
==========================================
  Files          64       65       +1     
  Lines        3388     3398      +10     
==========================================
+ Hits         2976     2986      +10     
  Misses        412      412
Impacted Files Coverage Δ
src/lib.rs 0% <ø> (ø) ⬆️
src/marshal.rs 100% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8399916...556e7ba. Read the comment docs.

@de-vri-es
Copy link
Contributor Author

Python 2.7 is no longer supported, so I think the marshal.rs module can be added directly into the ffi/ folder, not the ffi3/ folder.

Moved :)

I'm not sure what the policy is on expanding the ffi without a corresponding change in the safe Rust layer. I think it would be better to have a safe rust layer, but if it doesn't make sense to add one, then maybe just test the ffi layer.

I added a safe wrapper for Read/WriteObjectToString with a test that checks if a dict round-trips. I pretty much copied the interface of from the python marshal module.

The rest of the ffi functions take a *mut FILE. That makes it difficult to safely wrap them, and to test them. I considered not even adding those functions, but that seemed like half work. However, if tests are a rquirement, maybe we should just remove these? They don't really play well with Rust.

Though I'm not against adding the marshal module, I have no idea what we can use it for thinking

@kngwyu: The use case I have in mind is a proc macro that compiles python code and serializes it. Then at runtime, the compiled code is deserialized and executed (currently in a PR at m-ou-se/inline-python#5).

kngwyu
kngwyu previously approved these changes Apr 25, 2019
src/marshal.rs Outdated
///
/// The built-in marshalling only supports a limited range of object.
/// See the [python documentation](https://docs.python.org/3/library/marshal.html) for more details.
pub fn dumps(py: Python, object: &PyObject, version: i32) -> PyResult<Vec<u8>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about returning PyResult<&PyBytes>?
E.g.,

use crate::conversion::FromPyPointer;
...
FromPyPointer::from_owned_ptr_or_err(py, bytes)

would work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that avoids the possibly pointless copy into a Vec. Nice :)

src/marshal.rs Outdated
}

/// Deserialize an object from bytes using the Python built-in marshal module.
pub fn loads(py: Python, data: &impl AsRef<[u8]>) -> PyResult<PyObject> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to return PyResult<&PyAny>, since it has downcast* methods.
FromPyPointer::from_owned_ptr_or_err would work here too.

src/marshal.rs Show resolved Hide resolved
@kngwyu kngwyu dismissed their stale review April 25, 2019 03:45

Mistakenly pushed Approve button

@kngwyu
Copy link
Member

kngwyu commented Apr 25, 2019

Thanks, I left some comments but your implementation mostly looks good.
PyObject and &PyAny are really confusing objects.
In most cases we prefer to &PyAny, since it has a lifetime same as GILGuard.
But if you need to store objects jumping over GILGuards, you need to use PyObject.

However, if tests are a rquirement, maybe we should just remove these?

Currently we don't test all of FFI functions, so I don't think tests are absolutely necessary.
However, I'm for removing these functions if you don't need them.

The use case I have in mind is a proc macro that compiles python code and serializes it.

Wow it's exciting 😃

@de-vri-es
Copy link
Contributor Author

de-vri-es commented Apr 25, 2019

Thanks for the feedback! I believe I processed the requested changes.

FromPyPointer::from_owned_ptr_or_err also simplified the wrapper to just a few lines. Very nice :)

As input the dumps function now takes a &impl AsPyPointer instead of a &PyObject. That seemed like the right bound.

/edit: The macro is already working btw. Once this lands in a released version I can simplify the implementation a bit though. Currently I expose the ffi functions there locally. :)

Copy link
Member

@kngwyu kngwyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

///
/// See the [python documentation](https://docs.python.org/3/library/marshal.html) for more details.
///
/// # Example:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@kngwyu
Copy link
Member

kngwyu commented Apr 26, 2019

Thanks for the change, I approved this PR.
Since it adds a new module, it's better if @konstin would take a glance on it.

@kngwyu
Copy link
Member

kngwyu commented Apr 26, 2019

@de-vri-es
Could you please rebase on the master?
It would make CI green.

@de-vri-es
Copy link
Contributor Author

Rebased on master. Though it first had a DNS failure in the appveyor environment, but a re-trigger got it past that :)

Copy link
Member

@konstin konstin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@konstin konstin merged commit b5bf17f into PyO3:master Apr 28, 2019
@de-vri-es de-vri-es deleted the marshal branch April 28, 2019 13:36
@de-vri-es de-vri-es restored the marshal branch April 28, 2019 13:36
@m-ou-se m-ou-se deleted the marshal branch March 20, 2020 17:26
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.

4 participants