-
Notifications
You must be signed in to change notification settings - Fork 766
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
Ideas and progress #1
Comments
new code will look something like this #[py_class]
struct TestClass {
data: Cell<bool>
}
#[py_impl]
impl TestClass {
#[method]
fn test_method(&self, val: PyObject) {}
}
#[py_impl]
impl PyObjectProtocol for TestClass {
fn __call__(&self, args: PyTuple, kwargs: PyDict) -> PyResult<> {
}
...
}
#[py_impl]
impl PyAsyncProtocol for TestClass {
fn __await__(&self) -> PyResult<PyObject> {}
} |
py_class may accept parameters, #[py_class(MyFuture, base=asyncio::Future)]
struct PyFut {} |
big question at the moment, how to parse arguments, especially |
I agree that rust-cpython's class design isn't ideal. I would prefer to be able to not tie this library to the nightly compiler, if instead this functionality could be done through a custom derive. Something along the lines of the following: #[derive(PythonClass)]
#[py_methods(my_method(u64, String), my_other_method)]
#[py_traits(PyFunction(PyTuple, ())]
struct MyClass(...);
impl MyClass {
fn my_method(&self, x: u64) -> PyResult<String> {
...
}
fn my_other_method(&self) {
...
}
}
impl PyFunction for MyClass {
fn __call__(&self, y: PyTuple) -> PyResult<()> {
...
}
} It obviously isn't as nice as what you get with custom attributes (and maybe you could do better than this with some hackery, haven't really thought about it too much), but it should work with stable rust. |
problem is how to define special methods, like PyAsyncMethods of PyNumberMethods. you need access to impl block, and you need to enumerate and generate description during macro expansion. I couldn't find any other way :) |
right now, special method implementation is very simple, for example sequence protocol https://github.com/PyO3/PyO3/blob/master/src/class/sequence.rs#L19 |
added methods and properties implementation #[class]
struct MyClass {}
#[methods]
impl MyClass {
fn method(&self, py: Python, arg: PyObject) -> PyResult<()> {
Ok(())
}
#[getter]
fn get_prop1(&self, py: Python) -> PyResult<PyObject> {...}
#[setter]
fn set_prop1(&self, py: Python, value: PyObject) -> PyResult<()> {...}
#[getter(prop2)]
fn get_some_prop(&self, py: Python) -> PyResult<PyObject> {...}
#[setter(prop2)]
fn set_some_prop(&self, py: Python, value: PyObject) -> PyResult<()> {...}
} next is "#[class]" macro and argument parsing |
One thing that I like about trait PySequenceProtocol {
fn __len__(&self, py: Python) ->Self::Result where Self: PySequenceLenProtocol;
fn __getitem__(&self, py: Python, key: Self::Key) -> Self::Result where Self: PySequenceGetItemProtocol;
...
}
trait PySequenceLenProtocol: PySequenceProtocol {
type Result: IntoPyResult<Target=usize>;
}
trait PySequenceGetItemProtocol: PySequenceProtocol {
type Key: From<isize>; // or maybe something like TryFrom<isize, Err=Self::Result>
type Result: IntoPyResult;
} I'll try to prototype something along these lines latter tonight. |
arg parser is next after regarding dangling methods, those are visible only in rust code, python code does not see unimplemented methods. I don't know how to make method signature explicit and optional at the same time |
|
Unfortunately I didn't have as much time as I would like tonight to work on this. I pushed what I did tonight here: 49c3502. The idea is to make rust's trait system do most of the heavy lifting. I haven't touched the attribute macros yet, but all that it should need to do for slotted methods is take something like the following: #[py_impl]
impl PyMappingProtocol for MyClass {
fn __len__(&self, py: Python) -> usize {
...
}
fn __getitem__(&self, py: Python, key: String) -> PyResult<i32> {
...
}
} And add the following marker trait impls: impl PyMappingLenProtocol for MyClass {
type Success = usize;
type Result = usize;
}
impl PyMappingGetItemProtocol for MyClass {
type Key = String;
type Success = i32;
type Result = PyResult<i32>;
} After that is done, then some corresponding Impl traits will wrap the methods appropriately, and bundle them up into a I'll try to work more on this over the next couple of days. |
That's awesome. I'll play with this idea too |
@ohanar |
we can add default method implementation with attribute macro |
Yes, I noticed that right after writing my post, and added a default implementation: 3be2c9c. Because of the marker traits, those methods don't really exist unless you implement the corresponding marker trait (the rust compiler just won't let you call them), so the method is more or less unchanged. |
that is so awesome! I love rust :) |
Very cool! I'm glad the macro code is as straightforward I hoped (admittedly I haven't yet written any macros using syn+quote, but I've read through their docs, and it seemed like it would be straightforward). Now we just need macros to generate all of the traits and their impl's :). |
yes, that will take some time |
FYI, I'm working on a macro to help with this. |
@ohanar very good! could you check this code https://github.com/PyO3/PyO3/blob/master/src/conversion.rs#L136 |
This can't currently be resolved. The issue is rust doesn't know which impl to use for an I personally think that the impl for |
I pushed my work in progress of the boilerplate generator to my fork. I probably won't have time to work on it much more for a couple of days. It needs a little more work on the parsing side of things (mainly needs to handle special edge cases, like |
I came to similar conclusion on |
I added ability to specify py methods in protocol, some protocol fn needs to be py methods and not slots, i.e. |
This fork is interesting ! I'm new to |
@ohanar i am not sure how to use reference in assitiated type without attaching lifetime everywhere |
ok, figured this out myself. |
it seems it is not possible to use associated types for protocol implementation if type needs to be generic over lifetime (references), we need HKT for this. am I wrong? |
I haven't had the chance to look at your pyptr branch in depth enough to see why things are failing, but I'm not sure that we need HKTs for this. I think my original signature was a slightly off; I think it should be something more like this: trait PyMappingProtocol: ... {
fn __setitem__<'a, 'b>(&self, /* py: Python */, key: Self::Key, value: Self::Value) -> Self::Result
where Self: PyMappingSetItemProtocol<'a, 'b>
{ unimplemented!() }
....
}
trait PyMappingSetItemProtocol<'a, 'b>: PyMappingProtocol {
type Key: FromPyObject<'a>;
type Value: FromPyObject<'b>;
type Success: ToPyObject;
type Result: Into<PyResult<Self::Success>>;
} That is methods should be generic over a lifetime for each python object argument. If you still run into issues with this, we could always remove the lifetime parameter from |
I already removed |
experimenting with multiple lifetimes |
It's important the lifetimes be on the methods and method traits, not on the protocol traits. |
I am closing this ticket. all ideas get merged into master |
This prototype implements use of Py<BaseException> as the instance to use for exception instances. These instances integrate reasonably well with the Rust’s standard error mechanisms by implementing the `Display` and `Error` traits. These error types can also be stored into e.g. `failure::Fail`s or other error types as a cause of some greater error.
This prototype implements use of Py<BaseException> as the instance to use for exception instances. These instances integrate reasonably well with the Rust’s standard error mechanisms by implementing the `Display` and `Error` traits. These error types can also be stored into e.g. `failure::Fail`s or other error types as a cause of some greater error.
In pyca/cryptography this function is the PyO3#1 source of lines of generated LLVM IR, because it is duplicated 42x (and growing!). By rewriting it so most of the logic is monomorphic, we reduce the generated LLVM IR for this function by 4x.
In pyca/cryptography this function is the #1 source of lines of generated LLVM IR, because it is duplicated 42x (and growing!). By rewriting it so most of the logic is monomorphic, we reduce the generated LLVM IR for this function by 4x.
* Mappingproxy (#1) Adds in the MappingProxy type. * Move over from `iter` to `try_iter`. * Added lifetime to `try_iter`, preventing need to clone when iterating. * Remove unneccessary borrow. * Add newsfragment * Newline to newsfragment. * Remove explicit lifetime, * Review comments (#2) * Addressing more comments * Remove extract_bound. * Remove extract methods. * Update comments for list return type. --------- Co-authored-by: Kevin Matlock <[email protected]>
* Mappingproxy (#1) Adds in the MappingProxy type. * Move over from `iter` to `try_iter`. * Added lifetime to `try_iter`, preventing need to clone when iterating. * Remove unneccessary borrow. * Add newsfragment * Newline to newsfragment. * Remove explicit lifetime, * Review comments (#2) * Addressing more comments * Remove extract_bound. * Remove extract methods. * Update mapping to return PyList instead of Sequence. * Update comments for list return type. * Add newfragment. * Reimpliment copy with PyMapping type. * Trigger Build --------- Co-authored-by: Kevin Matlock <[email protected]>
I work on new py class implementation based on procedural macros and specialization, but that requires rust nightly. should be ready in several days.
The text was updated successfully, but these errors were encountered: