Opened 17 years ago

Closed 11 years ago

Last modified 10 years ago

#7261 closed New feature (fixed)

Support for __html__ for Library interoperability

Reported by: Armin Ronacher Owned by: Unai Zalakain
Component: Template system Version: dev
Severity: Normal Keywords: __html__
Cc: miracle2k, oliver@…, Wil Clouser, ivank, jdunck@… Triage Stage: Accepted
Has patch: yes Needs documentation: yes
Needs tests: yes Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

The pylons developers proposed the __html__ special method to determine the HTML representation of strings which is currently implemented by Pylons for mako, Jinja2 and soon Genshi. Having support for that in Django would make it possible to use the autoescaping facilities of these template engines in Django.

The idea is that if an object implements __html__ which returns a string this is used as HTML representation (eg: on escaping). If the object is a str or unicode subclass and returns itself the object is a safe string type.

This Genshi ticket shows some details about it: http://genshi.edgewall.org/ticket/202

Attachments (2)

html.diff (2.4 KB ) - added by Jeff Balogh 15 years ago.
implement html on SafeData for template engine interop
7261-add-__html__.diff (1.9 KB ) - added by ivank 14 years ago.
html.diff updated for django trunk

Download all attachments as: .zip

Change History (24)

comment:1 by edgarsj, 17 years ago

Triage Stage: UnreviewedDesign decision needed

comment:2 by David Cramer, 16 years ago

There is no reason this should not be in Django. I may write up a patch once I read up on how it's used everywhere. This could then easily replace the auto-escaping system which is in Django, for a better, standardized system.

comment:3 by Malcolm Tredinnick, 16 years ago

This shouldn't be thought of as *replacement* for autoescaping, since that's not required, but as something that uses it for interoperability. It's a feature addition. It looks like the __html__ method will be something along the lines of

#!
def __html__(self):
    return mark_safe(conditional_escape(self))

Possibly with a force_unicode or force_str call at the end, since it's not clear whether this method is expected to return an object that can be stringified or a bytestring or anything basestring-derived.

There's also the flip side to this, which is adjusting conditional_escape to know how to handle objects with this special method name. That should only be two or three lines as well, by the looks of it.

Note, however, that there is at least one reason for not including it: it goes against Python's guidelines of not introducing methods with leading and trailing double-underscores. It's the one namespace that Python has really reserved for internal object-level methods since pretty much forever. We'll have to make a decision about whether breaking that rule is acceptable.

comment:4 by miracle2k, 16 years ago

Cc: miracle2k added

comment:5 by miracle2k, 16 years ago

Summary: Support for __html__ for Library interobabilitySupport for __html__ for Library interoperability

comment:6 by anonymous, 15 years ago

Cc: oliver@… added

by Jeff Balogh, 15 years ago

Attachment: html.diff added

implement html on SafeData for template engine interop

comment:7 by Jeff Balogh, 15 years ago

Has patch: set
Owner: changed from nobody to Jeff Balogh
Status: newassigned

comment:8 by Wil Clouser, 15 years ago

Cc: Wil Clouser added

comment:9 by Malcolm Tredinnick, 14 years ago

Where is the spec for how this __html__() method is meant to work and what API guarantees it offers? Adding a method just to support introducing security problems isn't a good idea. Is there *any* documentation for how it's supposed to work?

comment:10 by Armin Ronacher, 14 years ago

How is that introducing security problems?

The spec is literally: "if an object has an html method it can be used to get a safe html representation of the object in unicode that is guaranteed to be convertible into an unicode string but might be a unicode string subclass". End of spec :)

by ivank, 14 years ago

Attachment: 7261-add-__html__.diff added

html.diff updated for django trunk

comment:11 by ivank, 14 years ago

Cc: ivank added

comment:12 by Luke Plant, 14 years ago

Severity: Normal
Type: New feature

comment:13 by Alex Gaynor, 13 years ago

