diff --git a/doc/python_api/conf.py b/doc/python_api/conf.py new file mode 100644 index 00000000000..f087d00cbf6 --- /dev/null +++ b/doc/python_api/conf.py @@ -0,0 +1,116 @@ +# SPDX-FileCopyrightText: 2024 Blender Authors +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from string import Template +import time + + +# These are substituted when this file is copied to the build directory. +BLENDER_VERSION_STRING = "${BLENDER_VERSION_STRING}" +BLENDER_VERSION_DOTS = "${BLENDER_VERSION_DOTS}" +BLENDER_REVISION = "${BLENDER_REVISION}" +BLENDER_REVISION_TIMESTAMP = "${BLENDER_REVISION_TIMESTAMP}" + +if BLENDER_REVISION != "Unknown": + # SHA1 Git hash + BLENDER_VERSION_HASH = BLENDER_REVISION + BLENDER_VERSION_HASH_HTML_LINK = "%s" % ( + BLENDER_VERSION_HASH, BLENDER_VERSION_HASH) + BLENDER_VERSION_DATE = time.strftime("%d/%m/%Y", time.localtime(BLENDER_REVISION_TIMESTAMP)) +else: + # Fallback: Should not be used + BLENDER_VERSION_HASH = "Hash Unknown" + BLENDER_VERSION_HASH_HTML_LINK = BLENDER_VERSION_HASH + BLENDER_VERSION_DATE = time.strftime("%Y-%m-%d") + +extensions = ['sphinx.ext.intersphinx'] +intersphinx_mapping = {'blender_manual': ("https://docs.blender.org/manual/en/dev/", None)} +project = "Blender %s Python API" % BLENDER_VERSION_STRING +root_doc = "index" +copyright = "Blender Authors" +version = BLENDER_VERSION_DOTS +release = BLENDER_VERSION_DOTS + +# Set this as the default is a super-set of Python3. +highlight_language = 'python3' +# No need to detect encoding. +highlight_options = {'default': {'encoding': 'utf-8'}} + +# Quiet file not in table-of-contents warnings. +exclude_patterns = [ + "include__bmesh.rst", +] + +html_title = "Blender Python API" + +# The fallback to a built-in theme when furo is not found. +html_theme = 'default' + +try: + import furo + html_theme = "furo" + del furo +except ModuleNotFoundError: + pass + +if html_theme == "furo": + html_theme_options = { + "light_css_variables": { + "color-brand-primary": "#265787", + "color-brand-content": "#265787", + }, + } + + html_sidebars = { + "**": [ + "sidebar/brand.html", + "sidebar/search.html", + "sidebar/scroll-start.html", + "sidebar/navigation.html", + "sidebar/scroll-end.html", + "sidebar/variant-selector.html", + ] + } + +# not helpful since the source is generated, adds to upload size. +html_copy_source = False +html_show_sphinx = False +html_baseurl = "https://docs.blender.org/api/current/" +html_use_opensearch = "https://docs.blender.org/api/current" +html_show_search_summary = True +html_split_index = True +html_static_path = ["static"] +templates_path = ["templates"] +html_context = {"commit": "%s - %s" % (BLENDER_VERSION_HASH_HTML_LINK, BLENDER_VERSION_DATE)} +html_extra_path = ["static"] +html_favicon = "static/favicon.ico" +html_logo = "static/blender_logo.svg" +# Disable default `last_updated` value, since this is the date of doc generation, not the one of the source commit. +html_last_updated_fmt = None +if html_theme == 'furo': + html_css_files = ["css/theme_overrides.css", "css/version_switch.css"] + html_js_files = ["js/version_switch.js"] + +# needed for latex, pdf gen +latex_elements = { + 'papersize': 'a4paper', +} + +latex_documents = [("contents", "contents.tex", "Blender Index", "Blender Foundation", "manual"), ] + +# Workaround for useless links leading to compile errors +# See https://github.com/sphinx-doc/sphinx/issues/3866 +from sphinx.domains.python import PythonDomain + + +class PatchedPythonDomain(PythonDomain): + def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): + if 'refspecific' in node: + del node['refspecific'] + return super(PatchedPythonDomain, self).resolve_xref( + env, fromdocname, builder, typ, target, node, contnode) + + +def setup(app): + app.add_domain(PatchedPythonDomain, override=True) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index bc0fbc15e41..39b80d5f43d 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -486,19 +486,6 @@ BLENDER_REVISION_TIMESTAMP = bpy.app.build_commit_timestamp BLENDER_VERSION_STRING = bpy.app.version_string BLENDER_VERSION_DOTS = "%d.%d" % (bpy.app.version[0], bpy.app.version[1]) -if BLENDER_REVISION != "Unknown": - # SHA1 Git hash - BLENDER_VERSION_HASH = BLENDER_REVISION - BLENDER_VERSION_HASH_HTML_LINK = "%s" % ( - BLENDER_VERSION_HASH, BLENDER_VERSION_HASH, - ) - BLENDER_VERSION_DATE = time.strftime("%d/%m/%Y", time.localtime(BLENDER_REVISION_TIMESTAMP)) -else: - # Fallback: Should not be used - BLENDER_VERSION_HASH = "Hash Unknown" - BLENDER_VERSION_HASH_HTML_LINK = BLENDER_VERSION_HASH - BLENDER_VERSION_DATE = time.strftime("%Y-%m-%d") - # Example: `2_83`. BLENDER_VERSION_PATH = "%d_%d" % (bpy.app.version[0], bpy.app.version[1]) @@ -1895,110 +1882,6 @@ def pyrna2sphinx(basepath): write_ops() -def write_sphinx_conf_py(basepath): - """ - Write sphinx's ``conf.py``. - """ - filepath = os.path.join(basepath, "conf.py") - file = open(filepath, "w", encoding="utf-8") - fw = file.write - - fw("import sys, os\n\n") - fw("extensions = ['sphinx.ext.intersphinx']\n\n") - fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n") - fw("project = 'Blender %s Python API'\n" % BLENDER_VERSION_STRING) - fw("root_doc = 'index'\n") - fw("copyright = 'Blender Authors'\n") - fw("version = '%s'\n" % BLENDER_VERSION_DOTS) - fw("release = '%s'\n" % BLENDER_VERSION_DOTS) - - # Set this as the default is a super-set of Python3. - fw("highlight_language = 'python3'\n") - # No need to detect encoding. - fw("highlight_options = {'default': {'encoding': 'utf-8'}}\n\n") - - # Quiet file not in table-of-contents warnings. - fw("exclude_patterns = [\n") - fw(" 'include__bmesh.rst',\n") - fw("]\n\n") - - fw("html_title = 'Blender Python API'\n") - - fw("html_theme = 'default'\n") - # The theme 'sphinx_rtd_theme' is no longer distributed with sphinx by default, only use when available. - fw(r""" -try: - import furo - html_theme = "furo" - del furo -except ModuleNotFoundError: - pass -if html_theme == "furo": - html_theme_options = { - "light_css_variables": { - "color-brand-primary": "#265787", - "color-brand-content": "#265787", - }, - } - - html_sidebars = { - "**": [ - "sidebar/brand.html", - "sidebar/search.html", - "sidebar/scroll-start.html", - "sidebar/navigation.html", - "sidebar/scroll-end.html", - "sidebar/variant-selector.html", - ] - } -""") - - # not helpful since the source is generated, adds to upload size. - fw("html_copy_source = False\n") - fw("html_show_sphinx = False\n") - fw("html_baseurl = 'https://docs.blender.org/api/current/'\n") - fw("html_use_opensearch = 'https://docs.blender.org/api/current'\n") - fw("html_show_search_summary = True\n") - fw("html_split_index = True\n") - fw("html_static_path = ['static']\n") - fw("templates_path = ['templates']\n") - fw("html_context = {'commit': '%s - %s'}\n" % (BLENDER_VERSION_HASH_HTML_LINK, BLENDER_VERSION_DATE)) - fw("html_extra_path = ['static']\n") - fw("html_favicon = 'static/favicon.ico'\n") - fw("html_logo = 'static/blender_logo.svg'\n") - # Disable default `last_updated` value, since this is the date of doc generation, not the one of the source commit. - fw("html_last_updated_fmt = None\n\n") - fw("if html_theme == 'furo':\n") - fw(" html_css_files = ['css/theme_overrides.css', 'css/version_switch.css']\n") - fw(" html_js_files = ['js/version_switch.js']\n") - - # needed for latex, pdf gen - fw("latex_elements = {\n") - fw(" 'papersize': 'a4paper',\n") - fw("}\n\n") - - fw("latex_documents = [ ('contents', 'contents.tex', 'Blender Index', 'Blender Foundation', 'manual'), ]\n") - - # Workaround for useless links leading to compile errors - # See https://github.com/sphinx-doc/sphinx/issues/3866 - fw(r""" -from sphinx.domains.python import PythonDomain - -class PatchedPythonDomain(PythonDomain): - def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - if 'refspecific' in node: - del node['refspecific'] - return super(PatchedPythonDomain, self).resolve_xref( - env, fromdocname, builder, typ, target, node, contnode) - -def setup(app): - app.add_domain(PatchedPythonDomain, override=True) -""") - # end workaround - - file.close() - - def write_rst_index(basepath): """ Write the RST file of the main page, needed for sphinx: ``index.html``. @@ -2411,7 +2294,7 @@ def copy_handwritten_extra(basepath): shutil.copy2(f_src, f_dst) -def copy_theme_assets(basepath): +def copy_sphinx_files(basepath): shutil.copytree( os.path.join(SCRIPT_DIR, "static"), os.path.join(basepath, "static"), @@ -2423,17 +2306,31 @@ def copy_theme_assets(basepath): copy_function=shutil.copy, ) + shutil.copy2(os.path.join(SCRIPT_DIR, "conf.py"), basepath, ) + + +def format_config(basepath): + """ + Updates conf.py with context infromation from Blender. + """ + from string import Template + + substitutions = { + 'BLENDER_VERSION_STRING': BLENDER_VERSION_STRING, + 'BLENDER_VERSION_DOTS': BLENDER_VERSION_DOTS, + 'BLENDER_REVISION_TIMESTAMP': BLENDER_REVISION_TIMESTAMP, + 'BLENDER_REVISION': BLENDER_REVISION, + } + + # Read the template string from the template file + with open(os.path.join(basepath, "conf.py"), 'r') as file: + template_file = file.read() + + with open(os.path.join(basepath, "conf.py"), 'w') as file: + file.write(Template(template_file).substitute(substitutions)) + def rna2sphinx(basepath): - - try: - os.mkdir(basepath) - except: - pass - - # sphinx setup - write_sphinx_conf_py(basepath) - # main page write_rst_index(basepath) @@ -2460,9 +2357,6 @@ def rna2sphinx(basepath): # copy source files referenced copy_handwritten_extra(basepath) - # copy extra files needed for theme - copy_theme_assets(basepath) - def align_sphinx_in_to_sphinx_in_tmp(dir_src, dir_dst): """ @@ -2583,10 +2477,22 @@ def main(): copy_function=shutil.copy, ) - # Dump the API in RST files. + # start from a clean directory everytime if os.path.exists(SPHINX_IN_TMP): shutil.rmtree(SPHINX_IN_TMP, True) + try: + os.mkdir(SPHINX_IN_TMP) + except: + pass + + # copy extra files needed for theme + copy_sphinx_files(SPHINX_IN_TMP) + + # write infromation needed for 'conf.py' + format_config(SPHINX_IN_TMP) + + # Dump the API in RST files. rna2sphinx(SPHINX_IN_TMP) if ARGS.changelog: