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