python script로 자동화된 프로세스를 만들때, 이때는 시간이 긴 작업이 동반될 수 있습니다. 만일, 사용자 input을 받아야 한다면, 이러한 긴 작업에 대해 모니터링을 해야 하는 단점이 있습니다.
python의 사용자 입력 함수인 input이 사용되긴한데, 해당 함수는 timeout이 지원되지 않아, 무한 대기하게 됩니다. 이러한 단점을 방지하기 위해, input의 timeout 속성을 넣는 시도가 많이 있는데, 모두 매우 어렵게 구현되어 있습니다. 즉, windows/linux OS의 특징을 이용하여, 통합 코드로 진행되지 못한다는 점입니다.
아래 함수, 즉, python 함수를 공유하며, 이는 input에 대한 timeout을 지원합니다.
현재 python3 대상으로 개발되었으며, 필요시 python2로 수정할 수 있을 겁니다.
중요한 논리는,
직접 input()을 호출하지 않고,
python -c "input()"
프로세스를 새로 생성한뒤, timeout으로 wait하는 방식입니다.
그래서 논리가 매우 단순합니다.
def input_timer(prompt, timeout_sec): import subprocess import sys import threading import locale
class Local: # check if timeout occured _timeout_occured = False
def on_timeout(self, process): self._timeout_occured = True process.kill() # clear stdin buffer (for linux) # when some keys hit and timeout occured before enter key press, # that input text passed to next input(). # remove stdin buffer. try: import termios termios.tcflush(sys.stdin, termios.TCIFLUSH) except ImportError: # windows, just exit pass
def input_timer_main(self, prompt_in, timeout_sec_in): # print with no new line print(prompt_in, end="")
# print prompt_in immediately sys.stdout.flush()
# new python input process create. # and print it for pass stdout cmd = [sys.executable, '-c', 'print(input())'] with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as proc: timer_proc = threading.Timer(timeout_sec_in, self.on_timeout, [proc]) try: # timer set timer_proc.start() stdout, stderr = proc.communicate()
# get stdout and trim new line character result = stdout.decode(locale.getpreferredencoding()).strip("\r\n") finally: # timeout clear timer_proc.cancel()
# timeout check if self._timeout_occured is True: # move the cursor to next line print("") raise TimeoutError return result
t = Local() return t.input_timer_main(prompt, timeout_sec)
# example code here... try: a = input_timer("* prompt >>> ", 3) print(a) except TimeoutError as e: print("timeout...") pass
a = input_timer("* prompt >>> ", 3) print(a)
print("done") |
위와 같이 input_timer("...", 초)를 호출하면 되며,
timeout 발생시 TimeoutError exception이 발생하니,
해당 부분을 try 하시면 됩니다.