Mocking `IPython.display`
fastai is a nice library for quickly getting started with a deep learning project. It was developed for interactive environments (i.e., Jupyter Notebooks) and using interactive environments, see nbdev. This is nice for most use-cases, however, we eventually run all of our scripts on a headless server without an interactive environment.
This means that we lose some of fastai’s functionality. For example, the ability to display the top loss images during image classification. We would still like this information, though, and we’ve figured out a way to make it work in a non-interactive environment.
Here is some code that causes problems (see the computer vision intro for more information):
interp = Interpretation.from_learner(learn)
interp.plot_top_losses(9)
This works fine in an interactive environment, but does not produce an output that we can save in a script. Other functions, like interp.plot_confusion_matrix()
, work fine because they create a matplotlib
figure that can be saved. Digging into interp.plot_top_losses()
leads us to display_df
, which I’ve copied below.
def display_df(df):
"Display `df` in a notebook or defaults to print"
try: from IPython.display import display, HTML
except: return print(df)
display(HTML(df.to_html()))
display_df
calls display
, which, as far as I was able to determine, does not produce an output that is easy to consume in a script. So, I created this simplified, two-file example to demonstrate and work on the problem.
# fake.py
def fake_plot_top_losses():
from IPython.display import HTML, display
display(HTML("<div>df</div>"))
# mocking_ipython.py
from unittest.mock import MagicMock, patch
from fake import fake_plot_top_losses
def my_HTML(html):
my_HTML.html = html
ipython_display_mock = MagicMock()
ipython_display_mock.HTML = my_HTML
with patch.dict("sys.modules", {"IPython.display": ipython_display_mock}):
fake_plot_top_losses()
print(my_HTML.html)
Using the patch.dict
context manager, we can replace the IPython.display
module with our own mock. We then provide a replacement for the HTML
function, which is passed the raw HTML that we want to save.
We are going to adapt this to our wandb
logging setup and add an example below once we have it working.