Skip to content

bpo-34995: Maintain func.__isabstractmethod__ in functools.cached_property#9904

Closed
mwilbz wants to merge 6 commits intopython:masterfrom
mwilbz:cached_property_maintains_isabstractmethod
Closed

bpo-34995: Maintain func.__isabstractmethod__ in functools.cached_property#9904
mwilbz wants to merge 6 commits intopython:masterfrom
mwilbz:cached_property_maintains_isabstractmethod

Conversation

@mwilbz
Copy link

@mwilbz mwilbz commented Oct 15, 2018

bpo-34995: Maintain func.isabstractmethod in functools.cached_property

https://bugs.python.org/issue34995

@the-knights-who-say-ni
Copy link

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!

Lib/functools.py Outdated
self.func = func
self.attrname = None
self.__doc__ = func.__doc__
self.__isabstractmethod__ = getattr(func, '__isabstractmethod__', False)
Copy link
Member

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?

Copy link
Author

Choose a reason for hiding this comment

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

Sure! Updated the implementation

def calculate(self):
pass

with self.assertRaises(TypeError):
Copy link
Member

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?

Copy link
Author

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

Lib/functools.py Outdated
self.func = func
self.attrname = None
self.__doc__ = func.__doc__
func_isabstractmethod = getattr(func, '__isabstractmethod__')
Copy link
Member

@vstinner vstinner Oct 25, 2018

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

Copy link
Author

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

def calculate(self):
pass

self.assertTrue(getattr(AbstractExpensiveCalculator.calculate, '__isabstractmethod__', False))
Copy link
Member

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()

Copy link
Member

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
Copy link
Member

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
Copy link

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
Copy link
Author

mwilbz commented Oct 25, 2018

I have made the requested changes; please review again

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

@bedevere-bot
Copy link

Thanks for making the requested changes!

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

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

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

LGTM.

But it seems like @serhiy-storchaka and @methane dislike the overall idea: https://bugs.python.org/issue34995

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

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__)
Copy link
Member

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
Copy link
Author

mwilbz commented Nov 16, 2018

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
Copy link
Author

mwilbz commented Nov 16, 2018

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
Copy link
Author

mwilbz commented Mar 27, 2019

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!

@mwilbz mwilbz closed this Mar 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants