forked from github/pelican
324 lines
12 KiB
Python
324 lines
12 KiB
Python
import copy
|
|
import locale
|
|
import os
|
|
from os.path import abspath, dirname, join
|
|
|
|
|
|
from pelican.settings import (
|
|
DEFAULT_CONFIG,
|
|
DEFAULT_THEME,
|
|
_printf_s_to_format_field,
|
|
configure_settings,
|
|
handle_deprecated_settings,
|
|
read_settings,
|
|
)
|
|
from pelican.tests.support import unittest
|
|
|
|
|
|
class TestSettingsConfiguration(unittest.TestCase):
|
|
"""Provided a file, it should read it, replace the default values,
|
|
append new values to the settings (if any), and apply basic settings
|
|
optimizations.
|
|
"""
|
|
|
|
def setUp(self):
|
|
self.old_locale = locale.setlocale(locale.LC_ALL)
|
|
locale.setlocale(locale.LC_ALL, "C")
|
|
self.PATH = abspath(dirname(__file__))
|
|
default_conf = join(self.PATH, "default_conf.py")
|
|
self.settings = read_settings(default_conf)
|
|
|
|
def tearDown(self):
|
|
locale.setlocale(locale.LC_ALL, self.old_locale)
|
|
|
|
def test_overwrite_existing_settings(self):
|
|
self.assertEqual(self.settings.get("SITENAME"), "Alexis' log")
|
|
self.assertEqual(self.settings.get("SITEURL"), "http://blog.notmyidea.org")
|
|
|
|
def test_keep_default_settings(self):
|
|
# Keep default settings if not defined.
|
|
self.assertEqual(
|
|
self.settings.get("DEFAULT_CATEGORY"), DEFAULT_CONFIG["DEFAULT_CATEGORY"]
|
|
)
|
|
|
|
def test_dont_copy_small_keys(self):
|
|
# Do not copy keys not in caps.
|
|
self.assertNotIn("foobar", self.settings)
|
|
|
|
def test_read_empty_settings(self):
|
|
# Ensure an empty settings file results in default settings.
|
|
settings = read_settings(None)
|
|
expected = copy.deepcopy(DEFAULT_CONFIG)
|
|
# Added by configure settings
|
|
expected["FEED_DOMAIN"] = ""
|
|
expected["ARTICLE_EXCLUDES"] = ["pages"]
|
|
expected["PAGE_EXCLUDES"] = [""]
|
|
self.maxDiff = None
|
|
self.assertDictEqual(settings, expected)
|
|
|
|
def test_settings_return_independent(self):
|
|
# Make sure that the results from one settings call doesn't
|
|
# effect past or future instances.
|
|
self.PATH = abspath(dirname(__file__))
|
|
default_conf = join(self.PATH, "default_conf.py")
|
|
settings = read_settings(default_conf)
|
|
settings["SITEURL"] = "new-value"
|
|
new_settings = read_settings(default_conf)
|
|
self.assertNotEqual(new_settings["SITEURL"], settings["SITEURL"])
|
|
|
|
def test_defaults_not_overwritten(self):
|
|
# This assumes 'SITENAME': 'A Pelican Blog'
|
|
settings = read_settings(None)
|
|
settings["SITENAME"] = "Not a Pelican Blog"
|
|
self.assertNotEqual(settings["SITENAME"], DEFAULT_CONFIG["SITENAME"])
|
|
|
|
def test_static_path_settings_safety(self):
|
|
# Disallow static paths from being strings
|
|
settings = {
|
|
"STATIC_PATHS": "foo/bar",
|
|
"THEME_STATIC_PATHS": "bar/baz",
|
|
# These 4 settings are required to run configure_settings
|
|
"PATH": ".",
|
|
"THEME": DEFAULT_THEME,
|
|
"SITEURL": "http://blog.notmyidea.org/",
|
|
"LOCALE": "",
|
|
}
|
|
configure_settings(settings)
|
|
self.assertEqual(settings["STATIC_PATHS"], DEFAULT_CONFIG["STATIC_PATHS"])
|
|
self.assertEqual(
|
|
settings["THEME_STATIC_PATHS"], DEFAULT_CONFIG["THEME_STATIC_PATHS"]
|
|
)
|
|
|
|
def test_configure_settings(self):
|
|
# Manipulations to settings should be applied correctly.
|
|
settings = {
|
|
"SITEURL": "http://blog.notmyidea.org/",
|
|
"LOCALE": "",
|
|
"PATH": os.curdir,
|
|
"THEME": DEFAULT_THEME,
|
|
}
|
|
configure_settings(settings)
|
|
|
|
# SITEURL should not have a trailing slash
|
|
self.assertEqual(settings["SITEURL"], "http://blog.notmyidea.org")
|
|
|
|
# FEED_DOMAIN, if undefined, should default to SITEURL
|
|
self.assertEqual(settings["FEED_DOMAIN"], "http://blog.notmyidea.org")
|
|
|
|
settings["FEED_DOMAIN"] = "http://feeds.example.com"
|
|
configure_settings(settings)
|
|
self.assertEqual(settings["FEED_DOMAIN"], "http://feeds.example.com")
|
|
|
|
def test_theme_settings_exceptions(self):
|
|
settings = self.settings
|
|
|
|
# Check that theme lookup in "pelican/themes" functions as expected
|
|
settings["THEME"] = os.path.split(settings["THEME"])[1]
|
|
configure_settings(settings)
|
|
self.assertEqual(settings["THEME"], DEFAULT_THEME)
|
|
|
|
# Check that non-existent theme raises exception
|
|
settings["THEME"] = "foo"
|
|
self.assertRaises(Exception, configure_settings, settings)
|
|
|
|
def test_deprecated_dir_setting(self):
|
|
settings = self.settings
|
|
|
|
settings["ARTICLE_DIR"] = "foo"
|
|
settings["PAGE_DIR"] = "bar"
|
|
|
|
settings = handle_deprecated_settings(settings)
|
|
|
|
self.assertEqual(settings["ARTICLE_PATHS"], ["foo"])
|
|
self.assertEqual(settings["PAGE_PATHS"], ["bar"])
|
|
|
|
with self.assertRaises(KeyError):
|
|
settings["ARTICLE_DIR"]
|
|
settings["PAGE_DIR"]
|
|
|
|
def test_default_encoding(self):
|
|
# Test that the user locale is set if not specified in settings
|
|
|
|
locale.setlocale(locale.LC_ALL, "C")
|
|
# empty string = user system locale
|
|
self.assertEqual(self.settings["LOCALE"], [""])
|
|
|
|
configure_settings(self.settings)
|
|
lc_time = locale.getlocale(locale.LC_TIME) # should be set to user locale
|
|
|
|
# explicitly set locale to user pref and test
|
|
locale.setlocale(locale.LC_TIME, "")
|
|
self.assertEqual(lc_time, locale.getlocale(locale.LC_TIME))
|
|
|
|
def test_invalid_settings_throw_exception(self):
|
|
# Test that the path name is valid
|
|
|
|
# test that 'PATH' is set
|
|
settings = {}
|
|
|
|
self.assertRaises(Exception, configure_settings, settings)
|
|
|
|
# Test that 'PATH' is valid
|
|
settings["PATH"] = ""
|
|
self.assertRaises(Exception, configure_settings, settings)
|
|
|
|
# Test nonexistent THEME
|
|
settings["PATH"] = os.curdir
|
|
settings["THEME"] = "foo"
|
|
|
|
self.assertRaises(Exception, configure_settings, settings)
|
|
|
|
def test__printf_s_to_format_field(self):
|
|
for s in ("%s", "{%s}", "{%s"):
|
|
option = "foo/{}/bar.baz".format(s)
|
|
result = _printf_s_to_format_field(option, "slug")
|
|
expected = option % "qux"
|
|
found = result.format(slug="qux")
|
|
self.assertEqual(expected, found)
|
|
|
|
def test_deprecated_extra_templates_paths(self):
|
|
settings = self.settings
|
|
settings["EXTRA_TEMPLATES_PATHS"] = ["/foo/bar", "/ha"]
|
|
|
|
settings = handle_deprecated_settings(settings)
|
|
|
|
self.assertEqual(settings["THEME_TEMPLATES_OVERRIDES"], ["/foo/bar", "/ha"])
|
|
self.assertNotIn("EXTRA_TEMPLATES_PATHS", settings)
|
|
|
|
def test_deprecated_paginated_direct_templates(self):
|
|
settings = self.settings
|
|
settings["PAGINATED_DIRECT_TEMPLATES"] = ["index", "archives"]
|
|
settings["PAGINATED_TEMPLATES"] = {"index": 10, "category": None}
|
|
settings = handle_deprecated_settings(settings)
|
|
self.assertEqual(
|
|
settings["PAGINATED_TEMPLATES"],
|
|
{"index": 10, "category": None, "archives": None},
|
|
)
|
|
self.assertNotIn("PAGINATED_DIRECT_TEMPLATES", settings)
|
|
|
|
def test_deprecated_paginated_direct_templates_from_file(self):
|
|
# This is equivalent to reading a settings file that has
|
|
# PAGINATED_DIRECT_TEMPLATES defined but no PAGINATED_TEMPLATES.
|
|
settings = read_settings(
|
|
None, override={"PAGINATED_DIRECT_TEMPLATES": ["index", "archives"]}
|
|
)
|
|
self.assertEqual(
|
|
settings["PAGINATED_TEMPLATES"],
|
|
{
|
|
"archives": None,
|
|
"author": None,
|
|
"index": None,
|
|
"category": None,
|
|
"tag": None,
|
|
},
|
|
)
|
|
self.assertNotIn("PAGINATED_DIRECT_TEMPLATES", settings)
|
|
|
|
def test_theme_and_extra_templates_exception(self):
|
|
settings = self.settings
|
|
settings["EXTRA_TEMPLATES_PATHS"] = ["/ha"]
|
|
settings["THEME_TEMPLATES_OVERRIDES"] = ["/foo/bar"]
|
|
|
|
self.assertRaises(Exception, handle_deprecated_settings, settings)
|
|
|
|
def test_slug_and_slug_regex_substitutions_exception(self):
|
|
settings = {}
|
|
settings["SLUG_REGEX_SUBSTITUTIONS"] = [("C++", "cpp")]
|
|
settings["TAG_SUBSTITUTIONS"] = [("C#", "csharp")]
|
|
|
|
self.assertRaises(Exception, handle_deprecated_settings, settings)
|
|
|
|
def test_deprecated_slug_substitutions(self):
|
|
default_slug_regex_subs = self.settings["SLUG_REGEX_SUBSTITUTIONS"]
|
|
|
|
# If no deprecated setting is set, don't set new ones
|
|
settings = {}
|
|
settings = handle_deprecated_settings(settings)
|
|
self.assertNotIn("SLUG_REGEX_SUBSTITUTIONS", settings)
|
|
self.assertNotIn("TAG_REGEX_SUBSTITUTIONS", settings)
|
|
self.assertNotIn("CATEGORY_REGEX_SUBSTITUTIONS", settings)
|
|
self.assertNotIn("AUTHOR_REGEX_SUBSTITUTIONS", settings)
|
|
|
|
# If SLUG_SUBSTITUTIONS is set, set {SLUG, AUTHOR}_REGEX_SUBSTITUTIONS
|
|
# correctly, don't set {CATEGORY, TAG}_REGEX_SUBSTITUTIONS
|
|
settings = {}
|
|
settings["SLUG_SUBSTITUTIONS"] = [("C++", "cpp")]
|
|
settings = handle_deprecated_settings(settings)
|
|
self.assertEqual(
|
|
settings.get("SLUG_REGEX_SUBSTITUTIONS"),
|
|
[(r"C\+\+", "cpp")] + default_slug_regex_subs,
|
|
)
|
|
self.assertNotIn("TAG_REGEX_SUBSTITUTIONS", settings)
|
|
self.assertNotIn("CATEGORY_REGEX_SUBSTITUTIONS", settings)
|
|
self.assertEqual(
|
|
settings.get("AUTHOR_REGEX_SUBSTITUTIONS"), default_slug_regex_subs
|
|
)
|
|
|
|
# If {CATEGORY, TAG, AUTHOR}_SUBSTITUTIONS are set, set
|
|
# {CATEGORY, TAG, AUTHOR}_REGEX_SUBSTITUTIONS correctly, don't set
|
|
# SLUG_REGEX_SUBSTITUTIONS
|
|
settings = {}
|
|
settings["TAG_SUBSTITUTIONS"] = [("C#", "csharp")]
|
|
settings["CATEGORY_SUBSTITUTIONS"] = [("C#", "csharp")]
|
|
settings["AUTHOR_SUBSTITUTIONS"] = [("Alexander Todorov", "atodorov")]
|
|
settings = handle_deprecated_settings(settings)
|
|
self.assertNotIn("SLUG_REGEX_SUBSTITUTIONS", settings)
|
|
self.assertEqual(
|
|
settings["TAG_REGEX_SUBSTITUTIONS"],
|
|
[(r"C\#", "csharp")] + default_slug_regex_subs,
|
|
)
|
|
self.assertEqual(
|
|
settings["CATEGORY_REGEX_SUBSTITUTIONS"],
|
|
[(r"C\#", "csharp")] + default_slug_regex_subs,
|
|
)
|
|
self.assertEqual(
|
|
settings["AUTHOR_REGEX_SUBSTITUTIONS"],
|
|
[(r"Alexander\ Todorov", "atodorov")] + default_slug_regex_subs,
|
|
)
|
|
|
|
# If {SLUG, CATEGORY, TAG, AUTHOR}_SUBSTITUTIONS are set, set
|
|
# {SLUG, CATEGORY, TAG, AUTHOR}_REGEX_SUBSTITUTIONS correctly
|
|
settings = {}
|
|
settings["SLUG_SUBSTITUTIONS"] = [("C++", "cpp")]
|
|
settings["TAG_SUBSTITUTIONS"] = [("C#", "csharp")]
|
|
settings["CATEGORY_SUBSTITUTIONS"] = [("C#", "csharp")]
|
|
settings["AUTHOR_SUBSTITUTIONS"] = [("Alexander Todorov", "atodorov")]
|
|
settings = handle_deprecated_settings(settings)
|
|
self.assertEqual(
|
|
settings["TAG_REGEX_SUBSTITUTIONS"],
|
|
[(r"C\+\+", "cpp")] + [(r"C\#", "csharp")] + default_slug_regex_subs,
|
|
)
|
|
self.assertEqual(
|
|
settings["CATEGORY_REGEX_SUBSTITUTIONS"],
|
|
[(r"C\+\+", "cpp")] + [(r"C\#", "csharp")] + default_slug_regex_subs,
|
|
)
|
|
self.assertEqual(
|
|
settings["AUTHOR_REGEX_SUBSTITUTIONS"],
|
|
[(r"Alexander\ Todorov", "atodorov")] + default_slug_regex_subs,
|
|
)
|
|
|
|
# Handle old 'skip' flags correctly
|
|
settings = {}
|
|
settings["SLUG_SUBSTITUTIONS"] = [("C++", "cpp", True)]
|
|
settings["AUTHOR_SUBSTITUTIONS"] = [("Alexander Todorov", "atodorov", False)]
|
|
settings = handle_deprecated_settings(settings)
|
|
self.assertEqual(
|
|
settings.get("SLUG_REGEX_SUBSTITUTIONS"),
|
|
[(r"C\+\+", "cpp")] + [(r"(?u)\A\s*", ""), (r"(?u)\s*\Z", "")],
|
|
)
|
|
self.assertEqual(
|
|
settings["AUTHOR_REGEX_SUBSTITUTIONS"],
|
|
[(r"Alexander\ Todorov", "atodorov")] + default_slug_regex_subs,
|
|
)
|
|
|
|
def test_deprecated_slug_substitutions_from_file(self):
|
|
# This is equivalent to reading a settings file that has
|
|
# SLUG_SUBSTITUTIONS defined but no SLUG_REGEX_SUBSTITUTIONS.
|
|
settings = read_settings(
|
|
None, override={"SLUG_SUBSTITUTIONS": [("C++", "cpp")]}
|
|
)
|
|
self.assertEqual(
|
|
settings["SLUG_REGEX_SUBSTITUTIONS"],
|
|
[(r"C\+\+", "cpp")] + self.settings["SLUG_REGEX_SUBSTITUTIONS"],
|
|
)
|
|
self.assertNotIn("SLUG_SUBSTITUTIONS", settings)
|