Search code examples
pythonjinja2

Jinja2 - Create python list containing objects from a prefixed list


I use Jinja2 to create a Python class from a template. My template looks like

class {{class_name}}({{base_class_name}}):
    
    def __init__(self, {{ parameters|join(', ') }}):
        {{comment}}

        super().__init__()

        {% for param in parameters%}
        self.{{param}} = {{param}}
        {%- endfor %}

        {# First variant #}
        self.parameters1 = {{parameter_list}}

        {# Second variant #}
        self.parameters2 = {{['self.'] | product(parameters) | map('join') | list}}

And my python script is defined as

from itertools import product
from pathlib import Path

import jinja2

def create_class_from_template():

    templates_path = Path(__file__).parent / 'templates'

    jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path))

    jinja_env.filters['product'] = product

    parameters = ['param1', 'param2', 'param3']  # For first variant
    parameter_list = [f'self.{param}' for param in parameters]  # For second variant

    template_variables = { 
        'class_name': 'TestClass',
        'base_class_name': 'BaseClass',
        'comment': '"""My generated class"""',
        'parameters': parameters,
        'parameter_list': parameter_list
    }

    template = jinja_env.get_template('class_template.py.jinja2')
    my_class = template.render(template_variables)

    with open('my_new_class.py', 'w') as file:
        file.write(my_class)


create_class_from_template()

Which creates the following python file

class TestClass(BaseClass):
    
    def __init__(self, param1, param2, param3):
        """My generated class"""

        super().__init__()
        
        self.param1 = param1
        self.param2 = param2
        self.param3 = param3

        self.parameters1 = ['self.param1', 'self.param2', 'self.param3']
        self.parameters2 = ['self.param1', 'self.param2', 'self.param3']

But instead of strings the list should contain the members itself, so that it is self.parameters = [self.param1, self.param2, self.param3].

Does anybody have an idea how I could create such a list using Jinja2 and Python?


Solution

  • It can work without changing your script, just make the template like this:

    class {{class_name}}({{base_class_name}}):
    
        def __init__(self, {{ parameters|join(', ') }}):
            {{comment}}
    
            super().__init__()
            {% for param in parameters%}
            self.{{param}} = {{param}}
            {%- endfor %}
    
            self.parameters = [{% for param in parameters  %}self.{{ param }}{%- if not loop.last %}, {% endif %}{% endfor %}]
    

    Slightly neater output as well. And then you only need one template variable (parameters), you can do the formatting in the template itself.

    class TestClass(BaseClass):
    
        def __init__(self, param1, param2, param3):
            """My generated class"""
    
            super().__init__()
    
            self.param1 = param1
            self.param2 = param2
            self.param3 = param3
    
            self.parameters = [self.param1, self.param2, self.param3]