From c952c574b71dbcc872f6b017f962e58007aea960 Mon Sep 17 00:00:00 2001 From: Bastian Venthur Date: Thu, 1 Jun 2023 13:35:33 +0200 Subject: [PATCH 1/2] Don't use internal templates anymore. Blag will throw an error if a template is not found locally. The error message contains an explanation for the user on where to get the missing templates. Quickstart will generate templates for the user in the working directory. Updated tests appropriately. --- CHANGELOG.md | 15 +++++++++++++++ blag/blag.py | 43 +++++++++++++++++++++++-------------------- blag/quickstart.py | 22 ++++++++++++++++++++++ docs/blag.rst | 10 ++++------ tests/conftest.py | 11 ++++++----- tests/test_blag.py | 20 ++++++++++++++++++-- 6 files changed, 88 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21bb927..eb9cf8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [unreleased] + +### Breaking + +* blag does not use default fallback templates anymore and will return an error + if it is unable to find required templates, e.g. in `templates/`. + + Users upgrading from older versions can either run `blag quickstart` (don't + forget to backup your `config.ini` or copy the templates from blag's + resources (the resource path is shown in the error message). + + New users are not affected as `blag quickstart` will generate the needed + templates. + + ## [1.5.0] - 2023-04-16 * moved to pyproject.toml diff --git a/blag/blag.py b/blag/blag.py index 490348b..8ef4b9b 100644 --- a/blag/blag.py +++ b/blag/blag.py @@ -16,13 +16,13 @@ import sys from jinja2 import ( Environment, - ChoiceLoader, FileSystemLoader, - PackageLoader, Template, + TemplateNotFound, ) import feedgenerator +import blag from blag.markdown import markdown_factory, convert_markdown from blag.devserver import serve from blag.version import __VERSION__ @@ -185,15 +185,14 @@ def get_config(configfile: str) -> configparser.SectionProxy: def environment_factory( - template_dir: str | None = None, + template_dir: str, globals_: dict[str, object] | None = None, ) -> Environment: """Environment factory. - Creates a Jinja2 Environment with the default templates and - additional templates from `template_dir` loaded. If `globals` are - provided, they are attached to the environment and thus available to - all contexts. + Creates a Jinja2 Environment with the templates from `template_dir` loaded. + If `globals` are provided, they are attached to the environment and thus + available to all contexts. Parameters ---------- @@ -206,13 +205,7 @@ def environment_factory( jinja2.Environment """ - # first we try the custom templates, and fall back the ones provided - # by blag - loaders: list[FileSystemLoader | PackageLoader] = [] - if template_dir: - loaders.append(FileSystemLoader([template_dir])) - loaders.append(PackageLoader('blag', 'templates')) - env = Environment(loader=ChoiceLoader(loaders)) + env = Environment(loader=FileSystemLoader(template_dir)) if globals_: env.globals = globals_ return env @@ -261,11 +254,21 @@ def build(args: argparse.Namespace) -> None: env = environment_factory(args.template_dir, dict(site=config)) - page_template = env.get_template('page.html') - article_template = env.get_template('article.html') - archive_template = env.get_template('archive.html') - tags_template = env.get_template('tags.html') - tag_template = env.get_template('tag.html') + try: + page_template = env.get_template('page.html') + article_template = env.get_template('article.html') + archive_template = env.get_template('archive.html') + tags_template = env.get_template('tags.html') + tag_template = env.get_template('tag.html') + except TemplateNotFound as exc: + tmpl = os.path.join(blag.__path__[0], 'templates') + logger.error( + f'Template "{exc.name}" not found in {args.template_dir}! ' + 'Consider running `blag quickstart` or copying the ' + f'missing template from {tmpl}.' + ) + + sys.exit(1) articles, pages = process_markdown( convertibles, @@ -309,7 +312,7 @@ def process_markdown( input_dir output_dir page_template, archive_template - templats for pages and articles + templates for pages and articles Returns ------- diff --git a/blag/quickstart.py b/blag/quickstart.py index c27e473..aee73e1 100644 --- a/blag/quickstart.py +++ b/blag/quickstart.py @@ -6,6 +6,10 @@ from __future__ import annotations import configparser import argparse +import shutil +import os + +import blag def get_input(question: str, default: str) -> str: @@ -33,6 +37,22 @@ def get_input(question: str, default: str) -> str: return reply +def copy_templates() -> None: + """Copy templates into current directory. + + It will not overwrite existing files. + + """ + print("Copying templates...") + try: + shutil.copytree( + os.path.join(blag.__path__[0], 'templates'), + 'templates', + ) + except FileExistsError: + print("Templates already exist. Skipping.") + + def quickstart(args: argparse.Namespace | None) -> None: """Quickstart. @@ -71,3 +91,5 @@ def quickstart(args: argparse.Namespace | None) -> None: } with open('config.ini', 'w') as fh: config.write(fh) + + copy_templates() diff --git a/docs/blag.rst b/docs/blag.rst index b00450e..2c7ac0c 100644 --- a/docs/blag.rst +++ b/docs/blag.rst @@ -13,7 +13,7 @@ Install blag from PyPI_ .. _pypi: https://pypi.org/project/blag/ -Run blag's quickstart command to create the configuration needed +Run blag's quickstart command to create the configuration and templates needed .. code-block:: sh @@ -40,8 +40,8 @@ If you want more separation between the static files and the markdown content, you can put all static files into the ``static`` directory. Blag will copy them over to the ``build`` directory. -If you want to customize the looks of the generated site, create a -``template`` directory and put your jinja2 templates here. +If you want to customize the look of the generated site, visit the ``template`` +directory. It contains jinja2 templates and can be modified as needed. Those directories can be changed via command line arguments. See @@ -186,9 +186,7 @@ becomes Templating ---------- -Custom templates are **optional** and stored by default in the ``templates`` -directory. blag will search the ``templates`` directory first, and fall back -to blag's default built-in templates. +Templates are stored by default in the ``templates`` directory. ============ ====================================== =================== Template Used For Variables diff --git a/tests/conftest.py b/tests/conftest.py index da40e05..4f49918 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,18 +8,18 @@ import os import pytest from jinja2 import Environment, Template -from blag import blag +from blag import blag, quickstart @pytest.fixture -def environment() -> Iterator[Environment]: +def environment(cleandir: str) -> Iterator[Environment]: site = { 'base_url': 'site base_url', 'title': 'site title', 'description': 'site description', 'author': 'site author', } - env = blag.environment_factory(globals_=dict(site=site)) + env = blag.environment_factory('templates', globals_=dict(site=site)) yield env @@ -50,7 +50,7 @@ def tag_template(environment: Environment) -> Iterator[Template]: @pytest.fixture def cleandir() -> Iterator[str]: - """Create a temporary workind directory and cwd.""" + """Create a temporary working directory and cwd.""" config = """ [main] base_url = https://example.com/ @@ -60,13 +60,14 @@ author = a. u. thor """ with TemporaryDirectory() as dir: - for d in 'content', 'build', 'static', 'templates': + for d in 'content', 'build', 'static': os.mkdir(f'{dir}/{d}') with open(f'{dir}/config.ini', 'w') as fh: fh.write(config) # change directory old_cwd = os.getcwd() os.chdir(dir) + quickstart.copy_templates() yield dir # and change back afterwards os.chdir(old_cwd) diff --git a/tests/test_blag.py b/tests/test_blag.py index 74e8512..56cd153 100644 --- a/tests/test_blag.py +++ b/tests/test_blag.py @@ -179,9 +179,9 @@ author = a. u. thor assert config_parsed['base_url'] == 'https://example.com/' -def test_environment_factory() -> None: +def test_environment_factory(cleandir: str) -> None: globals_: dict[str, object] = {'foo': 'bar', 'test': 'me'} - env = blag.environment_factory(globals_=globals_) + env = blag.environment_factory("templates", globals_=globals_) assert env.globals['foo'] == 'bar' assert env.globals['test'] == 'me' @@ -299,6 +299,22 @@ foo bar assert os.path.exists(f'{args.output_dir}/tags/bar.html') +@pytest.mark.parametrize( + 'template', + [ + 'page.html', + 'article.html', + 'archive.html', + 'tags.html', + 'tag.html', + ] +) +def test_missing_template_raises(template: str, args: Namespace) -> None: + os.remove(f'templates/{template}') + with pytest.raises(SystemExit): + blag.build(args) + + def test_main(cleandir: str) -> None: blag.main(['build']) From f97e641bd8ad8f7ba8ecef654252a8d68aca616a Mon Sep 17 00:00:00 2001 From: Bastian Venthur Date: Thu, 1 Jun 2023 14:02:04 +0200 Subject: [PATCH 2/2] added test for quickstart creating the templates --- tests/test_quickstart.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_quickstart.py b/tests/test_quickstart.py index ac6ccaf..95b54c1 100644 --- a/tests/test_quickstart.py +++ b/tests/test_quickstart.py @@ -1,5 +1,6 @@ # remove when we don't support py38 anymore from __future__ import annotations +import os from pytest import MonkeyPatch @@ -27,3 +28,13 @@ def test_quickstart(cleandir: str, monkeypatch: MonkeyPatch) -> None: assert 'title = foo' in data assert 'description = foo' in data assert 'author = foo' in data + + for template in ( + "archive.html", + "article.html", + "base.html", + "page.html", + "tag.html", + "tags.html", + ): + assert os.path.exists(f'templates/{template}')