Example #1
0
def test_warning_location(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.warning('message1', location='index')
    assert 'index.txt: WARNING: message1' in warning.getvalue()

    logger.warning('message2', location=('index', 10))
    assert 'index.txt:10: WARNING: message2' in warning.getvalue()

    logger.warning('message3', location=None)
    assert colorize('darkred', 'WARNING: message3') in warning.getvalue()

    node = nodes.Node()
    node.source, node.line = ('index.txt', 10)
    logger.warning('message4', location=node)
    assert 'index.txt:10: WARNING: message4' in warning.getvalue()

    node.source, node.line = ('index.txt', None)
    logger.warning('message5', location=node)
    assert 'index.txt:: WARNING: message5' in warning.getvalue()

    node.source, node.line = (None, 10)
    logger.warning('message6', location=node)
    assert '<unknown>:10: WARNING: message6' in warning.getvalue()

    node.source, node.line = (None, None)
    logger.warning('message7', location=node)
    assert colorize('darkred', 'WARNING: message7') in warning.getvalue()
Example #2
0
def test_add_is_parallel_allowed(app, status, warning):
    logging.setup(app, status, warning)

    assert app.is_parallel_allowed('read') is True
    assert app.is_parallel_allowed('write') is True
    assert warning.getvalue() == ''

    app.setup_extension('read_parallel')
    assert app.is_parallel_allowed('read') is True
    assert app.is_parallel_allowed('write') is True
    assert warning.getvalue() == ''
    app.extensions.pop('read_parallel')

    app.setup_extension('write_parallel')
    assert app.is_parallel_allowed('read') is False
    assert app.is_parallel_allowed('write') is True
    assert ("the write_parallel extension does not declare if it is safe "
            "for parallel reading, assuming it isn't - please ") in warning.getvalue()
    app.extensions.pop('write_parallel')
    warning.truncate(0)  # reset warnings

    app.setup_extension('read_serial')
    assert app.is_parallel_allowed('read') is False
    assert app.is_parallel_allowed('write') is True
    assert warning.getvalue() == ''
    app.extensions.pop('read_serial')

    app.setup_extension('write_serial')
    assert app.is_parallel_allowed('read') is False
    assert app.is_parallel_allowed('write') is False
    assert ("the write_serial extension does not declare if it is safe "
            "for parallel reading, assuming it isn't - please ") in warning.getvalue()
    app.extensions.pop('write_serial')
    warning.truncate(0)  # reset warnings
Example #3
0
def test_suppress_warnings(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    app._warncount = 0  # force reset

    app.config.suppress_warnings = []
    warning.truncate(0)
    logger.warning('message1', type='test', subtype='logging')
    logger.warning('message2', type='test', subtype='crash')
    logger.warning('message3', type='actual', subtype='logging')
    assert 'message1' in warning.getvalue()
    assert 'message2' in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert app._warncount == 3

    app.config.suppress_warnings = ['test']
    warning.truncate(0)
    logger.warning('message1', type='test', subtype='logging')
    logger.warning('message2', type='test', subtype='crash')
    logger.warning('message3', type='actual', subtype='logging')
    assert 'message1' not in warning.getvalue()
    assert 'message2' not in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert app._warncount == 4

    app.config.suppress_warnings = ['test.logging']
    warning.truncate(0)
    logger.warning('message1', type='test', subtype='logging')
    logger.warning('message2', type='test', subtype='crash')
    logger.warning('message3', type='actual', subtype='logging')
    assert 'message1' not in warning.getvalue()
    assert 'message2' in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert app._warncount == 6
Example #4
0
def test_colored_logs(app, status, warning):
    app.verbosity = 2
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    # default colors
    logger.debug('message1')
    logger.verbose('message2')
    logger.info('message3')
    logger.warning('message4')
    logger.critical('message5')
    logger.error('message6')

    assert colorize('darkgray', 'message1') in status.getvalue()
    assert 'message2\n' in status.getvalue()  # not colored
    assert 'message3\n' in status.getvalue()  # not colored
    assert colorize('darkred', 'WARNING: message4') in warning.getvalue()
    assert 'WARNING: message5\n' in warning.getvalue()  # not colored
    assert 'WARNING: message6\n' in warning.getvalue()  # not colored

    # color specification
    logger.debug('message7', color='white')
    logger.info('message8', color='red')
    assert colorize('white', 'message7') in status.getvalue()
    assert colorize('red', 'message8') in status.getvalue()
Example #5
0
def test_new_documenter():
    logging.setup(app, app._status, app._warning)

    class MyDocumenter(ModuleLevelDocumenter):
        objtype = 'integer'
        directivetype = 'data'
        priority = 100

        @classmethod
        def can_document_member(cls, member, membername, isattr, parent):
            return isinstance(member, int)

        def document_members(self, all_members=False):
            return

    add_documenter(MyDocumenter)

    def assert_result_contains(item, objtype, name, **kw):
        app._warning.truncate(0)
        inst = app.registry.documenters[objtype](directive, name)
        inst.generate(**kw)
        # print '\n'.join(directive.result)
        assert app._warning.getvalue() == ''
        assert item in directive.result
        del directive.result[:]

    options.members = ['integer']
    assert_result_contains('.. py:data:: integer', 'module', 'target')
Example #6
0
def test_info_location(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1', location='index')
    assert 'index.txt: message1' in status.getvalue()

    logger.info('message2', location=('index', 10))
    assert 'index.txt:10: message2' in status.getvalue()

    logger.info('message3', location=None)
    assert '\nmessage3' in status.getvalue()

    node = nodes.Node()
    node.source, node.line = ('index.txt', 10)
    logger.info('message4', location=node)
    assert 'index.txt:10: message4' in status.getvalue()

    node.source, node.line = ('index.txt', None)
    logger.info('message5', location=node)
    assert 'index.txt:: message5' in status.getvalue()

    node.source, node.line = (None, 10)
    logger.info('message6', location=node)
    assert '<unknown>:10: message6' in status.getvalue()

    node.source, node.line = (None, None)
    logger.info('message7', location=node)
    assert '\nmessage7' in status.getvalue()
Example #7
0
def test_status_iterator(app, status, warning):
    logging.setup(app, status, warning)

    # test for old_status_iterator
    status.truncate(0)
    yields = list(status_iterator(['hello', 'sphinx', 'world'], 'testing ... '))
    output = strip_escseq(status.getvalue())
    assert 'testing ... hello sphinx world \n' in output
    assert yields == ['hello', 'sphinx', 'world']

    # test for status_iterator (verbosity=0)
    status.truncate(0)
    yields = list(status_iterator(['hello', 'sphinx', 'world'], 'testing ... ',
                                  length=3, verbosity=0))
    output = strip_escseq(status.getvalue())
    assert 'testing ... [ 33%] hello                \r' in output
    assert 'testing ... [ 66%] sphinx               \r' in output
    assert 'testing ... [100%] world                \r\n' in output
    assert yields == ['hello', 'sphinx', 'world']

    # test for status_iterator (verbosity=1)
    status.truncate(0)
    yields = list(status_iterator(['hello', 'sphinx', 'world'], 'testing ... ',
                                  length=3, verbosity=1))
    output = strip_escseq(status.getvalue())
    assert 'testing ... [ 33%] hello\n' in output
    assert 'testing ... [ 66%] sphinx\n' in output
    assert 'testing ... [100%] world\n\n' in output
    assert yields == ['hello', 'sphinx', 'world']
Example #8
0
def test_nonl_info_log(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1', nonl=True)
    logger.info('message2')
    logger.info('message3')

    assert 'message1message2\nmessage3' in status.getvalue()
        def __init__(self,
                     confoverrides=None,
                     srcdir=None,
                     raise_on_warning=False):
            self.extensions = {}
            self.registry = SphinxComponentRegistry()
            try:
                self.html_themes = {}
            except AttributeError:
                # changed to property in sphinx 4.1
                pass
            self.events = EventManager(self)

            # logging
            self.verbosity = 0
            self._warncount = 0
            self.warningiserror = raise_on_warning
            self._status = StringIO()
            self._warning = StringIO()
            logging.setup(self, self._status, self._warning)

            self.tags = Tags([])
            self.config = Config({}, confoverrides or {})
            self.config.pre_init_values()
            self._init_i18n()
            for extension in builtin_extensions:
                self.registry.load_extension(self, extension)
            # fresh env
            self.doctreedir = ""
            self.srcdir = srcdir
            self.confdir = None
            self.outdir = ""
            self.project = Project(srcdir=srcdir,
                                   source_suffix={".md": "markdown"})
            self.project.docnames = {"mock_docname"}
            self.env = BuildEnvironment()
            self.env.setup(self)
            self.env.temp_data["docname"] = "mock_docname"
            # Ignore type checkers because we disrespect superclass typing here
            self.builder = None  # type: ignore[assignment]

            if not with_builder:
                return

            # this code is only required for more complex parsing with extensions
            for extension in self.config.extensions:
                self.setup_extension(extension)
            buildername = "dummy"
            self.preload_builder(buildername)
            self.config.init_values()
            self.events.emit("config-inited", self.config)

            with tempfile.TemporaryDirectory() as tempdir:
                # creating a builder attempts to make the doctreedir
                self.doctreedir = tempdir
                self.builder = self.create_builder(buildername)
            self.doctreedir = ""
Example #10
0
def test_nonl_info_log(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1', nonl=True)
    logger.info('message2')
    logger.info('message3')

    assert 'message1message2\nmessage3' in status.getvalue()
def test_once_warning_log(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.warning('message: %d', 1, once=True)
    logger.warning('message: %d', 1, once=True)
    logger.warning('message: %d', 2, once=True)

    assert 'WARNING: message: 1\nWARNING: message: 2\n' in strip_escseq(warning.getvalue())
def test_annotation_html(app, status, warning):
    app.config.sphinx_autodoc_alias = {("A", "B"), ("C", "D")}
    app.verbosity = 2
    logging.setup(app, status, warning)
    app.builder.doctreedir.rmtree()
    app.builder.outdir.rmtree()
    app.builder.build_all()
    assert not warning.getvalue()
    messages = [i for i in status.getvalue().split("\n") if "[autodoc-typehints][process-docstring] " in i]
    assert len(messages) == 5
Example #13
0
def test_suppress_logging(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.warning('message1')
    with logging.suppress_logging():
        logger.warning('message2')
        assert 'WARNING: message1' in warning.getvalue()
        assert 'WARNING: message2' not in warning.getvalue()

    assert 'WARNING: message1' in warning.getvalue()
    assert 'WARNING: message2' not in warning.getvalue()
Example #14
0
def test_warningiserror(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    # if False, warning is not error
    app.warningiserror = False
    logger.warning('message')

    # if True, warning raises SphinxWarning exception
    app.warningiserror = True
    with pytest.raises(SphinxWarning):
        logger.warning('message')
Example #15
0
def test_warningiserror(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    # if False, warning is not error
    app.warningiserror = False
    logger.warning('message')

    # if True, warning raises SphinxWarning exception
    app.warningiserror = True
    with pytest.raises(SphinxWarning):
        logger.warning('message')
Example #16
0
def test_output_with_unencodable_char(app, status, warning):
    class StreamWriter(codecs.StreamWriter):
        def write(self, object):
            self.stream.write(object.encode('cp1252').decode('cp1252'))

    logging.setup(app, StreamWriter(status), warning)
    logger = logging.getLogger(__name__)

    # info with UnicodeEncodeError
    status.truncate(0)
    status.seek(0)
    logger.info(u"unicode \u206d...")
    assert status.getvalue() == "unicode ?...\n"
Example #17
0
def main(argv: List[str] = sys.argv[1:]) -> None:
    sphinx.locale.setlocale(locale.LC_ALL, '')
    sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx')

    app = DummyApplication()
    logging.setup(app, sys.stdout, sys.stderr)  # type: ignore
    setup_documenters(app)
    args = get_parser().parse_args(argv)
    generate_autosummary_docs(args.source_file, args.output_dir,
                              '.' + args.suffix,
                              template_dir=args.templates,
                              imported_members=args.imported_members,
                              app=app)
Example #18
0
def test_logging_in_ParallelTasks(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    def child_process():
        logger.info('message1')
        logger.warning('message2', location='index')

    tasks = ParallelTasks(1)
    tasks.add_task(child_process)
    tasks.join()
    assert 'message1' in status.getvalue()
    assert 'index.txt: WARNING: message2' in warning.getvalue()
Example #19
0
def test_output_with_unencodable_char(app, status, warning):
    class StreamWriter(codecs.StreamWriter):
        def write(self, object):
            self.stream.write(object.encode('cp1252').decode('cp1252'))

    logging.setup(app, StreamWriter(status), warning)
    logger = logging.getLogger(__name__)

    # info with UnicodeEncodeError
    status.truncate(0)
    status.seek(0)
    logger.info(u"unicode \u206d...")
    assert status.getvalue() == "unicode ?...\n"
Example #20
0
def test_execfile_python2(capsys, app, status, warning, tempdir):
    logging.setup(app, status, warning)

    conf_py = tempdir / 'conf.py'
    conf_py.write_bytes(b'print "hello"\n')
    execfile_(conf_py, {})

    msg = ('Support for evaluating Python 2 syntax is deprecated '
           'and will be removed in Sphinx 4.0. '
           'Convert %s to Python 3 syntax.\n' % conf_py)
    assert msg in strip_escseq(warning.getvalue())
    captured = capsys.readouterr()
    assert captured.out == 'hello\n'
Example #21
0
def test_logging_in_ParallelTasks(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    def child_process():
        logger.info('message1')
        logger.warning('message2', location='index')

    tasks = ParallelTasks(1)
    tasks.add_task(child_process)
    tasks.join()
    assert 'message1' in status.getvalue()
    assert 'index.txt: WARNING: message2' in warning.getvalue()
Example #22
0
        def __init__(self,
                     confoverrides=None,
                     srcdir=None,
                     raise_on_warning=False):
            self.extensions = {}
            self.registry = SphinxComponentRegistry()
            self.html_themes = {}
            self.events = EventManager(self)

            # logging
            self.verbosity = 0
            self._warncount = 0
            self.warningiserror = raise_on_warning
            self._status = StringIO()
            self._warning = StringIO()
            logging.setup(self, self._status, self._warning)

            self.tags = Tags(None)
            self.config = Config({}, confoverrides or {})
            self.config.pre_init_values()
            self._init_i18n()
            for extension in builtin_extensions:
                self.registry.load_extension(self, extension)
            # fresh env
            self.doctreedir = None
            self.srcdir = srcdir
            self.confdir = None
            self.outdir = None
            self.project = Project(srcdir=srcdir, source_suffix=".md")
            self.project.docnames = ["mock_docname"]
            self.env = BuildEnvironment()
            self.env.setup(self)
            self.env.temp_data["docname"] = "mock_docname"
            self.builder = None

            if not with_builder:
                return

            # this code is only required for more complex parsing with extensions
            for extension in self.config.extensions:
                self.setup_extension(extension)
            buildername = "dummy"
            self.preload_builder(buildername)
            self.config.init_values()
            self.events.emit("config-inited", self.config)

            with tempfile.TemporaryDirectory() as tempdir:
                # creating a builder attempts to make the doctreedir
                self.doctreedir = tempdir
                self.builder = self.create_builder(buildername)
            self.doctreedir = None
Example #23
0
def test_execfile_python2(capsys, app, status, warning):
    logging.setup(app, status, warning)

    ns = {}
    with tempfile.NamedTemporaryFile() as tmp:
        tmp.write(b'print "hello"\n')
        tmp.flush()
        execfile_(tmp.name, ns)
    msg = ('Support for evaluating Python 2 syntax is deprecated '
           'and will be removed in Sphinx 4.0. '
           'Convert %s to Python 3 syntax.\n' % tmp.name)
    assert msg in strip_escseq(warning.getvalue())
    captured = capsys.readouterr()
    assert captured.out == 'hello\n'
Example #24
0
def test_advanced(app, status, warning):
    logging.setup(app, status, warning)
    app.builder.build_all()
    assert (app.outdir / 'api').isdir()
    assert (app.outdir / 'api' / 'modules.html').exists()
    for module in [
            'apidoc_dummy_module.html',
            'apidoc_dummy_package.apidoc_dummy_submodule_a.html',
            'apidoc_dummy_package.apidoc_dummy_submodule_b.html'
    ]:
        assert (app.outdir / 'api' / module).exists()
    assert (app.outdir / 'api' / 'apidoc_dummy_package.html').exists()
    assert not (app.outdir / 'api' / 'conf.html').exists()
    assert not warning.getvalue()
Example #25
0
 def sphinx_mute(self):
     try:
         original_status = self.sphinx._status
         original_warning = self.sphinx._warning
         self.sphinx._status = StringIO()
         self.sphinx._warning = StringIO()
         logging.setup(self.sphinx, self.sphinx._status,
                       self.sphinx._warning)
         yield
     finally:
         self.sphinx._status = original_status
         self.sphinx._warning = original_warning
         logging.setup(self.sphinx, self.sphinx._status,
                       self.sphinx._warning)
Example #26
0
def test_pending_warnings(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.warning('message1')
    with logging.pending_warnings():
        # not logged yet (bufferred) in here
        logger.warning('message2')
        logger.warning('message3')
        assert 'WARNING: message1' in warning.getvalue()
        assert 'WARNING: message2' not in warning.getvalue()
        assert 'WARNING: message3' not in warning.getvalue()

    # actually logged as ordered
    assert 'WARNING: message2\nWARNING: message3' in strip_escseq(warning.getvalue())
Example #27
0
def test_basics(app, status, warning):
    logging.setup(app, status, warning)
    app.builder.build_all()

    assert (app.srcdir / 'api').isdir()
    assert (app.srcdir / 'api' / 'modules.rst').exists()
    assert (app.srcdir / 'api' / 'apidoc_dummy_module.rst').exists()
    assert not (app.srcdir / 'api' / 'conf.rst').exists()

    assert (app.outdir / 'api').isdir()
    assert (app.outdir / 'api' / 'modules.html').exists()
    assert (app.outdir / 'api' / 'apidoc_dummy_module.html').exists()
    assert not (app.outdir / 'api' / 'conf.html').exists()

    assert not warning.getvalue()
def test_execfile_python2(capsys, app, status, warning):
    logging.setup(app, status, warning)

    ns = {}
    with tempfile.NamedTemporaryFile() as tmp:
        tmp.write(b'print "hello"\n')
        tmp.flush()
        execfile_(tmp.name, ns)
    msg = (
        'Support for evaluating Python 2 syntax is deprecated '
        'and will be removed in Sphinx 4.0. '
        'Convert %s to Python 3 syntax.\n' % tmp.name)
    assert msg in strip_escseq(warning.getvalue())
    captured = capsys.readouterr()
    assert captured.out == 'hello\n'
Example #29
0
def test_pending_warnings(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.warning('message1')
    with logging.pending_warnings():
        # not logged yet (bufferred) in here
        logger.warning('message2')
        logger.warning('message3')
        assert 'WARNING: message1' in warning.getvalue()
        assert 'WARNING: message2' not in warning.getvalue()
        assert 'WARNING: message3' not in warning.getvalue()

    # actually logged as ordered
    assert 'WARNING: message2\nWARNING: message3' in strip_escseq(warning.getvalue())
Example #30
0
def test_warningiserror(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    # if False, warning is not error
    app.warningiserror = False
    logger.warning('message')

    # if True, warning raises SphinxWarning exception
    app.warningiserror = True
    with pytest.raises(SphinxWarning):
        logger.warning('message: %s', 'arg')

    # message contains format string (refs: #4070)
    with pytest.raises(SphinxWarning):
        logger.warning('%s')
Example #31
0
def test_warningiserror(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    # if False, warning is not error
    app.warningiserror = False
    logger.warning('message')

    # if True, warning raises SphinxWarning exception
    app.warningiserror = True
    with pytest.raises(SphinxWarning):
        logger.warning('message: %s', 'arg')

    # message contains format string (refs: #4070)
    with pytest.raises(SphinxWarning):
        logger.warning('%s')
Example #32
0
def test_prefixed_warnings(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.warning('message1')
    with prefixed_warnings('PREFIX:'):
        logger.warning('message2')
        with prefixed_warnings('Another PREFIX:'):
            logger.warning('message3')
        logger.warning('message4')
    logger.warning('message5')

    assert 'WARNING: message1' in warning.getvalue()
    assert 'WARNING: PREFIX: message2' in warning.getvalue()
    assert 'WARNING: Another PREFIX: message3' in warning.getvalue()
    assert 'WARNING: PREFIX: message4' in warning.getvalue()
    assert 'WARNING: message5' in warning.getvalue()
Example #33
0
def test_prefixed_warnings(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.warning('message1')
    with prefixed_warnings('PREFIX:'):
        logger.warning('message2')
        with prefixed_warnings('Another PREFIX:'):
            logger.warning('message3')
        logger.warning('message4')
    logger.warning('message5')

    assert 'WARNING: message1' in warning.getvalue()
    assert 'WARNING: PREFIX: message2' in warning.getvalue()
    assert 'WARNING: Another PREFIX: message3' in warning.getvalue()
    assert 'WARNING: PREFIX: message4' in warning.getvalue()
    assert 'WARNING: message5' in warning.getvalue()
Example #34
0
def main(argv: List[str] = sys.argv[1:]) -> None:
    sphinx.locale.setlocale(locale.LC_ALL, '')
    sphinx.locale.init_console(os.path.join(package_dir, 'locale'), 'sphinx')
    translator, _ = sphinx.locale.init([], None)

    app = DummyApplication(translator)
    logging.setup(app, sys.stdout, sys.stderr)  # type: ignore
    setup_documenters(app)
    args = get_parser().parse_args(argv)

    if args.templates:
        app.config.templates_path.append(path.abspath(args.templates))
    app.config.autosummary_ignore_module_all = not args.respect_module_all  # type: ignore

    generate_autosummary_docs(args.source_file, args.output_dir,
                              '.' + args.suffix,
                              imported_members=args.imported_members,
                              app=app)
Example #35
0
def test_parse_name():
    logging.setup(app, app._status, app._warning)

    def verify(objtype, name, result):
        inst = app.registry.documenters[objtype](directive, name)
        assert inst.parse_name()
        assert (inst.modname, inst.objpath, inst.args, inst.retann) == result

    # for modules
    verify('module', 'test_autodoc', ('test_autodoc', [], None, None))
    verify('module', 'test.test_autodoc',
           ('test.test_autodoc', [], None, None))
    verify('module', 'test(arg)', ('test', [], 'arg', None))
    assert 'signature arguments' in app._warning.getvalue()

    # for functions/classes
    verify('function', 'test_autodoc.raises',
           ('test_autodoc', ['raises'], None, None))
    verify('function', 'test_autodoc.raises(exc) -> None',
           ('test_autodoc', ['raises'], 'exc', 'None'))
    directive.env.temp_data['autodoc:module'] = 'test_autodoc'
    verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
    del directive.env.temp_data['autodoc:module']
    directive.env.ref_context['py:module'] = 'test_autodoc'
    verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
    verify('class', 'Base', ('test_autodoc', ['Base'], None, None))

    # for members
    directive.env.ref_context['py:module'] = 'foo'
    verify('method', 'util.SphinxTestApp.cleanup',
           ('util', ['SphinxTestApp', 'cleanup'], None, None))
    directive.env.ref_context['py:module'] = 'util'
    directive.env.ref_context['py:class'] = 'Foo'
    directive.env.temp_data['autodoc:class'] = 'SphinxTestApp'
    verify('method', 'cleanup',
           ('util', ['SphinxTestApp', 'cleanup'], None, None))
    verify('method', 'SphinxTestApp.cleanup',
           ('util', ['SphinxTestApp', 'cleanup'], None, None))

    # and clean up
    del directive.env.ref_context['py:module']
    del directive.env.ref_context['py:class']
    del directive.env.temp_data['autodoc:class']
Example #36
0
def test_parse_name():
    logging.setup(app, app._status, app._warning)

    def verify(objtype, name, result):
        inst = app.registry.documenters[objtype](directive, name)
        assert inst.parse_name()
        assert (inst.modname, inst.objpath, inst.args, inst.retann) == result

    # for modules
    verify('module', 'test_autodoc', ('test_autodoc', [], None, None))
    verify('module', 'test.test_autodoc', ('test.test_autodoc', [], None, None))
    verify('module', 'test(arg)', ('test', [], 'arg', None))
    assert 'signature arguments' in app._warning.getvalue()

    # for functions/classes
    verify('function', 'test_autodoc.raises',
           ('test_autodoc', ['raises'], None, None))
    verify('function', 'test_autodoc.raises(exc) -> None',
           ('test_autodoc', ['raises'], 'exc', 'None'))
    directive.env.temp_data['autodoc:module'] = 'test_autodoc'
    verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
    del directive.env.temp_data['autodoc:module']
    directive.env.ref_context['py:module'] = 'test_autodoc'
    verify('function', 'raises', ('test_autodoc', ['raises'], None, None))
    verify('class', 'Base', ('test_autodoc', ['Base'], None, None))

    # for members
    directive.env.ref_context['py:module'] = 'foo'
    verify('method', 'util.SphinxTestApp.cleanup',
           ('util', ['SphinxTestApp', 'cleanup'], None, None))
    directive.env.ref_context['py:module'] = 'util'
    directive.env.ref_context['py:class'] = 'Foo'
    directive.env.temp_data['autodoc:class'] = 'SphinxTestApp'
    verify('method', 'cleanup', ('util', ['SphinxTestApp', 'cleanup'], None, None))
    verify('method', 'SphinxTestApp.cleanup',
           ('util', ['SphinxTestApp', 'cleanup'], None, None))

    # and clean up
    del directive.env.ref_context['py:module']
    del directive.env.ref_context['py:class']
    del directive.env.temp_data['autodoc:class']
def test_suppress_warnings(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    app._warncount = 0  # force reset

    app.config.suppress_warnings = []
    warning.truncate(0)
    logger.warning('message0', type='test')
    logger.warning('message1', type='test', subtype='logging')
    logger.warning('message2', type='test', subtype='crash')
    logger.warning('message3', type='actual', subtype='logging')
    assert 'message0' in warning.getvalue()
    assert 'message1' in warning.getvalue()
    assert 'message2' in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert app._warncount == 4

    app.config.suppress_warnings = ['test']
    warning.truncate(0)
    logger.warning('message0', type='test')
    logger.warning('message1', type='test', subtype='logging')
    logger.warning('message2', type='test', subtype='crash')
    logger.warning('message3', type='actual', subtype='logging')
    assert 'message0' not in warning.getvalue()
    assert 'message1' not in warning.getvalue()
    assert 'message2' not in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert app._warncount == 5

    app.config.suppress_warnings = ['test.logging']
    warning.truncate(0)
    logger.warning('message0', type='test')
    logger.warning('message1', type='test', subtype='logging')
    logger.warning('message2', type='test', subtype='crash')
    logger.warning('message3', type='actual', subtype='logging')
    assert 'message0' in warning.getvalue()
    assert 'message1' not in warning.getvalue()
    assert 'message2' in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert app._warncount == 8
Example #38
0
def test_info_and_warning(app, status, warning):
    app.verbosity = 2
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.debug('message1')
    logger.info('message2')
    logger.warning('message3')
    logger.critical('message4')
    logger.error('message5')

    assert 'message1' in status.getvalue()
    assert 'message2' in status.getvalue()
    assert 'message3' not in status.getvalue()
    assert 'message4' not in status.getvalue()
    assert 'message5' not in status.getvalue()

    assert 'message1' not in warning.getvalue()
    assert 'message2' not in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert 'message4' in warning.getvalue()
    assert 'message5' in warning.getvalue()
Example #39
0
def test_mangle_docstring_validation_warnings(
    f,
    numpydoc_validation_checks,
    expected_warn,
    non_warnings,
):
    app = MockApp()
    # Set up config for test
    app.config.numpydoc_validation_checks = numpydoc_validation_checks
    # Update configuration
    update_config(app)
    # Set up logging
    status, warning = StringIO(), StringIO()
    logging.setup(app, status, warning)
    # Run mangle docstrings with the above configuration
    mangle_docstrings(app, 'function', 'f', f, None, f.__doc__.split('\n'))
    # Assert that all (and only) expected warnings are logged
    warnings = warning.getvalue()
    for w in expected_warn:
        assert w in warnings
    for w in non_warnings:
        assert w not in warnings
Example #40
0
def test_info_and_warning(app, status, warning):
    app.verbosity = 2
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.debug('message1')
    logger.info('message2')
    logger.warning('message3')
    logger.critical('message4')
    logger.error('message5')

    assert 'message1' in status.getvalue()
    assert 'message2' in status.getvalue()
    assert 'message3' not in status.getvalue()
    assert 'message4' not in status.getvalue()
    assert 'message5' not in status.getvalue()

    assert 'message1' not in warning.getvalue()
    assert 'message2' not in warning.getvalue()
    assert 'message3' in warning.getvalue()
    assert 'message4' in warning.getvalue()
    assert 'message5' in warning.getvalue()
Example #41
0
def test_skip_warningiserror(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    app.warningiserror = True
    with logging.skip_warningiserror():
        logger.warning('message')

    # if False, warning raises SphinxWarning exception
    with pytest.raises(SphinxWarning):
        with logging.skip_warningiserror(False):
            logger.warning('message')

    # It also works during pending_warnings.
    with logging.pending_warnings():
        with logging.skip_warningiserror():
            logger.warning('message')

    with pytest.raises(SphinxWarning):
        with logging.pending_warnings():
            with logging.skip_warningiserror(False):
                logger.warning('message')
Example #42
0
def test_skip_warningiserror(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    app.warningiserror = True
    with logging.skip_warningiserror():
        logger.warning('message')

    # if False, warning raises SphinxWarning exception
    with pytest.raises(SphinxWarning):
        with logging.skip_warningiserror(False):
            logger.warning('message')

    # It also works during pending_warnings.
    with logging.pending_warnings():
        with logging.skip_warningiserror():
            logger.warning('message')

    with pytest.raises(SphinxWarning):
        with logging.pending_warnings():
            with logging.skip_warningiserror(False):
                logger.warning('message')
Example #43
0
def test_add_is_parallel_allowed(app, status, warning):
    logging.setup(app, status, warning)

    assert app.is_parallel_allowed('read') is True
    assert app.is_parallel_allowed('write') is True
    assert warning.getvalue() == ''

    app.setup_extension('read_parallel')
    assert app.is_parallel_allowed('read') is True
    assert app.is_parallel_allowed('write') is True
    assert warning.getvalue() == ''
    app.extensions.pop('read_parallel')

    app.setup_extension('write_parallel')
    assert app.is_parallel_allowed('read') is False
    assert app.is_parallel_allowed('write') is True
    assert ("the write_parallel extension does not declare if it is safe "
            "for parallel reading, assuming it isn't - please "
            ) in warning.getvalue()
    app.extensions.pop('write_parallel')
    warning.truncate(0)  # reset warnings

    app.setup_extension('read_serial')
    assert app.is_parallel_allowed('read') is False
    assert "the read_serial extension is not safe for parallel reading" in warning.getvalue(
    )
    warning.truncate(0)  # reset warnings
    assert app.is_parallel_allowed('write') is True
    assert warning.getvalue() == ''
    app.extensions.pop('read_serial')

    app.setup_extension('write_serial')
    assert app.is_parallel_allowed('read') is False
    assert app.is_parallel_allowed('write') is False
    assert ("the write_serial extension does not declare if it is safe "
            "for parallel reading, assuming it isn't - please "
            ) in warning.getvalue()
    app.extensions.pop('write_serial')
    warning.truncate(0)  # reset warnings
Example #44
0
def test_advanced(app, status, warning):
    if sphinx.version_info < (1, 8, 0):
        pytest.xfail('This should fail on older Sphinx versions')

    logging.setup(app, status, warning)
    app.builder.build_all()

    assert (app.srcdir / 'api').isdir()
    assert (app.srcdir / 'api' / 'custom.rst').exists()
    for module in [
            'apidoc_dummy_module.rst',
            'apidoc_dummy_package.apidoc_dummy_submodule_a.rst',
            'apidoc_dummy_package.apidoc_dummy_submodule_b.rst',
            'apidoc_dummy_package._apidoc_private_dummy_submodule.rst',
    ]:
        assert (app.srcdir / 'api' / module).exists()
    assert (app.srcdir / 'api' / 'apidoc_dummy_package.rst').exists()
    assert not (app.srcdir / 'api' / 'conf.rst').exists()

    with open(app.srcdir / 'api' / 'apidoc_dummy_package.rst') as fh:
        package_doc = [x.strip() for x in fh.readlines()]

    # The 'Module contents' header isn't present if '--module-first' used
    assert 'Module contents' not in package_doc

    assert (app.outdir / 'api').isdir()
    assert (app.outdir / 'api' / 'custom.html').exists()
    for module in [
            'apidoc_dummy_module.html',
            'apidoc_dummy_package.apidoc_dummy_submodule_a.html',
            'apidoc_dummy_package.apidoc_dummy_submodule_b.html',
            'apidoc_dummy_package._apidoc_private_dummy_submodule.html',
    ]:
        assert (app.outdir / 'api' / module).exists()
    assert (app.outdir / 'api' / 'apidoc_dummy_package.html').exists()
    assert not (app.outdir / 'api' / 'conf.html').exists()

    assert not warning.getvalue()
Example #45
0
def test_status_iterator(app, status, warning):
    logging.setup(app, status, warning)

    # test for old_status_iterator
    status.truncate(0)
    yields = list(status_iterator(['hello', 'sphinx', 'world'],
                                  'testing ... '))
    output = strip_escseq(status.getvalue())
    assert 'testing ... hello sphinx world \n' in output
    assert yields == ['hello', 'sphinx', 'world']

    # test for status_iterator (verbosity=0)
    status.truncate(0)
    yields = list(
        status_iterator(['hello', 'sphinx', 'world'],
                        'testing ... ',
                        length=3,
                        verbosity=0))
    output = strip_escseq(status.getvalue())
    assert 'testing ... [ 33%] hello                \r' in output
    assert 'testing ... [ 66%] sphinx               \r' in output
    assert 'testing ... [100%] world                \r\n' in output
    assert yields == ['hello', 'sphinx', 'world']

    # test for status_iterator (verbosity=1)
    status.truncate(0)
    yields = list(
        status_iterator(['hello', 'sphinx', 'world'],
                        'testing ... ',
                        length=3,
                        verbosity=1))
    output = strip_escseq(status.getvalue())
    assert 'testing ... [ 33%] hello\n' in output
    assert 'testing ... [ 66%] sphinx\n' in output
    assert 'testing ... [100%] world\n\n' in output
    assert yields == ['hello', 'sphinx', 'world']
Example #46
0
def test_progress_message(app, status, warning):
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    # standard case
    with progress_message('testing'):
        logger.info('blah ', nonl=True)

    output = strip_escseq(status.getvalue())
    assert 'testing... blah done\n' in output

    # skipping case
    with progress_message('testing'):
        raise SkipProgressMessage('Reason: %s', 'error')

    output = strip_escseq(status.getvalue())
    assert 'testing... skipped\nReason: error\n' in output

    # error case
    try:
        with progress_message('testing'):
            raise
    except Exception:
        pass

    output = strip_escseq(status.getvalue())
    assert 'testing... failed\n' in output

    # decorator
    @progress_message('testing')
    def func():
        logger.info('in func ', nonl=True)

    func()
    output = strip_escseq(status.getvalue())
    assert 'testing... in func done\n' in output
Example #47
0
def test_verbosity_filter(app, status, warning):
    # verbosity = 0: INFO
    app.verbosity = 0
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1')
    logger.verbose('message2')
    logger.debug('message3')

    assert 'message1' in status.getvalue()
    assert 'message2' not in status.getvalue()
    assert 'message3' not in status.getvalue()
    assert 'message4' not in status.getvalue()

    # verbosity = 1: VERBOSE
    app.verbosity = 1
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1')
    logger.verbose('message2')
    logger.debug('message3')

    assert 'message1' in status.getvalue()
    assert 'message2' in status.getvalue()
    assert 'message3' not in status.getvalue()
    assert 'message4' not in status.getvalue()

    # verbosity = 2: DEBUG
    app.verbosity = 2
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1')
    logger.verbose('message2')
    logger.debug('message3')

    assert 'message1' in status.getvalue()
    assert 'message2' in status.getvalue()
    assert 'message3' in status.getvalue()
    assert 'message4' not in status.getvalue()
Example #48
0
def test_verbosity_filter(app, status, warning):
    # verbosity = 0: INFO
    app.verbosity = 0
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1')
    logger.verbose('message2')
    logger.debug('message3')

    assert 'message1' in status.getvalue()
    assert 'message2' not in status.getvalue()
    assert 'message3' not in status.getvalue()
    assert 'message4' not in status.getvalue()

    # verbosity = 1: VERBOSE
    app.verbosity = 1
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1')
    logger.verbose('message2')
    logger.debug('message3')

    assert 'message1' in status.getvalue()
    assert 'message2' in status.getvalue()
    assert 'message3' not in status.getvalue()
    assert 'message4' not in status.getvalue()

    # verbosity = 2: DEBUG
    app.verbosity = 2
    logging.setup(app, status, warning)
    logger = logging.getLogger(__name__)

    logger.info('message1')
    logger.verbose('message2')
    logger.debug('message3')

    assert 'message1' in status.getvalue()
    assert 'message2' in status.getvalue()
    assert 'message3' in status.getvalue()
    assert 'message4' not in status.getvalue()
Example #49
0
def test_generate():
    logging.setup(app, app._status, app._warning)

    def assert_warns(warn_str, objtype, name, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.generate(**kw)
        assert len(directive.result) == 0, directive.result
        assert warn_str in app._warning.getvalue()
        app._warning.truncate(0)

    def assert_works(objtype, name, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.generate(**kw)
        assert directive.result
        # print '\n'.join(directive.result)
        assert app._warning.getvalue() == ''
        del directive.result[:]

    def assert_processes(items, objtype, name, **kw):
        del processed_docstrings[:]
        del processed_signatures[:]
        assert_works(objtype, name, **kw)
        assert set(processed_docstrings) | set(processed_signatures) == set(items)

    def assert_result_contains(item, objtype, name, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.generate(**kw)
        # print '\n'.join(directive.result)
        assert app._warning.getvalue() == ''
        assert item in directive.result
        del directive.result[:]

    def assert_order(items, objtype, name, member_order, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.options.member_order = member_order
        inst.generate(**kw)
        assert app._warning.getvalue() == ''
        items = list(reversed(items))
        lineiter = iter(directive.result)
        # for line in directive.result:
        #     if line.strip():
        #         print repr(line)
        while items:
            item = items.pop()
            for line in lineiter:
                if line == item:
                    break
            else:  # ran out of items!
                assert False, ('item %r not found in result or not in the '
                               ' correct order' % item)
        del directive.result[:]

    options.members = []

    # no module found?
    assert_warns("import for autodocumenting 'foobar'",
                 'function', 'foobar', more_content=None)
    # importing
    assert_warns("failed to import module 'test_foobar'",
                 'module', 'test_foobar', more_content=None)
    # attributes missing
    assert_warns("failed to import function 'foobar' from module 'util'",
                 'function', 'util.foobar', more_content=None)
    # method missing
    assert_warns("failed to import method 'Class.foobar' from module 'test_autodoc_py35';",
                 'method', 'test_autodoc_py35.Class.foobar', more_content=None)

    # test auto and given content mixing
    directive.env.ref_context['py:module'] = 'test_autodoc_py35'
    assert_result_contains('   Function.', 'method', 'Class.meth')
    add_content = ViewList()
    add_content.append('Content.', '', 0)
    assert_result_contains('   Function.', 'method',
                           'Class.meth', more_content=add_content)
    assert_result_contains('   Content.', 'method',
                           'Class.meth', more_content=add_content)

    # test check_module
    inst = FunctionDocumenter(directive, 'add_documenter')
    inst.generate(check_module=True)
    assert len(directive.result) == 0

    # assert that exceptions can be documented
    assert_works('exception', 'test_autodoc_py35.CustomEx', all_members=True)
    assert_works('exception', 'test_autodoc_py35.CustomEx')

    # test diverse inclusion settings for members
    should = [('class', 'test_autodoc_py35.Class')]
    assert_processes(should, 'class', 'Class')
    should.extend([('method', 'test_autodoc_py35.Class.meth')])
    options.members = ['meth']
    options.exclude_members = set(['excludemeth'])
    assert_processes(should, 'class', 'Class')
    should.extend([('attribute', 'test_autodoc_py35.Class.prop'),
                   ('attribute', 'test_autodoc_py35.Class.descr'),
                   ('attribute', 'test_autodoc_py35.Class.attr'),
                   ('attribute', 'test_autodoc_py35.Class.docattr'),
                   ('attribute', 'test_autodoc_py35.Class.udocattr'),
                   ('attribute', 'test_autodoc_py35.Class.mdocattr'),
                   ('attribute', 'test_autodoc_py35.Class.inst_attr_comment'),
                   ('attribute', 'test_autodoc_py35.Class.inst_attr_inline'),
                   ('attribute', 'test_autodoc_py35.Class.inst_attr_string'),
                   ('method', 'test_autodoc_py35.Class.moore'),
                   ])
    if six.PY3 and sys.version_info[:2] >= (3, 5):
        should.extend([
            ('method', 'test_autodoc_py35.Class.do_coroutine'),
        ])
    options.members = ALL
    assert_processes(should, 'class', 'Class')
    options.undoc_members = True
    should.extend((('attribute', 'test_autodoc_py35.Class.skipattr'),
                   ('method', 'test_autodoc_py35.Class.undocmeth'),
                   ('method', 'test_autodoc_py35.Class.roger')))
    assert_processes(should, 'class', 'Class')
    options.inherited_members = True
    should.append(('method', 'test_autodoc_py35.Class.inheritedmeth'))
    assert_processes(should, 'class', 'Class')

    # test special members
    options.special_members = ['__special1__']
    should.append(('method', 'test_autodoc_py35.Class.__special1__'))
    assert_processes(should, 'class', 'Class')
    options.special_members = ALL
    should.append(('method', 'test_autodoc_py35.Class.__special2__'))
    assert_processes(should, 'class', 'Class')
    options.special_members = False
Example #50
0
    def __init__(self, srcdir, confdir, outdir, doctreedir, buildername,
                 confoverrides=None, status=sys.stdout, warning=sys.stderr,
                 freshenv=False, warningiserror=False, tags=None, verbosity=0,
                 parallel=0, keep_going=False):
        # type: (str, str, str, str, str, Dict, IO, IO, bool, bool, List[str], int, int, bool) -> None  # NOQA
        self.phase = BuildPhase.INITIALIZATION
        self.verbosity = verbosity
        self.extensions = {}                    # type: Dict[str, Extension]
        self.builder = None                     # type: Builder
        self.env = None                         # type: BuildEnvironment
        self.project = None                     # type: Project
        self.registry = SphinxComponentRegistry()
        self.html_themes = {}                   # type: Dict[str, str]

        # validate provided directories
        self.srcdir = abspath(srcdir)
        self.outdir = abspath(outdir)
        self.doctreedir = abspath(doctreedir)
        self.confdir = confdir
        if self.confdir:  # confdir is optional
            self.confdir = abspath(self.confdir)
            if not path.isfile(path.join(self.confdir, 'conf.py')):
                raise ApplicationError(__("config directory doesn't contain a "
                                          "conf.py file (%s)") % confdir)

        if not path.isdir(self.srcdir):
            raise ApplicationError(__('Cannot find source directory (%s)') %
                                   self.srcdir)

        if self.srcdir == self.outdir:
            raise ApplicationError(__('Source directory and destination '
                                      'directory cannot be identical'))

        self.parallel = parallel

        if status is None:
            self._status = StringIO()      # type: IO
            self.quiet = True
        else:
            self._status = status
            self.quiet = False

        if warning is None:
            self._warning = StringIO()     # type: IO
        else:
            self._warning = warning
        self._warncount = 0
        self.keep_going = warningiserror and keep_going
        if self.keep_going:
            self.warningiserror = False
        else:
            self.warningiserror = warningiserror
        logging.setup(self, self._status, self._warning)

        self.events = EventManager()

        # keep last few messages for traceback
        # This will be filled by sphinx.util.logging.LastMessagesWriter
        self.messagelog = deque(maxlen=10)  # type: deque

        # say hello to the world
        logger.info(bold(__('Running Sphinx v%s') % sphinx.__display_version__))

        # status code for command-line application
        self.statuscode = 0

        # read config
        self.tags = Tags(tags)
        if self.confdir is None:
            self.config = Config({}, confoverrides or {})
        else:
            self.config = Config.read(self.confdir, confoverrides or {}, self.tags)

        # initialize some limited config variables before initialize i18n and loading
        # extensions
        self.config.pre_init_values()

        # set up translation infrastructure
        self._init_i18n()

        # check the Sphinx version if requested
        if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__:
            raise VersionRequirementError(
                __('This project needs at least Sphinx v%s and therefore cannot '
                   'be built with this version.') % self.config.needs_sphinx)

        # set confdir to srcdir if -C given (!= no confdir); a few pieces
        # of code expect a confdir to be set
        if self.confdir is None:
            self.confdir = self.srcdir

        # load all built-in extension modules
        for extension in builtin_extensions:
            self.setup_extension(extension)

        # load all user-given extension modules
        for extension in self.config.extensions:
            self.setup_extension(extension)

        # preload builder module (before init config values)
        self.preload_builder(buildername)

        if not path.isdir(outdir):
            with progress_message(__('making output directory')):
                ensuredir(outdir)

        # the config file itself can be an extension
        if self.config.setup:
            prefix = __('while setting up extension %s:') % "conf.py"
            with prefixed_warnings(prefix):
                if callable(self.config.setup):
                    self.config.setup(self)
                else:
                    raise ConfigError(
                        __("'setup' as currently defined in conf.py isn't a Python callable. "
                           "Please modify its definition to make it a callable function. "
                           "This is needed for conf.py to behave as a Sphinx extension.")
                    )

        # now that we know all config values, collect them from conf.py
        self.config.init_values()
        self.emit('config-inited', self.config)

        # create the project
        self.project = Project(self.srcdir, self.config.source_suffix)
        # create the builder
        self.builder = self.create_builder(buildername)
        # set up the build environment
        self._init_env(freshenv)
        # set up the builder
        self._init_builder()
Example #51
0
    def __init__(self,
                 srcdir,
                 confdir,
                 outdir,
                 doctreedir,
                 buildername,
                 confoverrides=None,
                 status=sys.stdout,
                 warning=sys.stderr,
                 freshenv=False,
                 warningiserror=False,
                 tags=None,
                 verbosity=0,
                 parallel=0,
                 keep_going=False):
        # type: (str, str, str, str, str, Dict, IO, IO, bool, bool, List[str], int, int, bool) -> None  # NOQA
        self.phase = BuildPhase.INITIALIZATION
        self.verbosity = verbosity
        self.extensions = {}  # type: Dict[str, Extension]
        self.builder = None  # type: Builder
        self.env = None  # type: BuildEnvironment
        self.project = None  # type: Project
        self.registry = SphinxComponentRegistry()
        self.html_themes = {}  # type: Dict[str, str]

        # validate provided directories
        self.srcdir = abspath(srcdir)
        self.outdir = abspath(outdir)
        self.doctreedir = abspath(doctreedir)
        self.confdir = confdir
        if self.confdir:  # confdir is optional
            self.confdir = abspath(self.confdir)
            if not path.isfile(path.join(self.confdir, 'conf.py')):
                raise ApplicationError(
                    __("config directory doesn't contain a "
                       "conf.py file (%s)") % confdir)

        if not path.isdir(self.srcdir):
            raise ApplicationError(
                __('Cannot find source directory (%s)') % self.srcdir)

        if self.srcdir == self.outdir:
            raise ApplicationError(
                __('Source directory and destination '
                   'directory cannot be identical'))

        self.parallel = parallel

        if status is None:
            self._status = StringIO()  # type: IO
            self.quiet = True
        else:
            self._status = status
            self.quiet = False

        if warning is None:
            self._warning = StringIO()  # type: IO
        else:
            self._warning = warning
        self._warncount = 0
        self.keep_going = warningiserror and keep_going
        if self.keep_going:
            self.warningiserror = False
        else:
            self.warningiserror = warningiserror
        logging.setup(self, self._status, self._warning)

        self.events = EventManager(self)

        # keep last few messages for traceback
        # This will be filled by sphinx.util.logging.LastMessagesWriter
        self.messagelog = deque(maxlen=10)  # type: deque

        # say hello to the world
        logger.info(bold(
            __('Running Sphinx v%s') % sphinx.__display_version__))

        # notice for parallel build on macOS and py38+
        if sys.version_info > (
                3, 8) and platform.system() == 'Darwin' and parallel > 1:
            logger.info(
                bold(
                    __("For security reason, parallel mode is disabled on macOS and "
                       "python3.8 and above.  For more details, please read "
                       "https://github.com/sphinx-doc/sphinx/issues/6803")))

        # status code for command-line application
        self.statuscode = 0

        # read config
        self.tags = Tags(tags)
        if self.confdir is None:
            self.config = Config({}, confoverrides or {})
        else:
            self.config = Config.read(self.confdir, confoverrides or {},
                                      self.tags)

        # initialize some limited config variables before initialize i18n and loading
        # extensions
        self.config.pre_init_values()

        # set up translation infrastructure
        self._init_i18n()

        # check the Sphinx version if requested
        if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__:
            raise VersionRequirementError(
                __('This project needs at least Sphinx v%s and therefore cannot '
                   'be built with this version.') % self.config.needs_sphinx)

        # set confdir to srcdir if -C given (!= no confdir); a few pieces
        # of code expect a confdir to be set
        if self.confdir is None:
            self.confdir = self.srcdir

        # load all built-in extension modules
        for extension in builtin_extensions:
            self.setup_extension(extension)

        # load all user-given extension modules
        for extension in self.config.extensions:
            self.setup_extension(extension)

        # preload builder module (before init config values)
        self.preload_builder(buildername)

        if not path.isdir(outdir):
            with progress_message(__('making output directory')):
                ensuredir(outdir)

        # the config file itself can be an extension
        if self.config.setup:
            prefix = __('while setting up extension %s:') % "conf.py"
            with prefixed_warnings(prefix):
                if callable(self.config.setup):
                    self.config.setup(self)
                else:
                    raise ConfigError(
                        __("'setup' as currently defined in conf.py isn't a Python callable. "
                           "Please modify its definition to make it a callable function. "
                           "This is needed for conf.py to behave as a Sphinx extension."
                           ))

        # now that we know all config values, collect them from conf.py
        self.config.init_values()
        self.events.emit('config-inited', self.config)

        # create the project
        self.project = Project(self.srcdir, self.config.source_suffix)
        # create the builder
        self.builder = self.create_builder(buildername)
        # set up the build environment
        self._init_env(freshenv)
        # set up the builder
        self._init_builder()
Example #52
0
    def __init__(self, srcdir, confdir, outdir, doctreedir, buildername,
                 confoverrides=None, status=sys.stdout, warning=sys.stderr,
                 freshenv=False, warningiserror=False, tags=None, verbosity=0,
                 parallel=0):
        # type: (unicode, unicode, unicode, unicode, unicode, Dict, IO, IO, bool, bool, List[unicode], int, int) -> None  # NOQA
        self.verbosity = verbosity
        self.extensions = {}                    # type: Dict[unicode, Extension]
        self._setting_up_extension = ['?']      # type: List[unicode]
        self.builder = None                     # type: Builder
        self.env = None                         # type: BuildEnvironment
        self.registry = SphinxComponentRegistry()
        self.enumerable_nodes = {}              # type: Dict[nodes.Node, Tuple[unicode, Callable]]  # NOQA
        self.post_transforms = []               # type: List[Transform]
        self.html_themes = {}                   # type: Dict[unicode, unicode]

        self.srcdir = srcdir
        self.confdir = confdir
        self.outdir = outdir
        self.doctreedir = doctreedir

        self.parallel = parallel

        if status is None:
            self._status = cStringIO()      # type: IO
            self.quiet = True
        else:
            self._status = status
            self.quiet = False

        if warning is None:
            self._warning = cStringIO()     # type: IO
        else:
            self._warning = warning
        self._warncount = 0
        self.warningiserror = warningiserror
        logging.setup(self, self._status, self._warning)

        self.events = EventManager()

        # keep last few messages for traceback
        # This will be filled by sphinx.util.logging.LastMessagesWriter
        self.messagelog = deque(maxlen=10)  # type: deque

        # say hello to the world
        logger.info(bold('Running Sphinx v%s' % sphinx.__display_version__))

        # status code for command-line application
        self.statuscode = 0

        if not path.isdir(outdir):
            logger.info('making output directory...')
            os.makedirs(outdir)

        # read config
        self.tags = Tags(tags)
        self.config = Config(confdir, CONFIG_FILENAME,
                             confoverrides or {}, self.tags)
        self.config.check_unicode()
        # defer checking types until i18n has been initialized

        # initialize some limited config variables before initialize i18n and loading
        # extensions
        self.config.pre_init_values()

        # set up translation infrastructure
        self._init_i18n()

        # check the Sphinx version if requested
        if self.config.needs_sphinx and self.config.needs_sphinx > sphinx.__display_version__:
            raise VersionRequirementError(
                __('This project needs at least Sphinx v%s and therefore cannot '
                   'be built with this version.') % self.config.needs_sphinx)

        # set confdir to srcdir if -C given (!= no confdir); a few pieces
        # of code expect a confdir to be set
        if self.confdir is None:
            self.confdir = self.srcdir

        # load all built-in extension modules
        for extension in builtin_extensions:
            self.setup_extension(extension)

        # load all user-given extension modules
        for extension in self.config.extensions:
            self.setup_extension(extension)

        # preload builder module (before init config values)
        self.preload_builder(buildername)

        # the config file itself can be an extension
        if self.config.setup:
            self._setting_up_extension = ['conf.py']
            # py31 doesn't have 'callable' function for below check
            if hasattr(self.config.setup, '__call__'):
                self.config.setup(self)
            else:
                raise ConfigError(
                    __("'setup' as currently defined in conf.py isn't a Python callable. "
                       "Please modify its definition to make it a callable function. This is "
                       "needed for conf.py to behave as a Sphinx extension.")
                )

        # now that we know all config values, collect them from conf.py
        self.config.init_values()

        # check extension versions if requested
        verify_required_extensions(self, self.config.needs_extensions)

        # check primary_domain if requested
        primary_domain = self.config.primary_domain
        if primary_domain and not self.registry.has_domain(primary_domain):
            logger.warning(__('primary_domain %r not found, ignored.'), primary_domain)

        # create the builder
        self.builder = self.create_builder(buildername)
        # check all configuration values for permissible types
        self.config.check_types()
        # set up source_parsers
        self._init_source_parsers()
        # set up the build environment
        self._init_env(freshenv)
        # set up the builder
        self._init_builder()
        # set up the enumerable nodes
        self._init_enumerable_nodes()
Example #53
0
def test_generate():
    logging.setup(app, app._status, app._warning)

    def assert_warns(warn_str, objtype, name, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.generate(**kw)
        assert len(directive.result) == 0, directive.result

        assert warn_str in app._warning.getvalue()
        app._warning.truncate(0)

    def assert_works(objtype, name, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.generate(**kw)
        assert directive.result
        # print '\n'.join(directive.result)
        assert app._warning.getvalue() == ''
        del directive.result[:]

    def assert_processes(items, objtype, name, **kw):
        del processed_docstrings[:]
        del processed_signatures[:]
        assert_works(objtype, name, **kw)
        assert set(processed_docstrings) | set(processed_signatures) == set(items)

    def assert_result_contains(item, objtype, name, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.generate(**kw)
        # print '\n'.join(directive.result)
        assert app._warning.getvalue() == ''
        assert item in directive.result
        del directive.result[:]

    def assert_order(items, objtype, name, member_order, **kw):
        inst = app.registry.documenters[objtype](directive, name)
        inst.options.member_order = member_order
        inst.generate(**kw)
        assert app._warning.getvalue() == ''
        items = list(reversed(items))
        lineiter = iter(directive.result)
        # for line in directive.result:
        #     if line.strip():
        #         print repr(line)
        while items:
            item = items.pop()
            for line in lineiter:
                if line == item:
                    break
            else:  # ran out of items!
                assert False, ('item %r not found in result or not in the '
                               ' correct order' % item)
        del directive.result[:]

    options.members = []

    # no module found?
    assert_warns("import for autodocumenting 'foobar'",
                 'function', 'foobar', more_content=None)
    # importing
    assert_warns("failed to import module 'test_foobar'",
                 'module', 'test_foobar', more_content=None)
    # attributes missing
    assert_warns("failed to import function 'foobar' from module 'util'",
                 'function', 'util.foobar', more_content=None)
    # method missing
    assert_warns("failed to import method 'Class.foobar' from module 'target';",
                 'method', 'target.Class.foobar', more_content=None)

    # test auto and given content mixing
    directive.env.ref_context['py:module'] = 'target'
    assert_result_contains('   Function.', 'method', 'Class.meth')
    add_content = ViewList()
    add_content.append('Content.', '', 0)
    assert_result_contains('   Function.', 'method',
                           'Class.meth', more_content=add_content)
    assert_result_contains('   Content.', 'method',
                           'Class.meth', more_content=add_content)

    # test check_module
    inst = FunctionDocumenter(directive, 'add_documenter')
    inst.generate(check_module=True)
    assert len(directive.result) == 0

    # assert that exceptions can be documented
    assert_works('exception', 'target.CustomEx', all_members=True)
    assert_works('exception', 'target.CustomEx')

    # test diverse inclusion settings for members
    should = [('class', 'target.Class')]
    assert_processes(should, 'class', 'Class')
    should.extend([('method', 'target.Class.meth')])
    options.members = ['meth']
    options.exclude_members = set(['excludemeth'])
    assert_processes(should, 'class', 'Class')
    should.extend([('attribute', 'target.Class.prop'),
                   ('attribute', 'target.Class.descr'),
                   ('attribute', 'target.Class.attr'),
                   ('attribute', 'target.Class.docattr'),
                   ('attribute', 'target.Class.udocattr'),
                   ('attribute', 'target.Class.mdocattr'),
                   ('attribute', 'target.Class.inst_attr_comment'),
                   ('attribute', 'target.Class.inst_attr_inline'),
                   ('attribute', 'target.Class.inst_attr_string'),
                   ('method', 'target.Class.moore'),
                   ])
    options.members = ALL
    assert_processes(should, 'class', 'Class')
    options.undoc_members = True
    should.extend((('attribute', 'target.Class.skipattr'),
                   ('method', 'target.Class.undocmeth'),
                   ('method', 'target.Class.roger')))
    assert_processes(should, 'class', 'Class')
    options.inherited_members = True
    should.append(('method', 'target.Class.inheritedmeth'))
    should.append(('method', 'target.Class.inheritedclassmeth'))
    should.append(('method', 'target.Class.inheritedstaticmeth'))
    assert_processes(should, 'class', 'Class')

    # test special members
    options.special_members = ['__special1__']
    should.append(('method', 'target.Class.__special1__'))
    assert_processes(should, 'class', 'Class')
    options.special_members = ALL
    should.append(('method', 'target.Class.__special2__'))
    assert_processes(should, 'class', 'Class')
    options.special_members = False

    options.members = []
    # test module flags
    assert_result_contains('.. py:module:: target',
                           'module', 'target')
    options.synopsis = 'Synopsis'
    assert_result_contains('   :synopsis: Synopsis', 'module', 'target')
    options.deprecated = True
    assert_result_contains('   :deprecated:', 'module', 'target')
    options.platform = 'Platform'
    assert_result_contains('   :platform: Platform', 'module', 'target')
    # test if __all__ is respected for modules
    options.members = ALL
    assert_result_contains('.. py:class:: Class(arg)', 'module', 'target')
    try:
        assert_result_contains('.. py:exception:: CustomEx',
                               'module', 'target')
    except AssertionError:
        pass
    else:
        assert False, 'documented CustomEx which is not in __all__'

    # test ignore-module-all
    options.ignore_module_all = True
    assert_result_contains('.. py:class:: Class(arg)', 'module', 'target')
    assert_result_contains('.. py:exception:: CustomEx', 'module', 'target')

    # test noindex flag
    options.members = []
    options.noindex = True
    assert_result_contains('   :noindex:', 'module', 'target')
    assert_result_contains('   :noindex:', 'class', 'Base')

    # okay, now let's get serious about mixing Python and C signature stuff
    assert_result_contains('.. py:class:: CustomDict', 'class', 'CustomDict',
                           all_members=True)

    # test inner class handling
    assert_processes([('class', 'target.Outer'),
                      ('class', 'target.Outer.Inner'),
                      ('method', 'target.Outer.Inner.meth')],
                     'class', 'Outer', all_members=True)

    # test descriptor docstrings
    assert_result_contains('   Descriptor instance docstring.',
                           'attribute', 'target.Class.descr')

    # test generation for C modules (which have no source file)
    directive.env.ref_context['py:module'] = 'time'
    assert_processes([('function', 'time.asctime')], 'function', 'asctime')
    assert_processes([('function', 'time.asctime')], 'function', 'asctime')

    # test autodoc_member_order == 'source'
    directive.env.ref_context['py:module'] = 'target'
    options.private_members = True
    if PY3:
        roger_line = '   .. py:classmethod:: Class.roger(a, *, b=2, c=3, d=4, e=5, f=6)'
    else:
        roger_line = '   .. py:classmethod:: Class.roger(a, e=5, f=6)'
    assert_order(['.. py:class:: Class(arg)',
                  '   .. py:attribute:: Class.descr',
                  '   .. py:method:: Class.meth()',
                  '   .. py:method:: Class.undocmeth()',
                  '   .. py:attribute:: Class.attr',
                  '   .. py:attribute:: Class.prop',
                  '   .. py:attribute:: Class.docattr',
                  '   .. py:attribute:: Class.udocattr',
                  '   .. py:attribute:: Class.mdocattr',
                  roger_line,
                  '   .. py:classmethod:: Class.moore(a, e, f) -> happiness',
                  '   .. py:attribute:: Class.inst_attr_comment',
                  '   .. py:attribute:: Class.inst_attr_string',
                  '   .. py:attribute:: Class._private_inst_attr',
                  '   .. py:classmethod:: Class.inheritedclassmeth()',
                  '   .. py:method:: Class.inheritedmeth()',
                  '   .. py:staticmethod:: Class.inheritedstaticmeth()',
                  ],
                 'class', 'Class', member_order='bysource', all_members=True)
    del directive.env.ref_context['py:module']

    # test attribute initialized to class instance from other module
    directive.env.temp_data['autodoc:class'] = 'target.Class'
    assert_result_contains(u'   should be documented as well - s\xfc\xdf',
                           'attribute', 'mdocattr')
    del directive.env.temp_data['autodoc:class']

    # test autodoc_docstring_signature
    assert_result_contains(
        '.. py:method:: DocstringSig.meth(FOO, BAR=1) -> BAZ', 'method',
        'target.DocstringSig.meth')
    assert_result_contains(
        '   rest of docstring', 'method', 'target.DocstringSig.meth')
    assert_result_contains(
        '.. py:method:: DocstringSig.meth2()', 'method',
        'target.DocstringSig.meth2')
    assert_result_contains(
        '       indented line', 'method',
        'target.DocstringSig.meth2')
    assert_result_contains(
        '.. py:classmethod:: Class.moore(a, e, f) -> happiness', 'method',
        'target.Class.moore')

    # test new attribute documenter behavior
    directive.env.ref_context['py:module'] = 'target'
    options.undoc_members = True
    assert_processes([('class', 'target.AttCls'),
                      ('attribute', 'target.AttCls.a1'),
                      ('attribute', 'target.AttCls.a2'),
                      ], 'class', 'AttCls')
    assert_result_contains(
        '   :annotation: = hello world', 'attribute', 'AttCls.a1')
    assert_result_contains(
        '   :annotation: = None', 'attribute', 'AttCls.a2')

    # test explicit members with instance attributes
    del directive.env.temp_data['autodoc:class']
    del directive.env.temp_data['autodoc:module']
    directive.env.ref_context['py:module'] = 'target'
    options.inherited_members = False
    options.undoc_members = False
    options.members = ALL
    assert_processes([
        ('class', 'target.InstAttCls'),
        ('attribute', 'target.InstAttCls.ca1'),
        ('attribute', 'target.InstAttCls.ca2'),
        ('attribute', 'target.InstAttCls.ca3'),
        ('attribute', 'target.InstAttCls.ia1'),
        ('attribute', 'target.InstAttCls.ia2'),
    ], 'class', 'InstAttCls')
    del directive.env.temp_data['autodoc:class']
    del directive.env.temp_data['autodoc:module']
    options.members = ['ca1', 'ia1']
    assert_processes([
        ('class', 'target.InstAttCls'),
        ('attribute', 'target.InstAttCls.ca1'),
        ('attribute', 'target.InstAttCls.ia1'),
    ], 'class', 'InstAttCls')
    del directive.env.temp_data['autodoc:class']
    del directive.env.temp_data['autodoc:module']
    del directive.env.ref_context['py:module']

    # test members with enum attributes
    directive.env.ref_context['py:module'] = 'target'
    options.inherited_members = False
    options.undoc_members = False
    options.members = ALL
    assert_processes([
        ('class', 'target.EnumCls'),
        ('attribute', 'target.EnumCls.val1'),
        ('attribute', 'target.EnumCls.val2'),
        ('attribute', 'target.EnumCls.val3'),
    ], 'class', 'EnumCls')
    assert_result_contains(
        '   :annotation: = 12', 'attribute', 'EnumCls.val1')
    assert_result_contains(
        '   :annotation: = 23', 'attribute', 'EnumCls.val2')
    assert_result_contains(
        '   :annotation: = 34', 'attribute', 'EnumCls.val3')
    del directive.env.temp_data['autodoc:class']
    del directive.env.temp_data['autodoc:module']

    # test descriptor class documentation
    options.members = ['CustomDataDescriptor', 'CustomDataDescriptor2']
    assert_result_contains('.. py:class:: CustomDataDescriptor(doc)',
                           'module', 'target')
    assert_result_contains('   .. py:method:: CustomDataDescriptor.meth()',
                           'module', 'target')
    assert_result_contains('.. py:class:: CustomDataDescriptor2(doc)',
                           'module', 'target')

    # test mocked module imports
    options.members = ['TestAutodoc']
    options.undoc_members = False
    assert_result_contains('.. py:class:: TestAutodoc',
                           'module', 'autodoc_missing_imports')
    assert_result_contains('   .. py:method:: TestAutodoc.decoratedMethod()',
                           'module', 'autodoc_missing_imports')
    options.members = ['decoratedFunction']
    assert_result_contains('.. py:function:: decoratedFunction()',
                           'module', 'autodoc_missing_imports')