Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Mock Import for Read the Docs?

Problem:

I have been fighting with Read the Docs. An imported module interacts with I/O, so the documentation does not contain any text. But the build does not fail.

Attempted Solution:

I am trying to use mock or MagicMock in doc/conf.py but it isn't working.

Desired Solution

Basically, I would like to mock the entire import. So RTD does not attempt to run any of the code. Just generate documentation from the DocStrings.

I simply want to mock ALL of the elements for a module. The classes, functions, and variables. Anything with a DocString.

Currently I MUST install the project inside a virtualenv, to satisfy the import. I would like to avoid this, if it isn't necessary. Right now... If I don't, again the documentation does not contain any text. Again, the build does not fail.

Details

example.py

"""Basic DocSting Comments"""
from external.module import *

foo = module()
foo.connect()
"""
I want this to show up in RTD.
"""

My specific case can be found here.

docs/conf.py

from mock import MagicMock

MOCK_MODULES = ['external.module', 'eternal.module.module', 'external.module.module.connect']
for mod_name in MOCK_MODULES:
    sys.modules[mod_name] = MagicMock()

I have tried a dozen different things, with no luck. Using mock and MagicMock, different advanced settings in RTD. All with no luck.

An Ugly Hack:

I did come across an ugly hack. But it defeats the purpose of using DocStrings. Writing the code a second time so RTD can catch the DocStings, may as well write it in a separate document.

if __name__ == "__main__":
    this = foo.connect()
    """
    This is where the real DocStrings go.
    """
else:
    this = 'this is the connect'
    """
    This is where the RTD DocStrings would go
    """

I do not want to end up with twice the code, just to add some documentation.

MySQL Connector/Python

I would also like to use this with the MySQL Connector. Since RTD also breaks when it encounters this package. And I can not fix it with requirements.txt.

import mysql.connector as db

db_connection = db.connect(**my_config)
"""
Perhaps I want to include some details here.
"""
like image 337
Brian LaVallee Avatar asked Nov 22 '16 07:11

Brian LaVallee


1 Answers

The following solution that I found on this blog post worked for me. I wanted to mock open3d and I was able to do that with:

from unittest import mock

# Mock open3d because it fails to build in readthedocs
MOCK_MODULES = ["open3d"]
for mod_name in MOCK_MODULES:
    sys.modules[mod_name] = mock.Mock()

Note that you need to import mock from unittest because unittest.mock is a builtin module starting with Python 3.3 (source).

If you wanted to mock multiple packages, you could do something like:

from unittest import mock

# Mock open3d because it fails to build in readthedocs
MOCK_MODULES = ["open3d", "numpy", "matplotlib", "matplotlib.pyplot"]
for mod_name in MOCK_MODULES:
    sys.modules[mod_name] = mock.Mock()
like image 146
Eric Wiener Avatar answered Nov 03 '22 08:11

Eric Wiener