1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/python/mock-1.0.0/docs/helpers.txt Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,583 @@ 1.4 +========= 1.5 + Helpers 1.6 +========= 1.7 + 1.8 +.. currentmodule:: mock 1.9 + 1.10 +.. testsetup:: 1.11 + 1.12 + mock.FILTER_DIR = True 1.13 + from pprint import pprint as pp 1.14 + original_dir = dir 1.15 + def dir(obj): 1.16 + print pp(original_dir(obj)) 1.17 + 1.18 + import urllib2 1.19 + __main__.urllib2 = urllib2 1.20 + 1.21 +.. testcleanup:: 1.22 + 1.23 + dir = original_dir 1.24 + mock.FILTER_DIR = True 1.25 + 1.26 + 1.27 + 1.28 +call 1.29 +==== 1.30 + 1.31 +.. function:: call(*args, **kwargs) 1.32 + 1.33 + `call` is a helper object for making simpler assertions, for comparing 1.34 + with :attr:`~Mock.call_args`, :attr:`~Mock.call_args_list`, 1.35 + :attr:`~Mock.mock_calls` and :attr: `~Mock.method_calls`. `call` can also be 1.36 + used with :meth:`~Mock.assert_has_calls`. 1.37 + 1.38 + .. doctest:: 1.39 + 1.40 + >>> m = MagicMock(return_value=None) 1.41 + >>> m(1, 2, a='foo', b='bar') 1.42 + >>> m() 1.43 + >>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()] 1.44 + True 1.45 + 1.46 +.. method:: call.call_list() 1.47 + 1.48 + For a call object that represents multiple calls, `call_list` 1.49 + returns a list of all the intermediate calls as well as the 1.50 + final call. 1.51 + 1.52 +`call_list` is particularly useful for making assertions on "chained calls". A 1.53 +chained call is multiple calls on a single line of code. This results in 1.54 +multiple entries in :attr:`~Mock.mock_calls` on a mock. Manually constructing 1.55 +the sequence of calls can be tedious. 1.56 + 1.57 +:meth:`~call.call_list` can construct the sequence of calls from the same 1.58 +chained call: 1.59 + 1.60 +.. doctest:: 1.61 + 1.62 + >>> m = MagicMock() 1.63 + >>> m(1).method(arg='foo').other('bar')(2.0) 1.64 + <MagicMock name='mock().method().other()()' id='...'> 1.65 + >>> kall = call(1).method(arg='foo').other('bar')(2.0) 1.66 + >>> kall.call_list() 1.67 + [call(1), 1.68 + call().method(arg='foo'), 1.69 + call().method().other('bar'), 1.70 + call().method().other()(2.0)] 1.71 + >>> m.mock_calls == kall.call_list() 1.72 + True 1.73 + 1.74 +.. _calls-as-tuples: 1.75 + 1.76 +A `call` object is either a tuple of (positional args, keyword args) or 1.77 +(name, positional args, keyword args) depending on how it was constructed. When 1.78 +you construct them yourself this isn't particularly interesting, but the `call` 1.79 +objects that are in the :attr:`Mock.call_args`, :attr:`Mock.call_args_list` and 1.80 +:attr:`Mock.mock_calls` attributes can be introspected to get at the individual 1.81 +arguments they contain. 1.82 + 1.83 +The `call` objects in :attr:`Mock.call_args` and :attr:`Mock.call_args_list` 1.84 +are two-tuples of (positional args, keyword args) whereas the `call` objects 1.85 +in :attr:`Mock.mock_calls`, along with ones you construct yourself, are 1.86 +three-tuples of (name, positional args, keyword args). 1.87 + 1.88 +You can use their "tupleness" to pull out the individual arguments for more 1.89 +complex introspection and assertions. The positional arguments are a tuple 1.90 +(an empty tuple if there are no positional arguments) and the keyword 1.91 +arguments are a dictionary: 1.92 + 1.93 +.. doctest:: 1.94 + 1.95 + >>> m = MagicMock(return_value=None) 1.96 + >>> m(1, 2, 3, arg='one', arg2='two') 1.97 + >>> kall = m.call_args 1.98 + >>> args, kwargs = kall 1.99 + >>> args 1.100 + (1, 2, 3) 1.101 + >>> kwargs 1.102 + {'arg2': 'two', 'arg': 'one'} 1.103 + >>> args is kall[0] 1.104 + True 1.105 + >>> kwargs is kall[1] 1.106 + True 1.107 + 1.108 + >>> m = MagicMock() 1.109 + >>> m.foo(4, 5, 6, arg='two', arg2='three') 1.110 + <MagicMock name='mock.foo()' id='...'> 1.111 + >>> kall = m.mock_calls[0] 1.112 + >>> name, args, kwargs = kall 1.113 + >>> name 1.114 + 'foo' 1.115 + >>> args 1.116 + (4, 5, 6) 1.117 + >>> kwargs 1.118 + {'arg2': 'three', 'arg': 'two'} 1.119 + >>> name is m.mock_calls[0][0] 1.120 + True 1.121 + 1.122 + 1.123 +create_autospec 1.124 +=============== 1.125 + 1.126 +.. function:: create_autospec(spec, spec_set=False, instance=False, **kwargs) 1.127 + 1.128 + Create a mock object using another object as a spec. Attributes on the 1.129 + mock will use the corresponding attribute on the `spec` object as their 1.130 + spec. 1.131 + 1.132 + Functions or methods being mocked will have their arguments checked to 1.133 + ensure that they are called with the correct signature. 1.134 + 1.135 + If `spec_set` is `True` then attempting to set attributes that don't exist 1.136 + on the spec object will raise an `AttributeError`. 1.137 + 1.138 + If a class is used as a spec then the return value of the mock (the 1.139 + instance of the class) will have the same spec. You can use a class as the 1.140 + spec for an instance object by passing `instance=True`. The returned mock 1.141 + will only be callable if instances of the mock are callable. 1.142 + 1.143 + `create_autospec` also takes arbitrary keyword arguments that are passed to 1.144 + the constructor of the created mock. 1.145 + 1.146 +See :ref:`auto-speccing` for examples of how to use auto-speccing with 1.147 +`create_autospec` and the `autospec` argument to :func:`patch`. 1.148 + 1.149 + 1.150 +ANY 1.151 +=== 1.152 + 1.153 +.. data:: ANY 1.154 + 1.155 +Sometimes you may need to make assertions about *some* of the arguments in a 1.156 +call to mock, but either not care about some of the arguments or want to pull 1.157 +them individually out of :attr:`~Mock.call_args` and make more complex 1.158 +assertions on them. 1.159 + 1.160 +To ignore certain arguments you can pass in objects that compare equal to 1.161 +*everything*. Calls to :meth:`~Mock.assert_called_with` and 1.162 +:meth:`~Mock.assert_called_once_with` will then succeed no matter what was 1.163 +passed in. 1.164 + 1.165 +.. doctest:: 1.166 + 1.167 + >>> mock = Mock(return_value=None) 1.168 + >>> mock('foo', bar=object()) 1.169 + >>> mock.assert_called_once_with('foo', bar=ANY) 1.170 + 1.171 +`ANY` can also be used in comparisons with call lists like 1.172 +:attr:`~Mock.mock_calls`: 1.173 + 1.174 +.. doctest:: 1.175 + 1.176 + >>> m = MagicMock(return_value=None) 1.177 + >>> m(1) 1.178 + >>> m(1, 2) 1.179 + >>> m(object()) 1.180 + >>> m.mock_calls == [call(1), call(1, 2), ANY] 1.181 + True 1.182 + 1.183 + 1.184 + 1.185 +FILTER_DIR 1.186 +========== 1.187 + 1.188 +.. data:: FILTER_DIR 1.189 + 1.190 +`FILTER_DIR` is a module level variable that controls the way mock objects 1.191 +respond to `dir` (only for Python 2.6 or more recent). The default is `True`, 1.192 +which uses the filtering described below, to only show useful members. If you 1.193 +dislike this filtering, or need to switch it off for diagnostic purposes, then 1.194 +set `mock.FILTER_DIR = False`. 1.195 + 1.196 +With filtering on, `dir(some_mock)` shows only useful attributes and will 1.197 +include any dynamically created attributes that wouldn't normally be shown. 1.198 +If the mock was created with a `spec` (or `autospec` of course) then all the 1.199 +attributes from the original are shown, even if they haven't been accessed 1.200 +yet: 1.201 + 1.202 +.. doctest:: 1.203 + 1.204 + >>> dir(Mock()) 1.205 + ['assert_any_call', 1.206 + 'assert_called_once_with', 1.207 + 'assert_called_with', 1.208 + 'assert_has_calls', 1.209 + 'attach_mock', 1.210 + ... 1.211 + >>> import urllib2 1.212 + >>> dir(Mock(spec=urllib2)) 1.213 + ['AbstractBasicAuthHandler', 1.214 + 'AbstractDigestAuthHandler', 1.215 + 'AbstractHTTPHandler', 1.216 + 'BaseHandler', 1.217 + ... 1.218 + 1.219 +Many of the not-very-useful (private to `Mock` rather than the thing being 1.220 +mocked) underscore and double underscore prefixed attributes have been 1.221 +filtered from the result of calling `dir` on a `Mock`. If you dislike this 1.222 +behaviour you can switch it off by setting the module level switch 1.223 +`FILTER_DIR`: 1.224 + 1.225 +.. doctest:: 1.226 + 1.227 + >>> import mock 1.228 + >>> mock.FILTER_DIR = False 1.229 + >>> dir(mock.Mock()) 1.230 + ['_NonCallableMock__get_return_value', 1.231 + '_NonCallableMock__get_side_effect', 1.232 + '_NonCallableMock__return_value_doc', 1.233 + '_NonCallableMock__set_return_value', 1.234 + '_NonCallableMock__set_side_effect', 1.235 + '__call__', 1.236 + '__class__', 1.237 + ... 1.238 + 1.239 +Alternatively you can just use `vars(my_mock)` (instance members) and 1.240 +`dir(type(my_mock))` (type members) to bypass the filtering irrespective of 1.241 +`mock.FILTER_DIR`. 1.242 + 1.243 + 1.244 +mock_open 1.245 +========= 1.246 + 1.247 +.. function:: mock_open(mock=None, read_data=None) 1.248 + 1.249 + A helper function to create a mock to replace the use of `open`. It works 1.250 + for `open` called directly or used as a context manager. 1.251 + 1.252 + The `mock` argument is the mock object to configure. If `None` (the 1.253 + default) then a `MagicMock` will be created for you, with the API limited 1.254 + to methods or attributes available on standard file handles. 1.255 + 1.256 + `read_data` is a string for the `read` method of the file handle to return. 1.257 + This is an empty string by default. 1.258 + 1.259 +Using `open` as a context manager is a great way to ensure your file handles 1.260 +are closed properly and is becoming common:: 1.261 + 1.262 + with open('/some/path', 'w') as f: 1.263 + f.write('something') 1.264 + 1.265 +The issue is that even if you mock out the call to `open` it is the 1.266 +*returned object* that is used as a context manager (and has `__enter__` and 1.267 +`__exit__` called). 1.268 + 1.269 +Mocking context managers with a :class:`MagicMock` is common enough and fiddly 1.270 +enough that a helper function is useful. 1.271 + 1.272 +.. doctest:: 1.273 + 1.274 + >>> from mock import mock_open 1.275 + >>> m = mock_open() 1.276 + >>> with patch('__main__.open', m, create=True): 1.277 + ... with open('foo', 'w') as h: 1.278 + ... h.write('some stuff') 1.279 + ... 1.280 + >>> m.mock_calls 1.281 + [call('foo', 'w'), 1.282 + call().__enter__(), 1.283 + call().write('some stuff'), 1.284 + call().__exit__(None, None, None)] 1.285 + >>> m.assert_called_once_with('foo', 'w') 1.286 + >>> handle = m() 1.287 + >>> handle.write.assert_called_once_with('some stuff') 1.288 + 1.289 +And for reading files: 1.290 + 1.291 +.. doctest:: 1.292 + 1.293 + >>> with patch('__main__.open', mock_open(read_data='bibble'), create=True) as m: 1.294 + ... with open('foo') as h: 1.295 + ... result = h.read() 1.296 + ... 1.297 + >>> m.assert_called_once_with('foo') 1.298 + >>> assert result == 'bibble' 1.299 + 1.300 + 1.301 +.. _auto-speccing: 1.302 + 1.303 +Autospeccing 1.304 +============ 1.305 + 1.306 +Autospeccing is based on the existing `spec` feature of mock. It limits the 1.307 +api of mocks to the api of an original object (the spec), but it is recursive 1.308 +(implemented lazily) so that attributes of mocks only have the same api as 1.309 +the attributes of the spec. In addition mocked functions / methods have the 1.310 +same call signature as the original so they raise a `TypeError` if they are 1.311 +called incorrectly. 1.312 + 1.313 +Before I explain how auto-speccing works, here's why it is needed. 1.314 + 1.315 +`Mock` is a very powerful and flexible object, but it suffers from two flaws 1.316 +when used to mock out objects from a system under test. One of these flaws is 1.317 +specific to the `Mock` api and the other is a more general problem with using 1.318 +mock objects. 1.319 + 1.320 +First the problem specific to `Mock`. `Mock` has two assert methods that are 1.321 +extremely handy: :meth:`~Mock.assert_called_with` and 1.322 +:meth:`~Mock.assert_called_once_with`. 1.323 + 1.324 +.. doctest:: 1.325 + 1.326 + >>> mock = Mock(name='Thing', return_value=None) 1.327 + >>> mock(1, 2, 3) 1.328 + >>> mock.assert_called_once_with(1, 2, 3) 1.329 + >>> mock(1, 2, 3) 1.330 + >>> mock.assert_called_once_with(1, 2, 3) 1.331 + Traceback (most recent call last): 1.332 + ... 1.333 + AssertionError: Expected to be called once. Called 2 times. 1.334 + 1.335 +Because mocks auto-create attributes on demand, and allow you to call them 1.336 +with arbitrary arguments, if you misspell one of these assert methods then 1.337 +your assertion is gone: 1.338 + 1.339 +.. code-block:: pycon 1.340 + 1.341 + >>> mock = Mock(name='Thing', return_value=None) 1.342 + >>> mock(1, 2, 3) 1.343 + >>> mock.assret_called_once_with(4, 5, 6) 1.344 + 1.345 +Your tests can pass silently and incorrectly because of the typo. 1.346 + 1.347 +The second issue is more general to mocking. If you refactor some of your 1.348 +code, rename members and so on, any tests for code that is still using the 1.349 +*old api* but uses mocks instead of the real objects will still pass. This 1.350 +means your tests can all pass even though your code is broken. 1.351 + 1.352 +Note that this is another reason why you need integration tests as well as 1.353 +unit tests. Testing everything in isolation is all fine and dandy, but if you 1.354 +don't test how your units are "wired together" there is still lots of room 1.355 +for bugs that tests might have caught. 1.356 + 1.357 +`mock` already provides a feature to help with this, called speccing. If you 1.358 +use a class or instance as the `spec` for a mock then you can only access 1.359 +attributes on the mock that exist on the real class: 1.360 + 1.361 +.. doctest:: 1.362 + 1.363 + >>> import urllib2 1.364 + >>> mock = Mock(spec=urllib2.Request) 1.365 + >>> mock.assret_called_with 1.366 + Traceback (most recent call last): 1.367 + ... 1.368 + AttributeError: Mock object has no attribute 'assret_called_with' 1.369 + 1.370 +The spec only applies to the mock itself, so we still have the same issue 1.371 +with any methods on the mock: 1.372 + 1.373 +.. code-block:: pycon 1.374 + 1.375 + >>> mock.has_data() 1.376 + <mock.Mock object at 0x...> 1.377 + >>> mock.has_data.assret_called_with() 1.378 + 1.379 +Auto-speccing solves this problem. You can either pass `autospec=True` to 1.380 +`patch` / `patch.object` or use the `create_autospec` function to create a 1.381 +mock with a spec. If you use the `autospec=True` argument to `patch` then the 1.382 +object that is being replaced will be used as the spec object. Because the 1.383 +speccing is done "lazily" (the spec is created as attributes on the mock are 1.384 +accessed) you can use it with very complex or deeply nested objects (like 1.385 +modules that import modules that import modules) without a big performance 1.386 +hit. 1.387 + 1.388 +Here's an example of it in use: 1.389 + 1.390 +.. doctest:: 1.391 + 1.392 + >>> import urllib2 1.393 + >>> patcher = patch('__main__.urllib2', autospec=True) 1.394 + >>> mock_urllib2 = patcher.start() 1.395 + >>> urllib2 is mock_urllib2 1.396 + True 1.397 + >>> urllib2.Request 1.398 + <MagicMock name='urllib2.Request' spec='Request' id='...'> 1.399 + 1.400 +You can see that `urllib2.Request` has a spec. `urllib2.Request` takes two 1.401 +arguments in the constructor (one of which is `self`). Here's what happens if 1.402 +we try to call it incorrectly: 1.403 + 1.404 +.. doctest:: 1.405 + 1.406 + >>> req = urllib2.Request() 1.407 + Traceback (most recent call last): 1.408 + ... 1.409 + TypeError: <lambda>() takes at least 2 arguments (1 given) 1.410 + 1.411 +The spec also applies to instantiated classes (i.e. the return value of 1.412 +specced mocks): 1.413 + 1.414 +.. doctest:: 1.415 + 1.416 + >>> req = urllib2.Request('foo') 1.417 + >>> req 1.418 + <NonCallableMagicMock name='urllib2.Request()' spec='Request' id='...'> 1.419 + 1.420 +`Request` objects are not callable, so the return value of instantiating our 1.421 +mocked out `urllib2.Request` is a non-callable mock. With the spec in place 1.422 +any typos in our asserts will raise the correct error: 1.423 + 1.424 +.. doctest:: 1.425 + 1.426 + >>> req.add_header('spam', 'eggs') 1.427 + <MagicMock name='urllib2.Request().add_header()' id='...'> 1.428 + >>> req.add_header.assret_called_with 1.429 + Traceback (most recent call last): 1.430 + ... 1.431 + AttributeError: Mock object has no attribute 'assret_called_with' 1.432 + >>> req.add_header.assert_called_with('spam', 'eggs') 1.433 + 1.434 +In many cases you will just be able to add `autospec=True` to your existing 1.435 +`patch` calls and then be protected against bugs due to typos and api 1.436 +changes. 1.437 + 1.438 +As well as using `autospec` through `patch` there is a 1.439 +:func:`create_autospec` for creating autospecced mocks directly: 1.440 + 1.441 +.. doctest:: 1.442 + 1.443 + >>> import urllib2 1.444 + >>> mock_urllib2 = create_autospec(urllib2) 1.445 + >>> mock_urllib2.Request('foo', 'bar') 1.446 + <NonCallableMagicMock name='mock.Request()' spec='Request' id='...'> 1.447 + 1.448 +This isn't without caveats and limitations however, which is why it is not 1.449 +the default behaviour. In order to know what attributes are available on the 1.450 +spec object, autospec has to introspect (access attributes) the spec. As you 1.451 +traverse attributes on the mock a corresponding traversal of the original 1.452 +object is happening under the hood. If any of your specced objects have 1.453 +properties or descriptors that can trigger code execution then you may not be 1.454 +able to use autospec. On the other hand it is much better to design your 1.455 +objects so that introspection is safe [#]_. 1.456 + 1.457 +A more serious problem is that it is common for instance attributes to be 1.458 +created in the `__init__` method and not to exist on the class at all. 1.459 +`autospec` can't know about any dynamically created attributes and restricts 1.460 +the api to visible attributes. 1.461 + 1.462 +.. doctest:: 1.463 + 1.464 + >>> class Something(object): 1.465 + ... def __init__(self): 1.466 + ... self.a = 33 1.467 + ... 1.468 + >>> with patch('__main__.Something', autospec=True): 1.469 + ... thing = Something() 1.470 + ... thing.a 1.471 + ... 1.472 + Traceback (most recent call last): 1.473 + ... 1.474 + AttributeError: Mock object has no attribute 'a' 1.475 + 1.476 +There are a few different ways of resolving this problem. The easiest, but 1.477 +not necessarily the least annoying, way is to simply set the required 1.478 +attributes on the mock after creation. Just because `autospec` doesn't allow 1.479 +you to fetch attributes that don't exist on the spec it doesn't prevent you 1.480 +setting them: 1.481 + 1.482 +.. doctest:: 1.483 + 1.484 + >>> with patch('__main__.Something', autospec=True): 1.485 + ... thing = Something() 1.486 + ... thing.a = 33 1.487 + ... 1.488 + 1.489 +There is a more aggressive version of both `spec` and `autospec` that *does* 1.490 +prevent you setting non-existent attributes. This is useful if you want to 1.491 +ensure your code only *sets* valid attributes too, but obviously it prevents 1.492 +this particular scenario: 1.493 + 1.494 +.. doctest:: 1.495 + 1.496 + >>> with patch('__main__.Something', autospec=True, spec_set=True): 1.497 + ... thing = Something() 1.498 + ... thing.a = 33 1.499 + ... 1.500 + Traceback (most recent call last): 1.501 + ... 1.502 + AttributeError: Mock object has no attribute 'a' 1.503 + 1.504 +Probably the best way of solving the problem is to add class attributes as 1.505 +default values for instance members initialised in `__init__`. Note that if 1.506 +you are only setting default attributes in `__init__` then providing them via 1.507 +class attributes (shared between instances of course) is faster too. e.g. 1.508 + 1.509 +.. code-block:: python 1.510 + 1.511 + class Something(object): 1.512 + a = 33 1.513 + 1.514 +This brings up another issue. It is relatively common to provide a default 1.515 +value of `None` for members that will later be an object of a different type. 1.516 +`None` would be useless as a spec because it wouldn't let you access *any* 1.517 +attributes or methods on it. As `None` is *never* going to be useful as a 1.518 +spec, and probably indicates a member that will normally of some other type, 1.519 +`autospec` doesn't use a spec for members that are set to `None`. These will 1.520 +just be ordinary mocks (well - `MagicMocks`): 1.521 + 1.522 +.. doctest:: 1.523 + 1.524 + >>> class Something(object): 1.525 + ... member = None 1.526 + ... 1.527 + >>> mock = create_autospec(Something) 1.528 + >>> mock.member.foo.bar.baz() 1.529 + <MagicMock name='mock.member.foo.bar.baz()' id='...'> 1.530 + 1.531 +If modifying your production classes to add defaults isn't to your liking 1.532 +then there are more options. One of these is simply to use an instance as the 1.533 +spec rather than the class. The other is to create a subclass of the 1.534 +production class and add the defaults to the subclass without affecting the 1.535 +production class. Both of these require you to use an alternative object as 1.536 +the spec. Thankfully `patch` supports this - you can simply pass the 1.537 +alternative object as the `autospec` argument: 1.538 + 1.539 +.. doctest:: 1.540 + 1.541 + >>> class Something(object): 1.542 + ... def __init__(self): 1.543 + ... self.a = 33 1.544 + ... 1.545 + >>> class SomethingForTest(Something): 1.546 + ... a = 33 1.547 + ... 1.548 + >>> p = patch('__main__.Something', autospec=SomethingForTest) 1.549 + >>> mock = p.start() 1.550 + >>> mock.a 1.551 + <NonCallableMagicMock name='Something.a' spec='int' id='...'> 1.552 + 1.553 +.. note:: 1.554 + 1.555 + An additional limitation (currently) with `autospec` is that unbound 1.556 + methods on mocked classes *don't* take an "explicit self" as the first 1.557 + argument - so this usage will fail with `autospec`. 1.558 + 1.559 + .. doctest:: 1.560 + 1.561 + >>> class Foo(object): 1.562 + ... def foo(self): 1.563 + ... pass 1.564 + ... 1.565 + >>> Foo.foo(Foo()) 1.566 + >>> MockFoo = create_autospec(Foo) 1.567 + >>> MockFoo.foo(MockFoo()) 1.568 + Traceback (most recent call last): 1.569 + ... 1.570 + TypeError: <lambda>() takes exactly 1 argument (2 given) 1.571 + 1.572 + The reason is that its very hard to tell the difference between functions, 1.573 + unbound methods and staticmethods across Python 2 & 3 and the alternative 1.574 + implementations. This restriction may be fixed in future versions. 1.575 + 1.576 + 1.577 +------ 1.578 + 1.579 +.. [#] This only applies to classes or already instantiated objects. Calling 1.580 + a mocked class to create a mock instance *does not* create a real instance. 1.581 + It is only attribute lookups - along with calls to `dir` - that are done. A 1.582 + way round this problem would have been to use `getattr_static 1.583 + <http://docs.python.org/dev/library/inspect.html#inspect.getattr_static>`_, 1.584 + which can fetch attributes without triggering code execution. Descriptors 1.585 + like `classmethod` and `staticmethod` *need* to be fetched correctly though, 1.586 + so that their signatures can be mocked correctly.