New submission from Jason R. Coombs <jar...@jaraco.com>:

Originally [reported in 
testing-cabal/mock#405](https://github.com/testing-cabal/mock/issues/405), I 
believe I've discovered an inconsistency that manifests as a flaw:

`patch` and `patch.object` allow the target to be specified as string referring 
to the target object and this object is resolved at the time the patch 
effected, not when the patch is declared. `patch.dict` contrarily seems to 
resolve the dict eagerly, when the patch is declared. Observe with this pytest:

```
import mock


target = dict(a=1)

@mock.patch.dict('test_patch_dict.target', dict(b=2))
def test_after_patch():
        assert target == dict(a=2, b=2)

target = dict(a=2)
```

Here's the output:

```
$ rwt mock pytest -- -m pytest test_patch_dict.py
Collecting mock
  Using cached mock-2.0.0-py2.py3-none-any.whl
Collecting pbr>=0.11 (from mock)
  Using cached pbr-3.0.0-py2.py3-none-any.whl
Collecting six>=1.9 (from mock)
  Using cached six-1.10.0-py2.py3-none-any.whl
Installing collected packages: pbr, six, mock
Successfully installed mock-2.0.0 pbr-3.0.0 six-1.10.0
====================================== test session starts 
=======================================
platform darwin -- Python 3.6.1, pytest-3.0.5, py-1.4.33, pluggy-0.4.0
rootdir: /Users/jaraco, inifile: 
collected 1 items 

test_patch_dict.py F

============================================ FAILURES 
============================================
________________________________________ test_after_patch 
________________________________________

    @mock.patch.dict('test_patch_dict.target', dict(b=2))
    def test_after_patch():
>       assert target == dict(a=2, b=2)
E    assert {'a': 2} == {'a': 2, 'b': 2}
E      Omitting 1 identical items, use -v to show
E      Right contains more items:
E      {'b': 2}
E      Use -v to get the full diff

test_patch_dict.py:8: AssertionError
==================================== 1 failed in 0.05 seconds 
====================================
```

The target is unpatched because `test_patch_dict.target` was resolved during 
decoration rather than during test run.

Removing the initial assignment of `target = dict(a=1)`, the failure is thus:

```
______________________________ ERROR collecting test_patch_dict.py 
_______________________________
ImportError while importing test module '/Users/jaraco/test_patch_dict.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-pcm3552g/mock/mock.py:1197:
 in _dot_lookup
    return getattr(thing, comp)
E   AttributeError: module 'test_patch_dict' has no attribute 'target'

During handling of the above exception, another exception occurred:
<frozen importlib._bootstrap>:942: in _find_and_load_unlocked
    ???
E   AttributeError: module 'test_patch_dict' has no attribute '__path__'

During handling of the above exception, another exception occurred:
test_patch_dict.py:4: in <module>
    @mock.patch.dict('test_patch_dict.target', dict(b=2))
/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-pcm3552g/mock/mock.py:1708:
 in __init__
    in_dict = _importer(in_dict)
/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-pcm3552g/mock/mock.py:1210:
 in _importer
    thing = _dot_lookup(thing, comp, import_path)
/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-pcm3552g/mock/mock.py:1199:
 in _dot_lookup
    __import__(import_path)
E   ModuleNotFoundError: No module named 'test_patch_dict.target'; 
'test_patch_dict' is not a package
!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
==================================== 1 error in 0.41 seconds 
=====================================
```

Is there any reason `patch.dict` doesn't have a similar deferred resolution 
behavior as its sister methods?

----------
components: Library (Lib)
messages: 331937
nosy: jason.coombs
priority: normal
severity: normal
status: open
title: patch.dict resolves in_dict eagerly (should be late resolved)

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue35512>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to