Spaces:
Sleeping
Sleeping
# Copyright (c) 2000 David Abrahams. Permission to copy, use, modify, sell | |
# and distribute this software is granted provided this copyright | |
# notice appears in all copies. This software is provided "as is" without | |
# express or implied warranty, and with no claim as to its suitability for | |
# any purpose. | |
"""Provides a class Stdin which can be used to emulate the regular old | |
sys.stdin for the PythonWin interactive window. Right now it just pops | |
up a raw_input() dialog. With luck, someone will integrate it into the | |
actual PythonWin interactive window someday. | |
WARNING: Importing this file automatically replaces sys.stdin with an | |
instance of Stdin (below). This is useful because you can just open | |
Stdin.py in PythonWin and hit the import button to get it set up right | |
if you don't feel like changing PythonWin's source. To put things back | |
the way they were, simply use this magic incantation: | |
import sys | |
sys.stdin = sys.stdin.real_file | |
""" | |
import sys | |
try: | |
get_input_line = raw_input # py2x | |
except NameError: | |
get_input_line = input # py3k | |
class Stdin: | |
def __init__(self): | |
self.real_file = sys.stdin # NOTE: Likely to be None in py3k | |
self.buffer = "" | |
self.closed = False | |
def __getattr__(self, name): | |
"""Forward most functions to the real sys.stdin for absolute realism.""" | |
if self.real_file is None: | |
raise AttributeError(name) | |
return getattr(self.real_file, name) | |
def isatty(self): | |
"""Return 1 if the file is connected to a tty(-like) device, else 0.""" | |
return 1 | |
def read(self, size=-1): | |
"""Read at most size bytes from the file (less if the read | |
hits EOF or no more data is immediately available on a pipe, | |
tty or similar device). If the size argument is negative or | |
omitted, read all data until EOF is reached. The bytes are | |
returned as a string object. An empty string is returned when | |
EOF is encountered immediately. (For certain files, like ttys, | |
it makes sense to continue reading after an EOF is hit.)""" | |
result_size = self.__get_lines(size) | |
return self.__extract_from_buffer(result_size) | |
def readline(self, size=-1): | |
"""Read one entire line from the file. A trailing newline | |
character is kept in the string2.6 (but may be absent when a file ends | |
with an incomplete line). If the size argument is present and | |
non-negative, it is a maximum byte count (including the trailing | |
newline) and an incomplete line may be returned. An empty string is | |
returned when EOF is hit immediately. Note: unlike stdio's fgets(), | |
the returned string contains null characters ('\0') if they occurred | |
in the input. | |
""" | |
maximum_result_size = self.__get_lines(size, lambda buffer: "\n" in buffer) | |
if "\n" in self.buffer[:maximum_result_size]: | |
result_size = self.buffer.find("\n", 0, maximum_result_size) + 1 | |
assert result_size > 0 | |
else: | |
result_size = maximum_result_size | |
return self.__extract_from_buffer(result_size) | |
def __extract_from_buffer(self, character_count): | |
"""Remove the first character_count characters from the internal buffer and | |
return them. | |
""" | |
result = self.buffer[:character_count] | |
self.buffer = self.buffer[character_count:] | |
return result | |
def __get_lines(self, desired_size, done_reading=lambda buffer: False): | |
"""Keep adding lines to our internal buffer until done_reading(self.buffer) | |
is true or EOF has been reached or we have desired_size bytes in the buffer. | |
If desired_size < 0, we are never satisfied until we reach EOF. If done_reading | |
is not supplied, it is not consulted. | |
If desired_size < 0, returns the length of the internal buffer. Otherwise, | |
returns desired_size. | |
""" | |
while not done_reading(self.buffer) and ( | |
desired_size < 0 or len(self.buffer) < desired_size | |
): | |
try: | |
self.__get_line() | |
except ( | |
EOFError, | |
KeyboardInterrupt, | |
): # deal with cancellation of get_input_line dialog | |
desired_size = len(self.buffer) # Be satisfied! | |
if desired_size < 0: | |
return len(self.buffer) | |
else: | |
return desired_size | |
def __get_line(self): | |
"""Grab one line from get_input_line() and append it to the buffer.""" | |
line = get_input_line() | |
print(">>>", line) # echo input to console | |
self.buffer = self.buffer + line + "\n" | |
def readlines(self, *sizehint): | |
"""Read until EOF using readline() and return a list containing the lines | |
thus read. If the optional sizehint argument is present, instead of | |
reading up to EOF, whole lines totalling approximately sizehint bytes | |
(possibly after rounding up to an internal buffer size) are read. | |
""" | |
result = [] | |
total_read = 0 | |
while sizehint == () or total_read < sizehint[0]: | |
line = self.readline() | |
if line == "": | |
break | |
total_read = total_read + len(line) | |
result.append(line) | |
return result | |
if __name__ == "__main__": | |
test_input = r"""this is some test | |
input that I am hoping | |
~ | |
will be very instructive | |
and when I am done | |
I will have tested everything. | |
Twelve and twenty blackbirds | |
baked in a pie. Patty cake | |
patty cake so am I. | |
~ | |
Thirty-five niggling idiots! | |
Sell you soul to the devil, baby | |
""" | |
def fake_raw_input(prompt=None): | |
"""Replacement for raw_input() which pulls lines out of global test_input. | |
For testing only! | |
""" | |
global test_input | |
if "\n" not in test_input: | |
end_of_line_pos = len(test_input) | |
else: | |
end_of_line_pos = test_input.find("\n") | |
result = test_input[:end_of_line_pos] | |
test_input = test_input[end_of_line_pos + 1 :] | |
if len(result) == 0 or result[0] == "~": | |
raise EOFError() | |
return result | |
get_input_line = fake_raw_input | |
# Some completely inadequate tests, just to make sure the code's not totally broken | |
try: | |
x = Stdin() | |
print(x.read()) | |
print(x.readline()) | |
print(x.read(12)) | |
print(x.readline(47)) | |
print(x.readline(3)) | |
print(x.readlines()) | |
finally: | |
get_input_line = raw_input | |
else: | |
import sys | |
sys.stdin = Stdin() | |