2016-08-11 3 views
0

Die Funktion patch aus der Bibliothek mock reagiert empfindlich darauf, wie Dinge importiert werden. Gibt es einen tiefen Grund, warum ich nicht den vollständig qualifizierten Namen verwenden kann, in dem die Funktion ursprünglich definiert wurde, unabhängig davon, wie sie in anderen Modulen importiert wird?Warum ändert sich das Verhalten der Patch-Bibliothek in Abhängigkeit davon, wie Werte importiert werden?

ein "Modul-Import" arbeitet mit feinen

patch_example.py:

# WORKS! 
from mock import patch 
import inner 

def outer(x): 
    return ("outer", inner.inner(x)) 

@patch("inner.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

inner.py:

def inner(x): 
    return ("inner.inner", x) 

python patch_example.py Laufen nur Erfolg gibt.

kann jedoch den Import zu ändern haben ziemlich dramatische Folgen

ein Modul alias noch Verwendung arbeitet

# WORKS! 
from mock import patch 
import inner as inner2 

def outer(x): 
    return ("outer", inner2.inner(x)) 

@patch("inner.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

direkt auf das Symbol Importieren, jedoch erfordert, dass Sie den vollständigen Namen zu ändern.

direkten Import, inner.inner als voll qualifizierten Namen.

# FAILS! 
from mock import patch 
from inner import inner 

def outer(x): 
    return ("outer", inner(x)) 

@patch("inner.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

% python patch_example.py 
Traceback (most recent call last): 
    File "patch_example.py", line 14, in <module> 
    print test() 
    File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched 
    return func(*args, **keywargs) 
    File "patch_example.py", line 10, in test 
    assert outer(1) == ("outer", "MOCK") 
AssertionError 

produziert Wenn ich den vollständigen Pfad zu patch_example.inner aktualisieren, der Patch immer noch nicht.

# FAILS! 
from mock import patch 
from inner import inner 

def outer(x): 
    return ("outer", inner(x)) 

@patch("patch_example.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

% python patch_example.py 

Traceback (most recent call last): 
    File "patch_example.py", line 14, in <module> 
    print test() 
    File "/usr/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched 
    return func(*args, **keywargs) 
    File "patch_example.py", line 10, in test 
    assert outer(1) == ("outer", "MOCK") 
AssertionError 

mit __main__.inner als meine voll qualifizierten Namen obwohl das Richtige Patches.

# WORKS! 
from mock import patch 
from inner import inner 

def outer(x): 
    return ("outer", inner(x)) 

@patch("__main__.inner") 
def test(mock_inner): 
    mock_inner.return_value = "MOCK" 
    assert outer(1) == ("outer", "MOCK") 
    return "SUCCESS" 

if __name__ == "__main__": 
    print test() 

prints „SUCCESS“

Also, warum kann ich den Wert der inneren nicht patchen, wenn es als from inner import inner entweder den vollständig qualifizierten Namen des ursprünglichen Symbol inner.inner oder die Verwendung der Name der importiert wird Haupt Python-Modul statt __name__?

mit Python 2.7.12 auf OS X getestet

Antwort

1

Das Problem ist, dass, wenn Sie direkt auf das Symbol importieren gibt es ohne dass eine Verbindung zwischen der Bindung Du im __main__-Modul verwenden und die gefundene Bindung in das inner Modul. So patch ing das Modul tut nicht ändern Sie die bereits importierten Symbole.

Importieren eines Moduls eines Pseudonyms gestattet keine Rolle spielt, weil patch wird Nachschlag das sys.modules Wörterbuch, die noch den Überblick über den ursprünglichen Namen behalten, ist also, warum das funktioniert (eigentlich: wenn die mock Aufruf das Modul frisch importiert wird, so Es spielt keine Rolle, in welchem ​​Namen Sie es beim Aufruf patch)

mit anderen Worten: Sie müssen beide Bindings patch, weil sie effektiv nicht verwandt sind. Es gibt keine Möglichkeit für den Patch zu wissen, wo alle Referenzen auf inner.inner gelandet sind und sie zu patchen.

In diesem Fall kann das zweite Argument von patch nützlich sein, um ein vorhandenes Mock-Objekt anzugeben, das zum Patchen aller Bindungen freigegeben werden kann.

Verwandte Themen