Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork34.1k
gh-100690: Prevent prefix "called_" for attributes of safe mock objects#100691
gh-100690: Prevent prefix "called_" for attributes of safe mock objects#100691cjw296 merged 6 commits intopython:mainfrom
Conversation
bedevere-bot commentedJan 2, 2023
Most changes to Pythonrequire a NEWS entry. Please add it using theblurb_it web app or theblurb command-line tool. |
25e26d8 to7bc8c46Compare
cjw296 left a comment
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'm -0 on this change, feels like we're into the diminishing realms where someone out there is going to have a legitimate use case forcalled_name or some such and this then prevents them using a safe mock.
Who else is hitting this?
7bc8c46 tob84bc75Comparecklein commentedJan 2, 2023
@cjw296, the same applies to any of the forbidden prefixes. This could be solved by allowing those prefixes with a spec. Currently, even if the name appears in |
cklein commentedJan 2, 2023 • edited by AlexWaygood
Loading Uh oh!
There was an error while loading.Please reload this page.
edited by AlexWaygood
Uh oh!
There was an error while loading.Please reload this page.
I have been thinking a bit more about the whole problem. It seems the current behavior does not match the error message: >>>classFoo:...defassert_bar(self):...pass...>>>from unittest.mockimport Mock>>> m= Mock(spec=Foo)>>> m.assert_bar()Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/unittest/mock.py", line 648, in __getattr__ raise AttributeError(AttributeError: 'assert_bar' is not a valid assertion. Use a spec for the mock if 'assert_bar' is meant to be an attribute. The error message says "Use a spec for the mock if 'assert_bar' is meant to be an attribute.", but this example should pass according to the error message. There's a spec and the name Withcklein@37aa291 applied, it behaves like described: >>>classFoo:...defassert_bar(self):...pass...>>>from unittest.mockimport Mock>>> m= Mock(spec=Foo)>>> m.assert_bar()<Mock name='mock.assert_bar()' id='4384202080'>>>> m.assert_frobnicated()Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/cklein/github/cklein/cpython/Lib/unittest/mock.py", line 652, in __getattr__ raise AttributeError("Mock object has no attribute %r" % name)AttributeError: Mock object has no attribute 'assert_frobnicated' |
merwok commentedJan 3, 2023
The prefixes checked could be more specific like |
cjw296 commentedJan 3, 2023
@cklein - I think you're right about this being a complicated issue, perhaps a PR isn't the best place to discuss it? Could you maybe close this PR an open an issue explaining your concerns and some possible ways forward? |
AlexWaygood commentedJan 3, 2023
OP has already done so:
|
cklein commentedJan 3, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I can also create another issue for my second branch about the spec not being properly checked, if that helps Edit: Seehttps://discuss.python.org/t/check-for-assert-prefixes-doesnt-respect-spec/22388 |
… modeRaise an AttributeError when calling e.g. `mock_obj.called_once` instead of`mock_obj.assert_called_once`.
b84bc75 to154012fComparecklein commentedJan 3, 2023
I'm aware that the documentation is now off. I'd like to get some feedback on the change first, if that's OK |
Uh oh!
There was an error while loading.Please reload this page.
| # gh-100690 Denylist for forbidden attribute names in safe mode | ||
| ATTRIB_DENY_LIST = {name.removeprefix("assert_") for name in dir(NonCallableMock) if name.startswith("assert_")} |
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.
Much prefer this approach! 🎉
cjw296 commentedJan 5, 2023
Approach is good, so once the docs are fixed up, should be good to land. |
cklein commentedJan 5, 2023
I'm struggling a bit with documentation. What about the following: |
Misc/NEWS.d/next/Library/2023-01-02-16-59-49.gh-issue-100690.2EgWPS.rst OutdatedShow resolvedHide resolved
Uh oh!
There was an error while loading.Please reload this page.
cklein commentedJan 6, 2023
Personally I'd like to see it in earlier versions of Python. |
cjw296 commentedJan 6, 2023 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@cklein - 3.10 and 3.11 are open for bug fixes so their next third point release would contain this once its landed. |
cjw296 commentedJan 6, 2023
The Azure Pipelines failure seems unrelated. |
AlexWaygood commentedJan 6, 2023
Yes, that failure happens intermittently on a lot of PRs |
bedevere-bot commentedJan 6, 2023
|
| # Denylist for forbidden attribute names in safe mode | ||
| ATTRIB_DENY_LIST = {name.removeprefix("assert_") for name in dir(NonCallableMock) if name.startswith("assert_")} |
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.
Sorry for being late to the party, but anyways :)
I think thatATTRIB_DENY_LIST is an implementation detail, so it should be_ATTRIB_DENY_LIST. And also, it is not suited for mutation, isn't it? So, it should be afrozenset instead :)
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.
Since this PR is already merged, I've opened#100819 with this proposal. Feel free to close if it should be public and mutable!
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.
It is already non-public by not being included in__all__, and the mutability is not really an issue.
Uh oh!
There was an error while loading.Please reload this page.
Prevent prefix "called_" for mocks in safe mode