From d93b215f2992f8d81d36035d8a7b54a1eed9cbc3 Mon Sep 17 00:00:00 2001 From: th3aftermath Date: Wed, 23 Apr 2014 23:16:36 -0400 Subject: [PATCH] Add multi theme support --- pelican/__init__.py | 9 ++++++ pelican/generators.py | 17 +++++++---- pelican/settings.py | 14 +++++---- pelican/tests/test_generators.py | 50 ++++++++++++++++---------------- pelican/tests/test_settings.py | 6 ++-- 5 files changed, 57 insertions(+), 39 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index d5de8f89..95918ffe 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -47,6 +47,7 @@ class Pelican(object): self.path = settings['PATH'] self.theme = settings['THEME'] + self.themes = settings['THEMES'] self.output_path = settings['OUTPUT_PATH'] self.ignore_files = settings['IGNORE_FILES'] self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY'] @@ -87,6 +88,10 @@ class Pelican(object): def _handle_deprecation(self): + if self.settings['EXTRA_TEMPLATES_PATHS']: + logger.warning('`EXTRA_TEMPLATES_PATHS` is soon to be deprecated.' + ' Use the `THEMES` setting for the same behaviour') + if self.settings.get('CLEAN_URLS', False): logger.warning('Found deprecated `CLEAN_URLS` in settings.' ' Modifying the following settings for the' @@ -152,6 +157,7 @@ class Pelican(object): settings=self.settings, path=self.path, theme=self.theme, + themes=self.themes, output_path=self.output_path, ) for cls in self.get_generator_classes() ] @@ -336,6 +342,9 @@ def main(): for static_path in settings.get("STATIC_PATHS", []): watchers[static_path] = folder_watcher(static_path, [''], pelican.ignore_files) + for theme in pelican.themes: + watchers[theme] = folder_watcher(pelican.themes[theme], [''], pelican.ignore_files) + try: if args.autoreload: print(' --- AutoReload Mode: Monitoring `content`, `theme`, and' diff --git a/pelican/generators.py b/pelican/generators.py index 298a17c5..58ec3dc4 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -30,12 +30,13 @@ logger = logging.getLogger(__name__) class Generator(object): """Baseclass generator""" - def __init__(self, context, settings, path, theme, output_path, + def __init__(self, context, settings, path, theme, themes, output_path, readers_cache_name='', **kwargs): self.context = context self.settings = settings self.path = path self.theme = theme + self.themes = themes self.output_path = output_path for arg, value in kwargs.items(): @@ -57,13 +58,13 @@ class Generator(object): "themes", "simple", "templates")) themes = {} - for theme in settings['THEMES']: - themes['!' + os.path.basename(theme)] = FileSystemLoader(os.path.join(theme, "templates")) + for theme in self.themes: + themes[theme] = FileSystemLoader(os.path.join(theme, "templates")) loader=ChoiceLoader([ FileSystemLoader(self._templates_path), - simple_loader, #implicit inheritance - PrefixLoader(themes), # explicit one + simple_loader, # implicit inheritance + PrefixLoader(themes) # explicit one ]) self.env = Environment( @@ -684,6 +685,12 @@ class StaticGenerator(Generator): self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.theme, self.settings['THEME_STATIC_DIR'], self.output_path, os.curdir) + + for theme in self.themes: + self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.themes[theme], + self.settings['THEME_STATIC_DIR'], self.output_path, + os.curdir) + # copy all Static files for sc in self.context['staticfiles']: source_path = os.path.join(self.path, sc.source_path) diff --git a/pelican/settings.py b/pelican/settings.py index c3ca07a8..c6f5f8d5 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -28,6 +28,9 @@ logger = logging.getLogger(__name__) DEFAULT_THEME = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'themes', 'notmyidea') +DEFAULT_THEMES = {'!simple': os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'themes', 'simple')} + DEFAULT_CONFIG = { 'PATH': os.curdir, 'ARTICLE_DIR': '', @@ -35,7 +38,7 @@ DEFAULT_CONFIG = { 'PAGE_DIR': 'pages', 'PAGE_EXCLUDES': (), 'THEME': DEFAULT_THEME, - 'THEMES':['simple',], + 'THEMES': DEFAULT_THEMES, 'OUTPUT_PATH': 'output', 'READERS': {}, 'STATIC_PATHS': ['images', ], @@ -159,7 +162,7 @@ def read_settings(path=None, override=None): if 'THEMES' in local_settings and local_settings[p] is not None: for p in local_settings['THEMES']: - if p is not isabs(p): + if local_settings['THEMES'][p] is not isabs(local_settings['THEMES'][p]): absp = os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(path), p))) if os.path.exists(absp): local_settings['THEMES'][p] = absp @@ -224,14 +227,13 @@ def configure_settings(settings): % settings['THEME']) for theme in settings['THEMES']: - if not os.path.isdir(theme): + if not os.path.isdir(settings['THEMES'][theme]): theme_path = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'themes', - theme) + settings['THEMES'][theme]) if os.path.exists(theme_path): - index = settings['THEMES'].index(theme) - settings['THEMES'][index] = theme_path + settings['THEMES'][theme] = theme_path else: raise Exception("Could not find the theme %s" % theme) diff --git a/pelican/tests/test_generators.py b/pelican/tests/test_generators.py index b349b934..757c6f45 100644 --- a/pelican/tests/test_generators.py +++ b/pelican/tests/test_generators.py @@ -27,7 +27,7 @@ class TestGenerator(unittest.TestCase): self.settings = get_settings() self.settings['READERS'] = {'asc': None} self.generator = Generator(self.settings.copy(), self.settings, - CUR_DIR, self.settings['THEME'], self.settings['BASE_THEME'], None) + CUR_DIR, self.settings['THEME'], self.settings['THEMES'], None) def tearDown(self): locale.setlocale(locale.LC_ALL, self.old_locale) @@ -53,7 +53,7 @@ class TestArticlesGenerator(unittest.TestCase): cls.generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) cls.generator.generate_context() cls.articles = [[page.title, page.status, page.category.name, page.template] for page in cls.generator.articles] @@ -69,7 +69,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['CACHE_DIRECTORY'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, - path=None, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) writer = MagicMock() generator.generate_feeds(writer) writer.write_feed.assert_called_with([], settings, @@ -77,7 +77,7 @@ class TestArticlesGenerator(unittest.TestCase): generator = ArticlesGenerator( context=settings, settings=get_settings(FEED_ALL_ATOM=None), - path=None, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) writer = MagicMock() generator.generate_feeds(writer) self.assertFalse(writer.write_feed.called) @@ -147,7 +147,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['filenames'] = {} generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() # test for name # categories are grouped by slug; if two categories have the same slug @@ -170,7 +170,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['CACHE_DIRECTORY'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, - path=None, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) write = MagicMock() generator.generate_direct_templates(write) write.assert_called_with("archives.html", @@ -185,7 +185,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['CACHE_DIRECTORY'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, - path=None, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) write = MagicMock() generator.generate_direct_templates(write) write.assert_called_with("archives/index.html", @@ -201,7 +201,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['CACHE_DIRECTORY'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, - path=None, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=None, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) write = MagicMock() generator.generate_direct_templates(write) write.assert_called_count == 0 @@ -228,7 +228,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['CACHE_DIRECTORY'] = self.temp_cache generator = ArticlesGenerator( context=settings, settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() write = MagicMock() generator.generate_period_archives(write) @@ -245,7 +245,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['MONTH_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/{date:%b}/index.html' generator = ArticlesGenerator( context=settings, settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() write = MagicMock() generator.generate_period_archives(write) @@ -263,7 +263,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['DAY_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/{date:%b}/{date:%d}/index.html' generator = ArticlesGenerator( context=settings, settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() write = MagicMock() generator.generate_period_archives(write) @@ -297,13 +297,13 @@ class TestArticlesGenerator(unittest.TestCase): generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator, '_cache')) generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() generator.readers.read_file.assert_called_count == 0 @@ -316,13 +316,13 @@ class TestArticlesGenerator(unittest.TestCase): generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator.readers, '_cache')) generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) readers = generator.readers.readers for reader in readers.values(): reader.read = MagicMock() @@ -340,7 +340,7 @@ class TestArticlesGenerator(unittest.TestCase): generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() self.assertTrue(hasattr(generator, '_cache_open')) @@ -349,7 +349,7 @@ class TestArticlesGenerator(unittest.TestCase): settings['LOAD_CONTENT_CACHE'] = False generator = ArticlesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() generator.readers.read_file.assert_called_count == orig_call_count @@ -378,7 +378,7 @@ class TestPageGenerator(unittest.TestCase): generator = PagesGenerator( context=settings.copy(), settings=settings, - path=CUR_DIR, theme=settings['THEME'], base_theme=settings['BASE_THEME'], output_path=None) + path=CUR_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() pages = self.distill_pages(generator.pages) hidden_pages = self.distill_pages(generator.hidden_pages) @@ -408,13 +408,13 @@ class TestPageGenerator(unittest.TestCase): generator = PagesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator, '_cache')) generator = PagesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() generator.readers.read_file.assert_called_count == 0 @@ -427,13 +427,13 @@ class TestPageGenerator(unittest.TestCase): generator = PagesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.generate_context() self.assertTrue(hasattr(generator.readers, '_cache')) generator = PagesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) readers = generator.readers.readers for reader in readers.values(): reader.read = MagicMock() @@ -451,7 +451,7 @@ class TestPageGenerator(unittest.TestCase): generator = PagesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() self.assertTrue(hasattr(generator, '_cache_open')) @@ -460,7 +460,7 @@ class TestPageGenerator(unittest.TestCase): settings['LOAD_CONTENT_CACHE'] = False generator = PagesGenerator( context=settings.copy(), settings=settings, - path=CONTENT_DIR, theme=settings['THEME'], output_path=None) + path=CONTENT_DIR, theme=settings['THEME'], themes=settings['THEMES'], output_path=None) generator.readers.read_file = MagicMock() generator.generate_context() generator.readers.read_file.assert_called_count == orig_call_count @@ -492,7 +492,7 @@ class TestTemplatePagesGenerator(unittest.TestCase): generator = TemplatePagesGenerator( context={'foo': 'bar'}, settings=settings, - path=self.temp_content, theme='', base_theme=settings['BASE_THEME'], output_path=self.temp_output) + path=self.temp_content, theme='', themes=settings['THEMES'], output_path=self.temp_output) # create a dummy template file template_dir = os.path.join(self.temp_content, 'template') diff --git a/pelican/tests/test_settings.py b/pelican/tests/test_settings.py index dcd5b8af..1e93f55f 100644 --- a/pelican/tests/test_settings.py +++ b/pelican/tests/test_settings.py @@ -6,7 +6,7 @@ import locale from os.path import dirname, abspath, join from pelican.settings import (read_settings, configure_settings, - DEFAULT_CONFIG, DEFAULT_THEME, DEFAULT_BASE_THEME) + DEFAULT_CONFIG, DEFAULT_THEME) from pelican.tests.support import unittest @@ -70,7 +70,7 @@ class TestSettingsConfiguration(unittest.TestCase): # These 4 settings are required to run configure_settings 'PATH': '.', 'THEME': DEFAULT_THEME, - 'BASE_THEME': DEFAULT_BASE_THEME, + 'THEMES': {'!simple': 'simple'}, 'SITEURL': 'http://blog.notmyidea.org/', 'LOCALE': '', } @@ -88,7 +88,7 @@ class TestSettingsConfiguration(unittest.TestCase): 'LOCALE': '', 'PATH': os.curdir, 'THEME': DEFAULT_THEME, - 'BASE_THEME': DEFAULT_BASE_THEME, + 'THEMES': {'!simple': 'simple'}, } configure_settings(settings) # SITEURL should not have a trailing slash