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.
  • [get | view] (2007-06-07 21:38:59, 19.9 KB) [[attachment:Bibliography.py]]
  • [get | view] (2008-05-20 16:12:49, 16.0 KB) [[attachment:Bibliography1.6.py]]
  • [get | view] (2007-06-07 21:40:16, 44.9 KB) [[attachment:bibliography-sample.png]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.