pythonkeyword-argumentpython-unittest.mock

Unpacking kwargs in python unittest Mock where the keyword argument has 'dot' in name


According to unittest doc (https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.configure_mock) and verified personally,

mock = Mock(some_attribute='eggs', **{'method.return_value': 3, 'other.side_effect': KeyError})

works.

Also verified

mock = Mock(some_attribute='eggs', method.return_value=3, other.side_effect=KeyError)

will raise SyntaxError: keyword can't be an expression

Should these 2 be equivalent at syntax level? What happened in the dict unpacking? If 2 doesn't work, how is 1 being handled? Is there a way to achieve the Mock init without using "**"?

Tested snippet 1: works; Tested snippet 2: raise error; Asked ChatGPT-3.5: It tells nothing valuable but keeps contradicting itself and apologizing to me. Maybe I should upgrade to 4.


Solution

  • This is a syntactic problem. When you unpack a dict, the only syntactic requirement for the keys is that they shall be valid strings. No more no less. And 'method.return_value' is a valid string.

    But when you pass keyword parameters, the syntactic requirement is that they shall be valid identifiers. And as it contain a dot, method.return_value is not a valid identifier.

    You are just realizing that the unpacking kwargs idiom is more powerful than simply passing arbitrary but declared parameters. With the **dict idiom, the Python interpretor uses a short-circuit under the hood and directly uses the passed dictionary to build the kwargs parameter whitout any requirement for the keys to be valid identifiers. Unsure whether it was really intended at language definition time, but it is now definitely part of the language and has real use cases like your example.