Where does doctest move classes that should be in __main__?

Viewed 63

I am rather confused about a snippet of code that runs as expected outside of doctest, but seems to fail when run by doctest because a class that exists in __main__ is no longer present. Does doctest do something funny to __main__, and if so where can I find this class?

Here is a minimal snippet that exhibits the problem. When run directly in python 3.7.7:

>>> from importlib import import_module

>>> class Foo:
...     pass

>>> print(Foo)
<class '__main__.Foo'>

>>> m = import_module(Foo.__module__)
>>> getattr(m, "Foo")
__main__.Foo

and in doctest via the command python3 -m doctest test.txt:

**********************************************************************
File "test.txt", line 10, in test.txt
Failed example:
    getattr(m, "Foo")
Exception raised:
    Traceback (most recent call last):
      File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/doctest.py", line 1330, in __run
        compileflags, 1), test.globs)
      File "<doctest test.txt[4]>", line 1, in <module>
        getattr(m, "Foo")
    AttributeError: module '__main__' has no attribute 'Foo'
**********************************************************************
1 items had failures:
   1 of   5 in test.txt
***Test Failed*** 1 failures.

I checked dir(__main__) to see if there was a difference. Directly in python:

>>> dir(__main__)
['Foo', '__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'import_module', 'm']

and from doctest:

>>> dir(__main__)
['BLANKLINE_MARKER', 'COMPARISON_FLAGS', 'DONT_ACCEPT_BLANKLINE', 'DONT_ACCEPT_TRUE_FOR_1', 'DebugRunner', 'DocFileCase', 'DocFileSuite', 'DocFileTest', 'DocTest', 'DocTestCase', 'DocTestFailure', 'DocTestFinder', 'DocTestParser', 'DocTestRunner', 'DocTestSuite', 'ELLIPSIS', 'ELLIPSIS_MARKER', 'Example', 'FAIL_FAST', 'IGNORE_EXCEPTION_DETAIL', 'NORMALIZE_WHITESPACE', 'OPTIONFLAGS_BY_NAME', 'OutputChecker', 'REPORTING_FLAGS', 'REPORT_CDIFF', 'REPORT_NDIFF', 'REPORT_ONLY_FIRST_FAILURE', 'REPORT_UDIFF', 'SKIP', 'SkipDocTestCase', 'StringIO', 'TestResults', 'UnexpectedException', '_DocTestSuite', '_OutputRedirectingPdb', '_SpoofOut', '_TestClass', '__all__', '__annotations__', '__builtins__', '__cached__', '__doc__', '__docformat__', '__file__', '__future__', '__loader__', '__name__', '__package__', '__spec__', '__test__', '_comment_line', '_ellipsis_match', '_exception_traceback', '_extract_future_flags', '_indent', '_load_testfile', '_module_relative_path', '_normalize_module', '_strip_exception_details', '_test', '_unittest_reportflags', 'debug', 'debug_script', 'debug_src', 'difflib', 'inspect', 'linecache', 'master', 'namedtuple', 'os', 'pdb', 're', 'register_optionflag', 'run_docstring_examples', 'script_from_examples', 'set_unittest_reportflags', 'sys', 'testfile', 'testmod', 'testsource', 'traceback', 'unittest']

Edit: I may have omitted too much context in my minimal example. I am trying to run doctest on a README file that defines Foo, and then runs code from another module that itself tries to import Foo.

0 Answers
Related