Debug Three Planted Bugs in the Mako Python Template Engine

Read the full interview experience this question came from →

Quick Overview

A bug-squash exercise on a copy of the Mako Python template engine with planted bugs: lambda parameters vanish from regenerated code, a directory is mistaken for a template during lookup, and a comment-only control block fails to compile. It tests tracing failures through a template compiler, minimal library fixes and regression tests.

Debug Three Planted Bugs in the Mako Python Template Engine

Company: Stripe

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Technical Screen

You are given a working copy of **Mako**, an open-source Python template engine, into which bugs have been planted. Find each bug, fix it with the smallest correct change to the library, and add a regression test for it. Background: Mako compiles every template into a Python module. It parses the template into a tree of nodes (plain text, `${...}` expressions, `%` control lines such as `% if` and `% endif`, `##` comments, and tags such as `<%def>`), parses the embedded Python with the standard `ast` module, and generates the module's source code from both. Three bugs are reported. Assume the failing tests show the symptoms described in the three parts below. ### Constraints and Clarifications - Fix the library, never the tests. You can run the test suite and any snippet you like. - Treat each symptom as the result of one planted bug, and fix them one at a time. - Mako can show the Python source it generates for a template; you may use it while debugging. ### Clarifying Questions - Am I expected to add regression tests, or only to make the existing tests pass? - When a requested template name matches a directory in one search directory and a file in a later one, should the lookup return the later file? - Should a control block whose body is only comments render nothing, or should the engine reject it with a clear error? - Which Python versions must the fixes support? The `ast` module's node types differ between versions. ### Part 1 — Parameters disappear from regenerated code When Mako turns a parsed Python expression back into source code, the parameter names of a `lambda` are lost: `lambda item: item.name` comes back as a lambda with no parameters, `lambda : item.name`. A template function whose signature has such a default value still compiles, but calling the default fails when the template renders: ```text <%def name="listing(items, key=lambda item: item.name)"> ... </%def> ``` ```hint Compare the tree with the text Print the parsed tree of `lambda item: item.name` with `ast.dump` and compare it, node by node, with what the generator writes. Find the first node whose output is missing. ``` #### What This Part Should Cover - How the missing text was traced to the code that handles one kind of `ast` node - The root cause and the minimal fix - A regression test that fails before the fix and passes after it ### Part 2 — A directory is taken for a template A template lookup is configured with several search directories. When the requested template name matches a directory inside one of them, the lookup tries to open that directory as a template and fails with an operating-system error such as `IsADirectoryError`, instead of moving on to the next search directory or raising the lookup's own "template not found" error. ```hint Reread the guard Find the check the lookup performs before it accepts a candidate path, and list every kind of filesystem entry that passes it. ``` #### What This Part Should Cover - The check that accepts the wrong candidate, and the corrected check - Behavior with several search directories, and when no directory has the template - Related cases: symbolic links, and a file that disappears between the check and the open ### Part 3 — A comment-only block fails to compile This template fails to compile with a Python syntax error, although a block whose body is only a comment should simply produce no output: ```text % if show_footer: ## the footer is disabled for now % endif ``` ```hint Compare with blocks that work Compile the same block with a line of text in its body, and with nothing at all in its body, and see which of the three variants generates valid Python. ``` #### What This Part Should Cover - Why a body made only of comments produces invalid Python - The exact rule for when an empty body needs special handling, including `% elif` and `% else` branches - Regression tests for each variant ### What a Strong Answer Covers - Reproduces each failure in isolation and inspects intermediate output (the parsed tree, the generated source) before changing code - Explains each root cause in terms of Python mechanics: `ast` node types and visitor dispatch, filesystem checks, block syntax - Minimal fixes in the style of the surrounding code, with no test edited to pass - A regression test per bug, plus the nearby variants of each - Steady progress across three unrelated areas, with hypotheses narrated while debugging ### Follow-up Questions - No existing test exercised lambda parameters. What kind of test would catch any node type the source generator mishandles, not just this one? - A new Python release adds a node type to the `ast` module. Should the generator silently skip a node it has no method for, or fail? - Should the lookup reject a requested name such as `../config/secrets.txt` that resolves outside its search directories? How would you enforce it? - A multi-line `<%doc>` comment is the only content of a control block. Does your Part 3 fix cover it?

