예제 #1
0
def test_sphinxdocs(tmpdir):
    from sphinx.application import Sphinx
    from rinoh.frontend.sphinx import setup as setup_rinoh_sphinx_builder

    template_configuration = Book.Configuration()
    template_configuration('title_page', show_date=False)

    sphinx = Sphinx(srcdir=SPHINX_DOC_DIR,
                    confdir=SPHINX_DOC_DIR,
                    outdir=tmpdir.join('rinoh').strpath,
                    doctreedir=tmpdir.join('doctrees').strpath,
                    buildername='html',
                    confoverrides=dict(extensions=['rinoh.frontend.sphinx']))
    setup_rinoh_sphinx_builder(sphinx)
    sphinx._init_builder('rinoh')
    sphinx.config.rinoh_template_configuration = template_configuration
    sphinx.build()

    out_file = tmpdir.join('rinoh').join('sphinx.pdf').strpath
    os.chdir(tmpdir.strpath)
    # _, _, _, badlinks, _, _ = check_pdf_links(out_file)
    # pytest.assume(badlinks == [], 'Output PDF contains broken '
    #                               'hyperlinks: {}'.format(badlinks))
    if not diff_pdf(os.path.join(TEST_DIR, 'reference/sphinx.pdf'), out_file):
        pytest.fail('The generated PDF is different from the reference PDF.\n'
                    'Generated files can be found in {}'.format(
                        tmpdir.strpath))
예제 #2
0
파일: docdirs.py 프로젝트: rlz/hyde
    def __run_sphinx(self):
        """Run sphinx to generate the necessary output files.

        This method creates a temporary directory for sphinx's output, then
        run sphinx against the Hyde input directory.
        """
        logger.info("running sphinx")
        self.__build_dir = Folder(tempfile.mkdtemp())
        sphinx_app = Sphinx(
            self.node().path,
            self.node().path,
            self.__build_dir.path,
            self.node().path,
            "json"
        )
        sphinx_app.add_builder(HydeJSONHTMLBuilder)
        sphinx_app._init_builder("hyde_json")
        sphinx_app.build()
