bpo-34995: Maintain func.isabstractmethod in functools.cached_property by mwilbz · Pull Request #9904 · python/cpython (original) (raw)

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 andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Conversation19 Commits6 Checks0 Files changed

Conversation

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters

[ Show hidden characters]({{ revealButtonHref }})

mwilbz

@the-knights-who-say-ni

Hello, and thanks for your contribution!

I'm a bot set up to make sure that the project can legally accept your contribution by verifying you have signed the PSF contributor agreement (CLA).

Unfortunately our records indicate you have not signed the CLA. For legal reasons we need you to sign this before we can look at your contribution. Please follow the steps outlined in the CPython devguide to rectify this issue.

You can check yourself to see if the CLA has been received.

Thanks again for your contribution, we look forward to reviewing it!

vstinner

@@ -882,6 +882,7 @@ def __init__(self, func):
self.func = func
self.attrname = None
self.__doc__ = func.__doc__
self.__isabstractmethod__ = getattr(func, '__isabstractmethod__', False)

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 only set the attribute (on self) if the attribute exists on func?

Choose a reason for hiding this comment

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

Sure! Updated the implementation

vstinner

def calculate(self):
pass
with self.assertRaises(TypeError):

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 (also) directly check the isabstractmethod attribute?

Choose a reason for hiding this comment

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

Good suggestion, added an assertion for that

vstinner

@@ -882,6 +882,9 @@ def __init__(self, func):
self.func = func
self.attrname = None
self.__doc__ = func.__doc__
func_isabstractmethod = getattr(func, '__isabstractmethod__')

Choose a reason for hiding this comment

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

Used like that, getattr() raises an exception if the attribute doesn't exist.

You can use:

try: self.__isabstractmethod__ = func.__isabstractmethod__
except AttributeError: pass

Choose a reason for hiding this comment

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

Ah, thank you. I opened the implementation in my IDE and it said default=None so I was mislead. Pushing the version you're suggesting

vstinner

def calculate(self):
pass
self.assertTrue(getattr(AbstractExpensiveCalculator.calculate, '__isabstractmethod__', False))

Choose a reason for hiding this comment

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

self.assertTrue(AbstractExpensiveCalculator.calculate.isabstractmethod) is enough.

self.assertTrue(getattr(AbstractExpensiveCalculator.calculate, '__isabstractmethod__', False))
with self.assertRaises(TypeError):
AbstractExpensiveCalculator()

Choose a reason for hiding this comment

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

Can you add a test on a method which doesn't have the __isabstractmethod__ attribute? I expect such test:

self.assertFalse(hasattr(AbstractExpensiveCalculator.calculate, '__isabstractmethod__'))
@@ -0,0 +1 @@
Maintain wrapped method's __isabstractmethod__ in functools.cached_property

Choose a reason for hiding this comment

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

I suggest:

:func:`functools.cached_property` now also copies the wrapped method's ``__isabstractmethod__`` attribute.

@bedevere-bot

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@mwilbz

I have made the requested changes; please review again

Thank you for your comments @vstinner ! Good suggestions around better test coverage + documentation. :)

@bedevere-bot

Thanks for making the requested changes!

@vstinner: please review the changes made to this pull request.

vstinner

Choose a reason for hiding this comment

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

serhiy-storchaka

Choose a reason for hiding this comment

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

I still think that it is better to use @property instead of @cached_property in abstract classes, but I have no strong objections. What would say ABC experts?

def calculate(self):
pass
self.assertTrue(AbstractExpensiveCalculator.calculate.__isabstractmethod__)

Choose a reason for hiding this comment

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

Too long line. Maybe make the class or property name a little shorter?

@mwilbz

Possibly outside the scope of this change, but I noticed that update_wrapper in functools is a common way to inherit various standard fields in a wrapped method. For example, it's used here: https://github.com/python/cpython/blob/master/Lib/functools.py#L906 This example also happens to maintain __isabstractmethod__ in its own way, slightly different from this PR's current implementation.

Is it worth considering more generally modifying the standard fields to update via update_wrapper to include __isabstractmethod__ as well? https://github.com/python/cpython/blob/master/Lib/functools.py#L30 Then cached_property can simply reuse update_wrapper to be consistent with other wrappers in functools.

@mwilbz

Regardless of my previous comment, what are the next steps to move forward with this PR? Anything I can do? Thanks again for the reviews up until now =)

@mwilbz

It sounds like there isn't interest from core contributors in merging this change, so I'll close the PR. Thanks reviewers for your time and feedback!