Overview: A bug-squash exercise on a copy of the Mako Python template engine with planted bugs: lambda parameters vanish from regenerated code, a directory is mistaken for a template during lookup, and a comment-only control block fails to compile. It tests tracing failures through a template compiler, minimal library fixes and regression tests.

Read the full Stripe Software Engineer interview experience this question came from

|Home/Software Engineering Fundamentals/Stripe
Stripe logo
Stripe
Oct 14, 2026
mediumSoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
0
0

You are given a working copy of Mako, an open-source Python template engine, into which bugs have been planted. Find each bug, fix it with the smallest correct change to the library, and add a regression test for it.

Background: Mako compiles every template into a Python module. It parses the template into a tree of nodes (plain text, ${...} expressions, % control lines such as % if and % endif, ## comments, and tags such as <%def>), parses the embedded Python with the standard ast module, and generates the module's source code from both.

Three bugs are reported. Assume the failing tests show the symptoms described in the three parts below.

Constraints and Clarifications

  • Fix the library, never the tests. You can run the test suite and any snippet you like.
  • Treat each symptom as the result of one planted bug, and fix them one at a time.
  • Mako can show the Python source it generates for a template; you may use it while debugging.

Clarifying Questions Guidance

  • Am I expected to add regression tests, or only to make the existing tests pass?
  • When a requested template name matches a directory in one search directory and a file in a later one, should the lookup return the later file?
  • Should a control block whose body is only comments render nothing, or should the engine reject it with a clear error?
  • Which Python versions must the fixes support? The ast module's node types differ between versions.

Part 1 — Parameters disappear from regenerated code

When Mako turns a parsed Python expression back into source code, the parameter names of a lambda are lost: lambda item: item.name comes back as a lambda with no parameters, lambda : item.name. A template function whose signature has such a default value still compiles, but calling the default fails when the template renders:

<%def name="listing(items, key=lambda item: item.name)">
...
</%def>

What This Part Should Cover Guidance

  • How the missing text was traced to the code that handles one kind of ast node
  • The root cause and the minimal fix
  • A regression test that fails before the fix and passes after it

Part 2 — A directory is taken for a template

A template lookup is configured with several search directories. When the requested template name matches a directory inside one of them, the lookup tries to open that directory as a template and fails with an operating-system error such as IsADirectoryError, instead of moving on to the next search directory or raising the lookup's own "template not found" error.

What This Part Should Cover Guidance

  • The check that accepts the wrong candidate, and the corrected check
  • Behavior with several search directories, and when no directory has the template
  • Related cases: symbolic links, and a file that disappears between the check and the open

Part 3 — A comment-only block fails to compile

This template fails to compile with a Python syntax error, although a block whose body is only a comment should simply produce no output:

% if show_footer:
    ## the footer is disabled for now
% endif

What This Part Should Cover Guidance

  • Why a body made only of comments produces invalid Python
  • The exact rule for when an empty body needs special handling, including % elif and % else branches
  • Regression tests for each variant

What a Strong Answer Covers Guidance

  • Reproduces each failure in isolation and inspects intermediate output (the parsed tree, the generated source) before changing code
  • Explains each root cause in terms of Python mechanics: ast node types and visitor dispatch, filesystem checks, block syntax
  • Minimal fixes in the style of the surrounding code, with no test edited to pass
  • A regression test per bug, plus the nearby variants of each
  • Steady progress across three unrelated areas, with hypotheses narrated while debugging

Follow-up Questions Guidance

  • No existing test exercised lambda parameters. What kind of test would catch any node type the source generator mishandles, not just this one?
  • A new Python release adds a node type to the ast module. Should the generator silently skip a node it has no method for, or fail?
  • Should the lookup reject a requested name such as ../config/secrets.txt that resolves outside its search directories? How would you enforce it?
  • A multi-line <%doc> comment is the only content of a control block. Does your Part 3 fix cover it?