1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9  """ 
 10  Miscellaneous utility functions that are used by multiple modules. 
 11   
 12  @group Python source types: is_module_file, is_package_dir, is_pyname, 
 13      py_src_filename 
 14  @group Text processing: wordwrap, decode_with_backslashreplace, 
 15      plaintext_to_html 
 16  """ 
 17  __docformat__ = 'epytext en' 
 18   
 19  import os, os.path, re 
 20   
 21   
 22   
 23   
 24   
 25  PY_SRC_EXTENSIONS = ['.py', '.pyw'] 
 26  PY_BIN_EXTENSIONS = ['.pyc', '.so', '.pyd'] 
 27   
 34   
 38       
 40      """ 
 41      Return true if the given directory is a valid package directory 
 42      (i.e., it names a directory that contsains a valid __init__ file, 
 43      and its name is a valid identifier). 
 44      """ 
 45       
 46      if not os.path.isdir(dirname): 
 47          return False 
 48       
 49       
 50      (parent, dir) = os.path.split(dirname) 
 51      if dir == '': (parent, dir) = os.path.split(parent) 
 52      if not re.match('\w+$', dir): 
 53          return False 
 54       
 55      for name in os.listdir(dirname): 
 56          filename = os.path.join(dirname, name) 
 57          if name.startswith('__init__.') and is_module_file(filename): 
 58              return True 
 59      else: 
 60          return False 
  61   
 63      return re.match(r"\w+(\.\w+)*$", name) 
  64   
 66      basefile, extension = os.path.splitext(filename) 
 67      if extension in PY_SRC_EXTENSIONS: 
 68          return filename 
 69      else: 
 70          for ext in PY_SRC_EXTENSIONS: 
 71              if os.path.isfile('%s%s' % (basefile, ext)): 
 72                  return '%s%s' % (basefile, ext) 
 73          else: 
 74              raise ValueError('Could not find a corresponding ' 
 75                               'Python source file.') 
  76   
 81   
 82   
 83   
 84   
 85   
 87      r""" 
 88      Convert the given 8-bit string into unicode, treating any 
 89      character c such that ord(c)<128 as an ascii character, and 
 90      converting any c such that ord(c)>128 into a backslashed escape 
 91      sequence. 
 92   
 93          >>> decode_with_backslashreplace('abc\xff\xe8') 
 94          u'abc\\xff\\xe8' 
 95      """ 
 96       
 97       
 98      assert isinstance(s, str) 
 99      return (s 
100              .decode('latin1') 
101              .encode('ascii', 'backslashreplace') 
102              .decode('ascii')) 
 103   
104 -def wordwrap(str, indent=0, right=75, startindex=0, splitchars=''): 
 105      """ 
106      Word-wrap the given string.  I.e., add newlines to the string such 
107      that any lines that are longer than C{right} are broken into 
108      shorter lines (at the first whitespace sequence that occurs before 
109      index C{right}).  If the given string contains newlines, they will 
110      I{not} be removed.  Any lines that begin with whitespace will not 
111      be wordwrapped. 
112   
113      @param indent: If specified, then indent each line by this number 
114          of spaces. 
115      @type indent: C{int} 
116      @param right: The right margin for word wrapping.  Lines that are 
117          longer than C{right} will be broken at the first whitespace 
118          sequence before the right margin. 
119      @type right: C{int} 
120      @param startindex: If specified, then assume that the first line 
121          is already preceeded by C{startindex} characters. 
122      @type startindex: C{int} 
123      @param splitchars: A list of non-whitespace characters which can 
124          be used to split a line.  (E.g., use '/\\' to allow path names 
125          to be split over multiple lines.) 
126      @rtype: C{str} 
127      """ 
128      if splitchars: 
129          chunks = re.split(r'( +|\n|[^ \n%s]*[%s])' % 
130                            (re.escape(splitchars), re.escape(splitchars)), 
131                            str.expandtabs()) 
132      else: 
133          chunks = re.split(r'( +|\n)', str.expandtabs()) 
134      result = [' '*(indent-startindex)] 
135      charindex = max(indent, startindex) 
136      for chunknum, chunk in enumerate(chunks): 
137          if (charindex+len(chunk) > right and charindex > 0) or chunk == '\n': 
138              result.append('\n' + ' '*indent) 
139              charindex = indent 
140              if chunk[:1] not in ('\n', ' '): 
141                  result.append(chunk) 
142                  charindex += len(chunk) 
143          else: 
144              result.append(chunk) 
145              charindex += len(chunk) 
146      return ''.join(result).rstrip()+'\n' 
147   
149      """ 
150      @return: An HTML string that encodes the given plaintext string. 
151      In particular, special characters (such as C{'<'} and C{'&'}) 
152      are escaped. 
153      @rtype: C{string} 
154      """ 
155      s = s.replace('&', '&').replace('"', '"') 
156      s = s.replace('<', '<').replace('>', '>') 
157      return s 
 158           
