Thank you Guido, Chris, Matt and Richard for your feedback to my last email.

Here is an updated version called "Template Literals".

I am looking for a core developer who can sponsor this PEP.

Please speak up if you want to help me.

Regards,
  Thomas Güttler

Source and updates: Pre-PEP 9999
<https://github.com/guettli/peps/blob/master/pep-9999.rst>

PEP: 9999
Title: Template Literals
Author: Thomas Güttler <info at thomas-guettler.de>
Sponsor: TODO
Status: Draft
Type: Standards Track
Content-Type: text/x-rst </dev/peps/pep-0012>
Created: 08-Jun-2021
Python-Version: TODO
Post-History: 08-Jun-2021
------------------------------

Contents

   - Abstract <#abstract>
   - Motivation <#motivation>
   - Rationale <#rationale>
   - Specification <#specification>
   - Security Implications <#security-implications>
   - Reference Implementation <#reference-implementation>
   - Alternative Ideas <#alternative-ideas>
   - Rejected Ideas <#rejected-ideas>
   - Open Issues <#open-issues>
   - References <#references>
   - Copyright <#copyright>

Abstract <#id6>

This PEP adds Template Literals to Python.

To avoid code injection like XSS or SQL-injection Template Literals can
help you to write save Python code.

Template Literals provide an easy way to access the local and global
variables (like f-strings), so that passing a dictionary to the Template is
not necessary.
Motivation <#id7>

In the context of web development Python can do more than providing REST
APIs via http. With the trend to Server-Side-Rendering, we face a
fundamental question:

How to create HTML with Python?

If you use the FrOW pattern (HTML fragments over the wire) [1] <#frow>,
then you will be writing small methods returning small HTML fragments.

As a developer I want to pass escaped data into template literals to be as
simple as possible.
Rationale <#id8>

Imagine you want to create a small HTML fragment in Python, and return it
as HTTP-Response:

   HttpResponse(f'''
<h1>Hi {name}</h1>
Your messages: {messages}''')

The problem in above example is, that no escaping gets done.

In above example "name" and "messages" should be treated differently.

The variable "name" should get escaped. For example if the name is "Mary &
Bob", the result should be "Mary &amp; Bob".

The variable "messages" contains HTML which is already escaped. It should
not be escaped again.

Most frameworks have a way to do this conditional escaping.

For example Django uses conditional_escape()
<https://docs.djangoproject.com/en/3.2/ref/utils/#django.utils.html.conditional_escape>
 [2] <#id2>

With the help of conditional_escape() the above problem could be solved
like this:

HttpResponse(f'''
    <h1>Hi {conditional_escape(name)}</h1>
    Your messages: {conditional_escape(messages)}''')

This solution has two drawbacks:

   1. It is too verbose. Typing "conditional_escape(...)" again and again
   is cumbersome.
   2. If a conditional_escape() gets forgotten Cross-site scripting attacks
   could be possible, since malicious users could inject HTML.

Specification <#id9>

Template Literals use backticks (like JavaScript Template Literals
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals>
 [3] <#id4>)

Example:

name = 'Mary & Bob'
messages = `<ul><li>message1</li><li>message2</li></ul>`
return HttpResponse(`
    <h1>Hi {name}</h1>
    Your messages: {messages}

    Today: {datetime.date.today()}`)

Expressions within curly braces get handled liked in f-strings (PEP-498).

The Template Literal creates an instance of the new class
types.TemplateLiteral.

types.TemplateLiteral has two attributes:

   - template: The raw string inside the backticks.
   - tokens: A list of tuples: (value, is_literal).

For above example this would mean:

template = '''
    <h1>Hi {name}</h1>
    Your messages: {messages}

    Today: {datetime.date.today()}'''

tokens = [
    ('\n        <h1>Hi ', True),
    ('Mary & Bob', False),
    ('</h1>\n        Your messages: ', True),
    (<TemplateLiteral "<ul><li>message1</li><li>message2</li></ul>">, False),
    ('\n\n        Today: ', True),
    (<datetime.date(2021, 6, 9)>, False)
    ]

It is outside this PEP how a consumer of TemplateLiteral handles this data
structure.

For example the Django web framework could transform a TemplateLiteral to a
SafeString like this:

def template_literal_to_safestring(template_literal):
    return mark_safe(
        ''.join(
            [
                conditional_escape(value) if not is_literal else value
                for (value, is_literal) in template_literal.tokens
            ]
        )
    )

This PEP is not related or constraint to the Django framework. It is even
not related to HTML. It can be used for any kind of templating.
Security Implications <#id10>

Template Literals can execute arbitrary code (like f-strings).

Template Literals get created by Python developers, not by users. If you
want to make templates available for users (for example if you develop a
CMS), then please use a different solution.
Reference Implementation <#id11>

TODO
Alternative Ideas <#id12>

Instead of backticks for example t'...' could be used.
Rejected Ideas <#id13>

TODO
Open Issues <#id14>

TODO
References <#id15>
[1] <#id1> FrOW, "HTML Fragments Over the Wire". Frameworks like Unpoly,
Hotwire or htmx.
[2] <#id3>
https://docs.djangoproject.com/en/3.2/ref/utils/#django.utils.html.conditional_escape
[3] <#id5>
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Copyright <#id16>

This document is placed in the public domain or under the CC0-1.0-Universal
license, whichever is more permissive.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/LYAC7JC5253QISKDLRMUCN27GZVIUWZC/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to