Attachment 'Bibliography1.6.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """MoinMoin - Bibliography
3
4 A macro to insert a bibliography automatically generated from embedded
5 bibtex markup, showing the entries cited with the Cite macro on the
6 current page. It can optionally include another page which may be in
7 bibtex format or contain further embedded bibtex markup.
8
9 Syntax:
10 [[Bibliography]]
11 [[Bibliography(bib_page_name[, abstracts=abstracts, label=label,
12 chronological=chronological, style=style)]]
13
14 Parameters:
15 bib_page_name -- page to include which contains additional embedded bibtex
16 entries
17
18 Keyword Parameters:
19 abstracts -- show abstracts (values: on,true,yes,off,false,no;
20 default off)
21 label -- show labels if the style is alpha, named, plain,
22 or unsort (values: on, true, yes, off, false, no;
23 default: on)
24 chronological -- sort chronologically first by year then by author
25 instead of first by author and then by year, can
26 also be reversed in order to sort from last to
27 earliest entry instead of from earliest to last
28 entry (values: on, true, yes, off, false, no,
29 reverse, reversed; default: off)
30 style -- determine a style to use (values: empty, plain,
31 alpha, named, unsort, unsortlist; default: named)
32
33 Configuration Options:
34 bibtex_bib2html_cmd -- path and command name of bib2xhtml, needs to
35 be set if bib2xhtml is not in PATH
36 bibtex_bst_path -- path to bib2xhtml bst-style files, needs to
37 be set if these are not found by bibtex
38 automatically
39
40 Notes:
41 This macro is intended to be used with the Cite macro and bibtex
42 parser. It depends on bibtex and bib2xhtml, see
43 http://en.wikipedia.org/wiki/Bibtex and
44 http://www.spinellis.gr/sw/textproc/bib2xhtml/ for more information.
45
46 $Id: Bibliography.py,v 1.1.1.1 2007-06-07 20:36:15 gber Exp $
47 Copyright 2007 by Guido Berhoerster <guido+moinmoin@berhoerster.name>
48 Licensed under the GNU GPL, see COPYING for details.
49
50 $Log: Bibliography.py,v $
51 Revision 1.1.1.1 2007-06-07 20:36:15 gber
52 initial import into CVS
53
54
55 """
56
57 import os
58 import tempfile
59 import subprocess
60 import codecs
61 import re
62 from MoinMoin import wikiutil
63 ### changed syntax (transition from Moin 1.5 to 1.6)
64 from MoinMoin import macro as wikimacro
65 ### remove redundancies
66 from MoinMoin.parser.bibtex import BibtexRenderer
67 #from MoinMoin.parser.bibtex import Parser as BibtexParser
68 from MoinMoin.Page import Page
69
70 Dependencies = []
71
72 # subprocess.check_call and CalledProcessError are only available in
73 # Python 2.5, so recreate them here
74 class CalledProcessError(Exception):
75 """ This exception is raised when a process run by check_call()
76 returns a non-zero exit status. The exit status will be stored in
77 the returncode attribute. """
78 def __init__(self, returncode, cmd):
79 self.returncode = returncode
80 self.cmd = cmd
81 def __str__(self):
82 return "Command '%s' returned non-zero exit status %d" \
83 % (self.cmd, self.returncode)
84
85 class Bibliography:
86 """The bibliography for the current page."""
87 def __init__(self, macro, args):
88 self.macro = macro
89 self.request = self.macro.request
90 self._ = self.request.getText
91 self.this_page_name = self.macro.formatter.page.page_name
92 self.abstracts = False
93 self.label = True
94 self.chronological = False
95 self.style = "named"
96 self.bib_page_name = None
97
98 if args and args != "":
99 # get the page name first
100 # better user args.partition(",") available in Python 2.5
101 if "," in args:
102 bib_page_name, bib_args = args.split(",", 1)
103 else:
104 bib_page_name = args.strip()
105 bib_args = ""
106
107 ### changed syntax (transition from Moin 1.5 to 1.6)
108 self.bib_page_name = wikiutil.AbsPageName(self.this_page_name, bib_page_name.strip())
109
110 # get the rest of the (named) parameters
111 for arg in bib_args.split(","):
112 if "=" in arg:
113 key, value = arg.lower().split("=", 1)
114 key = key.strip()
115 value = value.strip()
116 if key == "abstracts" and value not in ("on", "true",
117 "yes"):
118 self.abstracts = True
119 if key == "label" and value not in ("on", "true", "yes"):
120 self.label = False
121 if key == "chronological" and value in ("on", "true",
122 "yes"):
123 self.chronological = True
124 elif key == "chronological" and value in ("reverse",
125 "reversed"):
126 self.chronological = "reversed"
127 if key == "style" and value in ("empty", "plain", "alpha",
128 "named", "unsort", "unsortlist"):
129 self.style = value
130
131 # linebreaks
132 self.eol_re = re.compile(r'\r?\n', re.UNICODE)
133 # processing instructions and comments, matches format of format PI
134 self.re_pi_comment = re.compile(r'^\#(((\#|refresh|redirect|deprecated|pragma|form|acl|language)|(format\s*(?P<format>.*?)))(\s|$))', re.UNICODE|re.IGNORECASE)
135 # end of a formatted section
136 self.re_formatted_end = re.compile(r'(.*?)\}\}\}', re.UNICODE)
137 # comments (not inside PI)
138 self.re_comment = re.compile(r'^\#\#', re.UNICODE)
139 # formatted section, matches formatter
140 self.re_formatted = re.compile(
141 r'\{\{\{(?!.*\}\}\})((\#!\s*(?P<format>.*?)(\s|$))|(.*$))',
142 re.UNICODE)
143 # Cite macro, matches key
144 ### this needs to be fixed!!! 1.5 to 1.6
145 self.re_cite = re.compile(
146 r'\<\<Cite\((?P<key>.+?)((,.*?){1,2})?\)\>\>', re.UNICODE)
147 # other macros, excluding Cite
148 # FIXME what if <<Cite(<<Cite(bla)>>)>>?
149 macronames = [m for m in wikimacro.getNames(macro.request.cfg) \
150 if m != 'Cite']
151 # stuff to filter out (mostly because they cannot contain macros)
152 self.re_filter = re.compile(r'''(
153 (\^.*?\^)| # sup
154 ({\{\{.*?\}\}\})| # tt
155 (^\s+.*?::\s)| # dl
156 (^\s*(?P<hmarker>=+)\s.*\s(?P=hmarker) $)| # heading
157 (\[".*?"\])| # wikiname_bracket
158 (`.*?`)| # tt_bt
159 (\<\<(%(macronames)s)(?:\(.*?\))?\>\>) # macro
160 )''' % {"macronames": u"|".join(macronames)}, re.UNICODE|re.VERBOSE)
161
162 def run(self):
163 _ = self._
164 output = []
165 # parse current page first
166 cit_list, bib_list = self.parse(self.macro.parser.raw, True)
167
168 # parse a given page as well
169 if self.bib_page_name and self.bib_page_name != self.this_page_name:
170 if self.request.user.may.read(self.bib_page_name):
171 bib_page = Page(self.request, self.bib_page_name)
172 else:
173 output.append(self.macro.formatter.div(1, css_class="error"))
174 output.append(self.macro.formatter.escapedText(
175 _('Error: Page "%(page_name)s" may not be read and cannot be included by Bibliography')
176 % {"page_name": self.bib_page_name}))
177 output.append(self.macro.formatter.div(0))
178 return "".join(output)
179 if bib_page.exists():
180 add_cit_list, add_bib_list = self.parse(
181 bib_page.get_raw_body(), False)
182 bib_list.extend(add_bib_list)
183 elif self.bib_page_name.endswith('.bib'):
184 # add support for external bibtex file
185 try:
186 fname = self.bib_page_name
187 fname = fname.replace(self.this_page_name,'')
188 f = open(fname,"r")
189 except IOError:
190 output.append(self.macro.formatter.div(1, css_class="error"))
191 output.append(self.macro.formatter.escapedText(
192 _('Error: File "%(page_name)s" cannot be opened')
193 % {"page_name": fname}))
194 output.append(self.macro.formatter.div(0))
195 return "".join(output)
196 else:
197 body = "#format bibtex \n" + f.read()
198 f.close()
199 prefix = fname.rsplit('/',1)[0] + '/'
200 body = jabref2bib(body,prefix) #'/home/ingmar/Documents/References/'
201
202 add_cit_list, add_bib_list = self.parse(
203 body, False)
204 bib_list.extend(add_bib_list)
205 else:
206 output.append(self.macro.formatter.div(1, css_class="error"))
207 output.append(self.macro.formatter.escapedText(
208 _('Error: Page "%(page_name)s" does not exist and cannot be included by Bibliography')
209 % {"page_name": self.bib_page_name}))
210 output.append(self.macro.formatter.div(0))
211 return "".join(output)
212
213 bibtex = "\n".join(bib_list)
214
215 # try to render as HTML
216 bib_renderer = BibtexRenderer(bibtex, self.request,
217 citations=cit_list, abstracts=self.abstracts, label=self.label,
218 chronological=self.chronological, style=self.style)
219 try:
220 bib_output = bib_renderer.render()
221 except OSError, error:
222 output.append(self.macro.formatter.div(1, css_class="error"))
223 output.append(self.macro.formatter.escapedText(
224 _('Error: "%(bib2html_cmd)s" could not be found or executed by Bibliography')
225 % {"bib2html_cmd": bib_renderer.bib2html_cmd}))
226 output.append(self.macro.formatter.div(0))
227 return "".join(output)
228 except CalledProcessError, error:
229 output.append(self.macro.formatter.div(1, css_class="error"))
230 output.append(self.macro.formatter.escapedText(
231 _('Error: "%(bib2html_cmd)s" returned a non-zero exit status while being executed by Biblography')
232 % {"bib2html_cmd": bib_renderer.bib2html_cmd}))
233 output.append(self.macro.formatter.div(0))
234 return "".join(output)
235
236 # write through the rawHTML formatter if possible, otherwise write
237 # just the Bibtex markup as preformatted text
238 output.append(self.macro.formatter.div(1, css_class="bibliography"))
239 output.append(self.macro.formatter.heading(1,1))
240 output.append(self.macro.formatter.escapedText(_("Bibliography")))
241 output.append(self.macro.formatter.heading(0,1))
242 try:
243 output.append(self.macro.formatter.rawHTML(bib_output))
244 except:
245 output.append(self.macro.formatter.preformatted(1))
246 output.append(self.macro.formatter.text(bibtex.expandtabs()))
247 output.append(self.macro.formatter.preformatted(0))
248
249 ### fixed bug: close div!!
250 output.append(self.macro.formatter.div(0))
251 output = "".join(output)
252
253 return output
254
255 def parse(self, raw_page, find_cite_macro):
256 """Parse a page."""
257
258 lines = self.eol_re.split(raw_page.expandtabs())
259 in_pi_comment = True # inside processing instructions or comments
260 in_pre = None # inside a preformatted block
261 page_format = "wiki"
262 bib_list = [] # contains found embedded bibtex markup
263 cit_list = [] # contains found citations if requested
264
265 for line in lines:
266 if in_pi_comment:
267 # inside processing instructions or comments at the beginning
268 # of the page
269 m = self.re_pi_comment.match(line)
270 if m and m.group("format") is not None:
271 # set page format, the last one applies to the whole page
272 page_format = m.group("format")
273 elif m:
274 # other processing instruction or comment
275 continue
276 else:
277 # not a processing instruction or comment
278 in_pi_comment = False
279 elif in_pre is not None: # formatter might be empty!
280 # inside preformatted block
281 m = self.re_formatted_end.search(line)
282 if in_pre == "bibtex":
283 # format of preformatted block is bibtex
284 if m:
285 # preformatted block in bibtex format ends here
286 bib_list.append(m.group(1))
287 in_pre = None
288 line = line[m.end():]
289 else:
290 # preformatted block in bibtex format continues
291 bib_list.append(line)
292 continue
293 elif in_pre == "wiki":
294 # preformatted block is in wiki format
295 if m:
296 # preformatted block ends here
297 in_pre = None
298 # parse inside for citations, delete inside part
299 part_line = line[:m.end()-3]
300 if find_cite_macro:
301 for m in self.re_cite.finditer(line):
302 # cite macro found
303 if in_pre != None and \
304 m.group("key") != "":
305 cit_list.append(m.group("key"))
306 # continue parsing outside of this block, there might be
307 # further citations
308 line = line[m.end():]
309 else:
310 # preformatted block is not in wiki or bibtex format
311 if m:
312 # preformatted block ends here
313 in_pre = None
314 # continue parsing outside of this block, there might be
315 # citations
316 line = line[m.end():]
317 else:
318 # preformatted block continues
319 continue
320
321 if page_format == "bibtex":
322 # page is in bibtex format
323 bib_list.append(line)
324 continue
325 elif page_format != "wiki":
326 # page is in an unknown, unsupported format
327 break
328
329 if self.re_comment.match(line):
330 continue
331
332 m = self.re_formatted.search(line)
333 if m:
334 if m.group("format") is None:
335 # if there is no "#!" after "{{{" format will be None,
336 # thus default to ""
337 in_pre = ""
338 else:
339 # set the formatter to the found value
340 in_pre = m.group("format")
341 continue
342
343 if find_cite_macro:
344 # filter commands which do not allow (cite) macros inside
345 line = self.re_filter.sub("", line)
346 for m in self.re_cite.finditer(line):
347 # cite macro found
348 if not in_pre == "" and m.group("key") != "" and not \
349 m.group("key").count("}"):
350 # citation must not be empty and not contain a "}"
351 cit_list.append(m.group("key"))
352
353 return cit_list, bib_list
354
355
356 def execute(macro, args):
357 bib = Bibliography(macro, args)
358 return bib.run()
359
360 # this makes sure that jabref's bibtex files are compatible
361 def jabref2bib(body,prefix):
362
363 # read file and put everything in one string
364 body = body.split('\n')
365
366 # replace lines with pdf files
367 nLines = len(body)
368 for i in range(nLines):
369 pos = body[i].find('file = ')
370 if pos>0:
371 items = body[i].split(':')
372 if items[2][:3]=="PDF":
373 body[i] = ' pdf = {file://' + prefix + items[1] + items[-1].replace('PDF','')
374
375 return '\n'.join(body)
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.