From 06e3704395a1f4f36e2ece5e34aa7f7485b6e507 Mon Sep 17 00:00:00 2001 From: Alex Hall Date: Fri, 22 May 2026 14:01:55 +0200 Subject: [PATCH] Require handlebars for template field validation --- logfire/variables/_handlebars.py | 14 -------------- logfire/variables/abstract.py | 7 ------- tests/test_push_variables.py | 28 ---------------------------- 3 files changed, 49 deletions(-) diff --git a/logfire/variables/_handlebars.py b/logfire/variables/_handlebars.py index 097b25171..e4ef66db7 100644 --- a/logfire/variables/_handlebars.py +++ b/logfire/variables/_handlebars.py @@ -44,20 +44,6 @@ def ensure_handlebars_available() -> None: get_environment() -def is_handlebars_available() -> bool: - """Return True if pydantic-handlebars can be imported. - - Used by push/validate paths to skip template-field validation when the - optional dependency is missing (e.g. Python 3.9, where the `[variables]` - extra omits `pydantic-handlebars`). - """ - try: - ensure_handlebars_available() - except HandlebarsDependencyError: - return False - return True - - @cache def get_environment() -> HandlebarsEnvironment: """Return a cached `HandlebarsEnvironment` configured for `@{...}@` composition. diff --git a/logfire/variables/abstract.py b/logfire/variables/abstract.py index fe608cb79..eef6b350c 100644 --- a/logfire/variables/abstract.py +++ b/logfire/variables/abstract.py @@ -584,18 +584,11 @@ def _collect_template_field_issues( where a server-stored template was authored against an older schema that's incompatible with the current local `inputs_type`. - On Python 3.9 (where `pydantic-handlebars` is not installable), returns - an empty list — the AST-based schema check can't run, so push/validate - skip this step rather than crashing. """ - from logfire.variables._handlebars import is_handlebars_available from logfire.variables.config import LabeledValue from logfire.variables.template_validation import validate_template_composition from logfire.variables.variable import TemplateVariable, is_resolve_function - if not is_handlebars_available(): - return [] - issues: list[TemplateFieldIssue] = [] locals_by_name = {v.name: v for v in variables} diff --git a/tests/test_push_variables.py b/tests/test_push_variables.py index 1ddf661b7..00cb90313 100644 --- a/tests/test_push_variables.py +++ b/tests/test_push_variables.py @@ -226,10 +226,6 @@ def test_compute_diff_schema_change(mock_logfire_instance: MockLogfire) -> None: assert diff.has_changes is True -@pytest.mark.skipif( - __import__('importlib.util').util.find_spec('pydantic_handlebars') is None, - reason='Template field validation requires pydantic-handlebars (Python 3.10+)', -) def test_compute_diff_template_field_issues_local_default(mock_logfire_instance: MockLogfire) -> None: """A local code default that references an undeclared input field surfaces as a template_field_issue.""" @@ -256,10 +252,6 @@ class Inputs(BaseModel): assert issue.found_in_label is None -@pytest.mark.skipif( - __import__('importlib.util').util.find_spec('pydantic_handlebars') is None, - reason='Template field validation requires pydantic-handlebars (Python 3.10+)', -) def test_compute_diff_template_field_issues_server_label(mock_logfire_instance: MockLogfire) -> None: """Server-stored label values are validated against the local inputs_type schema.""" @@ -300,10 +292,6 @@ class Inputs(BaseModel): assert 'production' in labels -@pytest.mark.skipif( - __import__('importlib.util').util.find_spec('pydantic_handlebars') is None, - reason='Template field validation requires pydantic-handlebars (Python 3.10+)', -) def test_compute_diff_template_field_issues_follow_composition(mock_logfire_instance: MockLogfire) -> None: """A `{{field}}` reference inside a composed-in fragment is reported with the composition path.""" @@ -670,10 +658,6 @@ def test_validation_report_format_template_field_issues() -> None: assert report.is_valid is False -@pytest.mark.skipif( - __import__('importlib.util').util.find_spec('pydantic_handlebars') is None, - reason='Template field validation requires pydantic-handlebars (Python 3.10+)', -) def test_push_variables_strict_fails_with_template_field_issues(mock_logfire_instance: MockLogfire) -> None: """Strict push fails when template field issues are present, leaving the provider unchanged.""" @@ -693,10 +677,6 @@ class Inputs(BaseModel): assert provider.get_all_variables_config().variables == {} -@pytest.mark.skipif( - __import__('importlib.util').util.find_spec('pydantic_handlebars') is None, - reason='Template field validation requires pydantic-handlebars (Python 3.10+)', -) def test_compute_diff_template_field_issues_skips_label_refs(mock_logfire_instance: MockLogfire) -> None: """LabelRef entries in server labels are skipped when collecting serialized values for validation.""" @@ -733,10 +713,6 @@ class Inputs(BaseModel): assert diff.template_field_issues == [] -@pytest.mark.skipif( - __import__('importlib.util').util.find_spec('pydantic_handlebars') is None, - reason='Template field validation requires pydantic-handlebars (Python 3.10+)', -) def test_compute_diff_template_field_issues_tolerates_unserializable_composed_ref( mock_logfire_instance: MockLogfire, ) -> None: @@ -781,10 +757,6 @@ class Inputs(BaseModel): assert all(issue.found_in_variable != 'fragment' for issue in diff.template_field_issues) -@pytest.mark.skipif( - __import__('importlib.util').util.find_spec('pydantic_handlebars') is None, - reason='Template field validation requires pydantic-handlebars (Python 3.10+)', -) def test_compute_diff_template_field_issues_from_latest_version(mock_logfire_instance: MockLogfire) -> None: """A server `latest_version` value (without label coverage) is validated against the local inputs_type."""