3

The __repr__esentation of a Mock object that has been obtained as an attribute (or as the return of __call__) of another Mock shows what looks like a name attribute. This pseudoattribute however doesn't seem to exist in the class. For example:

>>> import mock
... x = mock.MagicMock()
... y = x.asdf
... z = y.hjkl
... a = z()

>>> a
<MagicMock name='mock.asdf.hjkl()' id='139706648472600'>

>>> 'name' in a.__dict__
False

In order to get this psuedoattribute, it seems that I can either parse the return of y.__repr__() or some sort of recursive function like this:

def get_mock_name(some_mock):
    if some_mock._mock_name:
        return f'{get_mock_name(some_mock._mock_parent)}.{some_mock._mock_name}'
    elif some_mock._mock_new_name:
        return f'{get_mock_name(some_mock._mock_new_parent)}{some_mock._mock_new_name}'
    else:
        return 'mock'                                                        

While both work, is there any standard and/or builtin way of doing this?

Edit: no, I am not asking how to override __repr__

  • Possible duplicate of [How to print objects of class using print()?](https://stackoverflow.com/questions/1535327/how-to-print-objects-of-class-using-print) – Alexander Santos Jul 18 '19 at 16:10
  • @Alexander Santos how so? I am trying to get a specific piece of information that is already printed, not change the behavior of the print function. – Christian Reall-Fluharty Jul 18 '19 at 16:16
  • You're getting back the `__repr__` method on the `Mock`. If you want to see how that is set, here is the source: `https://github.com/python/cpython/blob/master/Lib/unittest/mock.py#L693` – pythomatic Jul 18 '19 at 16:16
  • 1
    Fragile, but `__repr__` gets it from `a._extract_mock_name()`. – chepner Jul 18 '19 at 16:18
  • @chepner I'm afraid I don't understand. `a._extract_mock_name()` just returns another mock (``) for me – Christian Reall-Fluharty Jul 18 '19 at 16:21
  • 1
    Hm, could be a version issue. I only checked the [version that ships with Python 3](https://github.com/python/cpython/blob/3.7/Lib/unittest/mock.py#L659). I see an older version of the 3rd-party module doesn't abstract out the name-building into a separate (private) method. Like I said: fragile :) – chepner Jul 18 '19 at 16:24
  • @chepner Ope, I think I'm using the 3rd party library. It makes sense that they've moved that out since. Thanks for that info! If you wrote that as an answer, I'd definitely accept it! – Christian Reall-Fluharty Jul 18 '19 at 17:03

1 Answers1

3

Thanks @chepner for setting me up with this answer!

The "name" psuedo-attribute can be obtained with the Mock._extract_mock_name() method of the version of mock that ships with python 3.7.

This method is actually used in the implementation of __repr__ to get this information encapsulating the behavior that was previously just a part the __repr__ function.

You can use it like so:

$ python
Python 3.7.3 (default, Jul 19 2019, 10:33:54) 
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import unittest.mock as mock
>>> x = mock.MagicMock()
>>> y = x.asdf
>>> z = y.hjkl
>>> a = z()
>>> a._extract_mock_name()
'mock.asdf.hjkl()'