stdin.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. # Copyright (c) 2000 David Abrahams. Permission to copy, use, modify, sell
  2. # and distribute this software is granted provided this copyright
  3. # notice appears in all copies. This software is provided "as is" without
  4. # express or implied warranty, and with no claim as to its suitability for
  5. # any purpose.
  6. """Provides a class Stdin which can be used to emulate the regular old
  7. sys.stdin for the PythonWin interactive window. Right now it just pops
  8. up a raw_input() dialog. With luck, someone will integrate it into the
  9. actual PythonWin interactive window someday.
  10. WARNING: Importing this file automatically replaces sys.stdin with an
  11. instance of Stdin (below). This is useful because you can just open
  12. Stdin.py in PythonWin and hit the import button to get it set up right
  13. if you don't feel like changing PythonWin's source. To put things back
  14. the way they were, simply use this magic incantation:
  15. import sys
  16. sys.stdin = sys.stdin.real_file
  17. """
  18. import sys
  19. try:
  20. get_input_line = raw_input # py2x
  21. except NameError:
  22. get_input_line = input # py3k
  23. class Stdin:
  24. def __init__(self):
  25. self.real_file = sys.stdin # NOTE: Likely to be None in py3k
  26. self.buffer = ""
  27. self.closed = False
  28. def __getattr__(self, name):
  29. """Forward most functions to the real sys.stdin for absolute realism.
  30. """
  31. if self.real_file is None:
  32. raise AttributeError(name)
  33. return getattr(self.real_file, name)
  34. def isatty(self):
  35. """Return 1 if the file is connected to a tty(-like) device, else 0.
  36. """
  37. return 1
  38. def read(self, size = -1):
  39. """Read at most size bytes from the file (less if the read
  40. hits EOF or no more data is immediately available on a pipe,
  41. tty or similar device). If the size argument is negative or
  42. omitted, read all data until EOF is reached. The bytes are
  43. returned as a string object. An empty string is returned when
  44. EOF is encountered immediately. (For certain files, like ttys,
  45. it makes sense to continue reading after an EOF is hit.)"""
  46. result_size = self.__get_lines(size)
  47. return self.__extract_from_buffer(result_size)
  48. def readline(self, size = -1):
  49. """Read one entire line from the file. A trailing newline
  50. character is kept in the string2.6 (but may be absent when a file ends
  51. with an incomplete line). If the size argument is present and
  52. non-negative, it is a maximum byte count (including the trailing
  53. newline) and an incomplete line may be returned. An empty string is
  54. returned when EOF is hit immediately. Note: unlike stdio's fgets(),
  55. the returned string contains null characters ('\0') if they occurred
  56. in the input.
  57. """
  58. maximum_result_size = self.__get_lines(size, lambda buffer: '\n' in buffer)
  59. if '\n' in self.buffer[:maximum_result_size]:
  60. result_size = self.buffer.find('\n', 0, maximum_result_size) + 1
  61. assert(result_size > 0)
  62. else:
  63. result_size = maximum_result_size
  64. return self.__extract_from_buffer(result_size)
  65. def __extract_from_buffer(self, character_count):
  66. """Remove the first character_count characters from the internal buffer and
  67. return them.
  68. """
  69. result = self.buffer[:character_count]
  70. self.buffer = self.buffer[character_count:]
  71. return result
  72. def __get_lines(self, desired_size, done_reading = lambda buffer: False):
  73. """Keep adding lines to our internal buffer until done_reading(self.buffer)
  74. is true or EOF has been reached or we have desired_size bytes in the buffer.
  75. If desired_size < 0, we are never satisfied until we reach EOF. If done_reading
  76. is not supplied, it is not consulted.
  77. If desired_size < 0, returns the length of the internal buffer. Otherwise,
  78. returns desired_size.
  79. """
  80. while not done_reading(self.buffer) and (desired_size < 0
  81. or len(self.buffer) < desired_size):
  82. try:
  83. self.__get_line()
  84. except (EOFError, KeyboardInterrupt): # deal with cancellation of get_input_line dialog
  85. desired_size = len(self.buffer) # Be satisfied!
  86. if desired_size < 0:
  87. return len(self.buffer)
  88. else:
  89. return desired_size
  90. def __get_line(self):
  91. """Grab one line from get_input_line() and append it to the buffer.
  92. """
  93. line = get_input_line()
  94. print('>>>',line) # echo input to console
  95. self.buffer = self.buffer + line + '\n'
  96. def readlines(self, *sizehint):
  97. """Read until EOF using readline() and return a list containing the lines
  98. thus read. If the optional sizehint argument is present, instead of
  99. reading up to EOF, whole lines totalling approximately sizehint bytes
  100. (possibly after rounding up to an internal buffer size) are read.
  101. """
  102. result = []
  103. total_read = 0
  104. while sizehint == () or total_read < sizehint[0]:
  105. line = self.readline()
  106. if line == '':
  107. break
  108. total_read = total_read + len(line)
  109. result.append(line)
  110. return result
  111. if __name__ == "__main__":
  112. test_input = r"""this is some test
  113. input that I am hoping
  114. ~
  115. will be very instructive
  116. and when I am done
  117. I will have tested everything.
  118. Twelve and twenty blackbirds
  119. baked in a pie. Patty cake
  120. patty cake so am I.
  121. ~
  122. Thirty-five niggling idiots!
  123. Sell you soul to the devil, baby
  124. """
  125. def fake_raw_input(prompt=None):
  126. """Replacement for raw_input() which pulls lines out of global test_input.
  127. For testing only!
  128. """
  129. global test_input
  130. if '\n' not in test_input:
  131. end_of_line_pos = len(test_input)
  132. else:
  133. end_of_line_pos = test_input.find('\n')
  134. result = test_input[:end_of_line_pos]
  135. test_input = test_input[end_of_line_pos + 1:]
  136. if len(result) == 0 or result[0] == '~':
  137. raise EOFError()
  138. return result
  139. get_input_line = fake_raw_input
  140. # Some completely inadequate tests, just to make sure the code's not totally broken
  141. try:
  142. x = Stdin()
  143. print(x.read())
  144. print(x.readline())
  145. print(x.read(12))
  146. print(x.readline(47))
  147. print(x.readline(3))
  148. print(x.readlines())
  149. finally:
  150. get_input_line = raw_input
  151. else:
  152. import sys
  153. sys.stdin = Stdin()