Separately, I've been studying the differences between Django's template language and Jinja2 and I'm considering implementing the latter natively as well, especially because: there'd be a lot of shared code; the Django integration glue is already there; and it seems to allow even more opportunities for speed gains. Any thoughts?
Thanks for the offer! Currently, the best thing I can think of is to actually try it on real projects and report significant issues and differences in output.
One relatively small improvement I just thought of is to allow template loaders to parse top-level templates from a file path rather than accepting the source as a string. (Perhaps this is possible already?)
Though by far, the trickiest parts of the binding layer are the various gymnastics necessary to make arbitrary custom tags work (custom filters being much simpler.) I have some ideas about how that could be improved which I'll elaborate in a follow-up post.
* Ubuntu 14.04.1 SMP / Linux 3.13.0-32-generic / 6GB RAM:
~/code/synth$ python tests/timings.py
Loaded synth; version: 1.0.3
=== Prepping ===
Directories: ('tests/templates/django/blog', 'tests/templates/django', '.')
Data: {'bar': 2, 'qux': 3, 'posts': [{'url': 'http://example.org/posts/1', 'category': 'movies', 'title': 'Rocky'}, {'url': 'http://example.org/posts/2', 'category': 'shows', 'title': 'Blackjack'}], 'user': 'Dolph Lundgren', 'subtitle': 'A blog about movies and TV shows', 'foo': 1, 'categories': [{'url': 'http://example.org/categories/movies', 'title': 'Movies'}, {'url': 'http://example.org/categories/shows', 'title': 'Shows'}]} Files: ['base.html', 'home.html', 'index.html', 'A.tpl', 'B.tpl', 'base.tpl', 'C.tpl', 'D.tpl', 'derived.tpl', 'empty.tpl', 'layout.html', 'messages.html', 'variables.tpl', 'X.tpl']
Debug: False
=== Starting ===
Iterations: 1000
Django: 0.384s; Synth: 0.018s; +/-: 21.6x; File: 'base.html'
Django: 1.301s; Synth: 0.077s; +/-: 16.8x; File: 'home.html'
Django: 1.042s; Synth: 0.070s; +/-: 14.8x; File: 'index.html'
Django: 0.276s; Synth: 0.012s; +/-: 23.8x; File: 'A.tpl'
Django: 0.555s; Synth: 0.016s; +/-: 34.9x; File: 'B.tpl'
Django: 0.326s; Synth: 0.014s; +/-: 22.9x; File: 'base.tpl'
Django: 0.835s; Synth: 0.022s; +/-: 37.4x; File: 'C.tpl'
Django: 1.081s; Synth: 0.027s; +/-: 40.3x; File: 'D.tpl'
Django: 0.694s; Synth: 0.023s; +/-: 29.6x; File: 'derived.tpl'
Django: 0.229s; Synth: 0.008s; +/-: 29.8x; File: 'empty.tpl'
Django: 1.338s; Synth: 0.055s; +/-: 24.2x; File: 'layout.html'
Django: 0.573s; Synth: 0.021s; +/-: 27.8x; File: 'messages.html'
Django: 0.413s; Synth: 0.017s; +/-: 24.1x; File: 'variables.tpl'
Django: 0.549s; Synth: 0.016s; +/-: 34.8x; File: 'X.tpl'
Average: 27.4x
=== Finished ===
* Mac OS X 10.9.4 Mavericks / Intel Core i7 2.7GHz / 16GB RAM:
/Projects/code/synth$ python3 tests/timings.py
Loaded synth; version: 1.0.3
=== Prepping ===
Directories: ('tests/templates/django/blog', 'tests/templates/django', '.')
Data: {'categories': [{'title': 'Movies', 'url': 'http://example.org/categories/movies'}, {'title': 'Shows', 'url': 'http://example.org/categories/shows'}], 'posts': [{'title': 'Rocky', 'url': 'http://example.org/posts/1', 'category': 'movies'}, {'title': 'Blackjack', 'url': 'http://example.org/posts/2', 'category': 'shows'}], 'user': 'Dolph Lundgren', 'qux': 3, 'subtitle': 'A blog about movies and TV shows', 'foo': 1, 'bar': 2} Files: ['base.html', 'home.html', 'index.html', 'A.tpl', 'B.tpl', 'base.tpl', 'C.tpl', 'D.tpl', 'derived.tpl', 'empty.tpl', 'layout.html', 'messages.html', 'variables.tpl', 'X.tpl']
Debug: False
=== Starting ===
Iterations: 1000
Django: 0.352s; Synth: 0.030s; +/-: 11.9x; File: 'base.html'
Django: 1.733s; Synth: 0.128s; +/-: 13.5x; File: 'home.html'
Django: 1.337s; Synth: 0.117s; +/-: 11.4x; File: 'index.html'
Django: 0.284s; Synth: 0.018s; +/-: 16.0x; File: 'A.tpl'
Django: 0.683s; Synth: 0.027s; +/-: 25.7x; File: 'B.tpl'
Django: 0.353s; Synth: 0.022s; +/-: 15.8x; File: 'base.tpl'
Django: 1.066s; Synth: 0.034s; +/-: 31.3x; File: 'C.tpl'
Django: 1.451s; Synth: 0.041s; +/-: 35.2x; File: 'D.tpl'
Django: 0.852s; Synth: 0.036s; +/-: 23.9x; File: 'derived.tpl'
Django: 0.239s; Synth: 0.016s; +/-: 14.9x; File: 'empty.tpl'
Django: 2.014s; Synth: 0.084s; +/-: 24.0x; File: 'layout.html'
Django: 0.750s; Synth: 0.047s; +/-: 15.9x; File: 'messages.html'
Django: 0.417s; Synth: 0.028s; +/-: 15.0x; File: 'variables.tpl'
Django: 0.622s; Synth: 0.027s; +/-: 23.0x; File: 'X.tpl'
Average: 19.8x
=== Finished ===
* Windows 8.1 Pro / Intel Core i7-4790 3.60Ghz / 16GB RAM:
c:\code\synth>python.exe tests\timings.py
Loaded synth; version: 1.0.3
=== Prepping ===
Directories: ('tests/templates/django/blog', 'tests/templates/django', '.')
Data: {'user': 'Dolph Lundgren', 'subtitle': 'A blog about movies and TV shows', 'foo': 1, 'posts': [{'url': 'http://example.org/posts/1', 'category': 'movies', 'title': 'Rocky'}, {'url': 'http://exam : 'Shows'}], 'qux': 3, 'bar': 2}
Files: ['base.html', 'home.html', 'index.html', 'A.tpl', 'B.tpl', 'base.tpl', 'C.tpl', 'D.tpl', 'derived.tpl', 'empty.tpl', 'layout.html', 'messages.html', 'variables.tpl', 'X.tpl']
Debug: False
=== Starting ===
Iterations: 1000
Django: 0.339s; Synth: 0.049s; +/-: 7.0x; File: 'base.html'
Django: 1.438s; Synth: 0.152s; +/-: 9.4x; File: 'home.html'
Django: 1.089s; Synth: 0.126s; +/-: 8.6x; File: 'index.html'
Django: 0.274s; Synth: 0.035s; +/-: 7.8x; File: 'A.tpl'
Django: 0.680s; Synth: 0.056s; +/-: 12.1x; File: 'B.tpl'
Django: 0.326s; Synth: 0.038s; +/-: 8.7x; File: 'base.tpl'
Django: 1.049s; Synth: 0.077s; +/-: 13.6x; File: 'C.tpl'
Django: 1.431s; Synth: 0.096s; +/-: 14.9x; File: 'D.tpl'
Django: 0.797s; Synth: 0.065s; +/-: 12.2x; File: 'derived.tpl'
Django: 0.220s; Synth: 0.030s; +/-: 7.2x; File: 'empty.tpl'
Django: 1.566s; Synth: 0.092s; +/-: 17.1x; File: 'layout.html'
Django: 0.632s; Synth: 0.052s; +/-: 12.1x; File: 'messages.html'
Django: 0.391s; Synth: 0.042s; +/-: 9.3x; File: 'variables.tpl'
Django: 0.619s; Synth: 0.055s; +/-: 11.2x; File: 'X.tpl'
Average: 10.8x
=== Finished ===