159 -def plaintext_to_latex(str, nbsp=0, breakany=0): 
 160      """ 
161      @return: A LaTeX string that encodes the given plaintext string. 
162      In particular, special characters (such as C{'$'} and C{'_'}) 
163      are escaped, and tabs are expanded. 
164      @rtype: C{string} 
165      @param breakany: Insert hyphenation marks, so that LaTeX can 
166      break the resulting string at any point.  This is useful for 
167      small boxes (e.g., the type box in the variable list table). 
168      @param nbsp: Replace every space with a non-breaking space 
169      (C{'~'}). 
170      """ 
171       
172      if breakany: str = re.sub('(.)', '\\1\1', str) 
173   
174       
175      str = str.replace('\\', '\0') 
176   
177       
178      str = str.expandtabs() 
179   
180       
181      str = re.sub(r'([#$&%_\${}])', r'\\\1', str) 
182   
183       
184      str = str.replace('|', '{\\textbar}') 
185      str = str.replace('<', '{\\textless}') 
186      str = str.replace('>', '{\\textgreater}') 
187      str = str.replace('^', '{\\textasciicircum}') 
188      str = str.replace('~', '{\\textasciitilde}') 
189      str = str.replace('\0', r'{\textbackslash}') 
190   
191       
192      if nbsp: str = str.replace(' ', '~') 
193   
194       
195      if breakany: str = str.replace('\1', r'\-') 
196       
197      return str 
198   
201          OSError.__init__(self, '%s failed' % cmd[0]) 
202          self.out = out 
203          self.err = err 
  204   
206      """ 
207      Execute the command C{cmd} in a subprocess. 
208       
209      @param cmd: The command to execute, specified as a list 
210          of string. 
211      @param data: A string containing data to send to the 
212          subprocess. 
213      @return: A tuple C{(out, err)}. 
214      @raise OSError: If there is any problem executing the 
215          command, or if its exitval is not 0. 
216      """ 
217      if isinstance(cmd, basestring): 
218          cmd = cmd.split() 
219   
220       
221      try: 
222          from subprocess import Popen, PIPE 
223          pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) 
224          out, err = pipe.communicate(data) 
225          if hasattr(pipe, 'returncode'): 
226              if pipe.returncode == 0: 
227                  return out, err 
228              else: 
229                  raise RunSubprocessError(cmd, out, err) 
230          else: 
231               
232               
233              if err == '': 
234                  return out, err 
235              else: 
236                  raise RunSubprocessError(cmd, out, err) 
237      except ImportError: 
238          pass 
239   
240       
241       
242      import popen2 
243      if hasattr(popen2, 'Popen3'): 
244          pipe = popen2.Popen3(' '.join(cmd), True) 
245          to_child = pipe.tochild 
246          from_child = pipe.fromchild 
247          child_err = pipe.childerr 
248          if data: 
249              to_child.write(data) 
250          to_child.close() 
251          out = err = '' 
252          while pipe.poll() is None: 
253              out += from_child.read() 
254              err += child_err.read() 
255          out += from_child.read() 
256          err += child_err.read() 
257          if pipe.wait() == 0: 
258              return out, err 
259          else: 
260              raise RunSubprocessError(cmd, out, err) 
261   
262       
263      else: 
264          to_child, from_child, child_err = os.popen3(' '.join(cmd), 'b') 
265          if data: 
266              to_child.write(data) 
267          to_child.close() 
268          err = child_err.read() 
269          out = from_child.read() 
270           
271           
272          if err == '': 
273              return out, err 
274          else: 
275              raise RunSubprocessError(cmd, out, err) 
 276