mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Refactor `sphinx.theming
` to prepare for iterative loading
This commit is contained in:
parent
256c8f9de0
commit
99dd0cb4c6
@ -35,29 +35,6 @@ _NO_DEFAULT = object()
|
|||||||
_THEME_CONF = 'theme.conf'
|
_THEME_CONF = 'theme.conf'
|
||||||
|
|
||||||
|
|
||||||
def _extract_zip(filename: str, target_dir: str, /) -> None:
|
|
||||||
"""Extract zip file to target directory."""
|
|
||||||
ensuredir(target_dir)
|
|
||||||
|
|
||||||
with ZipFile(filename) as archive:
|
|
||||||
for name in archive.namelist():
|
|
||||||
if name.endswith('/'):
|
|
||||||
continue
|
|
||||||
entry = path.join(target_dir, name)
|
|
||||||
ensuredir(path.dirname(entry))
|
|
||||||
with open(path.join(entry), 'wb') as fp:
|
|
||||||
fp.write(archive.read(name))
|
|
||||||
|
|
||||||
|
|
||||||
def _load_theme_conf(theme_dir: os.PathLike[str] | str) -> configparser.RawConfigParser:
|
|
||||||
c = configparser.RawConfigParser()
|
|
||||||
config_file_path = path.join(theme_dir, _THEME_CONF)
|
|
||||||
if not os.path.isfile(config_file_path):
|
|
||||||
raise ThemeError(__('theme configuration file %r not found') % config_file_path)
|
|
||||||
c.read(config_file_path, encoding='utf-8')
|
|
||||||
return c
|
|
||||||
|
|
||||||
|
|
||||||
class Theme:
|
class Theme:
|
||||||
"""A Theme is a set of HTML templates and configurations.
|
"""A Theme is a set of HTML templates and configurations.
|
||||||
|
|
||||||
@ -169,15 +146,6 @@ class Theme:
|
|||||||
self._base._cleanup()
|
self._base._cleanup()
|
||||||
|
|
||||||
|
|
||||||
def _is_archived_theme(filename: str, /) -> bool:
|
|
||||||
"""Check whether the specified file is an archived theme file or not."""
|
|
||||||
try:
|
|
||||||
with ZipFile(filename) as f:
|
|
||||||
return _THEME_CONF in f.namelist()
|
|
||||||
except Exception:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class HTMLThemeFactory:
|
class HTMLThemeFactory:
|
||||||
"""A factory class for HTML Themes."""
|
"""A factory class for HTML Themes."""
|
||||||
|
|
||||||
@ -214,9 +182,10 @@ class HTMLThemeFactory:
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
self._app.registry.load_extension(self._app, entry_point.module)
|
self._app.registry.load_extension(self._app, entry_point.module)
|
||||||
_config_post_init(None, self._app.config)
|
_config_post_init(self._app, self._app.config)
|
||||||
|
|
||||||
def _find_themes(self, theme_path: str) -> dict[str, str]:
|
@staticmethod
|
||||||
|
def _find_themes(theme_path: str) -> dict[str, str]:
|
||||||
"""Search themes from specified directory."""
|
"""Search themes from specified directory."""
|
||||||
themes: dict[str, str] = {}
|
themes: dict[str, str] = {}
|
||||||
if not path.isdir(theme_path):
|
if not path.isdir(theme_path):
|
||||||
@ -246,3 +215,35 @@ class HTMLThemeFactory:
|
|||||||
raise ThemeError(__('no theme named %r found (missing theme.conf?)') % name)
|
raise ThemeError(__('no theme named %r found (missing theme.conf?)') % name)
|
||||||
|
|
||||||
return Theme(name, self._themes[name], self)
|
return Theme(name, self._themes[name], self)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_archived_theme(filename: str, /) -> bool:
|
||||||
|
"""Check whether the specified file is an archived theme file or not."""
|
||||||
|
try:
|
||||||
|
with ZipFile(filename) as f:
|
||||||
|
return _THEME_CONF in f.namelist()
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_zip(filename: str, target_dir: str, /) -> None:
|
||||||
|
"""Extract zip file to target directory."""
|
||||||
|
ensuredir(target_dir)
|
||||||
|
|
||||||
|
with ZipFile(filename) as archive:
|
||||||
|
for name in archive.namelist():
|
||||||
|
if name.endswith('/'):
|
||||||
|
continue
|
||||||
|
entry = path.join(target_dir, name)
|
||||||
|
ensuredir(path.dirname(entry))
|
||||||
|
with open(path.join(entry), 'wb') as fp:
|
||||||
|
fp.write(archive.read(name))
|
||||||
|
|
||||||
|
|
||||||
|
def _load_theme_conf(theme_dir: os.PathLike[str] | str, /) -> configparser.RawConfigParser:
|
||||||
|
c = configparser.RawConfigParser()
|
||||||
|
config_file_path = path.join(theme_dir, _THEME_CONF)
|
||||||
|
if not os.path.isfile(config_file_path):
|
||||||
|
raise ThemeError(__('theme configuration file %r not found') % config_file_path)
|
||||||
|
c.read(config_file_path, encoding='utf-8')
|
||||||
|
return c
|
||||||
|
@ -5,7 +5,8 @@ import os
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
import sphinx.builders.html
|
import sphinx.builders.html
|
||||||
from sphinx.theming import Theme, ThemeError
|
from sphinx.errors import ThemeError
|
||||||
|
from sphinx.theming import Theme
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx(
|
@pytest.mark.sphinx(
|
||||||
@ -26,7 +27,7 @@ def test_theme_api(app, status, warning):
|
|||||||
# test Theme instance API
|
# test Theme instance API
|
||||||
theme = app.builder.theme
|
theme = app.builder.theme
|
||||||
assert theme.name == 'ziptheme'
|
assert theme.name == 'ziptheme'
|
||||||
theme_dir = theme._theme_dir
|
tmp_dirs = (theme._theme_dir,)
|
||||||
assert theme._base.name == 'basic'
|
assert theme._base.name == 'basic'
|
||||||
assert len(theme.get_theme_dirs()) == 2
|
assert len(theme.get_theme_dirs()) == 2
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ def test_theme_api(app, status, warning):
|
|||||||
|
|
||||||
# cleanup temp directories
|
# cleanup temp directories
|
||||||
theme._cleanup()
|
theme._cleanup()
|
||||||
assert not os.path.exists(theme_dir)
|
assert not any(map(os.path.exists, tmp_dirs))
|
||||||
|
|
||||||
|
|
||||||
def test_nonexistent_theme_conf(tmp_path):
|
def test_nonexistent_theme_conf(tmp_path):
|
||||||
|
Loading…
Reference in New Issue
Block a user