From e8f577602a6aebbb979e339786a7685c761fd335 Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:11:36 -0700 Subject: [PATCH] Register template filters on the fallback Jinja2 environment When server.templates.path is configured, render_j2_template() creates a custom Environment and registers the to_json filter on it. If a requested template is not present in that directory, a second Environment is built for the built-in templates, but no filters were registered on it, so any built-in template using {{ ... | to_json }} (items.html, item.html, stac_items.html) failed with TemplateAssertionError: No filter named 'to_json'. Register the filter and global on the fallback environment as well, so a partial custom templates directory transparently falls back to the built-in templates. Adds tests/unittests/test_ogc_api_util.py covering both the custom template override and the fallback path. --- pycsw/ogc/api/util.py | 2 + tests/unittests/test_ogc_api_util.py | 70 ++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 tests/unittests/test_ogc_api_util.py diff --git a/pycsw/ogc/api/util.py b/pycsw/ogc/api/util.py index 48d2b6b32..acd525fc8 100644 --- a/pycsw/ogc/api/util.py +++ b/pycsw/ogc/api/util.py @@ -219,6 +219,8 @@ def render_j2_template(config, template, data): LOGGER.debug(err) LOGGER.debug('Custom template not found; using default') env = Environment(loader=FileSystemLoader(TEMPLATES)) + env.filters['to_json'] = to_json + env.globals.update(to_json=to_json) template = env.get_template(template) else: raise diff --git a/tests/unittests/test_ogc_api_util.py b/tests/unittests/test_ogc_api_util.py new file mode 100644 index 000000000..8b88d0fe2 --- /dev/null +++ b/tests/unittests/test_ogc_api_util.py @@ -0,0 +1,70 @@ +# ================================================================= +# +# Authors: Tom Kralidis +# +# Copyright (c) 2026 Tom Kralidis +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# ================================================================= +"""Unit tests for pycsw.ogc.api.util""" + +import pytest + +from pycsw.ogc.api import util + +pytestmark = pytest.mark.unit + +TEMPLATE_USING_TO_JSON = "{{ data | to_json }}" + + +def test_render_j2_template_custom_templates_path(tmp_path, monkeypatch): + default_templates = tmp_path / 'default' + default_templates.mkdir() + (default_templates / 'items.html').write_text(TEMPLATE_USING_TO_JSON) + monkeypatch.setattr(util, 'TEMPLATES', str(default_templates)) + + custom_templates = tmp_path / 'custom' + custom_templates.mkdir() + (custom_templates / 'items.html').write_text('custom') + + config = {'server': {'templates': {'path': str(custom_templates)}}} + + assert util.render_j2_template(config, 'items.html', {}) == 'custom' + + +def test_render_j2_template_fallback_keeps_filters(tmp_path, monkeypatch): + """a template missing from templates.path falls back to the default + templates, which must keep the to_json filter registered""" + + default_templates = tmp_path / 'default' + default_templates.mkdir() + (default_templates / 'items.html').write_text(TEMPLATE_USING_TO_JSON) + monkeypatch.setattr(util, 'TEMPLATES', str(default_templates)) + + custom_templates = tmp_path / 'custom' + custom_templates.mkdir() + (custom_templates / 'item.html').write_text('custom') + + config = {'server': {'templates': {'path': str(custom_templates)}}} + + assert util.render_j2_template(config, 'items.html', {}) == '{}'