Skip to content

Commit

Permalink
add TeX extension with custom jinja filters
Browse files Browse the repository at this point in the history
  • Loading branch information
weinbusch committed Feb 17, 2020
1 parent 9152158 commit e47a3d8
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 6 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,23 @@ from flask_tex import run_tex

pdf = run_tex(source, command="pdflatex", directory="/foo/bar/")
```

## Jinja integration

For deeper jinja integration, use `flask_tex` as an extension:

```python
from flask import Flask
from flask_tex import TeX

app = Flask(__app__)
TeX(app)
```

This adds some LaTeX specific filters to the jinja environment.

- LaTeX escape: `{{ foo | latex_escape }}` where `foo = "&$%#_{}"` renders as `"\\&\\$\\%\\#\\_\\{\\}"`.
Danger: Do not use this in a html template, because the escaped string is marked as safe
with `Markup`, so code that might be dangerous in html does not get escaped.

- LaTeX linebreaks: The `linebreaks` filter converts `\n` into `\\\\\n`.
41 changes: 37 additions & 4 deletions flask_tex/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,46 @@
import tempfile
from subprocess import run, PIPE, CalledProcessError

from markupsafe import Markup
from flask import render_template, make_response


class TexError(Exception):
pass


class TeX:
"""TeX Flask extension"""

def __init__(self, app=None):
self.app = app
if app:
self.init_app(app)

def init_app(self, app):
self.app = app

app.jinja_env.filters.update(
linebreaks=do_linebreaks, latex_escape=do_latex_escape,
)


def do_linebreaks(value):
return value.replace("\n", "\\\\\n")


def do_latex_escape(value):
return Markup(
value.replace("&", "\\&")
.replace("$", "\\$")
.replace("%", "\\%")
.replace("#", "\\#")
.replace("_", "\\_")
.replace("{", "\\{")
.replace("}", "\\}")
)


def render_to_pdf(template_name, filename="flask.pdf", **kwargs):
source = render_template(template_name, **kwargs)
pdf = compile_source(source)
Expand All @@ -14,10 +51,6 @@ def render_to_pdf(template_name, filename="flask.pdf", **kwargs):
return response


class TexError(Exception):
pass


def compile_source(source, command="pdflatex"):
with tempfile.TemporaryDirectory() as tempdir:
return run_tex(source, command, tempdir)
Expand Down
39 changes: 37 additions & 2 deletions tests/test_tex.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest
from subprocess import CalledProcessError

from flask import Flask
from flask import Flask, render_template_string, render_template

from flask_tex import compile_source, TexError, render_to_pdf
from flask_tex import compile_source, TexError, render_to_pdf, TeX


class TestRunTex:
Expand Down Expand Up @@ -48,3 +48,38 @@ def test_render_template_to_pdf(self):
rv = render_to_pdf("test.tex", foo="bar")

assert rv.status_code == 200

def test_no_autoescaping_in_tex_templates(self):
app = Flask(__name__)

with app.test_request_context():
rv = render_template("test.tex", foo="This \\& sign will not be escaped")

assert "This \\& sign will not be escaped" in rv

def test_newline_filter(self):
app = Flask(__name__)
TeX(app)

template_string = "{{ foo | linebreaks }}"

foo = "bar\nbaz"

with app.test_request_context():
rv = render_template_string(template_string, foo=foo)

assert rv == "bar\\\\\nbaz"

def test_latex_escape(self):
app = Flask(__name__)
TeX(app)

template_string = "{{ foo | latex_escape }}"
foo = "&$%#_{}"

with app.test_request_context():
rv = render_template_string(template_string, foo=foo)

assert (
rv == "\\&\\$\\%\\#\\_\\{\\}"
) # This works because latex_escape marks the escaped string as safe with `Markup`

0 comments on commit e47a3d8

Please sign in to comment.