Fix Three Mako Template Bugs: AST Arg Visitor, Directory Lookup, Comment-Only Blocks
StripeSoftware Engineer · Technical ScreenLast updated
A debugging exercise on Mako, the open-source Python template library, with three injected defects: an AST visitor missing its visit_arg method, a template lookup that fails on a directory path, and comment-only control blocks that do not compile. It tests NodeVisitor dispatch, reading generated code, minimal fixes and regression tests.
You are given a copy of Mako, the open-source Python template library, into which three defects have been introduced, together with the library's test suite. Find each defect, fix it with a minimal change, and add a regression test for it. Talk through your reasoning as you go.
Background on the library:
- Mako compiles each template into a Python module and renders the template by calling a function in that module.
- A line whose first non-space character is
%is a control line that becomes a Python statement, such as% if user:…% endifor% for item in items:…% endfor. - A line whose first non-space characters are
##is a template comment. It produces no output. ${...}embeds a Python expression, and a tag such as<%def name="greet(name, punct='!')">declares a callable whose signature is written in Python syntax. The library parses this embedded Python with the standardastmodule and walks the trees withast.NodeVisitorsubclasses.- A template lookup is configured with a list of directories and resolves a template name such as
/emails/welcome.txtagainst them in order.
Constraints and Clarifications
- Exactly three defects are reported, one per Part below. When you are done, the full test suite should pass.
- Keep each fix small and local, in the style of the surrounding code, and do not change behavior beyond the defect.
- Part 1 gives you the defect and asks for its consequences; Parts 2 and 3 start from a symptom.
Clarifying Questions
- Does a failing test point at each defect, or must some be found from the symptoms alone?
- Which Python versions must the fixes support? Syntax-tree node types differ between Python 2 and 3 and across 3.x releases.
- When one lookup directory contains a folder with the requested name and a later directory contains a file with that name, which should win?
- Should a block whose body is only comments behave exactly like an empty block, for every kind of control line?
Part 1 — A missing argument handler in the AST code
One of the library's ast.NodeVisitor subclasses no longer defines a visit_arg method. Explain which Python syntax produces ast.arg nodes, what the visitor does when it meets a node type it has no method for, and what goes wrong in the library as a result. Then restore the method and write a test that would have caught its removal.
What This Part Should Cover
- How visitor dispatch works and why this failure is silent
- Which constructs produce argument nodes, including every parameter kind
- The concrete effect on the visitor's job and on templates that use such syntax
- A test that exercises argument nodes directly and through a template
Part 2 — A directory where a template file was expected
Requesting a template whose name matches a directory rather than a file, for example /emails when emails/ is a folder inside one of the lookup directories, fails with an operating-system error raised while opening that path, instead of the library's normal "template not found" error. Find the cause and fix it.
What This Part Should Cover
- The faulty check and the exact predicate that should replace it
- Behavior across several lookup directories, including a folder that shadows a real file
- At least one alternative fix and why the chosen one is better
- Tests that build the directory layout in a temporary folder
Part 3 — A control block that contains only comments
This template is valid, but compiling it fails with a Python syntax error reported inside the generated module:
% if show_banner:
## banner removed until the redesign ships
% endif
Welcome
Find out why, and fix it so that a control block whose body contains only comments compiles and renders.
What This Part Should Cover
- Why the generated module is not valid Python
- Where the generator decides that a block needs a placeholder statement, and which node types it must treat as producing nothing
- Other control forms the same mistake breaks:
% elsebranches, loops, nested blocks - Template-level regression tests
Hints
Hint 1
Read the dispatch: Look at how NodeVisitor.visit chooses a method, and at which fields an argument node carries. Does anything raise when the method is missing?
Hint 2
Compare the predicates: List what the code checks about a candidate path before it opens it, and which kinds of filesystem entries pass that check.
Hint 3
Read the generated code: Print the module source the library generated and look at the lines around the error. Then compare the statements in that block with the lines of the template block.
Follow-up questions
- How could the test suite catch a missing visitor method like the one in Part 1 automatically, before any template exercised it?
- Instead of deciding when a block needs `pass`, the generator could emit it after every control line. What does each approach cost?
- Template names sometimes come from user input. What should the lookup check beyond "is a regular file"?
- Two of these defects surface far from their cause. How would you change error reporting so that a template author can diagnose them without reading generated code?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.