Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for objects as return_value when patching #133

Open
laserprec opened this issue Sep 14, 2021 · 1 comment
Open

Support for objects as return_value when patching #133

laserprec opened this issue Sep 14, 2021 · 1 comment

Comments

@laserprec
Copy link

laserprec commented Sep 14, 2021

Is it possible to patch an object and set its return_value to another object?

For example let's say a Jupyter Notebook defines a method that downloads some CSV from the internet and load it in as a pandas.DataFrame.

import pandas as pd
import requests

def load_csv_from_internet():
    csv_file = requests.get(....) # fetch some CSV from the internet
    ...
    return pd.read_csv(csv_file) # read it and return as pandas.DataFrame

When writing a unit test for such method, I would like to avoid the making the external call and probably patch the return_value of load_csv_from_internet() to some fake pandas.DataFrame I pre-computed. For example:

#setup a fake pandas.DataFrame
mock_df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)))
# patching the `load_csv_from_internet` method from the Notebook
with tb.patch('__main__.load_csv_from_internet', return_value=mock_df) as mock_data:
    .... # some assertion check

Unfortunately, at the moment when assigning the return_value to an object, the object is casted to string type leading to the following error:

from unittest.mock import patch
E                           _patcher_yrvzguhxnm = patch(
E                               "__main__.load_csv_from_internet",
E                               **{"return_value": "     0   1   2   3
E               0    2  66  60  22
E               1   87   1  65  54
E               2   95  99   7  20
E               3   45  84  48  66
E               4   85  96  85  23
E               ..  ..  ..  ..  ..
E               95  79  66  35  94
E               96  91  50  43  87
E               97   5  84  14  18
E               98  13  30  23  71
E               99  66  74  83  66
E               
E               [100 rows x 4 columns]"}
E                           )
E                           _mock_iqufzomgiw = _patcher_yrvzguhxnm.start()
E               
E               ------------------
E               
E                 File "<ipython-input-4-6c61a9b5d34f>", line 4
E                   **{"return_value": "     0   1   2   3
E                                                         ^
E               SyntaxError: EOL while scanning string literal
E               
E               SyntaxError: EOL while scanning string literal (<ipython-input-4-6c61a9b5d34f>, line 4)

Is there plan to support returning objects as it is?

@MSeal
Copy link
Member

MSeal commented Sep 15, 2021

Complex objects that don't have a serialization, like dataframes and mocks, need to be explicitly injected. We need to brainstorm some easier ways to represent complex object mock pass down, perhaps testing and enabling mock object side-effects.

But ultimately to make this work you'll need to tb.inject the code that's needed to do the mocking:

tb.inject('''
mock_df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)))
unittest.mock.patch('__main__.load_csv_from_internet', return_value=mock_df)
''')

See #72 for some further notes on the topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants