def test_str_method_calls(): template = '''{{ x.endswith(suffix) }}''' call_ast = parse(template).find(nodes.Call) rtype, struct = visit_call(call_ast, get_scalar_context(call_ast)) expected_rtype = Boolean() assert rtype == expected_rtype expected_struct = Dictionary({ 'x': String(label='x', linenos=[1]), # TODO suffix must be in struct too }) assert struct == expected_struct template = '''{{ x.split(separator) }}''' call_ast = parse(template).find(nodes.Call) ctx = Context(return_struct_cls=Unknown, predicted_struct=Unknown.from_ast(call_ast)) rtype, struct = visit_call(call_ast, ctx) expected_rtype = List(String()) assert rtype == expected_rtype expected_struct = Dictionary({ 'x': String(label='x', linenos=[1]), 'separator': String(label='separator', linenos=[1]), }) assert struct == expected_struct
def test_basics_4(): template = ''' {% set xys = [ ('a', 0.3), ('b', 0.3), ] %} {% if configuration is undefined %} {% set configuration = 'prefix-' ~ timestamp %} {% endif %} queue: {{ queue if queue is defined else 'wizard' }} description: >- {% for x, y in xys %} {{ loop.index }}: {{ x }} {{ y }} {% endfor %} ''' struct = infer(template) expected_struct = Dictionary({ 'configuration': String(label='configuration', may_be_defined=True, checked_as_undefined=True, constant=False, linenos=[6, 7]), 'queue': Scalar(label='queue', checked_as_defined=True, constant=False, linenos=[9]), 'timestamp': String(label='timestamp', constant=False, linenos=[7]) }) assert struct == expected_struct
def test_macro_visitor_1(): template = ''' {% macro input(name, value='', type='text', size=20) -%} <input type="{{ type }}" name="{{ name }}" value="{{value|e }}" size="{{ size }}"> {{ x }} {%- endmacro %} ''' ast = parse(template).find(nodes.Macro) macroses = {} struct = visit_macro(ast, macroses) expected_macro = Macro('input', [ ('name', Scalar(label='argument #1', linenos=[2])), ], [ ('value', String(label='argument "value"', linenos=[2])), ('type', String(label='argument "type"', linenos=[2])), ('size', Number(label='argument "size"', linenos=[2])), ]) macro = macroses['input'] assert macro.name == expected_macro.name assert macro.args == expected_macro.args assert macro.kwargs == expected_macro.kwargs expected_struct = Dictionary({'x': Scalar(label='x', linenos=[4])}) assert struct == expected_struct
def test_join_filter(): ast = parse('{{ xs|join(separator|default("|")) }}').find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) assert rtype == String(label='xs', linenos=[1]) assert struct == Dictionary({ 'xs': List(String(), label='xs', linenos=[1]), 'separator': String(label='separator', linenos=[1], used_with_default=True), })
def test_string_filters(): for filter in ('striptags', 'capitalize', 'title', 'upper', 'urlize'): template = '{{ x|' + filter + ' }}' ast = parse(template).find(nodes.Filter) ctx = Context(return_struct_cls=Scalar, predicted_struct=Scalar.from_ast(ast)) rtype, struct = visit_filter(ast, ctx) expected_rtype = String(label='x', linenos=[1]) expected_struct = Dictionary({ 'x': String(label='x', linenos=[1]), }) assert rtype == expected_rtype assert struct == expected_struct
def test_basics_15(): # 1. Accept no unknown filter (default behavior) config = Config() template = ''' {% for item in items %} {{ item.attr1|lower }} {{ item.attr2|bar }} {% endfor %} ''' with pytest.raises(InvalidExpression) as e: infer(template, config) assert 'line 4: unknown filter "bar"' == str(e.value) # 2. Accept all unknown filters config = Config() config.IGNORE_UNKNOWN_FILTERS = True template = ''' {% for item in items %} {{ item.attr1|lower }} {{ item.attr2|bar }} {% endfor %} ''' struct = infer(template, config) expected_struct = Dictionary({ 'items': List(Dictionary({ 'attr1': String(label='attr1', linenos=[3]), 'attr2': Unknown(label='attr2', linenos=[4]) }, label='item', linenos=[3, 4]), label='items', linenos=[2]), }) assert struct == expected_struct
def test_list_becomes_dict(): template = ''' {% for r in PrjList %} <tr><td><a class='btn btn-primary' href='/part/prj/{{ r[0] }}'>Select</a></td> <td> {{ r[1] }} [{{ r[0] }}] {{ ("<a href='mailto:"+r['email']+"'>") |safe if r['email'] }}</td> <td>{{ r['samplecount'] }}</td> </tr> {% endfor %} ''' struct = infer(template) expected_struct = Dictionary({ 'PrjList': List(Dictionary( { 0: Scalar(), 1: Scalar(), 'email': String(label="email", linenos=[4]), 'samplecount': Scalar(label="samplecount", linenos=[5]), }, label="r", linenos=[3, 4, 5]), label="PrjList", linenos=[2]), }) assert struct == expected_struct
def test_assign_2(): template = '''{% set y = "-" ~ y %}''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({'y': String(label='y', linenos=[1])}) assert struct == expected_struct
def test_basics_3(): template = ''' {% if x %} {% set x = '123' %} {% else %} {% set x = '456' %} {% endif %} {{ x }} ''' struct = infer(template) expected_struct = Dictionary({ 'x': String(label='x', linenos=[2, 3, 5, 7]), }) assert struct == expected_struct template = ''' {% if z %} {% set x = '123' %} {% else %} {% set x = '456' %} {% endif %} {{ x }} ''' struct = infer(template) expected_struct = Dictionary({ 'z': Unknown(label='z', linenos=[2]), }) assert struct == expected_struct
def test_2(): template = ''' {% if x is undefined %} {% set x = 'atata' %} {% endif %} {{ x }} {% if y is defined %} {# pass #} {% else %} {% set y = 'atata' %} {% endif %} {{ y }} ''' struct = infer(template) expected_struct = Dictionary({ 'x': String(linenos=[2, 3, 5], label='x', constant=False, may_be_defined=True), 'y': String(linenos=[7, 10, 12], label='y', constant=False, may_be_defined=True), }) assert struct == expected_struct template = ''' {{ x }} {% if x is undefined %} {% set x = 'atata' %} {% endif %} {{ x }} ''' struct = infer(template) expected_struct = Dictionary({ 'x': String(linenos=[2, 3, 4, 6], label='x', constant=False, may_be_defined=False), }) assert struct == expected_struct
def test_default_filter(): template = '''{{ x|default('g') }}''' ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) expected_struct = Dictionary({ 'x': String(label='x', linenos=[1], used_with_default=True), }) assert struct == expected_struct
def test_string_filter(): template = '{{ x|string }}' ast = parse(template).find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) assert rtype == String(label='x', linenos=[1]) expected_struct = Dictionary({ 'x': Scalar(label='x', linenos=[1]), }) assert struct == expected_struct
def test_hints_1(config): template = """ <html> <script src="{{ url_for(a, filename='vue.js') }}"></script> </html> """ struct = infer(template, config) expected_struct = Dictionary({ 'a': String(label='a', linenos=[3]), }) assert struct == expected_struct
def test_dict_get(): template = ''' {%if g.get(slswtch, 0) == 2 %} <link rel=stylesheet type=text/css href="/css/select2.css')"> {%endif %} {{ slswtch | safe }} ''' struct = infer(template) expected_struct = Dictionary( {'slswtch': String(label="slswtch", linenos=[2, 5])}) assert struct == expected_struct
def test_lipsum_call(): template = '{{ lipsum(n) }}' ast = parse(template).find(nodes.Call) rtype, struct = visit_call(ast, Context(predicted_struct=Unknown())) expected_rtype = String() assert rtype == expected_rtype expected_struct = Dictionary({ 'n': Scalar(label='n', linenos=[1]), # TODO must be Number }) assert struct == expected_struct
def test_basics_11(): template = ''' {{ a|xmlattr }} {{ a.attr1|join(',') }} {{ a.attr2|default([])|first }} {{ a.attr3|default('gsom') }} {% for x in xs|rejectattr('is_active') %} {{ x }} {% endfor %} ''' struct = infer(template) expected_struct = Dictionary({ 'a': Dictionary( { 'attr1': List(String(), label='attr1', linenos=[3]), 'attr2': List(Scalar(linenos=[4]), label='attr2', linenos=[4], used_with_default=True), 'attr3': String(label='attr3', linenos=[5], used_with_default=True, value='gsom') }, label='a', linenos=[2, 3, 4, 5]), 'xs': List( Scalar(label='x', linenos=[ 7 ]), # TODO it should be Dictionary({'is_active': Unknown()}) label='xs', linenos=[6]), }) assert struct == expected_struct
def test_assign_4(): template = '''{% set a, b = 1, {'gsom': 'gsom', z: z} %}''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({ 'a': Number(label='a', linenos=[1], constant=True, value=1), 'b': Dictionary(data={ 'gsom': String(linenos=[1], constant=True, value='gsom'), }, label='b', linenos=[1], constant=True), 'z': Scalar(label='z', linenos=[1]), }) assert struct == expected_struct
def test_assignment(): template = ''' {% set args = ['foo'] if foo else [] %} {% set args = args + ['bar'] %} {% set args = args + (['zork'] if zork else []) %} f({{ args|join(sep) }}); ''' struct = infer(template) expected_struct = Dictionary({ 'foo': Unknown(label='foo', linenos=[2]), 'zork': Unknown(label='zork', linenos=[4]), 'sep': String(label='sep', linenos=[5]) }) assert struct == expected_struct
def test_3(): config = Config(BOOLEAN_CONDITIONS=True) template = ''' {%- if new_configuration is undefined %} {%- if production is defined and production %} {% set new_configuration = 'prefix-' ~ timestamp %} {%- else %} {% set new_configuration = 'prefix-' ~ timestamp %} {%- endif %} {%- endif %} ''' struct = infer(template, config) expected_struct = Dictionary({ 'new_configuration': String(label='new_configuration', may_be_defined=True, checked_as_undefined=True, linenos=[2, 4, 6]), 'production': Boolean(label='production', checked_as_defined=True, linenos=[3]), 'timestamp': String(label='timestamp', linenos=[4, 6]), }) assert struct == expected_struct
def test_splitlines(): template = ''' {% macro NL2BR (text) -%} {% for line in (text or '').splitlines() %} {{line}}<br> {% endfor %} {%- endmacro %} {{ NL2BR(vin) }} ''' struct = infer(template) expected_struct = Dictionary({ 'vin': String(label="vin", linenos=[2, 7]), }) assert struct == expected_struct
def test_assign_5(): template = ''' {%- set weights = [ ('A', {'data': 0.3}), ('B', {'data': 0.9}), ] %} ''' ast = parse(template).find(nodes.Assign) struct = visit_assign(ast) expected_struct = Dictionary({ 'weights': List(Tuple([ String(linenos=[3, 4], constant=True), Dictionary({ 'data': Number(linenos=[3, 4], constant=True) }, linenos=[3, 4], constant=True), ], linenos=[3, 4], constant=True), label='weights', linenos=[2], constant=True) }) assert struct == expected_struct
def test_tuple_as_list(): template = ''' {% macro selectinputtuple(name, values, value='') -%} <select class="form-control" name="{{ name }}" id="{{ name }}"> {% for v2 in values %} <option value="{{ v2[0] }}" {{ 'selected' if value==v2[0] }}>{{ v2[1] }}</option> {% endfor %} </select> {%- endmacro %} </td><td style="padding-right: 5px;">{{ selectinputtuple("ipp",[('0','Fit'),('1','1'),('1000','1000')],data.ipp) }} ''' struct = infer(template) expected_struct = Dictionary({ 'data': Dictionary(label="data", data={ 'ipp': String(label="ipp", linenos=[2, 9], value=""), }, linenos=[9]), }) assert struct == expected_struct
def test_to_json_schema(): struct = Dictionary({ 'list': List(Tuple((Dictionary({ 'field': Scalar(label='field', linenos=[3]), }, label='a', linenos=[3]), Scalar(label='b', linenos=[4])), linenos=[2]), label='list', linenos=[2]), 'x': Unknown(may_be_defined=True), 'number_var': Number(), 'string_var': String(), 'boolean_var': Boolean(), }) scalar_anyof = [ { 'type': 'boolean' }, { 'type': 'null' }, { 'type': 'number' }, { 'type': 'string' }, ] unknown_anyof = [ { 'type': 'object' }, { 'type': 'array' }, { 'type': 'string' }, { 'type': 'number' }, { 'type': 'boolean' }, { 'type': 'null' }, ] json_schema = core.to_json_schema(struct) assert json_schema['type'] == 'object' assert set(json_schema['required']) == set( ['string_var', 'list', 'boolean_var', 'number_var']) assert json_schema['properties'] == { 'list': { 'title': 'list', 'type': 'array', 'items': { 'type': 'array', 'items': [{ 'title': 'a', 'type': 'object', 'required': ['field'], 'properties': { 'field': { 'anyOf': scalar_anyof, 'title': 'field' } }, }, { 'title': 'b', 'anyOf': scalar_anyof, }], }, }, 'x': { 'anyOf': unknown_anyof, }, 'number_var': { 'type': 'number', }, 'string_var': { 'type': 'string', }, 'boolean_var': { 'type': 'boolean', }, }
def test_wordcount_filter(): ast = parse('{{ x|wordcount }}').find(nodes.Filter) rtype, struct = visit_filter(ast, get_scalar_context(ast)) assert rtype == Number(label='x', linenos=[1]) assert struct == Dictionary({'x': String(label='x', linenos=[1])})