Why does monkeypatching os.path require a path argument?

855 views Asked by At

pytest has this example in the monkeypatching docs:

import os.path
def getssh(): # pseudo application code
    return os.path.join(os.path.expanduser("~admin"), '.ssh')

def test_mytest(monkeypatch):
    def mockreturn(path):
        return '/abc'
    monkeypatch.setattr(os.path, 'expanduser', mockreturn)
    x = getssh()
    assert x == '/abc/.ssh'

When I remove the path argument from the mockreturn function, I get the error

    def getssh():  # pseudo application code
>       return os.path.join(os.path.expanduser("~admin"), '.ssh')
E       TypeError: mockreturn() takes 0 positional arguments but 1 was given

I don't understand what is providing that positional argument?

Also, when I reimplement the same thing for pathlib.Path.home() I cannot have this argument path there, otherwise it won't work. Unfortunately, the documentation does not say anything about that ominous path argument.

Any illumination for what magic is happening here would be very helpful!

1

There are 1 answers

1
niemmi On BEST ANSWER

You're trying to replace os.path.expanduser that takes one argument with a mock that doesn't take arguments at all which results to an error when called. Under the hood monkeypatch.setattr uses builtin setattr so the original version is basically doing following which works since both expanduser and mock take single argument:

>>> import os.path
>>> def mock(path):
...     return '/abc'
... 
>>> setattr(os.path, 'expanduser', mock)
>>> os.path.expanduser('~admin')
'/abc'

Now if you try to replace expanduser with a method that doesn't take arguments and keep calling it the same way you'll get an error:

>>> setattr(os.path, 'expanduser', mock)
>>> os.path.expanduser('~admin')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: mock() takes 0 positional arguments but 1 was given

Note that you'll get exactly the same error if you try to call mock directly:

>>> mock('~admin')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: mock() takes 0 positional arguments but 1 was given