-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add #[py_class] attribute proc macro #764
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
Conversation
|
In Rust 1.34, which will be released around mid-April, extern_crate_self will be stabilised(rust-lang/rust#57407 (comment)). This allows adding: extern crate self as rustpython_vm;Which solves the problem, as we can then write rustpython_vm::xxx from within the crate. |
|
Oh, nice. This sort of hacky solution works for now, then. |
|
Um... what are the benefits of this? |
|
I would have kept |
Some that I can think of are:
I think that is the right thing to do. Also, while I think this is a good thing to have (see above reasons) I'm not totally convinced that using it for builtins / rustpython internals is the right thing to do. |
|
Oh, I was about to write a new response, so... I'm still not seeing benefits fully. Is it just moving type attribute definitions from
How does it make it easier?
I'd be cautious about putting Python-user-visible strings in the place that's normally used for implementation-level comments and docs.
How? Before seeing your comment I was about to say that it's more confusing now; it seems like all methods are now implicitly exposed with their function name by default? |
Less familiarity with
Implementation-level comments would use
Methods should definitely not be implicitly exposed. For example: impl MyNativeType {
fn helper_rust_only(&self) {
...
}
#[pymethod]
fn method_callable_from_python(self: PyRef<Self>) {
self.helper_rust_only();
}
}The benefit is that you don't have to jump all the way to the |
Alright.
I was commenting about the current version of the code, which does it implicitly - if methods (and properties? :) ) become explicit, that'll be nice indeed.
I'm speaking mostly from my minor experience with CPython, where I rarely had a problem of "is this an exposed method?", and more often of "which (magic) methods does this type expose/override?". For this use case I felt like a centralized spot like this allowed for quicker lookups. (but that was just my experience, I'd be okay with annotation approach - I was just trying to explain my original negative reaction) Anyway, with explicit |
|
Alright, I'll work on that then. |
BTW, are you sure this isn't rust-lang/rust#59406 ? Me and @OddCoincidence encountered this multiple times, it's relatively easy to trigger when doing "covert X to new style args" commits. This appears to be a bug with error reporting, and can be encountered when there's a coding error (referring to |
|
Hmmm, I'll look into that. |
|
More specifically, for example, it occurs when I did by accident Note the mismatch between |
|
Oh, you did it :) |
|
Okay, I think I've addressed all concerns and the current version looks much nicer and more explicit. |
vm/src/obj/objstr.rs
Outdated
| } | ||
| } | ||
|
|
||
| #[pyclass(__inside_vm, name = "str")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It kinda bothers me that this (and the doc comment) is on the impl block instead of the struct - is there any way to make that work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not the #[pyclass] attribute for methods, but if we made another trait PyDocItem or something then we could put the doc comment on the struct definition. I'd say it's probably not worth it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the impl block, PyO3 uses #[pymethods] and #[pyclass] goes on the struct. I think we should imitate that design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I think maybe #[pyimpl] would be better? (since the impl block can contain more than just methods)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like:
#[pyclass]
/// doc
struct PyString {
value: String,
}
type PyStringRef = PyRef<PyString>;
#[pymethods]
impl PyStringRef {
// ...
}The problem is that the type referenced in the impl block is different from the type in the struct declaration, so it won't be able to associate easily between those two proc macros.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite sure on what to call "PyClassTrait" either, do you have any ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to keep rust doc strings for rust, and add python docstrings explicitly, like this:
#[pymethod(name="add", doc="Adds two things (this is a python docstring)")
// This is rust documentation
fn add(a: PyObjectRef, b: PyObjectRef) -> PyResult {
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is, the functions probably aren't going to need Rust documentation, as they're just implementation details for the final Python API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree that this is the case. Still I think it is better to explicitly state that the documentation is for the python side.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@windelbouwman I disagree.
- Putting the docs in a
#[pyclass(doc = "...")]is pretty awkward to me because you have to manually specify the newlines. Also multi-line attributes are fairly uncommon and look out of place. - We can use regular
//comments for implementation-level comments. - Using
///comments also means that developers of native extensions can see the python docs from rustdoc. - It has precedent in the rust community - many binding generators do the same thing.
adrian17
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@coolreader18 could you also investigate how much #765 is compatible with this?
Seems to me like the approach in that PR wouldn't let set be converted to this (I guess we'll call it "new class style"? :) ). Would it be possible to eg add #[pymethod] to trait methods, or some other way to mark these as Python methods? Or would you recommend simply using extend_class! for these, or something else?
|
I think that would be possible, and it would make code reuse like that much easier and more intuitive. |
|
I'll work on trait |
|
The macro implementation is beyond my understanding. I will have to learn this. A single list of functions for an object has its benefits. Marking a method as such, also has benefits. I'm fine with both. In general, I'm for keeping things simple at the cost of some extra lines of code. That being said, I leave it to others to judge this PR. For me, its fine :). |
|
@windelbouwman is the naming better now? I renamed |
|
@windelbouwman @OddCoincidence Is this good to merge now? |
OddCoincidence
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for iterating on this! I didn't look at the proc-macro implementation in too much detail but the API is what's important and I think that's in a really good place. Great job!
All the naming is up for debate, and also the solution for using proc macros inside
rustpython_vm. I think it's a pretty good system, and I don't think there are really any other crates trying to use a proc macro in their own crate and in consumer crates.