Fixed #33465 -- Added empty __slots__ to SafeString and SafeData.

Despite inheriting from the str type, every SafeString instance gains
an empty __dict__ due to the normal, expected behaviour of type
subclassing in Python.

Adding __slots__ to SafeData is necessary, because otherwise inheriting
from that (as SafeString does) will give it a __dict__ and negate the
benefit added by modifying SafeString.
This commit is contained in:
Keryn Knight 2022-01-25 09:53:03 +00:00 committed by Mariusz Felisiak
parent 67db54a5a7
commit 55022f75c1
2 changed files with 18 additions and 1 deletions

View File

@ -9,6 +9,8 @@ from functools import wraps
class SafeData:
__slots__ = ()
def __html__(self):
"""
Return the html representation of a string for interoperability.
@ -23,6 +25,9 @@ class SafeString(str, SafeData):
A str subclass that has been specifically marked as "safe" for HTML output
purposes.
"""
__slots__ = ()
def __add__(self, rhs):
"""
Concatenating a safe string with another safe bytestring or

View File

@ -2,7 +2,7 @@ from django.template import Context, Template
from django.test import SimpleTestCase
from django.utils import html
from django.utils.functional import lazy, lazystr
from django.utils.safestring import SafeData, mark_safe
from django.utils.safestring import SafeData, SafeString, mark_safe
class customescape(str):
@ -98,3 +98,15 @@ class SafeStringTest(SimpleTestCase):
lazy_str = lazy(html_str, str)()
self.assertEqual(mark_safe(lazy_str), html_str())
def test_default_additional_attrs(self):
s = SafeString('a&b')
msg = "object has no attribute 'dynamic_attr'"
with self.assertRaisesMessage(AttributeError, msg):
s.dynamic_attr = True
def test_default_safe_data_additional_attrs(self):
s = SafeData()
msg = "object has no attribute 'dynamic_attr'"
with self.assertRaisesMessage(AttributeError, msg):
s.dynamic_attr = True