Package mopowg :: Module mopowg
[hide private]
[frames] | no frames]

Source Code for Module mopowg.mopowg

  1  """ 
  2  mopowg 
  3  ====== 
  4   
  5  mopowg is an easy to install, cross-platform doc generator which is based on docutils. 
  6   
  7  mopowg could generate full documents with figures, styles, and syntax highlighting blocks. 
  8   
  9  fredlin 2007, gasolin+mopowg@gmail.com 
 10   
 11      - Scanner 
 12      - Generator 
 13          - Convertor 
 14              - Formater 
 15                  - high_lighter 
 16          - Processor 
 17              - Templater (genshi) 
 18              - Saver 
 19                  - css_writer 
 20   
 21  ---- 
 22   
 23  doc processing 
 24  -------------- 
 25   
 26  Diagram:: 
 27   
 28      ___________ 
 29      |         | 
 30      |  files  | 
 31      |         | 
 32     \|_________|/ 
 33      \         / 
 34        Scanner  -> file_list 
 35          ||| 
 36       Generator - Formater -> contents 
 37          ||| 
 38       Processor   -> files (content, presentation) 
 39          \|/ 
 40      ___________ 
 41      |         | 
 42      |   docs  | 
 43      |         | 
 44      |_________| 
 45   
 46  ---- 
 47   
 48  doc hosting[1] 
 49  -------------- 
 50   
 51  Runner is the build in server which host the documents; 
 52   
 53  Plugins: 
 54   
 55  Interpreter is the crunchy interpreter that allow you to execute the demo codes on doc; 
 56   
 57  Commenter is append fields for comment 
 58   
 59  Diagram:: 
 60   
 61      ___________ 
 62      |         | 
 63      |  files  | 
 64      |         | 
 65      |_________| 
 66           | 
 67    ---------------- 
 68    |doc processing| 
 69    ---------------- 
 70           | 
 71         Runner - plugins 
 72                     | 
 73                     |- Interpreter 
 74                     | 
 75                     |_ Commenter 
 76   
 77  ---- 
 78   
 79  doc collaborative [1] 
 80  --------------------- 
 81   
 82  Diagram:: 
 83   
 84      ___________ 
 85      |         | 
 86      |  files  |--hg repository 
 87      |         | 
 88      |_________| 
 89           | 
 90    ---------------- 
 91    |doc processing| 
 92    ---------------- 
 93           |          
 94    ---------------- 
 95    | doc hosting  | 
 96    ---------------- 
 97           | 
 98         wikier 
 99   
100  ---- 
101   
102  [1]: not implemented yet 
103   
104  ---- 
105   
106  This is the MIT license: 
107  http://www.opensource.org/licenses/mit-license.php 
108   
109  Copyright (c) 2007 Fred Lin and contributors. Mopowg is a trademark of Fred Lin. 
110   
111  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 
112   
113  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 
114   
115  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
116  """ 
117  import os 
118       
119 -def proc_dir(file_list, dirName, files):
120 """ 121 The callback function of os.path.walk() to get the list of scanned 122 files. 123 """ 124 for i in files: 125 fn = os.path.join(dirName, i) 126 if os.path.isdir(fn): 127 continue 128 elif os.path.isfile(fn): 129 file_list.append(fn)
130
131 -def scanner(path=None):
132 """scan a folder 133 134 scanner is a preprocess class to collect files 135 136 scanner currently allow single layer only 137 """ 138 if path: 139 if os.path.isdir(path): 140 #search dir recursively 141 #os.listdir(path) 142 pass 143 else: 144 path = os.path.join(os.getcwd,path) 145 else: 146 path = os.getcwd() 147 148 file_list = [] 149 os.path.walk(path, proc_dir, file_list) 150 return file_list
151 152 # default css style 153 default_style="""body { 154 margin: 0; 155 padding: 0; 156 font-family: Verdana, "Lucida Grande", sans-serif; 157 text-align: left; 158 /*text-align: center;*/ 159 line-height: 1.3em; 160 color: #333; 161 background: #fff; 162 padding: 20px 20px 0 20px; 163 } 164 .literal-block { background: #fff0f0; border: solid 1px #ccc; 165 padding:2px 2px 2px 10px; margin: 5px 5px 5px 5px; line-height:1.2em; } /* Block */ 166 .note { background: #f0ff00; border: solid 1px #ccc; 167 padding:2px 2px 2px 10px; margin: 5px 5px 5px 5px; line-height:1.2em; } /* Notes */ 168 .highlight { background: #f0f0f0; border: solid 1px #ccc; 169 padding:2px 2px 2px 10px; margin: 5px 5px 5px 5px; line-height:1.2em; } 170 .highlight .c { color: #60a0b0; font-style: italic } /* Comment */ 171 .highlight .err { border: 1px solid #FF0000 } /* Error */ 172 .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 173 .highlight .o { color: #666666 } /* Operator */ 174 .highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ 175 .highlight .cp { color: #007020 } /* Comment.Preproc */ 176 .highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ 177 .highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ 178 .highlight .gd { color: #A00000 } /* Generic.Deleted */ 179 .highlight .ge { font-style: italic } /* Generic.Emph */ 180 .highlight .gr { color: #FF0000 } /* Generic.Error */ 181 .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 182 .highlight .gi { color: #00A000 } /* Generic.Inserted */ 183 .highlight .go { color: #808080 } /* Generic.Output */ 184 .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 185 .highlight .gs { font-weight: bold } /* Generic.Strong */ 186 .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 187 .highlight .gt { color: #0040D0 } /* Generic.Traceback */ 188 .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 189 .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 190 .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 191 .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 192 .highlight .kt { color: #007020; font-weight: bold } /* Keyword.Type */ 193 .highlight .m { color: #40a070 } /* Literal.Number */ 194 .highlight .s { color: #4070a0 } /* Literal.String */ 195 .highlight .na { color: #4070a0 } /* Name.Attribute */ 196 .highlight .nb { color: #007020 } /* Name.Builtin */ 197 .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 198 .highlight .no { color: #60add5 } /* Name.Constant */ 199 .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 200 .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 201 .highlight .ne { color: #007020 } /* Name.Exception */ 202 .highlight .nf { color: #06287e } /* Name.Function */ 203 .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 204 .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 205 .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 206 .highlight .nv { color: #bb60d5 } /* Name.Variable */ 207 .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 208 .highlight .mf { color: #40a070 } /* Literal.Number.Float */ 209 .highlight .mh { color: #40a070 } /* Literal.Number.Hex */ 210 .highlight .mi { color: #40a070 } /* Literal.Number.Integer */ 211 .highlight .mo { color: #40a070 } /* Literal.Number.Oct */ 212 .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 213 .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 214 .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 215 .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 216 .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 217 .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 218 .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 219 .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 220 .highlight .sr { color: #235388 } /* Literal.String.Regex */ 221 .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 222 .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 223 .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 224 .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 225 .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 226 .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 227 .highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ 228 """ 229
230 -def css_writer(output, style, filename='style.css'):
231 """write css 232 233 output: 234 output path 235 style: 236 custom style string 237 filename: 238 output filename 239 """ 240 outpath = os.path.join(output,filename) 241 if not os.path.exists(outpath): 242 print 'saved to %s'%outpath 243 fd = file(outpath, 'w') 244 fd.write(style) 245 fd.close()
246
247 -def saver(path, content, output, style='', nostyle=False, ext='.html'):
248 """save content to file 249 250 output: dir 251 252 saver is the processor which is used to store contents to actual files; 253 254 nostyle: 255 not generate the css style 256 ext: 257 the file extension. default value is '.html'. 258 """ 259 filename = os.path.splitext(os.path.split(path)[1])[0]+ext 260 261 if not output: 262 output = os.path.split(path)[0] 263 264 if not os.path.exists(output): 265 os.mkdir(output) 266 267 sav = os.path.join(output, filename) 268 print "saved to %s"%sav 269 fd = file(sav, 'w') 270 fd.write(content) 271 fd.close() 272 273 if (os.path.exists(os.path.join(path,style)) or os.path.exists(style)): 274 fd = file(style, 'r') 275 style = fd.read() 276 fd.close() 277 278 if not nostyle: 279 css_writer(output, style)
280 281 282 # default template 283 default_template = """ 284 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 285 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 286 <html xmlns="http://www.w3.org/1999/xhtml" 287 xmlns:py="http://genshi.edgewall.org/" 288 xmlns:xi="http://www.w3.org/2001/XInclude"> 289 <head> 290 <meta content="text/html; charset=UTF-8" http-equiv="content-type"/> 291 <title>Doc generated by mopowg</title> 292 <link rel="stylesheet" type="text/css" media="screen" href="style.css" /> 293 </head> 294 <body> 295 <div id="content" py:content="Markup(content)"> 296 hello world 297 </div> 298 </body> 299 </html> 300 """ 301
302 -def templater(input, content, template):
303 """ 304 generate with genshi template 305 """ 306 from genshi.template import MarkupTemplate 307 308 if (os.path.exists(os.path.join(input,template)) or os.path.exists(template)): 309 fd = file(style, 'r') 310 template = fd.read() 311 fd.close() 312 313 tmpl = MarkupTemplate(template) 314 stream = tmpl.generate(content=content) 315 data = stream.render('html') 316 return data
317
318 -def processor(input, content, output, template, style, preview=False):
319 """process the content 320 """ 321 content = templater(input, content, template) 322 if not preview: 323 saver(input, content, output, style) 324 else: 325 return content
326 327 #==================== 328 #Formater 329 from docutils import nodes 330 from docutils.parsers.rst import directives 331 from pygments import highlight 332 from pygments.lexers import get_lexer_by_name 333 from pygments.formatters import HtmlFormatter 334
335 -def pygments_directive(name, arguments, options, content, lineno, 336 content_offset, block_text, state, state_machine):
337 """register the docutils highlight function""" 338 try: 339 lexer = get_lexer_by_name(arguments[0]) 340 except ValueError: 341 # no lexer found - use the text one instead of an exception 342 lexer = get_lexer_by_name('text') 343 #formatter = ('linenos' in options) and lineno_fmter or normal_fmter 344 formater = HtmlFormatter()#linenos=True 345 parsed = highlight(u'\n'.join(content), lexer, formater) 346 return [nodes.raw('', parsed, format='html')]
347 pygments_directive.arguments = (1, 0, 1) 348 pygments_directive.content = 1 349 directives.register_directive('code', pygments_directive) 350 #==================== 351 352 import re 353 #match wiki word to url 354 wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)") 355
356 -def convertor(path, *arg, **kw):
357 """ 358 Convert file to target format, include syntax highlight function 359 360 input: path 361 output: content 362 363 support features: 364 rich(rich content), wikiword, wikipattern 365 """ 366 try: 367 from docutils.core import publish_parts 368 import pygments 369 #from pygments.lexers import get_lexer_by_name 370 371 except ImportError, e: 372 print e 373 374 fd = file(path, 'r') 375 data = fd.read() 376 fd.close() 377 378 if kw.get('rich', False):#kw['rich'] 379 #docutil 380 content = publish_parts(data,writer_name="html")['html_body'] 381 if kw.get('wikiword', False):#kw['wikiword'] 382 #wiki links 383 pattern = kw.get('wikipattern', r'<a href="\1.html">\1</a>') 384 print 'pattern: %s'%pattern 385 content = wikiwords.sub(pattern, content) 386 else: 387 content = data 388 389 return content
390
391 -def generator(input, filter = ['.rst','.txt'], output=None, 392 rich=True, wikiword=True, 393 template=default_template, style=default_style, preview=False):
394 """generate docs 395 396 generator is used to generate docs; 397 """ 398 for i in input: 399 if os.path.isfile(i) and os.path.splitext(i)[-1] in filter: 400 #print i 401 content = convertor(path=i, rich=rich, wikiword=wikiword) 402 processor(i, content, output, template, style, preview)
403
404 -def cmdtool():
405 from optparse import OptionParser 406 print "Please use --help to get more information" 407 #allow command args 408 parser = OptionParser( 409 usage="mopowg [input] [output]") 410 parser.add_option("-i", "--input", 411 help="speficy the input folder", 412 dest="input") 413 parser.add_option("-o", "--output", 414 help="speficy the output folder", 415 dest="output") 416 parser.add_option("-r", "--rich", 417 help="use rich content", 418 action="store_true", dest="rich", default = True) 419 parser.add_option("-w", "--wikiword", 420 help="Convert WikiWord to Urls", 421 action="store_true", dest="wikiword", default = True) 422 parser.add_option("-t", "--template", 423 help="speficy a custom template", 424 dest="template", default = default_template) 425 parser.add_option("-s", "--style", 426 help="speficy a custom css style", 427 dest="style", default = default_style) 428 parser.add_option("-p", "--preview", 429 help="preview the content", 430 action="store_true", dest="preview", default = False) 431 (options, args) = parser.parse_args() 432 #print "options:"+str(options) 433 ld = scanner(path=options.input) 434 #import profile 435 #profile.run("generator(ld, rich=rich, wikiword=wikiword)", 'myapp.prof') 436 generator(input=ld, output=options.output, 437 rich=options.rich, wikiword=options.wikiword, 438 template=options.template, style=options.style, 439 preview=options.preview)
440 #import pstats 441 #p = pstats.Stats('myapp.prof')# Cumulative time sort top 25 442 #p.sort_stats('cumulative').print_stats(25) 443 # Also may find time top 25 useful 444 #p.sort_stats('time').print_stats(25) 445 446 __all__ = ['scanner', 'processor', 'default_style', 'default_template', 447 'generator', 'convertor', 'css_writer'] 448 449 if __name__=="__main__": 450 #import sys 451 cmdtool() 452