This issue tracker has been migrated to GitHub ,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2019年05月07日 14:44 by spark, last changed 2022年04月11日 14:59 by admin.
| Files | ||||
|---|---|---|---|---|
| File name | Uploaded | Description | Edit | |
| minimal-test-case.zip | spark, 2019年05月07日 14:44 | ZIP file with minimal test case | ||
| Messages (2) | |||
|---|---|---|---|
| msg341738 - (view) | Author: Sam Park (spark) | Date: 2019年05月07日 14:44 | |
The expectation is that the __module__ attribute for a patched function should persist after patching. Minimal test case is attached. Simply run pytest in a venv with the files. Output: def test_zxc(): with mock.patch.object(mymodule, 'asd', side_effect=mymodule.asd, autospec=True) as spy_asd: > assert spy_asd.__module__ == 'mymodule' E AssertionError: assert None == 'mymodule' E + where None = <function asd at 0x7fe4cd6fd620>.__module__ test_mymodule.py:8: AssertionError Originally reported at https://github.com/pytest-dev/pytest-mock/issues/146 before it was determined this was a unittest.mock issue. Happens on both Python 2.7 and 3.7. Probably not really tied to a specific Python version and more of mock library issue. My local venv: Python 3.7.2 pytest 4.4.1 |
|||
| msg341756 - (view) | Author: Karthikeyan Singaravelan (xtreak) * (Python committer) | Date: 2019年05月07日 15:46 | |
I guess the problem is that to patch 'bar' in foo.bar the signature of bar is taken and then it's evaluated using exec [1] where the function body has _check_sig that checks for the signature during function call. _check_sig has attributes of func copied. Since it's evaluated using exec the returned funcopy variable might not have __module__ set as per the execution context. One possible approach would be to _copy_func_details(func, funcopy) so that the __module__ and other attributes are copied. This produces a test failure where in case of lambdas the __name__ is <lambda> which is not a valid identifier and hence funcopy is used. Then __name__ is set as '<lambda>' by my patch. Hence, 'funcopy' is replaced by '<lambda>' causing below test failure. This could be resolved by setting __name__ again to the expected value. This was newly added for test coverage with adbf178e49113b2de0042e86a1228560475a65c5. My main worry is that it's used in create_autospec hence do we really want to copy __module__ and others to the patched function for places with create_autospec also with functions supplying autospec=True. This is a user expectation but I would like to know maintainers opinion as well of this change. Reproducer # cat /tmp/foo.py def bar(a: int): pass # /tmp/bar.py from unittest import mock import foo with mock.patch.object(foo, 'bar', autospec=True) as mocked_attribute: assert mocked_attribute.__module__ == 'foo' # Python 3.7 __module__ is None ➜ cpython git:(master) ✗ python3.7 /tmp/bar.py Traceback (most recent call last): File "/tmp/bar.py", line 6, in <module> assert mocked_attribute.__module__ == 'foo', f'__module__ is {mocked_attribute.__module__}' AssertionError: __module__ is None # With patch ➜ cpython git:(master) ✗ ./python.exe /tmp/bar.py # No failure # Patch diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py index 1e8057d5f5..a7006fcf7d 100644 --- a/Lib/unittest/mock.py +++ b/Lib/unittest/mock.py @@ -165,6 +165,8 @@ def _set_signature(mock, original, instance=False): exec (src, context) funcopy = context[name] _setup_func(funcopy, mock, sig) + _copy_func_details(func, funcopy) + funcopy.__name__ = name return funcopy # Test failure without funcopy.__name__ = name in my patch where I don't restore the 'funcopy' for lambdas. But this can be fixed. ====================================================================== FAIL: test_spec_function_no_name (unittest.test.testmock.testhelpers.SpecSignatureTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/karthikeyansingaravelan/stuff/python/cpython/Lib/unittest/test/testmock/testhelpers.py", line 946, in test_spec_function_no_name self.assertEqual(mock.__name__, 'funcopy') AssertionError: '<lambda>' != 'funcopy' - <lambda> + funcopy ---------------------------------------------------------------------- Ran 386 tests in 2.911s [1] https://github.com/python/cpython/blob/e85ef7a7eacdef2f43e6bf2e67f335100e7ef2da/Lib/unittest/mock.py#L165 |
|||
| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2022年04月11日 14:59:14 | admin | set | github: 81015 |
| 2019年05月07日 15:46:44 | xtreak | set | versions:
+ Python 3.8, - Python 2.7 nosy: + cjw296, michael.foord, mariocj89, xtreak messages: + msg341756 type: behavior |
| 2019年05月07日 14:44:21 | spark | create | |