Package docs :: Package latex :: Module fetch_docstrings
[hide private]
[frames] | no frames]

Source Code for Module docs.latex.fetch_docstrings

   1  #! /usr/bin/python 
   2   
   3  ############################################################################### 
   4  #                                                                             # 
   5  # Copyright (C) 2005-2006 Edward d'Auvergne                                   # 
   6  #                                                                             # 
   7  # This file is part of the program relax.                                     # 
   8  #                                                                             # 
   9  # relax is free software; you can redistribute it and/or modify               # 
  10  # it under the terms of the GNU General Public License as published by        # 
  11  # the Free Software Foundation; either version 2 of the License, or           # 
  12  # (at your option) any later version.                                         # 
  13  #                                                                             # 
  14  # relax is distributed in the hope that it will be useful,                    # 
  15  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
  16  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
  17  # GNU General Public License for more details.                                # 
  18  #                                                                             # 
  19  # You should have received a copy of the GNU General Public License           # 
  20  # along with relax; if not, write to the Free Software                        # 
  21  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
  22  #                                                                             # 
  23  ############################################################################### 
  24   
  25   
  26   
  27   
  28  from inspect import formatargspec, getargspec, getdoc 
  29  from re import match, search 
  30  import sys 
  31  from string import lowercase, lstrip, punctuation, replace, rstrip, split, upper, whitespace 
  32   
  33  # Add the path to the relax base directory. 
  34  sys.path.append(sys.path[0]) 
  35  sys.path[0] = '../..' 
  36   
  37  # Import the program relax. 
  38  from prompt.interpreter import Interpreter 
  39   
  40   
