This commit is contained in:
hikmetba-bit 2026-10-12 22:00:36 +02:00 • committed by GitHub
commit 5f76bb8631
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 36 additions and 0 deletions

View file

@ -16,7 +16,15 @@ from pelican.paginator import PaginationRule
def load_source(name: str, path: str) -> ModuleType:
if not os.path.isfile(path):
raise FileNotFoundError(f"Settings file not found: {path}")
spec = importlib.util.spec_from_file_location(name, path)
if spec is None or spec.loader is None:
raise ImportError(
f"Unable to load settings file (unsupported file type): {path}"
)
mod = importlib.util.module_from_spec(spec)
sys.modules[name] = mod
spec.loader.exec_module(mod)

View file

@ -11,6 +11,7 @@ from pelican.settings import (
_printf_s_to_format_field,
configure_settings,
handle_deprecated_settings,
load_source,
read_settings,
)
from pelican.tests.support import LogCountHandler, unittest
@ -73,6 +74,33 @@ class TestSettingsConfiguration(unittest.TestCase):
settings["SITENAME"] = "Not a Pelican Blog"
self.assertNotEqual(settings["SITENAME"], DEFAULT_CONFIG["SITENAME"])
def test_load_source_missing_file_reports_path(self):
# A missing settings file should raise a clear error naming the
# path, not the cryptic "'NoneType' object has no attribute
# 'loader'" that importlib raises when spec_from_file_location
# can't determine a loader (e.g. no/unknown file extension).
missing_path = join(self.PATH, "this_settings_file_does_not_exist")
with self.assertRaises(FileNotFoundError) as ctx:
load_source("test_missing", missing_path)
self.assertIn(missing_path, str(ctx.exception))
def test_load_source_missing_file_with_extension_reports_path(self):
missing_path = join(self.PATH, "this_settings_file_does_not_exist.py")
with self.assertRaises(FileNotFoundError) as ctx:
load_source("test_missing_py", missing_path)
self.assertIn(missing_path, str(ctx.exception))
def test_load_source_unsupported_extension_reports_path(self):
unsupported_path = join(self.PATH, "default_conf.py.bak")
with open(unsupported_path, "w") as f:
f.write("SITENAME = 'unused'\n")
try:
with self.assertRaises(ImportError) as ctx:
load_source("test_unsupported", unsupported_path)
self.assertIn(unsupported_path, str(ctx.exception))
finally:
os.remove(unsupported_path)
def test_static_path_settings_safety(self):
# Disallow static paths from being strings
settings = {