rtf.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # coding=utf-8
  2. __author__ = 'marcos.medeiros'
  3. class RtfTemplate(object):
  4. """
  5. A file object that when read fills an RTF template with context data.
  6. The template variables must come between brackets "[]", instead of braces "{}",
  7. and will be interpreted with the builtin format rules (that means you can reference
  8. fields and elements, apply formatting rules (with comma ":") to the returned values, etc).
  9. Use two open brackets to represent an open bracket. Close brackets without an equivalent
  10. open bracket are repeated verbatim. Thus, to represent the text "[]", the original document
  11. must contain the text "[[]".
  12. Brackets were chosen because they aren't parsed by the RTF format, and thus can be inserted
  13. directly from WYSIWYG editors.
  14. """
  15. def __init__(self, file_name, context):
  16. """
  17. Open the template for reading, replacing the variables with the values from the
  18. given context.
  19. :param file_name: Template that will be read.
  20. :param context: Values that will be inserted at the place of the variables.
  21. """
  22. self.name = file_name
  23. self.template = open(file_name, 'r')
  24. self.encoding = self.template.encoding
  25. self.context = context
  26. self.pattern = ''
  27. self.brackets = 0
  28. self.partial = ''
  29. self.softspace = 0
  30. def format(self, template):
  31. """
  32. Formats the template with this object's context.
  33. Notice that a template may contain only part of a variable,
  34. what will make its value appear only at a later call of format.
  35. :param template: Original template text.
  36. :return: The formatted text.
  37. """
  38. ret = ''
  39. for c in template:
  40. if self.brackets == 0 and c != '[':
  41. ret += c
  42. else:
  43. if c == '[':
  44. if self.brackets != 0:
  45. self.pattern += c
  46. self.brackets += 1
  47. if self.brackets == 2 and self.pattern == '[':
  48. ret += '['
  49. self.brackets = 0
  50. self.pattern = ''
  51. elif c == ']':
  52. self.brackets -= 1
  53. if self.brackets == 0:
  54. ret += ('{'+self.pattern.strip()+'}').format(**self.context)
  55. self.pattern = ''
  56. else:
  57. self.pattern += c
  58. else:
  59. self.pattern += c
  60. return ret
  61. def _next_with(self, func):
  62. buf = func()
  63. f = self.format(buf)
  64. if buf and not f:
  65. return self._next_with(func)
  66. return f
  67. def next(self):
  68. return self._next_with(self.template.next)
  69. def __next__(self):
  70. # noinspection PyUnresolvedReferences
  71. return self._next_with(self.template.__next__)
  72. def _read_by(self, func, size):
  73. actual_size = size
  74. if self.partial:
  75. actual_size = size - len(self.partial)
  76. if actual_size < 0 < size:
  77. f = self.partial[0:size]
  78. self.partial = self.partial[size:]
  79. return f
  80. buf = func(actual_size)
  81. f = self.partial + self.format(buf)
  82. if buf and not f:
  83. return self.read(size)
  84. if 0 < size < len(f):
  85. self.partial = f[size:]
  86. return f[0:size]
  87. self.partial = ''
  88. return f
  89. def read(self, size=-1):
  90. return self._read_by(self.template.read, size)
  91. def readline(self, size):
  92. return self._read_by(self.template.readline, size)
  93. def close(self):
  94. self.template.close()
  95. def isatty(self):
  96. return self.template.isatty()
  97. def __iter__(self):
  98. return self
  99. @property
  100. def closed(self):
  101. return self.template.closed
  102. @property
  103. def newlines(self):
  104. return self.template.newlines
  105. @classmethod
  106. def format_into(cls, template, context, file_name):
  107. """
  108. Formats the template, writing the resulting data into the given file.
  109. :param template: Name of the template file.
  110. :param context: Context where variables will be evaluated.
  111. :param file_name: Name of the file that will be written with the formatted data.
  112. """
  113. t = RtfTemplate(template, context)
  114. f = open(file_name, 'w')
  115. for l in t:
  116. f.write(l)
  117. f.close()
  118. t.close()