Attachment 'bibtex.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """MoinMoin - Bibtex Parser
3
4 Configuration Options:
5
6 bibtex_bib2html_cmd -- path and command name of bib2xhtml, needs to
7 be set if bib2xhtml is not in PATH
8 bibtex_bst_path -- path to bib2xhtml bst-style files, needs to
9 be set if these are not found by bibtex
10 automatically
11
12 Notes:
13 This parser depends on bibtex and bib2xhtml, see
14 http://en.wikipedia.org/wiki/Bibtex and
15 http://www.spinellis.gr/sw/textproc/bib2xhtml/ for more information.
16
17 TODO:
18 - attachement links
19
20 $Id: bibtex.py,v 1.1.1.1 2007-06-07 20:36:15 gber Exp $
21 Copyright 2007 by Guido Berhoerster <guido+moinmoin@berhoerster.name>
22 Licensed under the GNU GPL, see COPYING for details.
23
24 $Log: bibtex.py,v $
25 Revision 1.1.1.1 2007-06-07 20:36:15 gber
26 initial import into CVS
27
28
29 """
30
31 import os
32 import tempfile
33 import subprocess
34 import codecs
35 import re
36 from MoinMoin import wikiutil
37
38 Dependencies = []
39
40 # subprocess.check_call and CalledProcessError are only available in
41 # Python 2.5, so recreate them here
42 class CalledProcessError(Exception):
43 """ This exception is raised when a process run by check_call()
44 returns a non-zero exit status. The exit status will be stored in
45 the returncode attribute. """
46 def __init__(self, returncode, cmd):
47 self.returncode = returncode
48 self.cmd = cmd
49 def __str__(self):
50 return "Command '%s' returned non-zero exit status %d" \
51 % (self.cmd, self.returncode)
52
53
54 class BibtexRenderer:
55 """Abstracted bibtex renderer
56
57 Arguments:
58 bibtex -- string containing bibtex markup to be rendered
59 request -- request object
60
61 Keyword arguments:
62 citations -- list with keys of bibtex entries to be
63 rendered (default: empty)
64 abstracts -- boolean, show abstracts or not
65 (default: False)
66 chronological -- boolean or the string "reversed",
67 chronological or reversed chronological
68 sorting (default: False)
69 style -- string "empty", "plain", "alpha", "named",
70 "unsort", "unsortlist", determining the style
71 to use (default: None)
72
73 Notes:
74 Raises OSError if bib2xhtml is not found or CalledProcessError if
75 bib2xhtml returns wit a non-zero exit status.
76
77 """
78
79 def __init__(self, bibtex, request, citations=[], abstracts=False,\
80 label=False, chronological=False, style=None):
81 cfg = request.cfg
82 self.bib2html_cmd = "bib2xhtml"
83 self.bst_path = None
84
85 # retrieve configuration
86 try:
87 self.bib2html_cmd = cfg.bibtex_bib2html
88 except AttributeError:
89 pass
90 try:
91 self.bst_path = cfg.bibtex_bst_path
92 except AttributeError:
93 pass
94
95 # the original bibtex implementation is not 8-bit clean, replace
96 # non-ASCII characters with "?"
97 self.bibtex = bibtex.encode("ascii", "replace")
98
99 self.args = [self.bib2html_cmd, "-u", "-dMoinMoin"]
100
101 if citations:
102 cit_list = []
103 cit_list.append(u"<!-- BEGIN CITATIONS MoinMoin -->")
104 cit_list.append(u"<!--")
105 cit_list.extend([ur"\citation{%s}" % c for c in citations])
106 cit_list.append(u"-->")
107 cit_list.append(u"<!-- END CITATIONS MoinMoin -->")
108 self.citations = u"\n".join(cit_list)
109 # also encode as ASCII
110 self.citations = self.citations.encode("ascii", "replace")
111 self.args.append("-i")
112 else:
113 self.citations = None
114
115 if abstracts:
116 self.args.append("-a")
117 if label:
118 self.args.append("-k")
119 if chronological and chronological == "reversed":
120 self.args.extend(["-c", "-r"])
121 elif chronological:
122 self.args.append("-c")
123 if style in ("empty", "plain", "alpha", "named", "unsort", "unsortlist"):
124 self.args.extend(["-s", style])
125
126 def render(self):
127 """Render the bibtex markup (if requested, only cited entries)
128 and return HTML output in a string.
129 """
130 output = []
131 # create temporary files for Bibtex input, HTML output, and logging
132 bibfd, bibfile = tempfile.mkstemp(".bib")
133 xhtmlfd, xhtmlfile = tempfile.mkstemp(".xhtml")
134 #logfd, logfile = tempfile.mkstemp(".log")
135 self.args.extend([bibfile, xhtmlfile])
136
137 # write Bibtex input to temporary file
138 f = open(bibfile, "w")
139 f.write(self.bibtex)
140 f.close()
141
142 if self.citations:
143 # write citations to temporary output file
144 f = open(xhtmlfile, "w")
145 f.write(self.citations)
146 f.close()
147
148 # execute bib2xhtml converter subprocess on forementionened
149 # temporary files, bib2xhtml creates its temporary files in the
150 # current working directory, so set it to a reasonable location, set
151 # the set the BSTINPUTS environment variable if required in order to
152 # help Bibtex finds the needed .bst files
153 if self.bst_path:
154 bstinputs = {"BSTINPUTS": self.bst_path}
155 else:
156 bstinputs = None
157 try:
158 retcode = subprocess.call(self.args,
159 env=bstinputs, cwd=tempfile.gettempdir(),
160 stdout=open(os.devnull, "w"), stderr=open(os.devnull, "w"))
161 #retcode = subprocess.call(self.args,
162 # env=bstinputs, cwd=tempfile.gettempdir(),
163 # stdout=open(os.devnull, "w"), stderr=open(logfile, "w"))
164 if retcode:
165 raise CalledProcessError(retcode, "".join(self.args))
166 except OSError, error:
167 # bib2xhtml not found or not executable
168 os.remove(bibfile)
169 os.remove(xhtmlfile)
170 raise
171 except CalledProcessError, error:
172 # non-zero exit status
173 os.remove(bibfile)
174 os.remove(xhtmlfile)
175 #os.remove(logfile)
176 raise
177
178 os.remove(bibfile)
179 #os.remove(logfile)
180
181 name_pattern = re.compile('<a name="(?P<anchor>[^"]*)">', re.UNICODE)
182 href_pattern = re.compile('<a href="#(?P<anchor>[^"]*)">', re.UNICODE)
183 inside_dl = False
184
185 # read the output (encoded as utf-8) back in
186 f = codecs.open(xhtmlfile, "r", encoding="utf-8")
187
188 for line in f.readlines():
189 if line.startswith(u'<!-- Generated by: '):
190 # throw away comments at the beginning...
191 inside_dl = True
192 continue
193 elif line == u'<!-- END BIBLIOGRAPHY MoinMoin -->\n':
194 # ...and the end
195 break
196 if inside_dl:
197 # use a ref:-prefix for anchor links in order to avoid
198 # interference with other anchors and replace the name- with
199 # the id-attribute (it would be more appropriate to fix this in
200 # the bst-file)
201 line = name_pattern.sub(ur'<a id="ref:\g<anchor>">', line)
202 line = href_pattern.sub(ur'<a href="#ref:\g<anchor>">', line)
203 output.append(line)
204
205 f.close()
206 os.remove(xhtmlfile)
207
208 output = "".join(output)
209 return output
210
211
212 class Parser:
213 """Parse Bibtex markup."""
214
215 extensions = ['.bib']
216 Dependencies = []
217
218 def __init__(self, raw, request, **kw):
219 self.request = request
220 self.show = True
221 self.abstracts = False
222 self.label = True
223 self.chronological = False
224 self.style = "named"
225 self.raw = raw
226 self.request = request
227 self._ = request.getText
228
229 # parse format arguments
230 attrs, msg = wikiutil.parseAttributes(self.request, kw.get(
231 'format_args',''))
232 if not msg:
233 if attrs.get('show','"on"')[1:-1].lower() not in ('on', 'true',
234 'yes'):
235 self.show = False
236 if attrs.get('abstracts','"off"')[1:-1].lower() in ('on', 'true',
237 'yes'):
238 self.abstracts = True
239 if attrs.get('label','"on"')[1:-1].lower() not in ('on', 'true',
240 'yes'):
241 self.label = False
242 if attrs.get('chronological','"off"')[1:-1].lower() in ('on',
243 'true', 'yes'):
244 self.chronological = True
245 elif attrs.get('chronological','"off"')[1:-1].lower() in (
246 'reverse', 'reversed'):
247 self.chronological = "reversed"
248 if attrs.get('style','"empty"')[1:-1].lower() in ('empty', 'plain',
249 'alpha', 'named', 'unsort', 'unsortlist'):
250 self.style = attrs.get('style','')[1:-1].lower()
251
252 def format(self, formatter):
253 """Format Bibtex markup as HTML and write output."""
254
255 if not self.show: return
256
257 _ = self._
258
259 bib_renderer = BibtexRenderer(self.raw, self.request,
260 abstracts=self.abstracts, label=self.label,
261 chronological=self.chronological, style=self.style)
262 try:
263 output = bib_renderer.render()
264 except OSError, error:
265 self.request.write(formatter.sysmsg(1))
266 self.request.write(formatter.escapedText(
267 _("Error: %(bib2html_cmd)s could not be found.") %
268 {"bib2html_cmd": self.bib2html_cmd}))
269 self.request.write(formatter.sysmsg(0))
270 return
271 except CalledProcessError, error:
272 msg = (_("An error occured while executing %(bib2html_cmd)s:" %
273 {"bib2html_cmd": self.bib2html_cmd}))
274 self.request.write(formatter.sysmsg(1))
275 self.request.write(formatter.escapedText(msg))
276 self.request.write(formatter.sysmsg(0))
277 return
278
279 # write through the rawHTML formatter if possible, otherwise write
280 # just the Bibtex markup as preformatted text
281 self.request.write(formatter.div(1, css_class="bibliography"))
282 self.request.write(formatter.heading(1, 1))
283 self.request.write(formatter.escapedText(_("Bibliography")))
284 self.request.write(formatter.heading(0, 1))
285 try:
286 self.request.write(formatter.rawHTML(output))
287 except:
288 self.request.write(formatter.preformatted(1))
289 self.request.write(formatter.text(self.raw.expandtabs()))
290 self.request.write(formatter.preformatted(0))
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.