-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
CLN: Replace Appender and Substitution with simpler doc decorator #31060
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
Changes from 2 commits
5911aa3
a04723f
b96a68f
7755c3f
4c5cd28
dd3f451
c57c51f
6ba6f9f
1cc0815
95668db
81b0888
88c6bf2
2103d61
f259bca
6a7b36c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -247,6 +247,36 @@ def wrapper(*args, **kwargs) -> Callable[..., Any]: | |||||
return decorate | ||||||
|
||||||
|
||||||
def doc(*args: Union[str, Callable], **kwargs: str) -> Callable: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
""" | ||||||
A decorator take docstring templates, concatenate them and perform string | ||||||
substitution on it. | ||||||
|
||||||
This decorator should be robust even if func.__doc__ is None. | ||||||
""" | ||||||
|
||||||
def decorator(func: Callable) -> Callable: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should use a TypeVar here - I think @simonjayhawkins might have done something similar with a Callable in another module |
||||||
@wraps(func) | ||||||
def wrapper(*args, **kwargs) -> Callable: | ||||||
return func(*args, **kwargs) | ||||||
|
||||||
templates = [func.__doc__ if func.__doc__ else ""] | ||||||
for arg in args: | ||||||
if isinstance(arg, str): | ||||||
templates.append(arg) | ||||||
elif hasattr(arg, "_docstr_template"): | ||||||
templates.append(arg._docstr_template) # type: ignore | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are all of the type: ignore comments for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems mypy didn't let us declare and use attributes of function objects. They have a issue for this, but seems there are no official solutions. We might be able to use some trick to handle this, but I am not sure if it worth. It will introducing more "unrelated" code. Also, this call of Just to be clear, I am open to make the adjustment to avoid this ignore comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think just adding |
||||||
elif arg.__doc__: | ||||||
templates.append(arg.__doc__) | ||||||
|
||||||
wrapper._docstr_template = "".join(dedent(t) for t in templates) # type: ignore | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain / add a comment why the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The Take this fake code as an example: @doc(method='cummax', operation='maximum')
def cummax(whatever):
"""
This is the {method} method.
It computes the cumulative {operation}.
"""
@doc(cummax, method='cummin', operation='minimum')
def cummin(whatever):
pass In I think it is a good idea to commenting this code because, at least for me, this is not intuitive. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@jorisvandenbossche I have add more detail doc under the decorator. May I have more feedback please? |
||||||
wrapper.__doc__ = wrapper._docstr_template.format(**kwargs) # type: ignore | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only do this if there actually are kwargs? (otherwise you need to use double { also when you are not doing any formatting) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, for current approach, we have to use There are two kinds of docstring, in my opinion. We might name one "doc decorator friendly" and the other "doc decorator indeterminate":
For the current approach, all template was guaranteed to be formatted before putting it in |
||||||
|
||||||
return wrapper | ||||||
|
||||||
return decorator | ||||||
|
||||||
|
||||||
# Substitution and Appender are derived from matplotlib.docstring (1.1.0) | ||||||
# module http://matplotlib.org/users/license.html | ||||||
|
||||||
|
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.
Would it be possible to get rid of the need for those
dedent
calls ? (thinking about how to make this even easier)I suppose one option is writing those dedented. Something like
but we might consider this ugly? (and does Black allow it?)
And in another this dedent could be handled by the decorator?
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.
+1 on adding indentation "magic" to the decorator. Not a big fan of automatic things, but I think making the docstring injection as simple as possible, so the important code is more readable, makes it worth.
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 think it is a good idea to add this "magic" to decorator so we can keep doc simple.
I am considering change from
to add
dedent
to all kwargs like thisAny thoughts? Comments? Please.
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.
That sounds good. I am only wondering if there are some cases where the to-be-inserted string starts with a space that we want to keep (to let it fit in the docstring)
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.
There are some cases where we don't do a
dedent
call, like in https://github.com/pandas-dev/pandas/blob/master/pandas/core/groupby/groupby.py#L66. So you might need to ensure something automatic works there as well.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.
Good point. The changes we made here should not change the actual docstring. Since there are mixed cases of usage, it seems hard for me to get a good solution for all of them. At least nothing comes out in my mind now.
I like the "magic", but for now, maybe it is better to keep it without a
dedent
call. Then, we can manually control what shows there. Also, if we do not adddedent
we can change the use ofAppender
andSubstitution
todoc
easily and straightforward, because thedoc
's behave is very close to simply combineAppender
andSubstitution
together.How about we just keep this unchanged now, and we can come back later when we have converted most decorator usages to
doc
? At that time, we might have more information to decided what could be the best way of solving that.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.
Sounds good, I also think it's better to start simple, see how things work, and add more features later.
I think adding the automatic indentation will be worth, since it'll make things much simpler when documenting, and it's not so complex to implement in the decorator. But let's forget about it for now, this is already a nice improvement.
Thanks!