annotate writer.py @ 0:984876b6a095

Initial commit of first two classes.
author David Barts <n5jrn@me.com>
date Thu, 26 Dec 2019 08:09:11 -0800
parents
children 091c03f1b2e8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
1 #!/usr/bin/env python3
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
3
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
4 # A simple HTML writer, so we can process HTML in a streamwise fashion
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
5 # via callbacks, which compared to a document tree tends to be all of:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
6 # easier to program, uses less memory, and uses less processor time.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
7
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
8 # I m p o r t s
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
9
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
10 import os, sys
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
11 import codecs
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
12 import io
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
13 import html
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
14
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
15 # V a r i a b l e s
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
16
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
17 # We only support ASCII, ISO-8859-1, and anything capable of encoding
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
18 # the full Unicode set. Anything else is too sticky a wicket to want
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
19 # to mess with.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
20 _CODECS_TO_NAME = {}
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
21 for i in [ "US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16", "UTF-16LE", "UTF-16BE", "UTF-32", "UTF-32LE", "UTF-32BE" ]:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
22 _CODECS_TO_NAME[codecs.lookup(i)] = i
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
23 del i
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
24 _MAXCHAR = { "US-ASCII": 127, "ISO-8859-1": 255 }
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
25
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
26 # There are WAY more HTML entities than this, but we're pessimistic about
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
27 # what browsers "in the wild" support, so we stick to what XML supports.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
28 _QUOTE_ENTITIES = {
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
29 "\"": "quot",
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
30 "'": "apos"
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
31 }
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
32 _OTHER_ENTITIES = {
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
33 "&": "amp",
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
34 "<": "lt",
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
35 ">": "gt"
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
36 }
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
37
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
38 # C l a s s e s
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
39
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
40 class HtmlStreamWriter(object):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
41 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
42 A simple HTML writer, intended to be used in a streamwise fashion.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
43 This class takes REASONABLE precautions against writing garbage, but
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
44 does not check every last thing. It will happily write tags like
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
45 "<garb<<age>>>" etc. if you feed it the right garbage in.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
46 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
47 def __init__(self, stream, encoding):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
48 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
49 Initialize this writer. An encoding is mandatory, even though we
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
50 produce character output, because the encoding governs which
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
51 characters we can send on for I/O without entity-escaping them.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
52 The supplied stream should be buffered or performance will suffer.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
53 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
54 # Stream we're using is available to the caller as .stream
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
55 self.stream = stream
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
56 try:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
57 # A codec to use is available to the caller as .codec
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
58 self.codec = codecs.lookup(encoding)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
59 # Normalized encoding name is available to the caller as .encoding
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
60 self.encoding = _CODECS_TO_NAME[self.codec]
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
61 except (KeyError, LookupError) as e:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
62 raise ValueError("invalid encoding {0!r}".format(encoding))
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
63 self._maxchar = _MAXCHAR.get(self.encoding, 0x7fffffff)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
64
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
65 # html.escape drops the ball, badly. It is too optimistic about what
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
66 # entity names are likely to be understood, and is too stupid to know
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
67 # that ASCII streams need lots of things escaped.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
68 def _escape(self, string, quote=False):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
69 for ch in string:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
70 entity = None
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
71 if quote and ch in _QUOTE_ENTITIES:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
72 entity = _QUOTE_ENTITIES[ch]
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
73 elif ch in _OTHER_ENTITIES:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
74 entity = _OTHER_ENTITIES[ch]
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
75 if entity:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
76 self.stream.write("&")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
77 self.stream.write(entity)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
78 self.stream.write(";")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
79 continue
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
80 ordch = ord(ch)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
81 if ordch > self._maxchar:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
82 self.stream.write("&#")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
83 self.stream.write(str(ordch))
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
84 self.stream.write(";")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
85 continue
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
86 self.stream.write(ch)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
87
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
88 def write_starttag(self, tag, attrs):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
89 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
90 Write a start tag.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
91 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
92 self.stream.write("<")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
93 self.stream.write(tag)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
94 self._writeattrs(attrs)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
95 self.stream.write(">")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
96
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
97 def _writeattrs(self, attrs):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
98 for k, v in attrs:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
99 self.stream.write(" ")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
100 self.stream.write(k)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
101 self.stream.write("=\"")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
102 self._escape(v, quote=True)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
103 self.stream.write("\"")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
104
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
105 def write_endtag(self, tag):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
106 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
107 Write an end tag.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
108 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
109 self.stream.write("</")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
110 self.stream.write(tag)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
111 self.stream.write(">")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
112
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
113 def write_startendtag(self, tag, attrs):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
114 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
115 Write a "start-end" (i.e. empty) tag.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
116 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
117 self.stream.write("<")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
118 self.stream.write(tag)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
119 self._writeattrs(attrs)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
120 self.stream.write("/>")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
121
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
122 def write_data(self, data):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
123 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
124 Write text data.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
125 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
126 self._escape(data)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
127
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
128 def write_raw_data(self, data):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
129 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
130 Write raw data (e.g. style sheets, scripts, etc.)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
131 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
132 self.stream.write(data)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
133
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
134 def write_charref(self, name):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
135 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
136 Write character reference (normally not needed).
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
137 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
138 is_number = False
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
139 try:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
140 junk = int(name)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
141 is_number = True
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
142 except ValueError:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
143 pass
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
144 if name.startswith("x"):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
145 try:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
146 junk = int(name[1:], 16)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
147 is_number = True
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
148 except ValueError:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
149 pass
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
150 self.stream.write("&")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
151 if is_number:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
152 self.stream.write("#")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
153 self.stream.write(name)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
154 else:
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
155 self.stream.write(name)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
156 self.stream.write(";")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
157
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
158 def write_comment(self, data):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
159 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
160 Write a comment.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
161 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
162 self.stream.write("<!--")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
163 self.stream.write(data)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
164 self.stream.write("-->")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
165
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
166 def write_decl(self, decl):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
167 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
168 Write a declarationm.
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
169 """
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
170 self.stream.write("<!")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
171 self.stream.write(decl)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
172 self.stream.write(">")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
173
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
174 def write_pi(self, data):
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
175 self.stream.write("<?")
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
176 self.stream.write(decl)
984876b6a095 Initial commit of first two classes.
David Barts <n5jrn@me.com>
parents:
diff changeset
177 self.stream.write(">")