annotate tests/conftest.py @ 53:805c7d768caa

Make feed parser more resilient, add ability to modify html doc. - Better handle errors found while parsing the html feed. - Add CSS-selector-based configuration to modify the html feed before parsing it. This allows using SiloRider with a feed that doesn't have proper micro-format markup.
author Ludovic Chabant <ludovic@chabant.com>
date Sun, 08 Oct 2023 13:52:26 -0700
parents d3c4c5082bbc
children b404445082f8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
1 import io
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
2 import os
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
3 import os.path
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
4 import re
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
5 import logging
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
6 import tempfile
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
7 import pytest
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
8 import silorider.main
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
9
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
10
19
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
11 logger = logging.getLogger(__name__)
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
12
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
13
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
14 # def pytest_collect_file(parent, path):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
15 # if path.ext == ".html" and path.basename.startswith("feeds"):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
16 # return FeedFile(path, parent)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
17
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
18
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
19 re_feed_test_sep = re.compile(r'^---$')
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
20
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
21
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
22 class FeedFile(pytest.File):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
23 def collect(self):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
24 with self.fspath.open() as fp:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
25 markup = fp.read()
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
26
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
27 name = self.fspath.basename
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
28 html_markup, yaml_markup = re_feed_test_sep.split(markup, 1)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
29 yield FeedItem(name, self, html_markup, yaml_markup)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
30
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
31
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
32 class FeedItem(pytest.Item):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
33 def __init__(self, name, parent, in_spec, out_spec):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
34 super().__init__(name, parent)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
35 self.in_spec = in_spec
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
36 self.out_spec = out_spec
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
37
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
38 def runtest(self):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
39 pass
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
40
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
41
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
42 @pytest.fixture
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
43 def cli():
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
44 return CliRunner()
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
45
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
46
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
47 class CliRunner:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
48 def __init__(self):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
49 self._cfgtxt = """
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
50 [cache]
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
51 uri=memory://for_test
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
52 """
18
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
53 self._feedcfg = []
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
54 self._pre_hooks = []
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
55 self._cleanup = []
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
56
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
57 def getFeedPath(self, name):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
58 return os.path.join(os.path.dirname(__file__),
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
59 'feeds',
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
60 '%s.html' % name)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
61
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
62 def createTempFeed(self, contents):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
63 tmpfd, tmpname = tempfile.mkstemp()
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
64 with os.fdopen(tmpfd, 'w', encoding='utf8') as tmpfp:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
65 tmpfp.write(contents)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
66 self._cleanup.append(tmpname)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
67 return tmpname
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
68
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
69 def setConfig(self, cfgtxt):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
70 self._cfgtxt = cfgtxt
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
71 return self
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
72
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
73 def appendConfig(self, cfgtxt):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
74 self._cfgtxt += cfgtxt
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
75 return self
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
76
18
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
77 def appendFeedConfig(self, feed_name, feed_url):
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
78 self._feedcfg.append((feed_name, feed_url))
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
79 return self
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
80
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
81 def setFeedConfig(self, feed_name, feed_url):
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
82 self._feedcfg = []
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
83 return self.appendFeedConfig(feed_name, feed_url)
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
84
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
85 def appendSiloConfig(self, silo_name, silo_type, **options):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
86 cfgtxt = '[silo:%s]\n' % silo_name
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
87 cfgtxt += 'type=%s\n' % silo_type
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
88 if options is not None:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
89 for n, v in options.items():
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
90 cfgtxt += '%s=%s\n' % (n, v)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
91 return self.appendConfig(cfgtxt)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
92
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
93 def preExecHook(self, hook):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
94 self._pre_hooks.append(hook)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
95
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
96 def run(self, *args):
19
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
97 pre_args = ['-v']
18
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
98 if self._cfgtxt or self._feedcfg:
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
99 cfgtxt = self._cfgtxt
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
100 cfgtxt += '\n\n[urls]\n'
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
101 for n, u in self._feedcfg:
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
102 cfgtxt += '%s=%s\n' % (n, u)
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
103
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
104 tmpfd, tmpcfg = tempfile.mkstemp()
19
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
105 logger.info("Creating temporary configuration file: %s" % tmpcfg)
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
106 with os.fdopen(tmpfd, 'w') as tmpfp:
18
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
107 tmpfp.write(cfgtxt)
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
108 self._cleanup.append(tmpcfg)
19
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
109 pre_args += ['-c', tmpcfg]
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
110
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
111 captured = io.StringIO()
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
112 handler = logging.StreamHandler(captured)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
113 handler.setLevel(logging.INFO)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
114 silorider_logger = logging.getLogger('silorider')
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
115 silorider_logger.addHandler(handler)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
116
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
117 main_ctx = None
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
118 main_res = None
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
119
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
120 def pre_exec_hook(ctx):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
121 for h in self._pre_hooks:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
122 h(ctx)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
123
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
124 def post_exec_hook(ctx, res):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
125 nonlocal main_ctx, main_res
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
126 main_ctx = ctx
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
127 main_res = res
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
128
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
129 silorider.main.pre_exec_hook = pre_exec_hook
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
130 silorider.main.post_exec_hook = post_exec_hook
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
131
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
132 args = pre_args + list(args)
19
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
133 logger.info("Running command: %s" % list(args))
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
134 try:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
135 silorider.main._unsafe_main(args)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
136 finally:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
137 silorider.main.pre_exec_hook = None
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
138 silorider.main.post_exec_hook = None
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
139
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
140 silorider_logger.removeHandler(handler)
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
141
19
d3c4c5082bbc Add Webmention silo.
Ludovic Chabant <ludovic@chabant.com>
parents: 18
diff changeset
142 logger.info("Cleaning %d temporary files." % len(self._cleanup))
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
143 for tmpname in self._cleanup:
18
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
144 try:
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
145 os.remove(tmpname)
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
146 except FileNotFoundError:
a921cc2306bc Do our own HTML parsing/stripping of micropost contents.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
147 pass
0
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
148
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
149 return main_ctx, main_res
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
150
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
151
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
152 @pytest.fixture
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
153 def feedutil():
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
154 return FeedUtil()
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
155
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
156
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
157 class FeedUtil:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
158 def makeFeed(self, *entries):
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
159 feed = '<html><body>\n'
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
160 for e in entries:
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
161 feed += '<article class="h-entry">\n'
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
162 feed += e
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
163 feed += '</article>\n'
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
164 feed += '</body></html>'
a1b7a459326a Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
165 return feed