Rename some methods, merge the loopable classes and just always try it

This commit is contained in:
Miguel Jacq 2025-11-28 12:28:46 +11:00
parent 2db80cc6e1
commit f66f58a7bb
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
20 changed files with 702 additions and 1051 deletions

View file

@ -31,4 +31,4 @@ def test_base_handler_abstract_methods_raise_not_implemented(tmp_path: Path):
handler.flatten(object())
with pytest.raises(NotImplementedError):
handler.generate_template(parsed=object(), role_prefix="role")
handler.generate_jinja2_template(parsed=object(), role_prefix="role")

View file

@ -10,8 +10,8 @@ from jinjaturtle.core import (
detect_format,
parse_config,
flatten_config,
generate_defaults_yaml,
generate_template,
generate_ansible_yaml,
generate_jinja2_template,
make_var_name,
)
@ -90,9 +90,9 @@ def test_parse_config_unsupported_format(tmp_path: Path):
parse_config(cfg_path, fmt="bogus")
def test_generate_template_type_and_format_errors():
def test_generate_jinja2_template_type_and_format_errors():
"""
Exercise the error branches in generate_template:
Exercise the error branches in generate_jinja2_template:
- toml with non-dict parsed
- ini with non-ConfigParser parsed
- yaml with wrong parsed type
@ -101,27 +101,29 @@ def test_generate_template_type_and_format_errors():
"""
# wrong type for TOML
with pytest.raises(TypeError):
generate_template("toml", parsed="not a dict", role_prefix="role")
generate_jinja2_template("toml", parsed="not a dict", role_prefix="role")
# wrong type for INI
with pytest.raises(TypeError):
generate_template("ini", parsed={"not": "a configparser"}, role_prefix="role")
generate_jinja2_template(
"ini", parsed={"not": "a configparser"}, role_prefix="role"
)
# wrong type for YAML
with pytest.raises(TypeError):
generate_template("yaml", parsed=None, role_prefix="role")
generate_jinja2_template("yaml", parsed=None, role_prefix="role")
# wrong type for JSON
with pytest.raises(TypeError):
generate_template("json", parsed=None, role_prefix="role")
generate_jinja2_template("json", parsed=None, role_prefix="role")
# unsupported format, no original_text
with pytest.raises(ValueError):
generate_template("bogusfmt", parsed=None, role_prefix="role")
generate_jinja2_template("bogusfmt", parsed=None, role_prefix="role")
# unsupported format, with original_text
with pytest.raises(ValueError):
generate_template(
generate_jinja2_template(
"bogusfmt",
parsed=None,
role_prefix="role",
@ -135,8 +137,8 @@ def test_normalize_default_value_true_false_strings():
(("section", "foo"), "true"),
(("section", "bar"), "FALSE"),
]
defaults_yaml = generate_defaults_yaml("role", flat_items)
data = yaml.safe_load(defaults_yaml)
ansible_yaml = generate_ansible_yaml("role", flat_items)
data = yaml.safe_load(ansible_yaml)
assert data["role_section_foo"] == "true"
assert data["role_section_bar"] == "FALSE"
@ -167,14 +169,14 @@ def test_fallback_str_representer_for_unknown_type():
def test_normalize_default_value_bool_inputs_are_stringified():
"""
Real boolean values should be turned into quoted 'true'/'false' strings
by _normalize_default_value via generate_defaults_yaml.
by _normalize_default_value via generate_ansible_yaml.
"""
flat_items = [
(("section", "flag_true"), True),
(("section", "flag_false"), False),
]
defaults_yaml = generate_defaults_yaml("role", flat_items)
data = yaml.safe_load(defaults_yaml)
ansible_yaml = generate_ansible_yaml("role", flat_items)
data = yaml.safe_load(ansible_yaml)
assert data["role_section_flag_true"] == "true"
assert data["role_section_flag_false"] == "false"

View file

@ -8,8 +8,8 @@ import yaml
from jinjaturtle.core import (
parse_config,
flatten_config,
generate_defaults_yaml,
generate_template,
generate_ansible_yaml,
generate_jinja2_template,
)
from jinjaturtle.handlers.ini import IniHandler
@ -26,8 +26,8 @@ def test_ini_php_sample_roundtrip():
flat_items = flatten_config(fmt, parsed)
assert flat_items, "Expected at least one flattened item from php.ini sample"
defaults_yaml = generate_defaults_yaml("php", flat_items)
defaults = yaml.safe_load(defaults_yaml)
ansible_yaml = generate_ansible_yaml("php", flat_items)
defaults = yaml.safe_load(ansible_yaml)
# defaults should be a non-empty dict
assert isinstance(defaults, dict)
@ -41,7 +41,7 @@ def test_ini_php_sample_roundtrip():
# template generation
original_text = ini_path.read_text(encoding="utf-8")
template = generate_template(fmt, parsed, "php", original_text=original_text)
template = generate_jinja2_template(fmt, parsed, "php", original_text=original_text)
assert "; About this file" in template
assert isinstance(template, str)
assert template.strip(), "Template for php.ini sample should not be empty"
@ -53,16 +53,16 @@ def test_ini_php_sample_roundtrip():
), f"Variable {var_name} not referenced in INI template"
def test_generate_template_fallback_ini():
def test_generate_jinja2_template_fallback_ini():
"""
When original_text is not provided, generate_template should use the
When original_text is not provided, generate_jinja2_template should use the
structural fallback path for INI configs.
"""
parser = configparser.ConfigParser()
# foo is quoted in the INI text to hit the "preserve quotes" branch
parser["section"] = {"foo": '"bar"', "num": "42"}
tmpl_ini = generate_template("ini", parsed=parser, role_prefix="role")
tmpl_ini = generate_jinja2_template("ini", parsed=parser, role_prefix="role")
assert "[section]" in tmpl_ini
assert "role_section_foo" in tmpl_ini
assert '"{{ role_section_foo }}"' in tmpl_ini # came from quoted INI value

