util.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. '''
  2. Utility classes for creating dynamic html documents
  3. '''
  4. __license__ = '''
  5. This file is part of Dominate.
  6. Dominate is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU Lesser General Public License as
  8. published by the Free Software Foundation, either version 3 of
  9. the License, or (at your option) any later version.
  10. Dominate is distributed in the hope that it will be useful, but
  11. WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General
  15. Public License along with Dominate. If not, see
  16. <http://www.gnu.org/licenses/>.
  17. '''
  18. import re
  19. from .dom_tag import dom_tag
  20. try:
  21. basestring = basestring
  22. except NameError:
  23. basestring = str
  24. unichr = chr
  25. def include(f):
  26. '''
  27. includes the contents of a file on disk.
  28. takes a filename
  29. '''
  30. fl = open(f, 'r')
  31. data = fl.read()
  32. fl.close()
  33. return raw(data)
  34. def system(cmd, data=None):
  35. '''
  36. pipes the output of a program
  37. '''
  38. import subprocess
  39. s = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
  40. out, err = s.communicate(data)
  41. return out.decode('utf8')
  42. def escape(data, quote=True): # stoled from std lib cgi
  43. '''
  44. Escapes special characters into their html entities
  45. Replace special characters "&", "<" and ">" to HTML-safe sequences.
  46. If the optional flag quote is true, the quotation mark character (")
  47. is also translated.
  48. This is used to escape content that appears in the body of an HTML cocument
  49. '''
  50. data = data.replace("&", "&amp;") # Must be done first!
  51. data = data.replace("<", "&lt;")
  52. data = data.replace(">", "&gt;")
  53. if quote:
  54. data = data.replace('"', "&quot;")
  55. return data
  56. _unescape = {
  57. 'quot': 34,
  58. 'amp': 38,
  59. 'lt': 60,
  60. 'gt': 62,
  61. 'nbsp': 32,
  62. # more here
  63. # http://www.w3.org/TR/html4/sgml/entities.html
  64. 'yuml': 255,
  65. }
  66. str_escape = escape
  67. def unescape(data):
  68. '''
  69. unescapes html entities. the opposite of escape.
  70. '''
  71. cc = re.compile('&(?:(?:#(\d+))|([^;]+));')
  72. result = []
  73. m = cc.search(data)
  74. while m:
  75. result.append(data[0:m.start()])
  76. d = m.group(1)
  77. if d:
  78. d = int(d)
  79. result.append(unichr(d))
  80. else:
  81. d = _unescape.get(m.group(2), ord('?'))
  82. result.append(unichr(d))
  83. data = data[m.end():]
  84. m = cc.search(data)
  85. result.append(data)
  86. return ''.join(result)
  87. _reserved = ";/?:@&=+$, "
  88. _replace_map = dict((c, '%%%2X' % ord(c)) for c in _reserved)
  89. def url_escape(data):
  90. return ''.join(_replace_map.get(c, c) for c in data)
  91. def url_unescape(data):
  92. return re.sub('%([0-9a-fA-F]{2})',
  93. lambda m: unichr(int(m.group(1), 16)), data)
  94. class lazy(dom_tag):
  95. '''
  96. delays function execution until rendered
  97. '''
  98. def __new__(_cls, *args, **kwargs):
  99. '''
  100. Need to reset this special method or else
  101. dom_tag will think it's being used as a dectorator.
  102. This means lazy() can't be used as a dectorator, but
  103. thinking about when you might want that just confuses me.
  104. '''
  105. return object.__new__(_cls)
  106. def __init__(self, func, *args, **kwargs):
  107. super(lazy, self).__init__()
  108. self.func = func
  109. self.args = args
  110. self.kwargs = kwargs
  111. def _render(self, sb, *a, **kw):
  112. r = self.func(*self.args, **self.kwargs)
  113. sb.append(str(r))
  114. # TODO rename this to raw?
  115. class text(dom_tag):
  116. '''
  117. Just a string. useful for inside context managers
  118. '''
  119. is_pretty = False
  120. is_inline = True
  121. def __init__(self, _text, escape=True):
  122. super(text, self).__init__()
  123. if escape:
  124. self.text = str_escape(_text)
  125. else:
  126. self.text = _text
  127. def _render(self, sb, *a, **kw):
  128. sb.append(self.text)
  129. return sb
  130. def raw(s):
  131. '''
  132. Inserts a raw string into the DOM. Unsafe.
  133. '''
  134. return text(s, escape=False)