1"""
2Functions for working with "safe strings": strings that can be displayed safely
3without further escaping in HTML. Marking something as a "safe string" means
4that the producer of the string has already turned characters that should not
5be interpreted by the HTML engine (e.g. '<') into the appropriate entities.
6"""
7
8from functools import wraps
9
10from django.utils.functional import keep_lazy
11
12
13class SafeData:
14 __slots__ = ()
15
16 def __html__(self):
17 """
18 Return the html representation of a string for interoperability.
19
20 This allows other template engines to understand Django's SafeData.
21 """
22 return self
23
24
25class SafeString(str, SafeData):
26 """
27 A str subclass that has been specifically marked as "safe" for HTML output
28 purposes.
29 """
30
31 __slots__ = ()
32
33 def __add__(self, rhs):
34 """
35 Concatenating a safe string with another safe bytestring or
36 safe string is safe. Otherwise, the result is no longer safe.
37 """
38 if isinstance(rhs, str):
39 t = super().__add__(rhs)
40 if isinstance(rhs, SafeData):
41 t = SafeString(t)
42 return t
43
44 # Give the rhs object a chance to handle the addition, for example if
45 # the rhs object's class implements `__radd__`. More details:
46 # https://docs.python.org/3/reference/datamodel.html#object.__radd__
47 return NotImplemented
48
49 def __str__(self):
50 return self
51
52
53SafeText = SafeString # For backwards compatibility since Django 2.0.
54
55
56def _safety_decorator(safety_marker, func):
57 @wraps(func)
58 def wrapper(*args, **kwargs):
59 return safety_marker(func(*args, **kwargs))
60
61 return wrapper
62
63
64@keep_lazy(SafeString)
65def mark_safe(s):
66 """
67 Explicitly mark a string as safe for (HTML) output purposes. The returned
68 object can be used everywhere a string is appropriate.
69
70 If used on a method as a decorator, mark the returned data as safe.
71
72 Can be called multiple times on a single string.
73 """
74 if hasattr(s, "__html__"):
75 return s
76 if callable(s):
77 return _safety_decorator(mark_safe, s)
78 return SafeString(s)