View file

@ -9,7 +9,7 @@ import yaml
from jinjaturtle.core import (
parse_config,
flatten_config,
generate_defaults_yaml,
generate_ansible_yaml,
)
from jinjaturtle.handlers.json import JsonHandler
@ -24,8 +24,8 @@ def test_json_roundtrip():
assert fmt == "json"
flat_items = flatten_config(fmt, parsed)
defaults_yaml = generate_defaults_yaml("foobar", flat_items)
defaults = yaml.safe_load(defaults_yaml)
ansible_yaml = generate_ansible_yaml("foobar", flat_items)
defaults = yaml.safe_load(ansible_yaml)
# Defaults: nested keys and list indices
assert defaults["foobar_foo"] == "bar"
@ -35,10 +35,12 @@ def test_json_roundtrip():
assert defaults["foobar_list_0"] == 10
assert defaults["foobar_list_1"] == 20
# Template generation is done via JsonHandler.generate_template; we just
# Template generation is done via JsonHandler.generate_jinja2_template; we just
# make sure it produces a structure with the expected placeholders.
handler = JsonHandler()
templated = json.loads(handler.generate_template(parsed, role_prefix="foobar"))
templated = json.loads(
handler.generate_jinja2_template(parsed, role_prefix="foobar")
)
assert templated["foo"] == "{{ foobar_foo }}"
assert "foobar_nested_a" in str(templated)
@ -47,10 +49,10 @@ def test_json_roundtrip():
assert "foobar_list_1" in str(templated)
def test_generate_template_json_type_error():
def test_generate_jinja2_template_json_type_error():
"""
Wrong type for JSON in JsonHandler.generate_template should raise TypeError.
Wrong type for JSON in JsonHandler.generate_jinja2_template should raise TypeError.
"""
handler = JsonHandler()
with pytest.raises(TypeError):
handler.generate_template(parsed="not a dict", role_prefix="role")
handler.generate_jinja2_template(parsed="not a dict", role_prefix="role")

View file

@ -8,8 +8,8 @@ import yaml
from jinjaturtle.core import (
parse_config,
flatten_config,
generate_defaults_yaml,
generate_template,
generate_ansible_yaml,
generate_jinja2_template,
)
from jinjaturtle.handlers.toml import TomlHandler
import jinjaturtle.handlers.toml as toml_module
@ -27,8 +27,8 @@ def test_toml_sample_roundtrip():
flat_items = flatten_config(fmt, parsed)
assert flat_items
defaults_yaml = generate_defaults_yaml("jinjaturtle", flat_items)
defaults = yaml.safe_load(defaults_yaml)
ansible_yaml = generate_ansible_yaml("jinjaturtle", flat_items)
defaults = yaml.safe_load(ansible_yaml)
# defaults should be a non-empty dict
assert isinstance(defaults, dict)
@ -42,7 +42,7 @@ def test_toml_sample_roundtrip():
# template generation **now with original_text**
original_text = toml_path.read_text(encoding="utf-8")
template = generate_template(
template = generate_jinja2_template(
fmt, parsed, "jinjaturtle", original_text=original_text
)
assert isinstance(template, str)
@ -72,9 +72,9 @@ def test_parse_config_toml_missing_tomllib(monkeypatch):
assert "tomllib/tomli is required" in str(exc.value)
def test_generate_template_fallback_toml():
def test_generate_jinja2_template_fallback_toml():
"""
When original_text is not provided, generate_template should use the
When original_text is not provided, generate_jinja2_template should use the
structural fallback path for TOML configs.
"""
parsed_toml = {
@ -84,7 +84,7 @@ def test_generate_template_fallback_toml():
"file": {"path": "/tmp/app.log"}
}, # nested table to hit recursive walk
}
tmpl_toml = generate_template("toml", parsed=parsed_toml, role_prefix="role")
tmpl_toml = generate_jinja2_template("toml", parsed=parsed_toml, role_prefix="role")
assert "[server]" in tmpl_toml
assert "role_server_port" in tmpl_toml
assert "[logging]" in tmpl_toml or "[logging.file]" in tmpl_toml