41 -class Fetch_docstrings:
42 - def __init__(self, file='docstring.tex'):
43 """Fetch all the docstrings of the user functions and format them LaTeX style.""" 44 45 # Some dummy data structures. 46 self.script_file = None 47 self.intro_string = '' 48 self.dummy_mode = 1 49 50 # Start the interpreter! 51 self.interpreter = Interpreter(self) 52 self.interpreter.run() 53 54 # Get the blacklisted objects. 55 self.get_blacklist() 56 57 # Open the LaTeX file. 58 self.file = open(file, 'w') 59 60 # Get the names of the data structures. 61 names = self.local.keys() 62 63 # Alphabetically sort the names of the data structures. 64 names.sort() 65 66 # Loop over the data structures. 67 #for name in ['minimise']: 68 for name in names: 69 # Skip the name if it is in the blacklist. 70 if name in self.blacklist: 71 continue 72 73 # Get the object. 74 object = self.local[name] 75 76 # Determine if the structure is user function containing class. 77 if hasattr(object, '__relax_help__'): 78 # Document the user class. 79 self.doc_user_class(name, object) 80 81 # Skip the object if there is no docstring. 82 if not hasattr(object, '__doc__') or not object.__doc__: 83 continue 84 85 # Print the docstring. 86 self.parse_docstring(name, object) 87 88 # Close the LaTeX file. 89 self.file.close()
90 91
92 - def doc_user_class(self, parent_name, parent_object):
93 """Document the user class.""" 94 95 # Get the names of the data structures. 96 names = dir(parent_object) 97 98 # Alphabetically sort the names of the data structures. 99 names.sort() 100 101 # Loop over the data structures. 102 for name in names: 103 # Skip names begining with an underscore. 104 if search('^_', name): 105 continue 106 107 # Get the object. 108 object = getattr(parent_object, name) 109 110 # Skip the object if there is no docstring. 111 if not hasattr(object, '__doc__') or not object.__doc__: 112 continue 113 114 # Print the docstring. 115 self.parse_docstring(parent_name + '.' + name, object)
116 117
118 - def get_blacklist(self):
119 """Maintained list of objects in the interpreter namespace which should not be documented.""" 120 121 # Initialise the list. 122 self.blacklist = [] 123 124 # Skip these. 125 self.blacklist.append('Numeric') 126 self.blacklist.append('Scientific') 127 self.blacklist.append('pi') 128 self.blacklist.append('script')
129 130
131 - def indexing(self, index, bold=0):
132 """Function of inserting index marks into the text.""" 133 134 # End string. 135 if bold: 136 end_string = '|textbf}' 137 else: 138 end_string = '}' 139 140 # Loop over the indecies. 141 for i in xrange(len(self.entries)): 142 # Find triple word entries. 143 if index+2 < len(self.words) and self.entries[i][2] == 3 and search(self.entries[i][0], self.words[index] + ' ' + self.words[index+1] + ' ' + self.words[index+2]): 144 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string 145 146 # Find double word entries. 147 elif index+1 < len(self.words) and self.entries[i][2] == 2 and search(self.entries[i][0], self.words[index] + ' ' + self.words[index+1]): 148 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string 149 150 # Find single word entries. 151 elif self.entries[i][2] == 1 and search(self.entries[i][0], self.words[index]): 152 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
153 154
155 - def index_entries(self):
156 """Function for returning a data structure containing all words which should be indexed.""" 157 158 # Initialise. 159 self.entries = [] 160 161 # The index entries (where to index and the index name). 162 ######################################################## 163 164 self.entries.append(['angle', 'angles']) 165 self.entries.append(['anisotropic', 'diffusion!anisotropic']) 166 self.entries.append(['asymmetric', 'diffusion!ellipsoid (asymmetric)']) 167 self.entries.append(['axially symmetric', 'diffusion!spheroid (axially symmetric)']) 168 169 self.entries.append(['BFGS', 'minimisation techniques!BFGS']) 170 self.entries.append(['bond length', 'bond length']) 171 self.entries.append(['bound', 'parameter!bounds']) 172 self.entries.append(['Brownian', 'diffusion!Brownian']) 173 self.entries.append(['bzip2', 'compression!bzip2']) 174 175 self.entries.append(['cauchy', 'minimisation techniques!Cauchy point']) 176 self.entries.append(['CG-Steihaug', 'minimisation techniques!CG-Steihaug']) 177 self.entries.append(['chemical exchange', 'chemical exchange']) 178 self.entries.append(['chi-squared', 'chi-squared']) 179 self.entries.append(['compression', 'compression']) 180 self.entries.append(['conjugate gradient', 'minimisation techniques!conjugate gradient']) 181 self.entries.append(['constraint', 'constraint']) 182 self.entries.append(['copy', 'copy']) 183 self.entries.append(['correlation time', 'correlation time']) 184 185 self.entries.append(['dasha', 'computer programs!Dasha']) 186 self.entries.append(['Dasha', 'computer programs!Dasha']) 187 self.entries.append(['delete', 'delete']) 188 self.entries.append(['diffusion tensor', 'diffusion!tensor']) 189 self.entries.append(['display', 'display']) 190 self.entries.append(['dogleg', 'minimisation techniques!dogleg']) 191 192 self.entries.append(['eigenvalue', 'eigenvalues']) 193 self.entries.append(['elimination', 'model elimination']) 194 self.entries.append(['ellipsoid', 'diffusion!ellipsoid (asymmetric)']) 195 self.entries.append(['Euler angle', 'Euler angles']) 196 self.entries.append(['exact trust region', 'minimisation techniques!exact trust region']) 197 198 self.entries.append(['Fletcher-Reeves', 'minimisation techniques!Fletcher-Reeves']) 199 self.entries.append(['floating point', 'floating point number']) 200 201 self.entries.append(['grace', 'computer programs!Grace']) 202 self.entries.append(['Grace', 'computer programs!Grace']) 203 self.entries.append(['gzip', 'compression!gzip']) 204 205 self.entries.append(['Hestenes-Stiefel', 'minimisation techniques!Hestenes-Stiefel']) 206 207 self.entries.append(['isotropic', 'diffusion!sphere (isotropic)']) 208 209 self.entries.append(['Levenberg-Marquardt', 'minimisation techniques!Levenberg-Marquardt']) 210 self.entries.append(['limit', 'parameter!limit']) 211 212 self.entries.append(['map', 'map']) 213 self.entries.append(['method of [Mm]ultipliers', 'minimisation techniques!Method of Multipliers']) 214 self.entries.append(['minimise', 'minimisation']) 215 self.entries.append(['minimisation', 'minimisation']) 216 self.entries.append(['model elimination', 'model elimination']) 217 self.entries.append(['modelfree4', 'computer programs!Modelfree4']) 218 self.entries.append(['Modelfree4', 'computer programs!Modelfree4']) 219 self.entries.append(['modelling', 'modelling']) 220 self.entries.append(['molecule', 'molecule']) 221 self.entries.append(['molmol', 'computer programs!Molmol']) 222 self.entries.append(['Molmol', 'computer programs!Molmol']) 223 224 self.entries.append(['opendx', 'computer programs!OpenDX']) 225 self.entries.append(['OpenDX', 'computer programs!OpenDX']) 226 self.entries.append(['optimise', 'optimise']) 227 self.entries.append(['order parameter', 'order parameter']) 228 229 self.entries.append(['newton', 'minimisation techniques!Newton']) 230 self.entries.append(['newton-CG', 'minimisation techniques!Newton conjugate gradient']) 231 self.entries.append(['NMR', 'NMR']) 232 233 self.entries.append(['PDB', 'PDB']) 234 self.entries.append(['Polak-Ribi.*re', 'minimisation techniques!Polak-Ribiere@Polak-Ribi\`ere']) 235 self.entries.append(['Polak-Ribi.*re +', 'minimisation techniques!Polak-Ribiere@Polak-Ribi\`ere +']) 236 self.entries.append(['plot', 'plot']) 237 self.entries.append(['python', 'Python']) 238 239 self.entries.append(['read', 'read']) 240 self.entries.append(['regular expression', 'regular expression']) 241 self.entries.append(['relaxation', 'relaxation']) 242 self.entries.append(['rotation', 'rotation']) 243 244 self.entries.append(['sequence', 'sequence']) 245 self.entries.append(['script', 'scripting!script file']) 246 self.entries.append(['scripting', 'scripting']) 247 self.entries.append(['simplex', 'minimisation techniques!simplex']) 248 self.entries.append(['sphere', 'diffusion!sphere (isotropic)']) 249 self.entries.append(['spheroid', 'diffusion!spheroid (axially symmetric)']) 250 self.entries.append(['sparky', 'computer programs!Sparky']) 251 self.entries.append(['Sparky', 'computer programs!Sparky']) 252 self.entries.append(['steepest descent', 'minimisation techniques!steepest descent']) 253 254 self.entries.append(['tar', 'tar']) 255 256 self.entries.append(['uncompressed', 'compression!uncompressed']) 257 258 self.entries.append(['write', 'write']) 259 260 self.entries.append(['xeasy', 'computer programs!XEasy']) 261 self.entries.append(['Xeasy', 'computer programs!XEasy']) 262 self.entries.append(['XEasy', 'computer programs!XEasy']) 263 264 # Modifications. 265 for i in xrange(len(self.entries)): 266 # Count the number of words. 267 self.entries[i].append(len(split(self.entries[i][0], ' '))) 268 269 # Accept capitalisation. 270 if search(self.entries[i][0][0], lowercase): 271 self.entries[i][0] = '[' + upper(self.entries[i][0][0]) + self.entries[i][0][0] + ']' + self.entries[i][0][1:] 272 273 # Add a carrot to the start of the match string. 274 self.entries[i][0] = '^' + self.entries[i][0] 275 276 # Reverse the subarray in prepartion for sorting. 277 self.entries[i].reverse() 278 279 # Reverse sort by word count. 280 self.entries.sort(reverse=1) 281 for i in xrange(len(self.entries)): 282 self.entries[i].reverse()
283 284
285 - def keywords(self):
286 """Change the keyword label to bold sans serif font.""" 287 288 # Initialise. 289 string = '' 290 291 # Loop until the end of the verbatim section. 292 while 1: 293 # End of the keywords section (go to the next line then break). 294 if self.i+1 > len(self.docstring_lines) or (self.docstring_lines[self.i] == '' and self.docstring_lines[self.i+1] == ''): 295 self.i = self.i + 1 296 break 297 298 # Empty line. 299 if self.docstring_lines[self.i] == '': 300 string = string + ' \n ' 301 302 # Continuation of an example. 303 else: 304 string = string + self.docstring_lines[self.i] + ' ' 305 306 # Increment the line counter. 307 self.i = self.i + 1 308 309 # Add the sting to the verbatim section. 310 self.section.append(string) 311 self.section_type.append('keywords')
312 313
314 - def latex_formatting(self, string):
315 """Function for handling LaTeX maths environments.""" 316 317 # Angstrom. 318 string = self.safe_replacement(string, 'Angstroms', '\AA') 319 string = self.safe_replacement(string, 'Angstrom', '\AA') 320 321 # Pi. 322 string = self.safe_replacement(string, 'pi', '$\pi$') 323 324 # Less than. 325 string = replace(string, ' < ', ' $<$ ') 326 327 # Less than or equal. 328 string = replace(string, ' <= ', ' $\le$ ') 329 330 # Much less than. 331 string = replace(string, ' << ', ' $<<$ ') 332 333 # Greater than. 334 string = replace(string, ' > ', ' $>$ ') 335 336 # Greater than or equal. 337 string = replace(string, ' >= ', ' $\ge$ ') 338 339 # Much greater than. 340 string = replace(string, ' >> ', ' $>>$ ') 341 342 # 1st, 2nd, etc. 343 string = replace(string, '1st', '1$^\mathrm{st}$') 344 string = replace(string, '2nd', '2$^\mathrm{nd}$') 345 string = replace(string, '3rd', '3$^\mathrm{rd}$') 346 string = replace(string, '4th', '4$^\mathrm{th}$') 347 string = replace(string, '5th', '5$^\mathrm{th}$') 348 string = replace(string, '6th', '6$^\mathrm{th}$') 349 string = replace(string, '7th', '7$^\mathrm{th}$') 350 string = replace(string, '8th', '8$^\mathrm{th}$') 351 string = replace(string, '9th', '9$^\mathrm{th}$') 352 string = replace(string, '0th', '0$^\mathrm{th}$') 353 string = replace(string, '1th', '1$^\mathrm{th}$') 354 string = replace(string, '2th', '2$^\mathrm{th}$') 355 string = replace(string, '3th', '3$^\mathrm{th}$') 356 357 358 # Relaxation data. 359 ################## 360 361 # R1 and R2. 362 string = self.safe_replacement(string, 'R1', 'R$_1$') 363 string = self.safe_replacement(string, 'R2', 'R$_1$') 364 365 366 # Model-free parameters. 367 ######################## 368 369 # S2f, S2s, S2, te, ts, tf, tm, Rex, r. 370 string = self.safe_replacement(string, 'S2f', '$S^2_f$') 371 string = self.safe_replacement(string, 'S2s', '$S^2_s$') 372 string = self.safe_replacement(string, 'S2', '$S^2$') 373 string = self.safe_replacement(string, 'te', '$\\tau_e$') 374 string = self.safe_replacement(string, 'ts', '$\\tau_s$') 375 string = self.safe_replacement(string, 'tf', '$\\tau_f$') 376 string = self.safe_replacement(string, 'tm', '$\\tau_m$') 377 string = self.safe_replacement(string, 'Rex', '$R_{ex}$') 378 string = self.safe_replacement(string, 'r', '$r$') 379 string = self.safe_replacement(string, '<r>', '$<$$r$$>$') 380 381 382 # Spectral densities. 383 ##################### 384 385 # J(w), J(0), J(wX), J(wH). 386 string = replace(string, 'J(w)', '$J(\omega)$') 387 string = replace(string, 'J(0)', '$J(0)$') 388 string = replace(string, 'J(wX)', '$J(\omega_X)$') 389 string = replace(string, 'J(wH)', '$J(\omega_H)$') 390 391 392 # Diffusion tensor parameters. 393 ############################## 394 395 # Diso, Da, Dr, Dx, Dy, Dz, Dpar, Dper, Dratio. 396 string = self.safe_replacement(string, 'Diso', '$\Diff_{iso}$') 397 string = self.safe_replacement(string, 'Da', '$\Diff_a$') 398 string = self.safe_replacement(string, 'Dr', '$\Diff_r$') 399 string = self.safe_replacement(string, 'R', '$\mathfrak{R}$') 400 string = self.safe_replacement(string, 'Dx', '$\Diff_x$') 401 string = self.safe_replacement(string, 'Dy', '$\Diff_y$') 402 string = self.safe_replacement(string, 'Dz', '$\Diff_z$') 403 string = self.safe_replacement(string, 'Dpar', '$\Diff_\Par$') 404 string = self.safe_replacement(string, 'Dper', '$\Diff_\Per$') 405 string = self.safe_replacement(string, 'Dratio', '$\Diff_{ratio}$') 406 407 408 # Angles. 409 ######### 410 411 # alpha, beta, gamma, theta, phi. 412 string = self.safe_replacement(string, 'alpha', '$\\alpha$') 413 string = self.safe_replacement(string, 'beta', '$\\beta$') 414 string = self.safe_replacement(string, 'gamma', '$\\gamma$') 415 string = self.safe_replacement(string, 'theta', '$\\theta$') 416 string = self.safe_replacement(string, 'phi', '$\\phi$') 417 418 419 # Direction cosines. 420 #################### 421 422 # delta_x, delta_y, delta_z. 423 string = self.safe_replacement(string, 'dx', '$\\delta_x$') 424 string = self.safe_replacement(string, 'dy', '$\\delta_y$') 425 string = self.safe_replacement(string, 'dz', '$\\delta_z$') 426 427 428 # Indecies. 429 ########### 430 431 # i, j, k, l, m, n, x, y, z, A, b, u. 432 string = self.safe_replacement(string, 'i', '$i$') 433 string = self.safe_replacement(string, 'j', '$j$') 434 string = self.safe_replacement(string, 'k', '$k$') 435 string = self.safe_replacement(string, 'l', '$l$') 436 string = self.safe_replacement(string, 'm', '$m$') 437 string = self.safe_replacement(string, 'n', '$n$') 438 string = self.safe_replacement(string, 'x', '$x$') 439 string = self.safe_replacement(string, 'y', '$y$') 440 string = self.safe_replacement(string, 'z', '$z$') 441 string = self.safe_replacement(string, 'b', '$b$') 442 string = self.safe_replacement(string, 'u', '$u$') 443 444 445 # Misc. 446 ####### 447 448 # tau. 449 string = self.safe_replacement(string, 'tau', '$\\tau$') 450 451 # Polak-Ribi\`ere. 452 string = self.safe_replacement(string, 'Polak-Ribiere', 'Polak-Ribi\`ere') 453 454 455 # Return the new text. 456 return string
457 458
459 - def latex_quotes(self, string):
460 """Function for changing the quotes for LaTeX processing.""" 461 462 # Initialise. 463 new_string = '' 464 in_quote = 0 465 466 # Loop over the characters. 467 for i in xrange(len(string)): 468 # Find the quote marks. 469 if search('\'', string[i]): 470 # Swap the opening ' with `. 471 if not in_quote and (i == 0 or not search('[a-z]', string[i-1])): 472 new_string = new_string + '`' 473 in_quote = 1 474 continue 475 476 # Just exited the quote 477 else: 478 in_quote = 0 479 480 # Append the character. 481 new_string = new_string + string[i] 482 483 return new_string
484 485
486 - def latex_special_chars(self, string):
487 """Function for handling LaTeX special characters.""" 488 489 # Damned backslashes. 490 string = replace(string, '\\', 'This is a backslash to be replaced at the end of this functioN') 491 492 # List of special characters (prefix a backslash). 493 for char in "#$%&_{}": 494 string = replace(string, char, '\\'+char) 495 496 # Doubly special characters (prefix a backslash and postfix '{}'). 497 for char in "^~": 498 string = replace(string, char, '\\'+char+'{}') 499 500 # Damned backslashes! 501 string = replace(string, 'This is a backslash to be replaced at the end of this functioN', '$\\backslash$') 502 503 # Return the new text. 504 return string
505 506
507 - def lists(self):
508 """Function for creating LaTeX lists.""" 509 510 # Initialise. 511 string = lstrip(self.docstring_lines[self.i]) 512 513 # Determine the element spacing. 514 j = self.i 515 while 1: 516 # Walk to the next line. 517 j = j + 1 518 519 # No more lines. 520 if len(self.docstring_lines) <= j: 521 list_spacing = 0 522 break 523 524 # Find the empty line. 525 if len(self.docstring_lines[j]) == 0: 526 # No more lines. 527 if len(self.docstring_lines) <= j+1: 528 list_spacing = 0 529 530 # Determine if the next line is an element of the list. 531 elif search('^ ', self.docstring_lines[j+1]): 532 list_spacing = 1 533 534 # or not. 535 else: 536 list_spacing = 0 537 538 # All done. 539 break 540 541 # Non-spaced list. 542 if not list_spacing: 543 # New line character. 544 string = string + ' \n ' 545 546 # Loop until the end of the list. 547 while 1: 548 # Increment the line counter. 549 self.i = self.i + 1 550 551 # End of a non-spaced list. 552 if self.i >= len(self.docstring_lines) or len(self.docstring_lines[self.i]) == 0: 553 break 554 555 # Add the next line. 556 string = string + lstrip(self.docstring_lines[self.i]) + ' \n ' 557 558 # Spaced list. 559 else: 560 # Loop until the end of the list. 561 while 1: 562 # Increment the line counter. 563 self.i = self.i + 1 564 565 # No more lines. 566 if self.i >= len(self.docstring_lines): 567 break 568 569 # Empty line. 570 if len(self.docstring_lines[self.i]) == 0: 571 # New line character. 572 string = string + ' \n ' 573 574 # Go to the next line. 575 continue 576 577 # End of the list. 578 if self.i >= len(self.docstring_lines) or not search('^ ', (self.docstring_lines[self.i])): 579 break 580 581 # Add the next line. 582 string = string + ' ' + lstrip(self.docstring_lines[self.i]) 583 584 # Walk back one line. 585 self.i = self.i - 1 586 587 # Add the sting to the list section. 588 self.section.append(string) 589 self.section_type.append('list')
590 591
592 - def paragraph(self):
593 """Function for extracting the paragraphs from the docstring.""" 594 595 # Initialise. 596 string = self.docstring_lines[self.i] 597 598 # Loop until the end of the paragraph. 599 while 1: 600 # Increment the line counter. 601 self.i = self.i + 1 602 603 # No more lines. 604 if self.i >= len(self.docstring_lines): 605 break 606 607 # Empty line. 608 if len(self.docstring_lines[self.i]) == 0: 609 break 610 611 # Start of table. 612 if search('^___', self.docstring_lines[self.i]): 613 break 614 615 # Start of list. 616 if search('^ ', self.docstring_lines[self.i]): 617 break 618 619 # Add the next line. 620 string = string + ' ' + self.docstring_lines[self.i] 621 622 # Walk back one line. 623 self.i = self.i - 1 624 625 # Add the sting to the verbatim section. 626 self.section.append(string) 627 self.section_type.append('paragraph')
628 629
630 - def parse_docstring(self, function, object):
631 """Function for creating the LaTeX file.""" 632 633 # Initialise. 634 ############# 635 636 # Print the function name to sys.stdout 637 sys.stdout.write("Function: " + `function` + "\n") 638 639 # Get the docstring. 640 docstring = getdoc(object) 641 642 # Split the docstring by newline characters. 643 self.docstring_lines = split(docstring, "\n") 644 645 # The section and section_type arrays. 646 self.section = [] 647 self.section_type = [] 648 649 650 # Function name. 651 ################ 652 653 self.section.append(function) 654 self.section_type.append('subsection') 655 656 657 # Synopsis. 658 ########### 659 660 # Heading. 661 self.section.append('Synopsis') 662 self.section_type.append('subsubsection') 663 664 # The synopsis. 665 self.section.append(self.docstring_lines[0]) 666 self.section_type.append('paragraph') 667 668 669 # Arguments. 670 ############ 671 672 # Heading. 673 self.section.append('Defaults') 674 self.section_type.append('subsubsection') 675 676 # Get the arguments. 677 args, varargs, varkw, defaults = getargspec(object) 678 679 # Format the arguments. 680 arguments = formatargspec(args, varargs, varkw, defaults) 681 682 # The string. 683 self.section.append(arguments) 684 self.section_type.append('arguments') 685 686 687 # First level parsing - sectioning. 688 ################################### 689 690 # Loop over the lines. 691 self.i = 1 # Skip the first two lines (synopsis and blank line). 692 while 1: 693 # Increment the line number. 694 self.i = self.i + 1 695 696 # End. 697 if self.i >= len(self.docstring_lines): 698 break 699 700 # Strip any whitespace from the end of the line (including newline characters). 701 self.docstring_lines[self.i] = rstrip(self.docstring_lines[self.i]) 702 703 # Skip the out of section empty lines. 704 if self.docstring_lines[self.i] == '': 705 continue 706 707 # Find the docstring sections. 708 if self.i+1 < len(self.docstring_lines) and search('^~~~', self.docstring_lines[self.i+1]): 709 # Title. 710 self.section_title = self.docstring_lines[self.i] 711 self.section.append(self.docstring_lines[self.i]) 712 self.section_type.append('subsubsection') 713 714 # Skip the title line, tilde line, and first blank line. 715 self.i = self.i + 2 716 continue 717 718 # Format the 'Keyword Arguements' section. 719 if search('^Keyword ', self.section_title): 720 self.keywords() 721 722 # Verbatim section. 723 elif search('---', self.docstring_lines[self.i]): 724 self.verbatim() 725 726 # relax> or '$ ...' example lines. 727 elif search('^relax>', self.docstring_lines[self.i]) or search('^\$ ', self.docstring_lines[self.i]): 728 self.relax_examples() 729 730 # Tables. 731 elif search('^___', self.docstring_lines[self.i]): 732 self.tables() 733 734 # Lists. 735 elif search('^ ', self.docstring_lines[self.i]): 736 self.lists() 737 738 # Normal paragraphs. 739 else: 740 self.paragraph() 741 742 743 744 # Low level parse - formatting. 745 ############################### 746 747 # Get the words to index. 748 self.index_entries() 749 750 # Loop over the sections. 751 for i in xrange(len(self.section)): 752 # The section type alias. 753 st = self.section_type[i] 754 755 # Translate to LaTeX quotation marks. 756 if st == 'arguments' or st == 'example': 757 self.section[i] = self.latex_quotes(self.section[i]) 758 759 # Handle the special LaTeX characters. 760 if not st == 'verbatim': 761 self.section[i] = self.latex_special_chars(self.section[i]) 762 763 # LaTeX formatting. 764 if not st == 'arguments' and not st == 'verbatim' and not st == 'example' and not st == 'subsection': 765 self.section[i] = self.latex_formatting(self.section[i]) 766 767 # Word by word formatting. 768 if not st == 'arguments' and not st == 'verbatim' and not st == 'example': 769 # Split the string. 770 self.words = split(self.section[i], ' ') 771 772 # Initialise. 773 self.in_quote = 0 774 775 # Loop over the words one by one. 776 for j in xrange(len(self.words)): 777 # Indexing. 778 if st == 'subsection' or st == 'subsubsection': 779 self.indexing(j, bold=1) 780 else: 781 self.indexing(j, bold=0) 782 783 # Quotes. 784 self.quotes(j) 785 786 # Recreate the section string. 787 if j == 0: 788 self.section[i] = self.words[j] 789 else: 790 self.section[i] = self.section[i] + ' ' + self.words[j] 791 792 793 # Write to file. 794 ################ 795 796 # Start a new page. 797 self.file.write(" \n\n \\newpage") 798 799 # Loop over the data. 800 for i in xrange(len(self.section)): 801 # The section type alias. 802 st = self.section_type[i] 803 804 # Subsection. 805 if st == 'subsection': 806 self.file.write(" \n\n \\subsection{" + self.section[i] + "}") 807 808 # Subsubsection. 809 elif st == 'subsubsection': 810 self.file.write(" \n \\subsubsection{" + self.section[i] + "}") 811 812 # Defaults. 813 elif st == 'arguments': 814 self.file.write("\\textsf{\\textbf{" + self.latex_special_chars(function) + "}" + self.section[i] + "}") 815 816 # Keywords. 817 elif st == 'keywords': 818 # Split the lines 819 lines = split(self.section[i], '\n') 820 821 # Loop over the lines. 822 for line in lines: 823 # Split the line. 824 line_elements = split(line, ':') 825 826 # Don't know what to do with this! 827 if len(line_elements) > 2: 828 sys.write("Keyword failure in: " + `line` + " \n ") 829 sys.exit() 830 831 # Format the keyword. 832 self.file.write("\\keyword{" + line_elements[0] + ":}" + line_elements[1] + " \n\n ") 833 834 835 # Verbatim. 836 elif st == 'verbatim': 837 self.file.write("{\\footnotesize \\begin{verbatim} \n " + self.section[i] + "\\end{verbatim}}") 838 839 # Example. 840 elif st == 'example': 841 self.file.write("\\example{" + self.section[i] + "}") 842 843 # Tables. 844 elif st == 'table': 845 # Split the lines 846 lines = split(self.section[i], '\n') 847 848 # Start the table, center it, and add the toprule. 849 self.file.write("\\begin{center} \n ") 850 self.file.write("\\begin{tabular}{" + (int(lines[0]))*"l" + "} \n ") 851 self.file.write("\\toprule \n ") 852 853 # Generate the LaTeX headings. 854 elements = split(lines[1], 'SEPARATOR') 855 self.file.write(elements[0]) 856 for j in range(1, len(elements)): 857 self.file.write('&' + elements[j]) 858 self.file.write(" \\\\ \n ") 859 860 # Add the midrule. 861 self.file.write("\\midrule \n ") 862 863 # Loop over the main table lines. 864 for line in lines[2:-1]: 865 # Split columns. 866 elements = split(line, 'SEPARATOR') 867 868 # Write the columns. 869 self.file.write(elements[0]) 870 for j in range(1, len(elements)): 871 self.file.write('&' + elements[j]) 872 self.file.write(" \\\\\n ") 873 874 # Add the bottomrule and terminate the tabular and center environment. 875 self.file.write("\\bottomrule \n ") 876 self.file.write("\\end{tabular} \n ") 877 self.file.write("\\end{center} \n ") 878 879 # Lists. 880 elif st == 'list': 881 # Split the lines 882 lines = split(self.section[i], '\n') 883 884 # Dump an empty last line. 885 if len(lines[-1]) == 0: 886 lines = lines[:-1] 887 888 # Determine the type of list. 889 elements = split(lines[0], ':') 890 891 # Badly formatted list. 892 if len(elements) > 2: 893 sys.stderr.write("Error: Badly formatted list element.\n") 894 sys.stderr.write("The element is: " + `lines[i]` + "\n") 895 sys.exit() 896 897 # Plain list. 898 if len(elements) == 1: 899 list_type = 0 900 901 # Formatted list. 902 else: 903 list_type = 1 904 905 # Start the list. 906 if list_type == 1: 907 self.file.write("\\begin{description} \n ") 908 else: 909 self.file.write("\\begin{itemize} \n ") 910 911 # Loop over the lines. 912 for j in xrange(len(lines)): 913 # Plain list. 914 if list_type == 0: 915 self.file.write("\\item[] " + lstrip(lines[j]) + ' \n ') 916 917 # Description. 918 else: 919 # Get the description. 920 elements = split(lines[j], ':') 921 922 # End of list. 923 if len(elements) != 2: 924 continue 925 926 # Format the element. 927 self.file.write("\\item[" + lstrip(elements[0]) + " --]" + elements[1] + ' \n ') 928 929 # End of the list. 930 if list_type == 1: 931 self.file.write("\\end{description} \n ") 932 else: 933 self.file.write("\\end{itemize} \n ") 934 935 # No special formatting. 936 else: 937 self.file.write(self.section[i] + ' \n ') 938 939 # Add two newlines. 940 self.file.write(" \n\n ")
941 942
943 - def quotes(self, index):
944 """Function for placing quotes within the quote environment.""" 945 946 # Split the word by '. 947 elements = split(self.words[index], "'") 948 949 # Single word quote. 950 if len(elements) == 3: 951 self.words[index] = elements[0] + '\quotecmd{' + elements[1] + '}' + elements[2] 952 953 # Weird quote. 954 elif len(elements) > 3: 955 sys.stderr.write('Unknown quote: ' + `self.words[index]`) 956 sys.exit() 957 958 # Multiword quote. 959 if len(elements) == 2: 960 # Start of the quote. 961 if not self.in_quote and not search('[a-z]$', elements[0]): 962 self.words[index] = elements[0] + '\quotecmd{' + elements[1] 963 self.in_quote = 1 964 965 # End of the quote. 966 elif self.in_quote: 967 self.words[index] = elements[0] + '}' + elements[1] 968 self.in_quote = 0
969 970
971 - def relax_examples(self):
972 """Use typewriter font for relax examples.""" 973 974 # Initialise. 975 string = self.docstring_lines[self.i] 976 977 # Loop until the end of the example. 978 while 1: 979 # Increment the line counter. 980 self.i = self.i + 1 981 982 # End of the example (jump back one line). 983 if self.i >= len(self.docstring_lines) or self.docstring_lines[self.i] == '' or search('^relax>', self.docstring_lines[self.i]) or search('^\$ ', self.docstring_lines[self.i]): 984 self.i = self.i - 1 985 break 986 987 # Add the line to the example. 988 string = string + ' ' + lstrip(self.docstring_lines[self.i]) 989 990 # Add the sting to the verbatim section. 991 self.section.append(string) 992 self.section_type.append('example')
993 994
995 - def safe_replacement(self, string, text, latex):
996 """Only replace in safe places within the text.""" 997 998 # Combos (if only RE could be used!) 999 1000 # A number out the front. 1001 string = replace(string, '0'+text, '0'+latex) 1002 string = replace(string, '1'+text, '1'+latex) 1003 string = replace(string, '2'+text, '2'+latex) 1004 string = replace(string, '3'+text, '3'+latex) 1005 string = replace(string, '4'+text, '4'+latex) 1006 string = replace(string, '5'+text, '5'+latex) 1007 string = replace(string, '6'+text, '6'+latex) 1008 string = replace(string, '7'+text, '7'+latex) 1009 string = replace(string, '8'+text, '8'+latex) 1010 string = replace(string, '9'+text, '9'+latex) 1011 1012 # In a sentence. 1013 string = replace(string, ' '+text+',', ' '+latex+',') 1014 string = replace(string, ' '+text+'.', ' '+latex+'.') 1015 string = replace(string, ' '+text+' ', ' '+latex+' ') 1016 string = replace(string, ' '+text+';', ' '+latex+';') 1017 string = replace(string, ' '+text+':', ' '+latex+':') 1018 1019 # In lists []. 1020 string = replace(string, '['+text+']', '['+latex+']') 1021 string = replace(string, '['+text+' ', '['+latex+' ') 1022 string = replace(string, '['+text+',', '['+latex+',') 1023 string = replace(string, '['+text+';', '['+latex+';') 1024 string = replace(string, ' '+text+']', ' '+latex+']') 1025 1026 # In lists (). 1027 string = replace(string, '('+text+')', '('+latex+')') 1028 string = replace(string, '('+text+' ', '('+latex+' ') 1029 string = replace(string, '('+text+',', '('+latex+',') 1030 string = replace(string, '('+text+';', '('+latex+';') 1031 string = replace(string, ' '+text+')', ' '+latex+')') 1032 1033 # In lists {}. 1034 string = replace(string, '{'+text+' ', '{'+latex+' ') 1035 string = replace(string, '{'+text+',', '{'+latex+',') 1036 string = replace(string, '{'+text+';', '{'+latex+';') 1037 string = replace(string, ' '+text+'\\', ' '+latex+'\\') 1038 1039 # Quoted. 1040 string = replace(string, '`'+text+'\'', '`'+latex+'\'') 1041 string = replace(string, '`'+text+' ', '`'+latex+' ') 1042 string = replace(string, '`'+text+',', '`'+latex+',') 1043 string = replace(string, '`'+text+'.', '`'+latex+'.') 1044 string = replace(string, '`'+text+';', '`'+latex+';') 1045 string = replace(string, ' '+text+'\'', ' '+latex+'\'') 1046 1047 # End of the line. 1048 substring = replace(string[-len(text)-1:], ' '+text, ' '+latex) 1049 string = string[0:-len(text)-1] + substring 1050 1051 substring = replace(string[-len(text)-1:], '.'+text, '.'+latex) 1052 string = string[0:-len(text)-1] + substring 1053 1054 string = replace(string, ' '+text+'\n', ' '+latex+'\n') 1055 string = replace(string, '.'+text+'\n', '.'+latex+'\n') 1056 1057 # Maths 1058 string = replace(string, ' '+text+'\^', ' '+latex+'\^') 1059 string = replace(string, '('+text+'\^', '('+latex+'\^') 1060 string = replace(string, '\n'+text+'\^', '\n'+latex+'\^') 1061 1062 # At the start of the line. 1063 if search('^'+text+'['+punctuation+']', string) or search('^'+text+'['+whitespace+']', string) or search('\n'+text+'['+punctuation+']', string) or search('\n'+text+'['+whitespace+']', string): 1064 string = replace(string, text+' ', latex+' ') 1065 string = replace(string, text+',', latex+',') 1066 string = replace(string, text+'.', latex+'.') 1067 string = replace(string, text+';', latex+';') 1068 string = replace(string, text+']', latex+']') 1069 string = replace(string, text+')', latex+')') 1070 string = replace(string, text+'^', latex+'^') 1071 string = replace(string, text+'\\', latex+'\\') 1072 string = replace(string, text+'\'', latex+'\'') 1073 string = replace(string, text+'\n', latex+'\n') 1074 1075 1076 # Return the string. 1077 return string
1078 1079
1080 - def tables(self):
1081 """Function for creating LaTeX tables.""" 1082 1083 # Increment the line counter. 1084 self.i = self.i + 1 1085 1086 # Count the number of columns. 1087 num_col = len(split(self.docstring_lines[self.i], '|')) 1088 string = `num_col-2` + ' \n ' 1089 1090 # Not really a table! 1091 if num_col == 1: 1092 sys.write('Not a table!') 1093 sys.exit() 1094 1095 # Shift to the next line. 1096 self.i = self.i + 1 1097 1098 # Get the headings. 1099 headings = split(self.docstring_lines[self.i], '|') 1100 headings = headings[1:-1] 1101 for j in xrange(len(headings)): 1102 headings[j] = lstrip(rstrip(headings[j])) 1103 1104 # Generate the LaTeX headings. 1105 string = string + headings[0] 1106 for j in range(1, len(headings)): 1107 string = string + " SEPARATOR " + headings[j] 1108 string = string + ' \n ' 1109 1110 # Skip three lines. 1111 self.i = self.i + 3 1112 1113 # Go through the table. 1114 while 1: 1115 # End of the table (go to the next line then break). 1116 if self.i >= len(self.docstring_lines) or search('^\\|_', self.docstring_lines[self.i]): 1117 self.i = self.i + 1 1118 break 1119 1120 # Split the columns. 1121 columns = split(self.docstring_lines[self.i], '|') 1122 1123 # Create the formatted tabular line. 1124 if len(columns) > 1: 1125 string = string + lstrip(rstrip(columns[1])) 1126 for j in range(2, len(columns)-1): 1127 string = string + " SEPARATOR " + lstrip(rstrip(columns[j])) 1128 string = string + ' \n ' 1129 else: 1130 string = string + columns[0] + ' \n ' 1131 1132 # Increment the line counter. 1133 self.i = self.i + 1 1134 1135 # Add the sting to the table section. 1136 self.section.append(string) 1137 self.section_type.append('table')
1138 1139
1140 - def verbatim(self):
1141 """Function for extracting the verbatim docstring section.""" 1142 1143 # Initialise. 1144 string = '' 1145 1146 # Loop until the end of the verbatim section. 1147 while 1: 1148 # Increment the line counter. 1149 self.i = self.i + 1 1150 1151 # End of Verbatim (go to the next line then break). 1152 if self.i >= len(self.docstring_lines) or search('---', self.docstring_lines[self.i]): 1153 self.i = self.i + 1 1154 break 1155 1156 # Add the next line. 1157 string = string + self.docstring_lines[self.i] + ' \n ' 1158 1159 # Add the sting to the verbatim section. 1160 self.section.append(string) 1161 self.section_type.append('verbatim')
1162