From 054e8243144f0e7b82e28dc6f8b189ed228abb2a Mon Sep 17 00:00:00 2001 From: Remy Blank Date: Thu, 28 Nov 2024 12:08:03 +0100 Subject: [PATCH] Move all sphinx-using code to tdoc.common.ext. --- tdoc/common/__init__.py | 134 +---------------------------------- tdoc/common/cli.py | 13 ++-- tdoc/common/defaults.py | 2 +- tdoc/common/ext/__init__.py | 136 ++++++++++++++++++++++++++++++++++++ tdoc/common/ext/defaults.py | 2 +- tdoc/common/ext/exec.py | 2 +- tdoc/common/ext/iframe.py | 2 +- tdoc/common/ext/metadata.py | 2 +- tdoc/common/ext/num.py | 2 +- tdoc/common/ext/solution.py | 2 +- 10 files changed, 150 insertions(+), 147 deletions(-) create mode 100644 tdoc/common/ext/__init__.py diff --git a/tdoc/common/__init__.py b/tdoc/common/__init__.py index 632ef8a..1126a46 100644 --- a/tdoc/common/__init__.py +++ b/tdoc/common/__init__.py @@ -1,137 +1,5 @@ # Copyright 2024 Remy Blank # SPDX-License-Identifier: MIT -import json -import pathlib - -from sphinx import config, locale -from sphinx.util import fileutil, logging - __project__ = 't-doc-common' -__version__ = '0.22' - -_log = logging.getLogger(__name__) -_messages = 'tdoc' -_ = locale.get_translation(_messages) - -_common = pathlib.Path(__file__).absolute().parent - -_license_urls = { - 'CC0-1.0': 'https://creativecommons.org/publicdomain/zero/1.0/', - 'CC-BY-4.0': 'https://creativecommons.org/licenses/by/4.0/', - 'CC-BY-SA-4.0': 'https://creativecommons.org/licenses/by-sa/4.0/', - 'CC-BY-NC-4.0': 'https://creativecommons.org/licenses/by-nc/4.0/', - 'CC-BY-NC-SA-4.0': 'https://creativecommons.org/licenses/by-nc-sa/4.0/', - 'CC-BY-ND-4.0': 'https://creativecommons.org/licenses/by-nd/4.0/', - 'MIT': 'https://opensource.org/license/mit', -} - - -def report_exceptions(fn): - def wrapper(self, /, *args, **kwargs): - try: - return fn(self, *args, **kwargs) - except Exception as e: - return [self.state.document.reporter.error(e, line=self.lineno)] - return wrapper - - -def format_attrs(translator, /, **kwargs): - return ' '.join(f'{k.replace('_', '-')}="{translator.attval(v)}"' - for k, v in sorted(kwargs.items()) if v is not None) - - -def format_data_attrs(translator, /, **kwargs): - return ' '.join(f'data-tdoc-{k.replace('_', '-')}="{translator.attval(v)}"' - for k, v in sorted(kwargs.items()) if v is not None) - - -def build_tag(app): - for tag in app.tags: - if tag.startswith('tdoc_build_'): - return tag - - -def setup(app): - app.add_event('tdoc-html-page-config') - - app.add_config_value('license', '', 'html') - app.add_config_value( - 'license_url', lambda c: _license_urls.get(c.license, ''), 'html', str) - app.add_config_value('tdoc_enable_sab', 'no', 'html', - config.ENUM('no', 'cross-origin-isolation', 'sabayon')) - - app.add_html_theme('t-doc', str(_common)) - app.add_message_catalog(_messages, str(_common / 'locale')) - - app.connect('config-inited', on_config_inited) - app.connect('builder-inited', on_builder_inited) - app.connect('html-page-context', on_html_page_context) - if build_tag(app): - app.connect('html-page-context', add_reload_js) - app.connect('write-started', write_static_files) - - return { - 'version': __version__, - 'parallel_read_safe': True, - 'parallel_write_safe': True, - } - - -def on_config_inited(app, config): - cv = config.values['html_title'] - super(cv.__class__, cv).__setattr__('default', lambda c: c.project) - config.templates_path.append(str(_common / 'templates')) - - # Override defaults in html_theme_options. - opts = config.html_theme_options - opts.setdefault('use_sidenotes', True) - opts.setdefault('path_to_docs', 'docs') - if opts.get('repository_url'): - opts.setdefault('use_repository_button', True) - opts.setdefault('use_source_button', True) - - # Set the global HTML context. - context = config.html_context - context['tdoc_enable_sab'] = app.config.tdoc_enable_sab - tag = build_tag(app) - context['tdoc_build'] = tag if tag is not None else '' - - -def on_builder_inited(app): - # Add our own static paths. - app.config.html_static_path.append(str(_common / 'static')) - app.config.html_static_path.append(str(_common / 'static.gen')) - - # Add a default static path. - if '_static' not in app.config.html_static_path: - app.config.html_static_path.append('_static') - - -def on_html_page_context(app, page, template, context, doctree): - license = app.config.license - if license: context['license'] = license - license_url = app.config.license_url - if license_url: context['license_url'] = license_url - - # Set up early and on-load JavaScript. - config = {'htmlData': {}} - app.emit('tdoc-html-page-config', page, config) - config = json.dumps(config, separators=(',', ':')) - app.add_js_file(None, priority=0, body=f'const tdocConfig = {config};') - app.add_js_file('tdoc/early.js', priority=1, - scope=context['pathto']('', resource=True)) - app.add_js_file('tdoc/load.js', type='module') - - -def add_reload_js(app, page, template, context, doctree): - app.add_js_file('tdoc/reload.js', type='module') - - -def write_static_files(app, builder): - if builder.format != 'html': return - - # The file must be at the root of the website, to avoid limiting the scope - # of the service worker to _static. - fileutil.copy_asset_file(_common / 'scripts' / 'tdoc-worker.js', - builder.outdir, force=True) +__version__ = '0.23.dev1' diff --git a/tdoc/common/cli.py b/tdoc/common/cli.py index c5590bb..4baaafa 100644 --- a/tdoc/common/cli.py +++ b/tdoc/common/cli.py @@ -19,8 +19,7 @@ import time from urllib import parse -from .. import common -from . import util +from . import __project__, __version__, util # TODO: Implement incremental builds, by copying previous build output @@ -138,7 +137,7 @@ class Handler(HandlerBase): def cmd_version(cfg): - cfg.stdout.write(f"{common.__project__}-{common.__version__}\n") + cfg.stdout.write(f"{__project__}-{__version__}\n") def sphinx_build(cfg, target, *, build, tags=(), **kwargs): @@ -276,14 +275,14 @@ def print_serving(self): def check_upgrade(self): try: - project = common.__project__ - upgrades, editable = pip_check_upgrades(self.cfg, project) - if project not in upgrades: return + upgrades, editable = pip_check_upgrades(self.cfg, __project__) + if __project__ not in upgrades: return msg = self.cfg.ansi( "@{LYELLOW}A t-doc upgrade is available:@{NORM} " "%s @{CYAN}%s@{NORM} => @{CYAN}%s@{NORM}\n" "See <@{LBLUE}https://t-doc.org/common/%s#upgrade@{NORM}>\n" - % (project, metadata.version(project), upgrades[project], + % (__project__, metadata.version(__project__), + upgrades[__project__], 'development' if editable else 'install')) with self.lock: self.upgrade_msg = msg diff --git a/tdoc/common/defaults.py b/tdoc/common/defaults.py index e1d54d9..5f42093 100644 --- a/tdoc/common/defaults.py +++ b/tdoc/common/defaults.py @@ -24,7 +24,7 @@ 'sphinx.ext.todo', 'sphinx_copybutton', 'sphinx_design', - 'tdoc.common', + 'tdoc.common.ext', 'tdoc.common.ext.defaults', 'tdoc.common.ext.exec', 'tdoc.common.ext.iframe', diff --git a/tdoc/common/ext/__init__.py b/tdoc/common/ext/__init__.py new file mode 100644 index 0000000..52072de --- /dev/null +++ b/tdoc/common/ext/__init__.py @@ -0,0 +1,136 @@ +# Copyright 2024 Remy Blank +# SPDX-License-Identifier: MIT + +import json +import pathlib + +from sphinx import config, locale +from sphinx.util import fileutil, logging + +from .. import __version__ + +_log = logging.getLogger(__name__) +_messages = 'tdoc' +_ = locale.get_translation(_messages) + +_base = pathlib.Path(__file__).absolute().parent.parent + +_license_urls = { + 'CC0-1.0': 'https://creativecommons.org/publicdomain/zero/1.0/', + 'CC-BY-4.0': 'https://creativecommons.org/licenses/by/4.0/', + 'CC-BY-SA-4.0': 'https://creativecommons.org/licenses/by-sa/4.0/', + 'CC-BY-NC-4.0': 'https://creativecommons.org/licenses/by-nc/4.0/', + 'CC-BY-NC-SA-4.0': 'https://creativecommons.org/licenses/by-nc-sa/4.0/', + 'CC-BY-ND-4.0': 'https://creativecommons.org/licenses/by-nd/4.0/', + 'MIT': 'https://opensource.org/license/mit', +} + + +def report_exceptions(fn): + def wrapper(self, /, *args, **kwargs): + try: + return fn(self, *args, **kwargs) + except Exception as e: + return [self.state.document.reporter.error(e, line=self.lineno)] + return wrapper + + +def format_attrs(translator, /, **kwargs): + return ' '.join(f'{k.replace('_', '-')}="{translator.attval(v)}"' + for k, v in sorted(kwargs.items()) if v is not None) + + +def format_data_attrs(translator, /, **kwargs): + return ' '.join(f'data-tdoc-{k.replace('_', '-')}="{translator.attval(v)}"' + for k, v in sorted(kwargs.items()) if v is not None) + + +def build_tag(app): + for tag in app.tags: + if tag.startswith('tdoc_build_'): + return tag + + +def setup(app): + app.add_event('tdoc-html-page-config') + + app.add_config_value('license', '', 'html') + app.add_config_value( + 'license_url', lambda c: _license_urls.get(c.license, ''), 'html', str) + app.add_config_value('tdoc_enable_sab', 'no', 'html', + config.ENUM('no', 'cross-origin-isolation', 'sabayon')) + + app.add_html_theme('t-doc', str(_base)) + app.add_message_catalog(_messages, str(_base / 'locale')) + + app.connect('config-inited', on_config_inited) + app.connect('builder-inited', on_builder_inited) + app.connect('html-page-context', on_html_page_context) + if build_tag(app): + app.connect('html-page-context', add_reload_js) + app.connect('write-started', write_static_files) + + return { + 'version': __version__, + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } + + +def on_config_inited(app, config): + cv = config.values['html_title'] + super(cv.__class__, cv).__setattr__('default', lambda c: c.project) + config.templates_path.append(str(_base / 'templates')) + + # Override defaults in html_theme_options. + opts = config.html_theme_options + opts.setdefault('use_sidenotes', True) + opts.setdefault('path_to_docs', 'docs') + if opts.get('repository_url'): + opts.setdefault('use_repository_button', True) + opts.setdefault('use_source_button', True) + + # Set the global HTML context. + context = config.html_context + context['tdoc_enable_sab'] = app.config.tdoc_enable_sab + tag = build_tag(app) + context['tdoc_build'] = tag if tag is not None else '' + + +def on_builder_inited(app): + # Add our own static paths. + app.config.html_static_path.append(str(_base / 'static')) + app.config.html_static_path.append(str(_base / 'static.gen')) + + # Add a default static path. + if '_static' not in app.config.html_static_path: + app.config.html_static_path.append('_static') + + +def on_html_page_context(app, page, template, context, doctree): + license = app.config.license + if license: context['license'] = license + license_url = app.config.license_url + if license_url: context['license_url'] = license_url + + # Set up early and on-load JavaScript. + config = {'htmlData': {}} + app.emit('tdoc-html-page-config', page, config) + config = json.dumps(config, separators=(',', ':')) + app.add_js_file(None, priority=0, body=f'const tdocConfig = {config};') + app.add_js_file('tdoc/early.js', priority=1, + scope=context['pathto']('', resource=True)) + app.add_js_file('tdoc/load.js', type='module') + + +def add_reload_js(app, page, template, context, doctree): + app.add_js_file('tdoc/reload.js', type='module') + + +def write_static_files(app, builder): + if builder.format != 'html': return + + # The file must be at the root of the website, to avoid limiting the scope + # of the service worker to _static. + fileutil.copy_asset_file(_base / 'scripts' / 'tdoc-worker.js', + builder.outdir, force=True) diff --git a/tdoc/common/ext/defaults.py b/tdoc/common/ext/defaults.py index 6c58840..97ac874 100644 --- a/tdoc/common/ext/defaults.py +++ b/tdoc/common/ext/defaults.py @@ -6,7 +6,7 @@ from docutils.parsers.rst import directives from sphinx.util import docutils, logging -from .. import __version__, report_exceptions +from . import __version__, report_exceptions _log = logging.getLogger(__name__) diff --git a/tdoc/common/ext/exec.py b/tdoc/common/ext/exec.py index 30f373d..e2963a6 100644 --- a/tdoc/common/ext/exec.py +++ b/tdoc/common/ext/exec.py @@ -10,7 +10,7 @@ from sphinx.directives import code from sphinx.util import logging, osutil -from .. import __version__, format_attrs, format_data_attrs, report_exceptions +from . import __version__, format_attrs, format_data_attrs, report_exceptions _log = logging.getLogger(__name__) _base = pathlib.Path(__file__).absolute().parent.parent diff --git a/tdoc/common/ext/iframe.py b/tdoc/common/ext/iframe.py index fc81017..f19001b 100644 --- a/tdoc/common/ext/iframe.py +++ b/tdoc/common/ext/iframe.py @@ -5,7 +5,7 @@ from docutils.parsers.rst import directives from sphinx.util import docutils, logging -from .. import __version__, report_exceptions +from . import __version__, report_exceptions _log = logging.getLogger(__name__) diff --git a/tdoc/common/ext/metadata.py b/tdoc/common/ext/metadata.py index 7d653fc..89c3834 100644 --- a/tdoc/common/ext/metadata.py +++ b/tdoc/common/ext/metadata.py @@ -6,7 +6,7 @@ from docutils import nodes from sphinx.util import docutils, logging -from .. import __version__, report_exceptions +from . import __version__, report_exceptions _log = logging.getLogger(__name__) diff --git a/tdoc/common/ext/num.py b/tdoc/common/ext/num.py index 99ecaf2..8440bce 100644 --- a/tdoc/common/ext/num.py +++ b/tdoc/common/ext/num.py @@ -6,7 +6,7 @@ from sphinx.environment import collectors from sphinx.util import docutils, logging, nodes as sphinx_nodes -from .. import __version__ +from . import __version__ _log = logging.getLogger(__name__) diff --git a/tdoc/common/ext/solution.py b/tdoc/common/ext/solution.py index 4da9ca9..10874c9 100644 --- a/tdoc/common/ext/solution.py +++ b/tdoc/common/ext/solution.py @@ -6,7 +6,7 @@ from docutils.parsers.rst.directives import admonitions from sphinx.util import logging -from .. import _, __version__ +from . import _, __version__ _log = logging.getLogger(__name__)