Source code for deepmodeling_sphinx.inject

import os
import types
from pathlib import Path
from typing import Any, Dict

import minify_html
from cssmin import cssmin
from jinja2 import Template
from jsmin import jsmin
from sphinx.application import Sphinx
from sphinx.util.fileutil import copy_asset_file

from .config import active_class, icp_no, sitemap


[docs] def render_banner(current_site="Docs") -> str: """Use jinja2 to render banner. Returns ------- str HTML content of banner. """ source = os.path.join( os.path.abspath(os.path.dirname(__file__)), "banner.html", ) with open(source) as f: template = Template(f.read()) for item in sitemap: if item["title"] == current_site: item["class"] = active_class return template.render( items=sitemap, )
[docs] def copy_custom_files(app): if not app.config.enable_deepmodeling: return if app.builder.format == "html": staticdir = os.path.join(app.builder.outdir, "_static") cwd = Path(__file__).parent.absolute() banner_css = cwd / "banner.css" banner_js = cwd / "banner.js" dark_css = cwd / "dark_rtd.css" os.makedirs(staticdir, exist_ok=True) staticdir = os.path.join(app.builder.outdir, "_static") copy_asset_file(str(banner_css), staticdir) copy_asset_file(str(banner_js), staticdir) copy_asset_file(str(dark_css), staticdir)
[docs] def insert_sidebar(app, pagename, templatename, context, doctree): if not app.config.enable_deepmodeling: return app.add_js_file("banner.js") app.add_css_file("banner.css") if not hasattr(app.builder.templates.render, "_deepmodeling_patched"): old_render = app.builder.templates.render def render(self, template, render_context): content = old_render(template, render_context) comment_begin = r"<!--deepmodeling begin-->" comment_end = r"<!--deepmodeling end-->" if comment_begin in content: return content begin_body = content.lower().find("</head>") banner = render_banner(current_site=app.config.deepmodeling_current_site) if begin_body != -1: content = ( content[:begin_body] + comment_begin + banner + comment_end + content[begin_body:] ) return content render.__dict__.update(old_render.__dict__) render._deepmodeling_patched = True app.builder.templates.render = types.MethodType(render, app.builder.templates)
[docs] def insert_icp(app, pagename, templatename, context, doctree): if not app.config.enable_deepmodeling: return if app.config.html_theme == "sphinx_book_theme": # sphinx_book_theme has provided the option, so there is no need to hack return if not hasattr(app.builder.templates.render, "_deepmodeling_icp_patched"): old_render = app.builder.templates.render def render(self, template, render_context): content = old_render(template, render_context) comment_begin = r"<!--deepmodeling icp begin-->" comment_end = r"<!--deepmodeling icp end-->" if comment_begin in content: return content footer = content.lower().rfind("</footer>") icp_footer = ( '<p><a href="https://beian.miit.gov.cn" target="_blank">%s</a></p>' % icp_no ) if footer != -1: content = ( content[:footer] + comment_begin + icp_footer + comment_end + content[footer:] ) return content render.__dict__.update(old_render.__dict__) render._deepmodeling_icp_patched = True app.builder.templates.render = types.MethodType(render, app.builder.templates)
[docs] def minify_html_files(app, pagename, templatename, context, doctree): if not hasattr(app.builder.templates.render, "_deepmodeling_minified"): old_render = app.builder.templates.render def render(self, template, render_context): content = old_render(template, render_context) try: return minify_html.minify( content, minify_js=True, minify_css=True, keep_html_and_head_opening_tags=True, keep_closing_tags=True, ) except SyntaxError: return content render.__dict__.update(old_render.__dict__) render._deepmodeling_minified = True app.builder.templates.render = types.MethodType(render, app.builder.templates)
[docs] def minify_js_files(app, exception): if not hasattr(app.builder, "script_files"): # not html builder return for js in app.builder.script_files: if js.filename is None: continue fn = os.path.join(app.builder.outdir, js.filename) if os.path.isfile(fn): with open(fn, "r+") as f: minified_js = jsmin(f.read()) f.seek(0) f.write(minified_js) f.truncate()
[docs] def minify_css_files(app, exception): if not hasattr(app.builder, "css_files"): # not html builder return for css in app.builder.css_files: if css.filename is None: continue fn = os.path.join(app.builder.outdir, css.filename) if os.path.isfile(fn): with open(fn, "r+") as f: minified_css = cssmin(f.read()) f.seek(0) f.write(minified_css) f.truncate()
[docs] def enable_dark_mode(app, config): """Enable dark mode if the theme is sphinx_rtd_theme.""" if config.html_theme == "sphinx_rtd_theme": app.add_css_file("dark_rtd.css")
[docs] def rtd_config(app, config): """Set RTD configurations. See https://about.readthedocs.com/blog/2024/07/addons-by-default/ """ config.html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") # Tell Jinja2 templates the build is running on Read the Docs if os.environ.get("READTHEDOCS", "") == "True": if "html_context" not in config: config.html_context = {} config.html_context["READTHEDOCS"] = True
[docs] def sphinx_book_theme(app, config): """Set configurations for sphinx_book_theme.""" if not config.enable_deepmodeling: return if config.html_theme != "sphinx_book_theme": return icp_footer = ( '<p><a href="https://beian.miit.gov.cn" target="_blank">%s</a></p>' % icp_no ) config.html_theme_options["extra_footer"] = ( config.html_theme_options.get("extra_footer", "") + icp_footer )
[docs] def setup(app: Sphinx) -> Dict[str, Any]: # enable deepmodeling sidebar and icp # if the repo is outside the deepmodeling, disable it app.add_config_value("enable_deepmodeling", True, "html") app.add_config_value("deepmodeling_current_site", "Docs", "html") app.connect("builder-inited", copy_custom_files) app.connect("html-page-context", insert_sidebar) app.connect("html-page-context", insert_icp) app.connect("html-page-context", minify_html_files) app.connect("build-finished", minify_js_files) app.connect("build-finished", minify_css_files) # dark mode for rtd theme app.connect("config-inited", enable_dark_mode) app.connect("config-inited", rtd_config) app.connect("config-inited", sphinx_book_theme) return {"parallel_read_safe": True}