Easy pickings: unset
Triage Stage: Design decision neededAccepted
UI/UX: unset

comment:14 by Kamu, 11 years ago

Needs documentation: set
Needs tests: set
Patch needs improvement: set

comment:15 by Kamu, 11 years ago

Owner: Jeff Balogh removed
Status: assignednew

comment:16 by Unai Zalakain, 11 years ago

Owner: set to Unai Zalakain
Status: newassigned

comment:18 by Unai Zalakain <unai@…>, 11 years ago

Resolution: fixed
Status: assignedclosed

In af64429b991471b7a441e133b5b7d29070984f24:

Fixed #7261 -- support for html for library interoperability

The idea is that if an object implements html which returns a string this is
used as HTML representation (eg: on escaping). If the object is a str or unicode
subclass and returns itself the object is a safe string type.

This is an updated patch based on jbalogh and ivank patches.

comment:19 by Alex Gaynor <alex.gaynor@…>, 11 years ago

In 694d7da6c53b9ad35381dccdf4f688771b0b932e:

Merge pull request #1744 from unaizalakain/ticket_7261

Fixed #7261 -- support for html for library interoperability

comment:20 by Jeremy Dunck, 11 years ago

Cc: jdunck@… added

comment:21 by Aymeric Augustin <aymeric.augustin@…>, 10 years ago

In 6d52f6f8e688b5c4e70be8352eb02c05fea60e85:

Fixed #23831 -- Supported strings escaped by third-party libs in Django.

Refs #7261 -- Made strings escaped by Django usable in third-party libs.

The changes in mark_safe and mark_for_escaping are straightforward. The
more tricky part is to handle correctly objects that implement html.

Historically escape() has escaped SafeData. Even if that doesn't seem a
good behavior, changing it would create security concerns. Therefore
support for html() was only added to conditional_escape() where this
concern doesn't exist.

Then using conditional_escape() instead of escape() in the Django
template engine makes it understand data escaped by other libraries.

Template filter |escape accounts for html() when it's available.
|force_escape forces the use of Django's HTML escaping implementation.

Here's why the change in render_value_in_context() is safe. Before Django
1.7 conditional_escape() was implemented as follows:

if isinstance(text, SafeData):

return text

else:

return escape(text)

render_value_in_context() never called escape() on SafeData. Therefore
replacing escape() with conditional_escape() doesn't change the
autoescaping logic as it was originally intended.

This change should be backported to Django 1.7 because it corrects a
feature added in Django 1.7.

Thanks mitsuhiko for the report.

comment:22 by Aymeric Augustin <aymeric.augustin@…>, 10 years ago

In 3483682749577b4b5a8141a766489d5b460e30e9:

[1.7.x] Fixed #23831 -- Supported strings escaped by third-party libs in Django.

Refs #7261 -- Made strings escaped by Django usable in third-party libs.

The changes in mark_safe and mark_for_escaping are straightforward. The
more tricky part is to handle correctly objects that implement html.

Historically escape() has escaped SafeData. Even if that doesn't seem a
good behavior, changing it would create security concerns. Therefore
support for html() was only added to conditional_escape() where this
concern doesn't exist.

Then using conditional_escape() instead of escape() in the Django
template engine makes it understand data escaped by other libraries.

Template filter |escape accounts for html() when it's available.
|force_escape forces the use of Django's HTML escaping implementation.

Here's why the change in render_value_in_context() is safe. Before Django
1.7 conditional_escape() was implemented as follows:

if isinstance(text, SafeData):

return text

else:

return escape(text)

render_value_in_context() never called escape() on SafeData. Therefore
replacing escape() with conditional_escape() doesn't change the
autoescaping logic as it was originally intended.

This change should be backported to Django 1.7 because it corrects a
feature added in Django 1.7.

Thanks mitsuhiko for the report.

Backport of 6d52f6f from master.

Note: See TracTickets for help on using tickets.
Back to Top