summaryrefslogtreecommitdiff
path: root/sphinx
diff options
context:
space:
mode:
authorTakeshi KOMIYA <i.tkomiya@gmail.com>2017-04-20 20:19:55 +0900
committerTakeshi KOMIYA <i.tkomiya@gmail.com>2017-04-20 20:45:44 +0900
commitfaefe2b5a522763e918ae1ad67b02ae0bcde824f (patch)
treebf5b21e60212186974b1124ef2dd31e6c85e2ca5 /sphinx
parentb405c0aaf52840e370a1ed6c88ab122fb1df644d (diff)
downloadsphinx-git-faefe2b5a522763e918ae1ad67b02ae0bcde824f.tar.gz
Add HTMLThemeFactory class
Diffstat (limited to 'sphinx')
-rw-r--r--sphinx/application.py1
-rw-r--r--sphinx/builders/changes.py6
-rw-r--r--sphinx/builders/html.py6
-rw-r--r--sphinx/theming.py133
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