Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Macro recursion issue: Variables in macros are not stored on the stack #577

Closed
oberlies opened this issue Nov 6, 2015 · 2 comments · Fixed by #653
Closed

Macro recursion issue: Variables in macros are not stored on the stack #577

oberlies opened this issue Nov 6, 2015 · 2 comments · Fixed by #653
Labels

Comments

@oberlies
Copy link

oberlies commented Nov 6, 2015

Consider the following template that renders a list of fully qualified property names from a JSON schema:

{% macro typeTable(node, prefix = "", name = "" %}
  {% set nodeName = prefix + ("." if prefix) + name) %}
  {% if nodeName %}
    <tr>
      <td><code>{{ nodeName | safe }}</code></td>
      <td>{{ node.type }}</td>
      <td>
        {% markdown %}{{ node.description }}{% endmarkdown %}
      </td>
    </tr>
  {% endif %}
  {% if node.type == "object" %}
    {% for propName, propSpec in node.properties %}
      {{ typeTable(propSpec, nodeName, propName) }}
    {% endfor %}
  {% endif %}
{% endmacro %}

<body>
  <table class='table table-bordered'>
    <thead>
      <tr>
        <th>Qualified name</th>
        <th>Type</th>
        <th>Description</th>
      </tr>
    </thead>
    <tbody>
      {{ typeTable(schema) }}
    </tbody>
  </table>
</body>

Where schema is for example the following JSON schema

{
  "$schema": "http://json-schema.org/draft-04/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "The ID of the node"
    },
    "name": {
      "type": "string",
      "description": "The name of the node"
    },
    "status": {
      "type": "object",
      "description": "The status of the node",
      "properties": {
        "vm": {
          "type": "string"
        },
        "app": {
          "type": "string"
        }
      }
    },
    "url": {
      "type": "string",
      "format": "uri",
      "description": "The URL of the node"
    }
  }
}

The expected result is a table with the following "qualified names":

id
name
status
status.vm
status.app
url

However the variable nodeName seems to scoped per declaration (i.e. there is only one instance) and not scoped per invocation. This means that changes to nodeName in recursive calls of typeTable can be seen by the caller. This results in the following "qualified names":

id
id.name
id.name.status
id.name.status.vm
id.name.status.vm.app
id.name.status.vm.app.url
@oberlies
Copy link
Author

oberlies commented Nov 6, 2015

The workaround for this issue is to not use any variables in macros that are called recursively. Instead, declare all local variables as parameters with default values. I.e. instead of

{% macro typeTable(node, prefix = "", name = "" %}
  {% set nodeName = prefix + ("." if prefix) + name) %}
  ...

write

{% macro typeTable(node, prefix = "", name = "", nodeName = prefix + ("." if prefix) + name) %}
  ...

Nevertheless, it would be nice if variables in macros worked as expected

@carljm carljm added the bug label Nov 6, 2015
@ptusch
Copy link

ptusch commented Jan 19, 2016

Vote up
A really annoying bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants