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

Decorator @modify_docstring #943

Merged
merged 13 commits into from
Oct 23, 2020

Conversation

rocco8773
Copy link
Member

@rocco8773 rocco8773 commented Oct 23, 2020

This is a simple decorator that allows for the programmatic prepending and/or appending of docstrings. The original docstring is stored in a new __original_doc__ attribute so it can still be retrieved.

This is useful in a scenario where you are overriding a method and the signature does not change, but you want add a little more info to the original docstring.

@rocco8773 rocco8773 added the plasmapy.utils Related to the plasmapy.utils subpackage label Oct 23, 2020
@rocco8773 rocco8773 requested a review from namurphy October 23, 2020 03:39
@rocco8773 rocco8773 self-assigned this Oct 23, 2020
@codecov
Copy link

codecov bot commented Oct 23, 2020

Codecov Report

Merging #943 into master will increase coverage by 0.02%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #943      +/-   ##
==========================================
+ Coverage   96.19%   96.21%   +0.02%     
==========================================
  Files          60       60              
  Lines        5413     5443      +30     
==========================================
+ Hits         5207     5237      +30     
  Misses        206      206              
Impacted Files Coverage Δ
plasmapy/utils/decorators/__init__.py 100.00% <100.00%> (ø)
plasmapy/utils/decorators/helpers.py 100.00% <100.00%> (ø)

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 6f27718...bc7eb54. Read the comment docs.

Copy link
Member

@namurphy namurphy left a comment

Choose a reason for hiding this comment

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

I do very much like this decorator! As we talked about earlier, we can wait until a future pull request to expand the functionality for this decorator...for example to inject the descriptions of common arguments like B that we keep having to repeat between functions.

The only substantive comment I have is to break out the different tasks in the decorator into private functions...since this will make it easier to work with the decorator later on should we expand its functionality.

Also...the file name test_helpers.py has the potential for ambiguity with the test helpers that I'm working on starting in #919. I'm wondering if we could change names to avoid this overlap. It's not important, but it did cause me a moment of confusion.

Thank you for doing this!

plasmapy/utils/decorators/helpers.py Show resolved Hide resolved
--------

>>> @modify_docstring(prepend='''Hello''', append='''World''')
... def foo():
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
... def foo():
... def vegan_spam():

Copy link
Member Author

Choose a reason for hiding this comment

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

This is staying foo. 😁

Comment on lines +95 to +100
if func is not None:
# `modify_docstring` called as a function
return decorator(func)
else:
# `modify_docstring` called as a decorator "sugar-syntax"
return decorator
Copy link
Member

Choose a reason for hiding this comment

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

This comes up for a whole bunch of decorators that have optional arguments, so I'm wondering if we should create a function for it. Doesn't have to be now, though.

Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe for the future. I do always look up one of our old decorators to remind me how to do it.

plasmapy/utils/decorators/tests/test_helpers.py Outdated Show resolved Hide resolved
Comment on lines +64 to +91
# save the original docstring
setattr(wrapper, "__original_doc__", wrapper.__doc__)
doclines = inspect.cleandoc(wrapper.__doc__).splitlines()

# prepend docstring lines
if isinstance(prepend, str):
prependlines = inspect.cleandoc(prepend).splitlines()
prependlines.append("")
elif prepend is None:
prependlines = []
else:
raise TypeError(
f"Expected type str for argument 'prepend', got {type(prepend)}."
)

# append docstring lines
if isinstance(append, str):
appendlines = inspect.cleandoc(append).splitlines()
appendlines = [""] + appendlines
elif append is None:
appendlines = []
else:
raise TypeError(
f"Expected type str for argument 'append', got {type(append)}."
)

# define new docstring
wrapper.__doc__ = "\n".join(prependlines + doclines + appendlines)
Copy link
Member

Choose a reason for hiding this comment

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

This decorator has the potential to get significantly more complex, so I would suggest break up the prepending and appending (prependation and appendation?) into different private functions that can be called inside the decorator.

It could be something vaguely along the lines of:

doclines = _save_original_docstring(...)
prependlines = _prepend_docstring_lines(prepend)
appendlines = _append_docstring_lines(append)
wrapper.__doc__ = _define_new_docstring(prependlines, appendlines, doclines)

where the comments describing the section of code become the function names (though there's probably a better way to break it up than the above code block). I think of this pattern of refactoring when there are sections of code separated by comments. I think I originally read it in Clean Code by R. Martin. We could also use the strategy of dropping one level of abstraction per function.

I'm also mentioning this because if I had followed this advice with the original implementation of plasmapy.utils.pytest_helpers.run_test, I wouldn't have needed to go through with the test helper refactoring that I'm doing in #919 through #929...oof.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I do have several ideas to tackle more complex scenarios. I'll probably migrate this to a class style decorator, much like we do for validate_quantities and ValidateQuantites. Once there, I'll have functionality for injecting into specific numpydoc sections.

However, I want to leave that for the future. I want to get this through so I can get PR #908 merged and move on with the diagnostics. That is much more important to me at this point.

Copy link
Member

Choose a reason for hiding this comment

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

Sure! I'm happy to save that for the future, in particular if we create an issue or two on GitHub so that we can keep track of it for the future.

@namurphy namurphy changed the title Decoratore @modify_docstring Decorator @modify_docstring Oct 23, 2020
@rocco8773
Copy link
Member Author

Also...the file name test_helpers.py has the potential for ambiguity with the test helpers that I'm working on starting in #919. I'm wondering if we could change names to avoid this overlap. It's not important, but it did cause me a moment of confusion.

If we rename test_helpers.py, then we have to rename plasmapy/utils/decorators/helpers.py too. However, I don't think this is needed. Functionality in #919 is in a completely different location to the decorators, it doesn't name any test_helpers.py file, and it's standard practice the test_<something>.py are tests for the <something>.py file one level up. We can't us unique names for every part of the package.

@namurphy namurphy merged commit 0914025 into PlasmaPy:master Oct 23, 2020
@rocco8773 rocco8773 deleted the modify_docstring_decorator branch October 23, 2020 19:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
plasmapy.utils Related to the plasmapy.utils subpackage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants