funkybob / stencil

A minimalist template engine for Python3
MIT License
58 stars 8 forks source link

Can't use nested functions #23

Closed oz123 closed 2 years ago

oz123 commented 2 years ago

Hi! Thank you for publishing stencil. It's been a nice experiecnce so far: I found a bug which I don't know how to fix:


>>> def foo(a):
...     return a.replace(".", ",")
... 
>>> Template("""here is foo {{foo('asdfdsf.asdff')}}""").render({"foo": foo})
'here is foo asdfdsf,asdff'
>>> Template("""here is foo {{foo(foo('asdfdsf.asdff'))}}""").render({"foo": foo})
ohh noo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/oznt/.local/share/virtualenvs/reporting-GIGR738x/lib/python3.9/site-packages/stencil.py", line 89, in __init__
    self.nodelist = self.parse_nodelist([])
  File "/home/oznt/.local/share/virtualenvs/reporting-GIGR738x/lib/python3.9/site-packages/stencil.py", line 109, in parse_nodelist
    node = next(self.parse())
  File "/home/oznt/.local/share/virtualenvs/reporting-GIGR738x/lib/python3.9/site-packages/stencil.py", line 96, in parse
    yield VarTag(tok.content)
  File "/home/oznt/.local/share/virtualenvs/reporting-GIGR738x/lib/python3.9/site-packages/stencil.py", line 304, in __init__
    self.expr = Expression.parse(content)
  File "/home/oznt/.local/share/virtualenvs/reporting-GIGR738x/lib/python3.9/site-packages/stencil.py", line 193, in parse
    result = p._parse()
  File "/home/oznt/.local/share/virtualenvs/reporting-GIGR738x/lib/python3.9/site-packages/stencil.py", line 273, in _parse
    raise SyntaxError(f"Expected ( but found {self.current}")
SyntaxError: Expected ( but found TokenInfo(type=4 (NEWLINE), string='', start=(1, 25), end=(1, 26), line='')

As the title says. one can't call more than one function in the template.

funkybob commented 2 years ago

Hi! I honestly had no idea anyone else was using this :)

I fear trying to support a more complex syntax like that would blow out the size of the code considerably, though that's only a gut reaction. My original goal with this project was small small small!

I'm not against efforts to support it... might take a look at it this week, see what it would involve.

oz123 commented 2 years ago

I especially appreciate small. Thank you for your help.

funkybob commented 2 years ago

So I've been digging into it, and (a) the error message is wrong - it should be ) not ( (b) the code is built to support function calls as arguments

Some step is swallowing the last ) too early.

funkybob commented 2 years ago

Found it, I think! Please try the current master code, and see if that fixes your issue (it did for me using your helpful sample code)

oz123 commented 2 years ago

Thank you for the quick response and fix! As I always wanted to learn more about template engines, I started using this project. Small projects allow me to study the code more easily, and this was indeed very useful. Eventually, I started using this in a few of my projects instead of Jinja2. Having this issue fixed, helps me a lot, and I hope others too. I hope you find the time to publish a new release on PyPi soon.

$ git clone git@github.com:funkybob/stencil.git
Cloning into 'stencil'...
remote: Enumerating objects: 668, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 668 (delta 1), reused 6 (delta 1), pack-reused 660
Receiving objects: 100% (668/668), 120.28 KiB | 486.00 KiB/s, done.
Resolving deltas: 100% (385/385), done.
$ cd stencil/
$ pip install -e .
Obtaining file:///home/oznt/Software/reporting/stencil
  Preparing metadata (setup.py) ... done
Installing collected packages: stencil-template
  Running setup.py develop for stencil-template
Successfully installed stencil-template-4.2.1
$ cd ..
$ python
Python 3.9.12 (main, Jun 16 2022, 21:25:44) 
[GCC 11.2.1 20220115] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from stencil import Template
>>> def foo(a):
...     return a.replace(".", ",")
... 
>>> Template("""here is foo {{foo(foo('asdfdsf.asdff'))}}""").render({"foo": foo})
'here is foo asdfdsf,asdff'
>>> Template("""here.... is foo.... {{foo(foo('asdfdsf.asdff'))}}""").render({"foo": foo})
'here.... is foo.... asdfdsf,asdff'
>>> Template("""here.... is foo.... {{foo(foo('asdfdsf......asdff'))}}""").render({"foo": foo})
'here.... is foo.... asdfdsf,,,,,,asdff'