Coverage for /Users/davegaeddert/Developer/dropseed/plain/plain/plain/utils/safestring.py: 64%

1"""

2 Functions for working with "safe strings": strings that can be displayed safely

3 without further escaping in HTML. Marking something as a "safe string" means

4 that the producer of the string has already turned characters that should not

5 be interpreted by the HTML engine (e.g. '<') into the appropriate entities.

6"""

7

8 from functools import wraps

9

10 from plain.utils.functional import keep_lazy

11

12

13 class 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 Plain's SafeData.

21 """

22 return self

23

24

25 class 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 t = super().__add__(rhs)

39 if isinstance(rhs, SafeData):

40 return SafeString(t)

41 return t

42

43 def __str__(self):

44 return self

45

46

47 SafeText = SafeString # For backwards compatibility since Plain 2.0.

48

49

50 def _safety_decorator(safety_marker, func):

51 @wraps(func)

52 def wrapper(*args, **kwargs):

53 return safety_marker(func(*args, **kwargs))

54

55 return wrapper

56

57

58@keep_lazy(SafeString)

59 def mark_safe(s):

60 """

61 Explicitly mark a string as safe for (HTML) output purposes. The returned

62 object can be used everywhere a string is appropriate.

63

64 If used on a method as a decorator, mark the returned data as safe.

65

66 Can be called multiple times on a single string.

67 """

68 if hasattr(s, "__html__"):

69 return s

70 if callable(s):

71 return _safety_decorator(mark_safe, s)

72 return SafeString(s)