Skip to content

Introduce __text_signature__ property - #2904

Merged
youknowone merged 10 commits into
RustPython:masterfrom
moreal:feature/add-text-signature-property
Aug 20, 2021
Merged

Introduce __text_signature__ property#2904
youknowone merged 10 commits into
RustPython:masterfrom
moreal:feature/add-text-signature-property

Conversation

@moreal

@moreal moreal commented Aug 18, 2021

Copy link
Copy Markdown
Contributor

This pull request tries to resolve #2410

This pull request does:

  • Fill 'object' type's missing docstrings 0b52d0c
  • Introduce new __text_signature__ property to PyType, PyBuiltinMethod, PyBuiltinFunction. 40ab1c4

Code to verify compatibility

print(object.__str__.__text_signature__)  # expected `($self, /)`
print(object.__text_signature__)  # expected `()`
print(type.__text_signature__)  # expected `None` (no output)

References

@moreal moreal changed the title Introduce '__text_signature__' property Introduce __text_signature__ property Aug 18, 2021
@moreal

moreal commented Aug 18, 2021

Copy link
Copy Markdown
Contributor Author

This pull request seems to resolve #2680 in some part 👀

Comment thread vm/src/builtins/builtinfunc.rs Outdated
format!("<built-in function {}>", self.value.name)
}
#[pyproperty(magic)]
fn text_signature(&self, vm: &VirtualMachine) -> PyObjectRef {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
fn text_signature(&self, vm: &VirtualMachine) -> PyObjectRef {
fn text_signature(&self, vm: &VirtualMachine) -> Option<String> {

With this signature, None will turn into Python None and Some(String) will turn into Python str

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried to apply it in d12d286 commit. Could you check it again?

@DimitrisJim

Copy link
Copy Markdown
Member

This is nice! It does introduce an issue though, __doc__ now contains that text signature in its contents, you'll need to tweak doc to ignore the signature at the start (similar to CPythons _PyType_DocWithoutSignature).

@moreal
moreal force-pushed the feature/add-text-signature-property branch from 2f06d9b to d12d286 Compare August 18, 2021 12:17
@moreal
moreal requested a review from youknowone August 18, 2021 12:42
@moreal

moreal commented Aug 18, 2021

Copy link
Copy Markdown
Contributor Author

This is nice! It does introduce an issue though, __doc__ now contains that text signature in its contents, you'll need to tweak doc to ignore the signature at the start (similar to CPythons _PyType_DocWithoutSignature).

Yeah, I missed it to comment. 😅 I made it as an issue #2907.

@youknowone youknowone left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nice work, I left a few comments about code style.

Comment thread vm/src/builtins/pytype.rs Outdated
Comment on lines +537 to +544
fn find_signature(name: &str, doc: &str) -> Option<String> {
let dot_index = name.rfind('.');
let name = match dot_index {
Some(index) => name[index + 1..].to_owned(),
_ => name.to_owned(),
};

if !doc.starts_with(&name) {
return None;
}

let doc = doc[name.len()..].to_owned();
if !doc.starts_with('(') {
None
} else {
Some(doc)
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I feel like find_signature should return the first index of string of signature, but this function returns docs starting with signature paranthesis.

My suggestions:

  1. if this function is just once used by get_text_signature_from_internal_doc, it doesn't look like to be an independent function.
  2. If this function is planned to be used from somewhere, giving it a better name or comments will be a good idea. For now, I don't have a good name suggestion.

by the way, here is my suggestion for the code itself.

Suggested change
fn find_signature(name: &str, doc: &str) -> Option<String> {
let dot_index = name.rfind('.');
let name = match dot_index {
Some(index) => name[index + 1..].to_owned(),
_ => name.to_owned(),
};
if !doc.starts_with(&name) {
return None;
}
let doc = doc[name.len()..].to_owned();
if !doc.starts_with('(') {
None
} else {
Some(doc)
}
}
fn find_signature<'a>(name: &str, doc: &'a str) -> Option<&'a str> {
let name = name.rsplit('.').next().unwrap(); // rsplit always have first item
let doc = doc.strip_prefix(name)?;
if !doc.starts_with('(') {
None
} else {
Some(doc)
}
}

@moreal moreal Aug 19, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I feel like find_signature should return the first index of string of signature, but this function returns docs starting with signature paranthesis.

My suggestions:

1. if this function is just once used by `get_text_signature_from_internal_doc`, it doesn't look like to be an independent function.

2. If this function is planned to be used from somewhere, giving it a better name or comments will be a good idea. For now, I don't have a good name suggestion.

by the way, here is my suggestion for the code itself.

Thanks for suggestions. I looked CPython implementation again and there is the usage of find_signature and skip_signature at _PyType_DocWithoutSignature (see also #2907). Current skip_signature implementation is incorrect and cannot be reused in _PyType_DocWithoutSignature. So I will implement the functions to return index not str like you said your feel 🙏🏻 .

static const char *
_PyType_DocWithoutSignature(const char *name, const char *internal_doc)
{
    const char *doc = find_signature(name, internal_doc);

    if (doc) {
        doc = skip_signature(doc);
        if (doc)
            return doc;
        }
    return internal_doc;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, I didn't know the name was CPython referenced, I am sorry to confuse you. The CPython code looks like intending Option<&str>. So keep going with it.

I got the feeling from the convention of Rust library, but CPython has its own convention. So never mind about it.

@moreal moreal Aug 20, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As a note, I fixed skip_signature implementation but it is not used in this pull request so I removed it. And I implemented get_signature renamed from skip_signature.

Comment thread vm/src/builtins/pytype.rs Outdated
Comment on lines +532 to +534
fn skip_signature(doc: String) -> Option<String> {
doc.find(SIGNATURE_END_MARKER)
.map(|index| doc[..index + 1].to_owned())
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
fn skip_signature(doc: String) -> Option<String> {
doc.find(SIGNATURE_END_MARKER)
.map(|index| doc[..index + 1].to_owned())
}
fn skip_signature(doc: &str) -> Option<&str> {
doc.find(SIGNATURE_END_MARKER)
.map(|index| &doc[..index + 1])
}

this functions doesn't need to copy doc

Comment thread vm/src/builtins/pytype.rs Outdated
Comment on lines +524 to +526
let doc_string: Option<PyStrRef> = doc_string.and_then(|o| o.downcast().ok());
doc_string.and_then(|doc| {
get_text_signature_from_internal_doc(self.name().as_str(), doc.as_str())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
let doc_string: Option<PyStrRef> = doc_string.and_then(|o| o.downcast().ok());
doc_string.and_then(|doc| {
get_text_signature_from_internal_doc(self.name().as_str(), doc.as_str())
let doc: PyStrRef = doc_string.and_then(|o| o.downcast().ok())?;
get_text_signature_from_internal_doc(self.name().as_str(), doc.as_str())

Comment thread vm/src/builtins/pytype.rs Outdated

#[pyproperty(magic)]
fn text_signature(&self) -> Option<String> {
let doc_string = self.get_attr("__doc__");

@youknowone youknowone Aug 18, 2021

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you are interested in, I think tp_doc which should be added in PyTypeSlots is related to improvement of this line. It can be a topic for next patch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I tried to apply your suggestion in 78ff936. Could you check that it was you said?

@moreal
moreal force-pushed the feature/add-text-signature-property branch from 34d5215 to 1931b9f Compare August 20, 2021 16:01
@moreal
moreal force-pushed the feature/add-text-signature-property branch from 1931b9f to 78ff936 Compare August 20, 2021 16:02
@moreal
moreal requested a review from youknowone August 20, 2021 16:04
@youknowone
youknowone merged commit 216b597 into RustPython:master Aug 20, 2021
@youknowone

Copy link
Copy Markdown
Member

it looks great, thank you for contributing!

@youknowone youknowone added the z-ca-2021 Tag to track contrubution-academy 2021 label Oct 16, 2021
@moreal moreal mentioned this pull request Nov 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

z-ca-2021 Tag to track contrubution-academy 2021

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Builtin functions and methods lack a .__text_signature__ property

3 participants