Format: text/x-python
⬇ Download File (4.6 KB)
   1  # encoding: utf-8
   2  """
   3  IO related utilities.
   4  """
   5  
   6  # Copyright (c) IPython Development Team.
   7  # Distributed under the terms of the Modified BSD License.
   8  
   9  
  10  
  11  import atexit
  12  import os
  13  import sys
  14  import tempfile
  15  from pathlib import Path
  16  from warnings import warn
  17  
  18  from IPython.utils.decorators import undoc
  19  from .capture import CapturedIO, capture_output
  20  
  21  class Tee(object):
  22      """A class to duplicate an output stream to stdout/err.
  23  
  24      This works in a manner very similar to the Unix 'tee' command.
  25  
  26      When the object is closed or deleted, it closes the original file given to
  27      it for duplication.
  28      """
  29      # Inspired by:
  30      # http://mail.python.org/pipermail/python-list/2007-May/442737.html
  31  
  32      def __init__(self, file_or_name, mode="w", channel='stdout'):
  33          """Construct a new Tee object.
  34  
  35          Parameters
  36          ----------
  37          file_or_name : filename or open filehandle (writable)
  38              File that will be duplicated
  39          mode : optional, valid mode for open().
  40              If a filename was give, open with this mode.
  41          channel : str, one of ['stdout', 'stderr']
  42          """
  43          if channel not in ['stdout', 'stderr']:
  44              raise ValueError('Invalid channel spec %s' % channel)
  45  
  46          if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
  47              self.file = file_or_name
  48          else:
  49              encoding = None if "b" in mode else "utf-8"
  50              self.file = open(file_or_name, mode, encoding=encoding)
  51          self.channel = channel
  52          self.ostream = getattr(sys, channel)
  53          setattr(sys, channel, self)
  54          self._closed = False
  55  
  56      def close(self):
  57          """Close the file and restore the channel."""
  58          self.flush()
  59          setattr(sys, self.channel, self.ostream)
  60          self.file.close()
  61          self._closed = True
  62  
  63      def write(self, data):
  64          """Write data to both channels."""
  65          self.file.write(data)
  66          self.ostream.write(data)
  67          self.ostream.flush()
  68  
  69      def flush(self):
  70          """Flush both channels."""
  71          self.file.flush()
  72          self.ostream.flush()
  73  
  74      def __del__(self):
  75          if not self._closed:
  76              self.close()
  77  
  78      def isatty(self):
  79          return False
  80  
  81  def ask_yes_no(prompt, default=None, interrupt=None):
  82      """Asks a question and returns a boolean (y/n) answer.
  83  
  84      If default is given (one of 'y','n'), it is used if the user input is
  85      empty. If interrupt is given (one of 'y','n'), it is used if the user
  86      presses Ctrl-C. Otherwise the question is repeated until an answer is
  87      given.
  88  
  89      An EOF is treated as the default answer.  If there is no default, an
  90      exception is raised to prevent infinite loops.
  91  
  92      Valid answers are: y/yes/n/no (match is not case sensitive)."""
  93  
  94      answers = {'y':True,'n':False,'yes':True,'no':False}
  95      ans = None
  96      while ans not in answers.keys():
  97          try:
  98              ans = input(prompt+' ').lower()
  99              if not ans:  # response was an empty string
 100                  ans = default
 101          except KeyboardInterrupt:
 102              if interrupt:
 103                  ans = interrupt
 104              print("\r")
 105          except EOFError:
 106              if default in answers.keys():
 107                  ans = default
 108                  print()
 109              else:
 110                  raise
 111  
 112      return answers[ans]
 113  
 114  
 115  def temp_pyfile(src, ext='.py'):
 116      """Make a temporary python file, return filename and filehandle.
 117  
 118      Parameters
 119      ----------
 120      src : string or list of strings (no need for ending newlines if list)
 121          Source code to be written to the file.
 122      ext : optional, string
 123          Extension for the generated file.
 124  
 125      Returns
 126      -------
 127      (filename, open filehandle)
 128          It is the caller's responsibility to close the open file and unlink it.
 129      """
 130      fname = tempfile.mkstemp(ext)[1]
 131      with open(Path(fname), "w", encoding="utf-8") as f:
 132          f.write(src)
 133          f.flush()
 134      return fname
 135  
 136  
 137  @undoc
 138  def raw_print(*args, **kw):
 139      """DEPRECATED: Raw print to sys.__stdout__, otherwise identical interface to print()."""
 140      warn("IPython.utils.io.raw_print has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
 141  
 142      print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
 143            file=sys.__stdout__)
 144      sys.__stdout__.flush()
 145  
 146  @undoc
 147  def raw_print_err(*args, **kw):
 148      """DEPRECATED: Raw print to sys.__stderr__, otherwise identical interface to print()."""
 149      warn("IPython.utils.io.raw_print_err has been deprecated since IPython 7.0", DeprecationWarning, stacklevel=2)
 150  
 151      print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
 152            file=sys.__stderr__)
 153      sys.__stderr__.flush()
 154