diff options
| author | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2017-04-20 20:19:55 +0900 |
|---|---|---|
| committer | Takeshi KOMIYA <i.tkomiya@gmail.com> | 2017-04-20 20:45:44 +0900 |
| commit | faefe2b5a522763e918ae1ad67b02ae0bcde824f (patch) | |
| tree | bf5b21e60212186974b1124ef2dd31e6c85e2ca5 /sphinx | |
| parent | b405c0aaf52840e370a1ed6c88ab122fb1df644d (diff) | |
| download | sphinx-git-faefe2b5a522763e918ae1ad67b02ae0bcde824f.tar.gz | |
Add HTMLThemeFactory class
Diffstat (limited to 'sphinx')
| -rw-r--r-- | sphinx/application.py | 1 | ||||
| -rw-r--r-- | sphinx/builders/changes.py | 6 | ||||
| -rw-r--r-- | sphinx/builders/html.py | 6 | ||||
| -rw-r--r-- | sphinx/theming.py | 133 |
4 files changed, 78 insertions, 68 deletions
diff --git a/sphinx/application.py b/sphinx/application.py index 6f1418b2f..5058fa1b1 100644 --- a/sphinx/application.py +++ b/sphinx/application.py @@ -127,6 +127,7 @@ class Sphinx(object): self.env = None # type: BuildEnvironment self.enumerable_nodes = {} # type: Dict[nodes.Node, Tuple[unicode, Callable]] # NOQA self.post_transforms = [] # type: List[Transform] + self.html_themes = {} # type: Dict[unicode, unicode] self.srcdir = srcdir self.confdir = confdir diff --git a/sphinx/builders/changes.py b/sphinx/builders/changes.py index 582593311..5c3072059 100644 --- a/sphinx/builders/changes.py +++ b/sphinx/builders/changes.py @@ -16,7 +16,7 @@ from six import iteritems from sphinx import package_dir from sphinx.locale import _ -from sphinx.theming import Theme +from sphinx.theming import HTMLThemeFactory from sphinx.builders import Builder from sphinx.util import logging from sphinx.util.osutil import ensuredir, os_path @@ -42,8 +42,8 @@ class ChangesBuilder(Builder): def init(self): # type: () -> None self.create_template_bridge() - Theme.init_themes(self.confdir, self.config.html_theme_path) - self.theme = Theme.create('default') + theme_factory = HTMLThemeFactory(self.app) + self.theme = theme_factory.create('default') self.templates.init(self, self.theme) def get_outdated_docs(self): diff --git a/sphinx/builders/html.py b/sphinx/builders/html.py index cf5cee280..c1a1ae9d5 100644 --- a/sphinx/builders/html.py +++ b/sphinx/builders/html.py @@ -40,7 +40,7 @@ from sphinx.util.matching import patmatch, Matcher, DOTFILES from sphinx.config import string_classes from sphinx.locale import _, l_ from sphinx.search import js_index -from sphinx.theming import Theme +from sphinx.theming import HTMLThemeFactory from sphinx.builders import Builder from sphinx.application import ENV_PICKLE_FILENAME from sphinx.highlighting import PygmentsBridge @@ -196,9 +196,9 @@ class StandaloneHTMLBuilder(Builder): def init_templates(self): # type: () -> None - Theme.init_themes(self.confdir, self.config.html_theme_path) + theme_factory = HTMLThemeFactory(self.app) themename, themeoptions = self.get_theme_config() - self.theme = Theme.create(themename) + self.theme = theme_factory.create(themename) self.theme_options = themeoptions.copy() self.create_template_bridge() self.templates.init(self, self.theme) diff --git a/sphinx/theming.py b/sphinx/theming.py index abb99d1c8..fbd4dbb62 100644 --- a/sphinx/theming.py +++ b/sphinx/theming.py @@ -30,12 +30,13 @@ logger = logging.getLogger(__name__) if False: # For type annotation from typing import Any, Dict, Iterator, List, Tuple # NOQA + from sphinx.application import Sphinx # NOQA NODEFAULT = object() THEMECONF = 'theme.conf' -class _Theme(object): +class Theme(object): def __init__(self): # type: () -> None self.name = None @@ -126,69 +127,56 @@ def is_archived_theme(filename): return False -def find_theme_entries(themedir): - # type: (unicode) -> Iterator[Tuple[unicode, unicode]] - for entry in os.listdir(themedir): - pathname = path.join(themedir, entry) - if path.isfile(pathname) and entry.lower().endswith('.zip'): - if is_archived_theme(pathname): - name = entry[:-4] - yield name, pathname - else: - logger.warning(_('file %r on theme path is not a valid ' - 'zipfile or contains no theme'), entry) - else: - if path.isfile(path.join(pathname, THEMECONF)): - yield entry, pathname +class HTMLThemeFactory(object): + """A factory class for HTML Themes.""" + def __init__(self, app): + # type: (Sphinx) -> None + self.confdir = app.confdir + self.themes = app.html_themes + self.load_builtin_themes() + if getattr(app.config, 'html_theme_path', None): + self.load_additional_themes(app.config.html_theme_path) -class Theme(object): - """ - Represents the theme chosen in the configuration. - """ - themes = {} # type: Dict[unicode, unicode] - - @classmethod - def init_themes(cls, confdir, theme_path): - # type: (unicode, unicode) -> None - """Search all theme paths for available themes.""" - themepath = list(theme_path) - themepath.append(path.join(package_dir, 'themes')) - - # search themes from theme_paths - for themedir in themepath: - themedir = path.abspath(path.join(confdir, themedir)) - if not path.isdir(themedir): - continue - else: - for name, theme in find_theme_entries(themedir): - cls.themes[name] = theme + def load_builtin_themes(self): + # type: () -> None + themes = self.find_themes(path.join(package_dir, 'themes')) + for name, theme in iteritems(themes): + self.themes[name] = theme + + def load_additional_themes(self, theme_paths): + # type: (unicode) -> None + for theme_path in theme_paths: + abs_theme_path = path.abspath(path.join(self.confdir, theme_path)) + themes = self.find_themes(abs_theme_path) + for name, theme in iteritems(themes): + self.themes[name] = theme - @classmethod - def load_extra_theme(cls, name): + def load_extra_theme(self, name): + # type: (unicode) -> None if name == 'alabaster': - cls.load_alabaster() + self.load_alabaster_theme() elif name == 'sphinx_rtd_theme': - cls.load_sphinx_rtd_theme() + self.load_sphinx_rtd_theme() else: - pass + self.load_external_theme(name) - @classmethod - def load_alabaster(cls): + def load_alabaster_theme(self): + # type: () -> None import alabaster - cls.themes['alabaster'] = path.join(alabaster.get_path(), 'alabaster') + self.themes['alabaster'] = path.join(alabaster.get_path(), 'alabaster') - @classmethod - def load_sphinx_rtd_theme(cls): + def load_sphinx_rtd_theme(self): + # type: () -> None try: import sphinx_rtd_theme - cls.themes['sphinx_rtd_theme'] = path.join(sphinx_rtd_theme.get_html_theme_path(), - 'sphinx_rtd_theme') + theme_path = sphinx_rtd_theme.get_html_theme_path() + self.themes['sphinx_rtd_theme'] = path.join(theme_path, 'sphinx_rtd_theme') except ImportError: pass - @classmethod - def load_external_themes(cls, name): + def load_external_themes(self, name): + # type: (unicode) -> None for entry_point in pkg_resources.iter_entry_points('sphinx_themes'): target = entry_point.load() if callable(target): @@ -199,17 +187,38 @@ class Theme(object): else: themedir = target - for entry, theme in find_theme_entries(themedir): + themes = self.find_themes(themedir) + for entry, theme in iteritems(themes): if name == entry: - cls.themes[entry] = theme + self.themes[name] = theme + + def find_themes(self, theme_path): + # type: (unicode) -> Dict[unicode, unicode] + themes = {} + if not path.isdir(theme_path): + return themes + + for entry in os.listdir(theme_path): + pathname = path.join(theme_path, entry) + if path.isfile(pathname) and entry.lower().endswith('.zip'): + if is_archived_theme(pathname): + name = entry[:-4] + themes[name] = pathname + else: + logger.warning(_('file %r on theme path is not a valid ' + 'zipfile or contains no theme'), entry) + else: + if path.isfile(path.join(pathname, THEMECONF)): + themes[entry] = pathname - @classmethod - def create(cls, name): - # type: (unicode) -> None - if name not in cls.themes: - cls.load_extra_theme(name) + return themes + + def create(self, name): + # type: (unicode) -> Theme + if name not in self.themes: + self.load_extra_theme(name) - if name not in cls.themes: + if name not in self.themes: if name == 'sphinx_rtd_theme': raise ThemeError(_('sphinx_rtd_theme is no longer a hard dependency ' 'since version 1.4.0. Please install it manually.' @@ -218,10 +227,10 @@ class Theme(object): raise ThemeError(_('no theme named %r found ' '(missing theme.conf?)') % name) - theme = _Theme() + theme = Theme() theme.name = name - themedir = cls.themes[name] + themedir = self.themes[name] if path.isdir(themedir): # already a directory, do nothing theme.rootdir = None @@ -253,10 +262,10 @@ class Theme(object): if inherit == 'none': theme.base = None - elif inherit not in cls.themes: + elif inherit not in self.themes: raise ThemeError('no theme named %r found, inherited by %r' % (inherit, name)) else: - theme.base = cls.create(inherit) + theme.base = self.create(inherit) return theme |
