Katkat

Fix Three Mako Template Bugs: AST Arg Visitor, Directory Lookup, Comment-Only Blocks

StripeSoftware Engineer · Technical Screen

Last 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: … % endif or % 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 standard ast module and walks the trees with ast.NodeVisitor subclasses.
  • A template lookup is configured with a list of directories and resolves a template name such as /emails/welcome.txt against 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: % else branches, 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?