예제 #3
0
class Mudkip:
    def __init__(
        self,
        *args,
        config=None,
        pyproject_file="pyproject.toml",
        mudkip_file="mudkip.toml",
        silence_pandoc_version_warning=True,
        **kwargs,
    ):
        pyproject = TOMLFile(pyproject_file)
        mudkip = TOMLFile(mudkip_file)

        if config is None:
            params = {}

            if pyproject.exists():
                tool = pyproject.extract().get("tool", {})
                params.update(tool.get("mudkip", {}),
                              poetry=tool.get("poetry"))

            if mudkip.exists():
                params.update(mudkip.extract().get("mudkip", {}))

            params.update(kwargs)

            config = Config(*args, **params)

        self.config = config
        self.pyproject = pyproject
        self.mudkip = mudkip

        self.create_sphinx_application()

        package_json_dir = locate_package_json(config)
        self.npm_driver = (NpmDriver(package_json_dir,
                                     show_output=config.verbose)
                           if package_json_dir else None)

        if silence_pandoc_version_warning:
            import nbconvert

            nbconvert.utils.pandoc._maximal_version = None

    def create_sphinx_application(self):
        extra_args = {}

        if not self.config.verbose:
            extra_args["status"] = None

        conf = self.config.sphinx_confoverrides

        if self.config.sphinx_project:
            conf.setdefault("project", self.config.sphinx_project)

        copyright = conf.setdefault("copyright", time.strftime("%Y"))

        if self.config.author:
            author = conf.setdefault("author", self.config.author)
            conf.setdefault("copyright", copyright + ", " + author)

        if self.config.copyright:
            conf.setdefault("copyright", self.config.copyright)
        if self.config.version:
            conf.setdefault("version", self.config.version)
        if self.config.release:
            conf.setdefault("release", self.config.release)
        if self.config.base_url:
            conf.setdefault("html_baseurl", self.config.base_url)

        conf.setdefault("master_doc", "index")
        conf.setdefault("nitpicky", True)

        conf.setdefault(
            "exclude_patterns",
            [
                ".*",
                "**/.*",
                "_*",
                "**/_*",
                "node_modules",
                "env",
                "venv",
                self.config.output_dir.name,
            ],
        )

        extensions = conf.setdefault("extensions", [])

        extensions.append("myst_nb")
        conf.setdefault("jupyter_execute_notebooks", "force")
        conf.setdefault("execution_allow_errors", True)
        conf.setdefault("nb_render_priority",
                        {"xml": get_default_render_priority("dirhtml")})

        extensions.append("sphinx.ext.autodoc")
        conf.setdefault("autodoc_member_order", "bysource")

        extensions.append("sphinx.ext.napoleon")
        extensions.append("sphinx.ext.doctest")

        if self.config.section_label_depth:
            extensions.append("sphinx.ext.autosectionlabel")
            conf.setdefault("autosectionlabel_maxdepth",
                            self.config.section_label_depth)

        extensions.append("sphinx_autodoc_typehints")

        extensions.append("mudkip.extension")

        self.sphinx = Sphinx(
            self.config.sphinx_srcdir,
            self.config.sphinx_confdir,
            self.config.sphinx_outdir,
            self.config.sphinx_doctreedir,
            self.config.sphinx_buildername,
            conf,
            **extra_args,
        )

        self.sphinx._init_env(True)
        self.sphinx._init_builder()

    @contextmanager
    def sphinx_warning_is_error(self):
        try:
            original_value = self.sphinx.warningiserror
            self.sphinx.warningiserror = True
            yield
        finally:
            self.sphinx.warningiserror = original_value

    @contextmanager
    def sphinx_builder(self, buildername):
        try:
            original_builder = self.sphinx.builder
            self.sphinx.preload_builder(buildername)
            self.sphinx.builder = self.sphinx.create_builder(buildername)
            self.sphinx._init_env(False)
            self.sphinx.builder.set_environment(self.sphinx.env)
            self.sphinx.builder.init()
            yield
        finally:
            self.sphinx.builder = original_builder

    @contextmanager
    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)

    @contextmanager
    def sphinx_config(self, **kwargs):
        not_present = object()
        conf = self.sphinx.config

        try:
            original_values = {}
            for key, value in kwargs.items():
                original_values[key] = getattr(conf, key, not_present)
                setattr(conf, key, value)
            yield
        finally:
            for key, value in original_values.items():
                if value is not_present:
                    delattr(conf, key)
                else:
                    setattr(conf, key, value)

    def init(self, title=None):
        table = tomlkit.table()
        table["title"] = title = (title or self.config.title
                                  or os.path.basename(os.path.abspath(".")))
        table["preset"] = self.config.preset.name

        source_dir = str(self.config.source_dir)
        output_dir = str(self.config.output_dir)

        if source_dir != self.config.default_source_dir:
            table["source_dir"] = source_dir

        if output_dir != self.config.default_output_dir:
            table["output_dir"] = output_dir

        table.add(tomlkit.nl())

        if self.mudkip.exists():
            doc = self.mudkip.read()

            if "mudkip" not in doc:
                doc["mudkip"] = table
            else:
                doc["mudkip"].update(table)

            self.mudkip.write(doc)

        elif self.pyproject.exists():
            doc = self.pyproject.read()
            tool = None

            try:
                tool = doc["tool"]
                tool["mudkip"].update(table)
            except KeyError:
                if tool is None:
                    doc["tool"] = {"mudkip": table}
                else:
                    tool["mudkip"] = table

            self.pyproject.write(doc)

        else:
            self.mudkip.write(tomlkit.document().add("mudkip", table))

        index_rst = self.config.source_dir / "index.rst"
        index_md = self.config.source_dir / "index.md"

        if not index_rst.is_file() and not index_md.is_file():
            index_rst.write_text(f"{title}\n{'=' * len(title)}\n")

    def build(self,
              *,
              check=False,
              skip_broken_links=False,
              update_gh_pages=False):
        self.delete_autodoc_cache()

        if update_gh_pages:
            self.sphinx.setup_extension("sphinx.ext.githubpages")

        try:
            if check:
                self.clean()
                os.makedirs(self.sphinx.outdir, exist_ok=True)

                with self.sphinx_warning_is_error():
                    with self.sphinx_config(execution_allow_errors=False):
                        self.sphinx.build()

                        if not skip_broken_links:
                            with self.sphinx_builder("linkcheck"):
                                self.sphinx.build()
            else:
                self.sphinx.build()
        except SphinxError as exc:
            raise MudkipError(exc.args[0]) from exc

        if self.npm_driver:
            self.npm_driver.build()

        if update_gh_pages:
            GitHubPagesUpdater(self.sphinx.outdir,
                               self.config.repository).update()

    def delete_autodoc_cache(self):
        if not self.config.project_name:
            return

        modules = [
            mod for mod in sys.modules if mod == self.config.project_name
            or mod.startswith(self.config.project_name + ".")
        ]

        for mod in modules:
            del sys.modules[mod]

    def develop(
        self,
        open_browser=False,
        host="localhost",
        port=5500,
        notebook=False,
        notebook_host="localhost",
        notebook_port=8888,
        build_manager=None,
    ):
        if not build_manager:
            build_manager = lambda *args: nullcontext()

        patterns = [f"*{suff}" for suff in self.sphinx.config.source_suffix]
        ignore_patterns = self.sphinx.config.exclude_patterns

        patterns += [
            "*.py", "*.pyi", "*.pyx", "*.js", "*.html", "*.css", "*.png"
        ]

        dirs = [self.config.source_dir]

        if self.config.project_dir:
            dirs.append(self.config.project_dir)

        with ExitStack() as stack:
            stack.enter_context(
                self.sphinx_config(jupyter_execute_notebooks="auto"))

            notebook_url = None
            if notebook:
                notebook_url = stack.enter_context(
                    jupyter_notebook(
                        str(self.config.source_dir),
                        self.config.verbose,
                        notebook_host,
                        notebook_port,
                    ))

            server_url = None
            if self.config.dev_server:
                server_url = stack.enter_context(
                    self.config.dev_server(self.sphinx.outdir, host, port))

                if open_browser:
                    try:
                        webbrowser.open(server_url)
                        if notebook_url:
                            webbrowser.open(notebook_url)
                    except webbrowser.Error:
                        pass

            if self.npm_driver:
                stack.enter_context(self.npm_driver.develop())

            with build_manager(server_url=server_url,
                               notebook_url=notebook_url):
                self.build()

            for event_batch in DirectoryWatcher(
                    directories=dirs,
                    patterns=patterns,
                    ignore_patterns=ignore_patterns,
                    output_directory=self.config.output_dir,
            ):
                with build_manager(event_batch):
                    self.build()

    def test(self):
        with self.sphinx_builder("doctest"):
            with nullcontext() if self.config.verbose else self.sphinx_mute():
                self.build()

        output = self.config.sphinx_outdir / "output.txt"
        content = output.read_text() if output.is_file() else ""
        _, _, result = content.partition("\n\n")

        return self.sphinx.statuscode == 0, result.strip()

    def clean(self):
        try:
            shutil.rmtree(self.config.output_dir)
        except FileNotFoundError:
            pass

        if self.npm_driver:
            self.npm_driver.clean()
예제 #4
0
def setup(app: Sphinx):
    app.add_config_value('extra_html_path', [], True)
    app._init_builder = lambda: expand_init_builder(app)
예제 #5
0
def expand_init_builder(app):
    Sphinx._init_builder(app)
    setup_simple_extra_html(app)
def setup(app: Sphinx):
    app.add_config_value('extra_html_path', [], True)  # If you add the variable which is not existed by default, then you should add it. Otherwise, you may consider heck the code.
    app._init_builder = lambda: expand_init_builder(app)
def expand_init_builder(app):
    """I did not change the original Sphinx process. I just tell it to do something after finished Sphinx._init_builder."""
    Sphinx._init_builder(app)
    setup_simple_extra_html(app)