View file

@ -10,8 +10,8 @@ import yaml
from jinjaturtle.core import (
parse_config,
flatten_config,
generate_defaults_yaml,
generate_template,
generate_ansible_yaml,
generate_jinja2_template,
)
from jinjaturtle.handlers.xml import XmlHandler
@ -28,8 +28,8 @@ def test_xml_roundtrip_ossec_web_rules():
flat_items = flatten_config(fmt, parsed)
assert flat_items, "Expected at least one flattened item from XML sample"
defaults_yaml = generate_defaults_yaml("ossec", flat_items)
defaults = yaml.safe_load(defaults_yaml)
ansible_yaml = generate_ansible_yaml("ossec", flat_items)
defaults = yaml.safe_load(ansible_yaml)
# defaults should be a non-empty dict
assert isinstance(defaults, dict)
@ -55,7 +55,9 @@ def test_xml_roundtrip_ossec_web_rules():
# Template generation (preserving comments)
original_text = xml_path.read_text(encoding="utf-8")
template = generate_template(fmt, parsed, "ossec", original_text=original_text)
template = generate_jinja2_template(
fmt, parsed, "ossec", original_text=original_text
)
assert isinstance(template, str)
assert template.strip(), "Template for XML sample should not be empty"
@ -108,13 +110,13 @@ def test_generate_xml_template_from_text_edge_cases():
assert "role_child_1" in tmpl
def test_generate_template_xml_type_error():
def test_generate_jinja2_template_xml_type_error():
"""
Wrong type for XML in XmlHandler.generate_template should raise TypeError.
Wrong type for XML in XmlHandler.generate_jinja2_template should raise TypeError.
"""
handler = XmlHandler()
with pytest.raises(TypeError):
handler.generate_template(parsed="not an element", role_prefix="role")
handler.generate_jinja2_template(parsed="not an element", role_prefix="role")
def test_flatten_config_xml_type_error():
@ -125,9 +127,9 @@ def test_flatten_config_xml_type_error():
flatten_config("xml", parsed="not-an-element")
def test_generate_template_xml_structural_fallback():
def test_generate_jinja2_template_xml_structural_fallback():
"""
When original_text is not provided for XML, generate_template should use
When original_text is not provided for XML, generate_jinja2_template should use
the structural fallback path (ET.tostring + handler processing).
"""
xml_text = textwrap.dedent(
@ -140,7 +142,7 @@ def test_generate_template_xml_structural_fallback():
)
root = ET.fromstring(xml_text)
tmpl = generate_template("xml", parsed=root, role_prefix="role")
tmpl = generate_jinja2_template("xml", parsed=root, role_prefix="role")
# Root attribute path ("@attr",) -> role_attr
assert "role_attr" in tmpl

View file

@ -8,8 +8,8 @@ import yaml
from jinjaturtle.core import (
parse_config,
flatten_config,
generate_defaults_yaml,
generate_template,
generate_ansible_yaml,
generate_jinja2_template,
)
from jinjaturtle.handlers.yaml import YamlHandler
@ -24,8 +24,8 @@ def test_yaml_roundtrip_with_list_and_comment():
assert fmt == "yaml"
flat_items = flatten_config(fmt, parsed)
defaults_yaml = generate_defaults_yaml("foobar", flat_items)
defaults = yaml.safe_load(defaults_yaml)
ansible_yaml = generate_ansible_yaml("foobar", flat_items)
defaults = yaml.safe_load(ansible_yaml)
# Defaults: keys are flattened with indices
assert defaults["foobar_foo"] == "bar"
@ -34,7 +34,9 @@ def test_yaml_roundtrip_with_list_and_comment():
# Template generation (preserving comments)
original_text = yaml_path.read_text(encoding="utf-8")
template = generate_template(fmt, parsed, "foobar", original_text=original_text)
template = generate_jinja2_template(
fmt, parsed, "foobar", original_text=original_text
)
# Comment preserved
assert "# Top comment" in template
@ -86,14 +88,14 @@ def test_generate_yaml_template_from_text_edge_cases():
assert "role_list_1" in tmpl
def test_generate_template_yaml_structural_fallback():
def test_generate_jinja2_template_yaml_structural_fallback():
"""
When original_text is not provided for YAML, generate_template should use
When original_text is not provided for YAML, generate_jinja2_template should use
the structural fallback path (yaml.safe_dump + handler processing).
"""
parsed = {"outer": {"inner": "val"}}
tmpl = generate_template("yaml", parsed=parsed, role_prefix="role")
tmpl = generate_jinja2_template("yaml", parsed=parsed, role_prefix="role")
# We don't care about exact formatting, just that the expected variable
# name shows up, proving we went through the structural path.