[pytest-dev] monkeypatch.setattr of functions and from imports
holger krekel
holger at merlinux.eu
Wed Oct 23 20:36:14 CEST 2013
Hi Daniel,
On Wed, Oct 23, 2013 at 19:30 +0200, Daniel Nouri wrote:
> Dear all
>
> I have a function 'somefunc' in module 'a'. Another module 'b' imports
> that function with a "from import":
>
> a.py:
>
> def somefunc():
> return 'hey!'
>
> b.py:
>
> from a import somefunc
>
> def someotherfunc():
> return somefunc() + 'there'
>
>
> I want to now test 'someotherfunc' while patching away 'somefunc':
>
> def test_someotherfunc(monkeypatch):
> from b import someotherfunc
> monkeypatch.setattr('a.somefunc', lambda: 'eh?')
> someotherfunc()
>
> But this will fail, since 'b' imported somefunc from 'a' before we
> monkey patched the module's attribute. Without a "from import", this
> would work:
>
> b.py:
>
> import a
>
> def someotherfunc():
> return a.somefunc() + 'there'
>
> What I would normally resort to is patch somefunc's func_code, so that
> even code that used a "from import" before I could patch will use the
> patched version.
I would probably patch b's somefunc. Note that setattr() will by
default raise an exception if "b.somefunc" does not exist.
As to patching func_code: good idea, i had forgotten about assigning func_code.
In earlier Python2.X versions assigning to func_code didn't work but i just
checked that it does on py27 and py33. So it's definitely worthwhile to
pursue. In your example you could do:
monkeypatch.setattr('a.somefunc.func_code', (lambda: 'eh?').func_code)
and it works (needs to use __code__ on py3). I guess we could think about a
monkeypatch.setcode("a.somefunc", lambda: 'eh?')
helper. You could either pass in a function or a code object.
We could even think about allowing non-string targets:
monkeypatch.setcode(a.somefunc, lambda: 'eh?')
Or would "monkeypatch.setfunc" be a better name?
best,
holger
More information about the Pytest-dev
mailing list