(root)/
Python-3.12.0/
Lib/
fileinput.py
       1  """Helper class to quickly write a loop over all standard input files.
       2  
       3  Typical use is:
       4  
       5      import fileinput
       6      for line in fileinput.input(encoding="utf-8"):
       7          process(line)
       8  
       9  This iterates over the lines of all files listed in sys.argv[1:],
      10  defaulting to sys.stdin if the list is empty.  If a filename is '-' it
      11  is also replaced by sys.stdin and the optional arguments mode and
      12  openhook are ignored.  To specify an alternative list of filenames,
      13  pass it as the argument to input().  A single file name is also allowed.
      14  
      15  Functions filename(), lineno() return the filename and cumulative line
      16  number of the line that has just been read; filelineno() returns its
      17  line number in the current file; isfirstline() returns true iff the
      18  line just read is the first line of its file; isstdin() returns true
      19  iff the line was read from sys.stdin.  Function nextfile() closes the
      20  current file so that the next iteration will read the first line from
      21  the next file (if any); lines not read from the file will not count
      22  towards the cumulative line count; the filename is not changed until
      23  after the first line of the next file has been read.  Function close()
      24  closes the sequence.
      25  
      26  Before any lines have been read, filename() returns None and both line
      27  numbers are zero; nextfile() has no effect.  After all lines have been
      28  read, filename() and the line number functions return the values
      29  pertaining to the last line read; nextfile() has no effect.
      30  
      31  All files are opened in text mode by default, you can override this by
      32  setting the mode parameter to input() or FileInput.__init__().
      33  If an I/O error occurs during opening or reading a file, the OSError
      34  exception is raised.
      35  
      36  If sys.stdin is used more than once, the second and further use will
      37  return no lines, except perhaps for interactive use, or if it has been
      38  explicitly reset (e.g. using sys.stdin.seek(0)).
      39  
      40  Empty files are opened and immediately closed; the only time their
      41  presence in the list of filenames is noticeable at all is when the
      42  last file opened is empty.
      43  
      44  It is possible that the last line of a file doesn't end in a newline
      45  character; otherwise lines are returned including the trailing
      46  newline.
      47  
      48  Class FileInput is the implementation; its methods filename(),
      49  lineno(), fileline(), isfirstline(), isstdin(), nextfile() and close()
      50  correspond to the functions in the module.  In addition it has a
      51  readline() method which returns the next input line, and a
      52  __getitem__() method which implements the sequence behavior.  The
      53  sequence must be accessed in strictly sequential order; sequence
      54  access and readline() cannot be mixed.
      55  
      56  Optional in-place filtering: if the keyword argument inplace=1 is
      57  passed to input() or to the FileInput constructor, the file is moved
      58  to a backup file and standard output is directed to the input file.
      59  This makes it possible to write a filter that rewrites its input file
      60  in place.  If the keyword argument backup=".<some extension>" is also
      61  given, it specifies the extension for the backup file, and the backup
      62  file remains around; by default, the extension is ".bak" and it is
      63  deleted when the output file is closed.  In-place filtering is
      64  disabled when standard input is read.  XXX The current implementation
      65  does not work for MS-DOS 8+3 filesystems.
      66  """
      67  
      68  import io
      69  import sys, os
      70  from types import GenericAlias
      71  
      72  __all__ = ["input", "close", "nextfile", "filename", "lineno", "filelineno",
      73             "fileno", "isfirstline", "isstdin", "FileInput", "hook_compressed",
      74             "hook_encoded"]
      75  
      76  _state = None
      77  
      78  def input(files=None, inplace=False, backup="", *, mode="r", openhook=None,
      79            encoding=None, errors=None):
      80      """Return an instance of the FileInput class, which can be iterated.
      81  
      82      The parameters are passed to the constructor of the FileInput class.
      83      The returned instance, in addition to being an iterator,
      84      keeps global state for the functions of this module,.
      85      """
      86      global _state
      87      if _state and _state._file:
      88          raise RuntimeError("input() already active")
      89      _state = FileInput(files, inplace, backup, mode=mode, openhook=openhook,
      90                         encoding=encoding, errors=errors)
      91      return _state
      92  
      93  def close():
      94      """Close the sequence."""
      95      global _state
      96      state = _state
      97      _state = None
      98      if state:
      99          state.close()
     100  
     101  def nextfile():
     102      """
     103      Close the current file so that the next iteration will read the first
     104      line from the next file (if any); lines not read from the file will
     105      not count towards the cumulative line count. The filename is not
     106      changed until after the first line of the next file has been read.
     107      Before the first line has been read, this function has no effect;
     108      it cannot be used to skip the first file. After the last line of the
     109      last file has been read, this function has no effect.
     110      """
     111      if not _state:
     112          raise RuntimeError("no active input()")
     113      return _state.nextfile()
     114  
     115  def filename():
     116      """
     117      Return the name of the file currently being read.
     118      Before the first line has been read, returns None.
     119      """
     120      if not _state:
     121          raise RuntimeError("no active input()")
     122      return _state.filename()
     123  
     124  def lineno():
     125      """
     126      Return the cumulative line number of the line that has just been read.
     127      Before the first line has been read, returns 0. After the last line
     128      of the last file has been read, returns the line number of that line.
     129      """
     130      if not _state:
     131          raise RuntimeError("no active input()")
     132      return _state.lineno()
     133  
     134  def filelineno():
     135      """
     136      Return the line number in the current file. Before the first line
     137      has been read, returns 0. After the last line of the last file has
     138      been read, returns the line number of that line within the file.
     139      """
     140      if not _state:
     141          raise RuntimeError("no active input()")
     142      return _state.filelineno()
     143  
     144  def fileno():
     145      """
     146      Return the file number of the current file. When no file is currently
     147      opened, returns -1.
     148      """
     149      if not _state:
     150          raise RuntimeError("no active input()")
     151      return _state.fileno()
     152  
     153  def isfirstline():
     154      """
     155      Returns true the line just read is the first line of its file,
     156      otherwise returns false.
     157      """
     158      if not _state:
     159          raise RuntimeError("no active input()")
     160      return _state.isfirstline()
     161  
     162  def isstdin():
     163      """
     164      Returns true if the last line was read from sys.stdin,
     165      otherwise returns false.
     166      """
     167      if not _state:
     168          raise RuntimeError("no active input()")
     169      return _state.isstdin()
     170  
     171  class ESC[4;38;5;81mFileInput:
     172      """FileInput([files[, inplace[, backup]]], *, mode=None, openhook=None)
     173  
     174      Class FileInput is the implementation of the module; its methods
     175      filename(), lineno(), fileline(), isfirstline(), isstdin(), fileno(),
     176      nextfile() and close() correspond to the functions of the same name
     177      in the module.
     178      In addition it has a readline() method which returns the next
     179      input line, and a __getitem__() method which implements the
     180      sequence behavior. The sequence must be accessed in strictly
     181      sequential order; random access and readline() cannot be mixed.
     182      """
     183  
     184      def __init__(self, files=None, inplace=False, backup="", *,
     185                   mode="r", openhook=None, encoding=None, errors=None):
     186          if isinstance(files, str):
     187              files = (files,)
     188          elif isinstance(files, os.PathLike):
     189              files = (os.fspath(files), )
     190          else:
     191              if files is None:
     192                  files = sys.argv[1:]
     193              if not files:
     194                  files = ('-',)
     195              else:
     196                  files = tuple(files)
     197          self._files = files
     198          self._inplace = inplace
     199          self._backup = backup
     200          self._savestdout = None
     201          self._output = None
     202          self._filename = None
     203          self._startlineno = 0
     204          self._filelineno = 0
     205          self._file = None
     206          self._isstdin = False
     207          self._backupfilename = None
     208          self._encoding = encoding
     209          self._errors = errors
     210  
     211          # We can not use io.text_encoding() here because old openhook doesn't
     212          # take encoding parameter.
     213          if (sys.flags.warn_default_encoding and
     214                  "b" not in mode and encoding is None and openhook is None):
     215              import warnings
     216              warnings.warn("'encoding' argument not specified.",
     217                            EncodingWarning, 2)
     218  
     219          # restrict mode argument to reading modes
     220          if mode not in ('r', 'rb'):
     221              raise ValueError("FileInput opening mode must be 'r' or 'rb'")
     222          self._mode = mode
     223          self._write_mode = mode.replace('r', 'w')
     224          if openhook:
     225              if inplace:
     226                  raise ValueError("FileInput cannot use an opening hook in inplace mode")
     227              if not callable(openhook):
     228                  raise ValueError("FileInput openhook must be callable")
     229          self._openhook = openhook
     230  
     231      def __del__(self):
     232          self.close()
     233  
     234      def close(self):
     235          try:
     236              self.nextfile()
     237          finally:
     238              self._files = ()
     239  
     240      def __enter__(self):
     241          return self
     242  
     243      def __exit__(self, type, value, traceback):
     244          self.close()
     245  
     246      def __iter__(self):
     247          return self
     248  
     249      def __next__(self):
     250          while True:
     251              line = self._readline()
     252              if line:
     253                  self._filelineno += 1
     254                  return line
     255              if not self._file:
     256                  raise StopIteration
     257              self.nextfile()
     258              # repeat with next file
     259  
     260      def nextfile(self):
     261          savestdout = self._savestdout
     262          self._savestdout = None
     263          if savestdout:
     264              sys.stdout = savestdout
     265  
     266          output = self._output
     267          self._output = None
     268          try:
     269              if output:
     270                  output.close()
     271          finally:
     272              file = self._file
     273              self._file = None
     274              try:
     275                  del self._readline  # restore FileInput._readline
     276              except AttributeError:
     277                  pass
     278              try:
     279                  if file and not self._isstdin:
     280                      file.close()
     281              finally:
     282                  backupfilename = self._backupfilename
     283                  self._backupfilename = None
     284                  if backupfilename and not self._backup:
     285                      try: os.unlink(backupfilename)
     286                      except OSError: pass
     287  
     288                  self._isstdin = False
     289  
     290      def readline(self):
     291          while True:
     292              line = self._readline()
     293              if line:
     294                  self._filelineno += 1
     295                  return line
     296              if not self._file:
     297                  return line
     298              self.nextfile()
     299              # repeat with next file
     300  
     301      def _readline(self):
     302          if not self._files:
     303              if 'b' in self._mode:
     304                  return b''
     305              else:
     306                  return ''
     307          self._filename = self._files[0]
     308          self._files = self._files[1:]
     309          self._startlineno = self.lineno()
     310          self._filelineno = 0
     311          self._file = None
     312          self._isstdin = False
     313          self._backupfilename = 0
     314  
     315          # EncodingWarning is emitted in __init__() already
     316          if "b" not in self._mode:
     317              encoding = self._encoding or "locale"
     318          else:
     319              encoding = None
     320  
     321          if self._filename == '-':
     322              self._filename = '<stdin>'
     323              if 'b' in self._mode:
     324                  self._file = getattr(sys.stdin, 'buffer', sys.stdin)
     325              else:
     326                  self._file = sys.stdin
     327              self._isstdin = True
     328          else:
     329              if self._inplace:
     330                  self._backupfilename = (
     331                      os.fspath(self._filename) + (self._backup or ".bak"))
     332                  try:
     333                      os.unlink(self._backupfilename)
     334                  except OSError:
     335                      pass
     336                  # The next few lines may raise OSError
     337                  os.rename(self._filename, self._backupfilename)
     338                  self._file = open(self._backupfilename, self._mode,
     339                                    encoding=encoding, errors=self._errors)
     340                  try:
     341                      perm = os.fstat(self._file.fileno()).st_mode
     342                  except OSError:
     343                      self._output = open(self._filename, self._write_mode,
     344                                          encoding=encoding, errors=self._errors)
     345                  else:
     346                      mode = os.O_CREAT | os.O_WRONLY | os.O_TRUNC
     347                      if hasattr(os, 'O_BINARY'):
     348                          mode |= os.O_BINARY
     349  
     350                      fd = os.open(self._filename, mode, perm)
     351                      self._output = os.fdopen(fd, self._write_mode,
     352                                               encoding=encoding, errors=self._errors)
     353                      try:
     354                          os.chmod(self._filename, perm)
     355                      except OSError:
     356                          pass
     357                  self._savestdout = sys.stdout
     358                  sys.stdout = self._output
     359              else:
     360                  # This may raise OSError
     361                  if self._openhook:
     362                      # Custom hooks made previous to Python 3.10 didn't have
     363                      # encoding argument
     364                      if self._encoding is None:
     365                          self._file = self._openhook(self._filename, self._mode)
     366                      else:
     367                          self._file = self._openhook(
     368                              self._filename, self._mode, encoding=self._encoding, errors=self._errors)
     369                  else:
     370                      self._file = open(self._filename, self._mode, encoding=encoding, errors=self._errors)
     371          self._readline = self._file.readline  # hide FileInput._readline
     372          return self._readline()
     373  
     374      def filename(self):
     375          return self._filename
     376  
     377      def lineno(self):
     378          return self._startlineno + self._filelineno
     379  
     380      def filelineno(self):
     381          return self._filelineno
     382  
     383      def fileno(self):
     384          if self._file:
     385              try:
     386                  return self._file.fileno()
     387              except ValueError:
     388                  return -1
     389          else:
     390              return -1
     391  
     392      def isfirstline(self):
     393          return self._filelineno == 1
     394  
     395      def isstdin(self):
     396          return self._isstdin
     397  
     398      __class_getitem__ = classmethod(GenericAlias)
     399  
     400  
     401  def hook_compressed(filename, mode, *, encoding=None, errors=None):
     402      if encoding is None and "b" not in mode:  # EncodingWarning is emitted in FileInput() already.
     403          encoding = "locale"
     404      ext = os.path.splitext(filename)[1]
     405      if ext == '.gz':
     406          import gzip
     407          stream = gzip.open(filename, mode)
     408      elif ext == '.bz2':
     409          import bz2
     410          stream = bz2.BZ2File(filename, mode)
     411      else:
     412          return open(filename, mode, encoding=encoding, errors=errors)
     413  
     414      # gzip and bz2 are binary mode by default.
     415      if "b" not in mode:
     416          stream = io.TextIOWrapper(stream, encoding=encoding, errors=errors)
     417      return stream
     418  
     419  
     420  def hook_encoded(encoding, errors=None):
     421      def openhook(filename, mode):
     422          return open(filename, mode, encoding=encoding, errors=errors)
     423      return openhook
     424  
     425  
     426  def _test():
     427      import getopt
     428      inplace = False
     429      backup = False
     430      opts, args = getopt.getopt(sys.argv[1:], "ib:")
     431      for o, a in opts:
     432          if o == '-i': inplace = True
     433          if o == '-b': backup = a
     434      for line in input(args, inplace=inplace, backup=backup):
     435          if line[-1:] == '\n': line = line[:-1]
     436          if line[-1:] == '\r': line = line[:-1]
     437          print("%d: %s[%d]%s %s" % (lineno(), filename(), filelineno(),
     438                                     isfirstline() and "*" or "", line))
     439      print("%d: %s[%d]" % (lineno(), filename(), filelineno()))
     440  
     441  if __name__ == '__main__':
     442      _test()