66import os
77import re
88import sys
9+ from collections .abc import Mapping
910from dataclasses import dataclass
1011from pathlib import Path
1112from typing import TYPE_CHECKING , NamedTuple
1213
1314import black
1415import jinja2
1516from ansible .errors import AnsibleError , AnsibleFilterError , AnsibleParserError
16- from ansible .parsing .yaml .objects import AnsibleUnicode
1717from jinja2 .exceptions import TemplateSyntaxError
1818
1919from ansiblelint .errors import RuleMatchTransformMeta
2222from ansiblelint .runner import get_matches
2323from ansiblelint .skip_utils import get_rule_skips_from_line
2424from ansiblelint .text import has_jinja
25+ from ansiblelint .types import AnsibleTemplateSyntaxError
2526from ansiblelint .utils import ( # type: ignore[attr-defined]
2627 Templar ,
2728 parse_yaml_from_file ,
@@ -187,6 +188,13 @@ def matchtask(
187188 elif re .match (r"^lookup plugin (.*) not found$" , exc .message ):
188189 # lookup plugin 'template' not found
189190 bypass = True
191+ elif isinstance (
192+ orig_exc , AnsibleTemplateSyntaxError
193+ ) and re .match (
194+ r"^Syntax error in template: No filter named '.*'." ,
195+ exc .message ,
196+ ):
197+ bypass = True
190198
191199 # AnsibleError: template error while templating string: expected token ':', got '}'. String: {{ {{ '1' }} }}
192200 # AnsibleError: template error while templating string: unable to locate collection ansible.netcommon. String: Foo {{ buildset_registry.host | ipwrap }}
@@ -195,6 +203,7 @@ def matchtask(
195203 self .create_matcherror (
196204 message = str (exc ),
197205 lineno = task .get_error_line (path ),
206+ data = v ,
198207 filename = file ,
199208 tag = f"{ self .id } [invalid]" ,
200209 ),
@@ -214,6 +223,7 @@ def matchtask(
214223 reformatted = reformatted ,
215224 ),
216225 lineno = task .get_error_line (path ),
226+ data = v ,
217227 details = details ,
218228 filename = file ,
219229 tag = f"{ self .id } [{ tag } ]" ,
@@ -237,10 +247,10 @@ def matchyaml(self, file: Lintable) -> list[MatchError]:
237247
238248 if str (file .kind ) == "vars" :
239249 data = parse_yaml_from_file (str (file .path ))
240- if not isinstance (data , dict ):
250+ if not isinstance (data , Mapping ):
241251 return results
242252 for key , v , _path in nested_items_path (data ):
243- if isinstance (v , AnsibleUnicode ):
253+ if isinstance (v , str ):
244254 reformatted , details , tag = self .check_whitespace (
245255 v ,
246256 key = key ,
@@ -254,7 +264,7 @@ def matchyaml(self, file: Lintable) -> list[MatchError]:
254264 value = v ,
255265 reformatted = reformatted ,
256266 ),
257- lineno = v . ansible_pos [ 1 ] ,
267+ data = v ,
258268 details = details ,
259269 filename = file ,
260270 tag = f"{ self .id } [{ tag } ]" ,
@@ -506,31 +516,23 @@ def blacken(text: str) -> str:
506516 from ansiblelint .runner import Runner
507517 from ansiblelint .transformer import Transformer
508518
509- @pytest .fixture (name = "error_expected_lines" )
510- def fixture_error_expected_lines () -> list [int ]:
511- """Return list of expected error lines."""
512- return [33 , 36 , 39 , 42 , 45 , 48 , 74 ]
513-
514- # 21 68
515- @pytest .fixture (name = "lint_error_lines" )
516- def fixture_lint_error_lines () -> list [int ]:
517- """Get VarHasSpacesRules linting results on test_playbook."""
519+ def test_jinja_spacing_playbook () -> None :
520+ """Ensure that expected error lines are matching found linting error lines."""
521+ # list unexpected error lines or non-matching error lines
522+ lineno_list = [33 , 36 , 39 , 42 , 45 , 48 , 74 ]
523+ lintable = Lintable ("examples/playbooks/jinja-spacing.yml" )
518524 collection = RulesCollection ()
519525 collection .register (JinjaRule ())
520- lintable = Lintable ("examples/playbooks/jinja-spacing.yml" )
521526 results = Runner (lintable , rules = collection ).run ()
522- return [item .lineno for item in results ]
527+ assert len (results ) == len (lineno_list )
528+ for index , result in enumerate (results ):
529+ assert result .tag == "jinja[spacing]"
530+ assert result .lineno == lineno_list [index ]
523531
524- def test_jinja_spacing_playbook (
525- error_expected_lines : list [int ],
526- lint_error_lines : list [int ],
527- ) -> None :
528- """Ensure that expected error lines are matching found linting error lines."""
529- # list unexpected error lines or non-matching error lines
530- error_lines_difference = list (
531- set (error_expected_lines ).symmetric_difference (set (lint_error_lines )),
532- )
533- assert len (error_lines_difference ) == 0
532+ # error_lines_difference = list(
533+ # set(error_expected_lines).symmetric_difference(set(lint_error_lines)),
534+ # )
535+ # assert len(error_lines_difference) == 0
534536
535537 def test_jinja_spacing_vars () -> None :
536538 """Ensure that expected error details are matching found linting error details."""
@@ -833,10 +835,10 @@ def test_jinja_invalid() -> None:
833835 assert len (errs ) == 2
834836 assert errs [0 ].tag == "jinja[spacing]"
835837 assert errs [0 ].rule .id == "jinja"
836- assert errs [0 ].lineno == 9
838+ assert errs [0 ].lineno in [ 7 , 9 ] # 2.19 has better line identification
837839 assert errs [1 ].tag == "jinja[invalid]"
838840 assert errs [1 ].rule .id == "jinja"
839- assert errs [1 ].lineno == 9
841+ assert errs [1 ].lineno in [ 9 , 10 ] # 2.19 has better line identification
840842
841843 def test_jinja_valid () -> None :
842844 """Tests our ability to parse jinja, even when variables may not be defined."""
0 commit comments