classification
Title: unittest.mock.Mock.parent is broken or undocumented
Type: behavior Stage:
Components: Documentation, Library (Lib) Versions: Python 3.9, Python 3.8, Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: cjw296, docs@python, florian.brucker, lisroach, mariocj89, michael.foord, xtreak
Priority: normal Keywords:

Created on 2020-01-05 14:58 by florian.brucker, last changed 2020-01-15 12:00 by mariocj89.

Messages (7)
msg359348 - (view) Author: Florian Brucker (florian.brucker) Date: 2020-01-05 14:58
The "parent" attribute of unittest.mock.Mock is either broken or undocumented.

For example, on Python 3.7.4:

>>> from unittest.mock import Mock
>>> m = Mock(x=1, parent=2)
>>> m.x
1
>>> m.parent
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.7/unittest/mock.py", line 659, in __repr__
    name = self._extract_mock_name()
  File "/usr/local/lib/python3.7/unittest/mock.py", line 638, in _extract_mock_name
    _name_list.append(_parent._mock_new_name + dot)
AttributeError: 'int' object has no attribute '_mock_new_name'
>>> parent = Mock()
>>> child = Mock(parent=parent)
>>> child.parent is parent
False

I stumbled upon this while trying to mock an object that has a "parent" attribute.

From the documentation I understand that mocks have built-in parents. However, the documentation never mentions the "parent" attribute specifically, so I always assumed that the built-in parent-child relationship was handled using private or name-mangled attributes. And since the "parent" attribute is not mentioned in the docs, I assumed I could set it by passing an additional kwarg to Mock.

I would have expected one of the following, in order of personal preference:

a) That a private or name-mangled attribute is used for the built-in parent-child relationship, so that I can mock objects which themselves have a "parent" attribute

b) That the special meaning of the "parent" attribute is documented, and that trying to set it directly (via the constructor or via attribute assignment, and without going through attach_mock) triggers a warning.
msg359578 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2020-01-08 10:49
It's a similar situation to name argument conflict [0] except that it's parent here. You can use configure_mock or attribute setting to do the same thing like below. parent is discussed in the docs to indicate the attributes being children like "a" being the child of parent "m" as you have mentioned. Adding others for thoughts. 

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.configure_mock(parent=2)
>>> m.parent
2
>>> m.a()
<Mock name='mock.a()' id='4367727104'>

>>> m = Mock()
>>> m.parent = 2
>>> m.parent
2

[0] https://docs.python.org/3/library/unittest.mock.html#mock-names-and-the-name-attribute
msg359724 - (view) Author: Mario Corchero (mariocj89) * (Python triager) Date: 2020-01-10 13:43
@cjw296 or @michael.foord might know why the attribute was exposed as plain "parent". It was added more than 8 years ago and I am unnable to follow the git commit history.

They should then decide whether this is intenteded to be used by the users (which I never have used on the init TBH) and therefore document it or whether it is a private name on the init and if in that case it would be worth trying to mangle it.

In the meantime, xtreak suggested workflow is probably the best to go.
msg359725 - (view) Author: Chris Withers (cjw296) * (Python committer) Date: 2020-01-10 13:46
I thought we'd already changed this to _mock_parent in the last year or so?
msg359726 - (view) Author: Mario Corchero (mariocj89) * (Python triager) Date: 2020-01-10 14:11
If you refer to https://bugs.python.org/issue35357, this issue refers to `parent` at the time of creation of the mock. In the init it is still referenced as "parent".

The question is whether we want to also mangle "parent" in the __init__, as it seems it is not expected to be part of the API.
msg359890 - (view) Author: Chris Withers (cjw296) * (Python committer) Date: 2020-01-13 07:02
Ah right. Well, it's called `parent` in the __init__ as that's what the attribute used to be called. 

My suggestion would be to add `parent` to the docs @xtreak links to as a way to resolve this issue.
msg360044 - (view) Author: Mario Corchero (mariocj89) * (Python triager) Date: 2020-01-15 12:00
> My suggestion would be to add `parent` to the docs @xtreak links to as a way to resolve this issue.

+1, we should probably add it on the docs of the constructor here https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock as it is done for name and having a section like the on for name.
History
Date User Action Args
2020-01-15 12:00:36mariocj89setmessages: + msg360044
2020-01-13 07:02:14cjw296setmessages: + msg359890
2020-01-10 14:11:17mariocj89setmessages: + msg359726
2020-01-10 13:46:18cjw296setmessages: + msg359725
2020-01-10 13:43:58mariocj89setmessages: + msg359724
2020-01-08 10:49:56xtreaksetnosy: + cjw296, michael.foord, lisroach, mariocj89

messages: + msg359578
versions: + Python 3.8, Python 3.9, - Python 3.6
2020-01-05 15:34:58xtreaksetnosy: + xtreak
2020-01-05 14:58:32florian.bruckercreate