2

I am trying to make a code that will ask for a user input and if that input is not given in a set amount of time will assume a default value and continue through the rest of the code without requiring the user to hit enter. I am running in Python 3.5.1 on Windows 10.

I have looked through: Keyboard input with timeout in Python, How to set time limit on raw_input, Timeout on a function call, and Python 3 Timed Input black boxing the answers but none of the answers are suitable as they are not usable on Windows (principally use of signal.SIGALRM which is only available on linux), or require a user to hit enter in order to exit the input.

Based upon the above answers however i have attempted to scrap together a solution using multiprocessing which (as i think it should work) creates one process to ask for the input and creates another process to terminate the first process after the timeout period.

import multiprocessing
from time import time,sleep

def wait(secs):
    if secs == 0:
        return
    end = time()+secs
    current = time()
    while end>current:
        current = time()
        sleep(.1)
    return

def delay_terminate_process(process,delay):
    wait(delay)
    process.terminate()
    process.join()

def ask_input(prompt,term_queue,out_queue):
    command = input(prompt)
    process = term_queue.get()
    process.terminate()
    process.join()
    out_queue.put(command)

##### this doesn't even remotly work.....
def input_with_timeout(prompt,timeout=15.0):   
    print(prompt)
    astring = 'no input'
    out_queue = multiprocessing.Queue()
    term_queue = multiprocessing.Queue()
    worker1 = multiprocessing.Process(target=ask_input,args=(prompt,term_queue,out_queue))
    worker2 = multiprocessing.Process(target=delay_terminate_process,args=(worker1,timeout))
    worker1.daemon = True
    worker2.daemon = True
    term_queue.put(worker2)
    print('Through overhead')
    if __name__ == '__main__':
        print('I am in if statement')
        worker2.start()
        worker1.start()
        astring = out_queue.get()
    else:
        print('I have no clue what happened that would cause this to print....')
        return
    print('returning')

    return astring

please = input_with_timeout('Does this work?',timeout=10)

But this fails miserably and yields:

    Does this work?
    Through overhead
    I am in if statement
    Traceback (most recent call last):
      File "C:\Anaconda3\lib\multiprocessing\queues.py", line 241, in _feed
        obj = ForkingPickler.dumps(obj)
      File "C:\Anaconda3\lib\multiprocessing\reduction.py", line 50, in dumps
        cls(buf, protocol).dump(obj)
      File "C:\Anaconda3\lib\multiprocessing\queues.py", line 58, in __getstate__
        context.assert_spawning(self)
      File "C:\Anaconda3\lib\multiprocessing\context.py", line 347, in assert_spawning
        ' through inheritance' % type(obj).__name__
    RuntimeError: Queue objects should only be shared between processes through inheritance
    Does this work?
    Through overhead
    I have no clue what happened that would cause this to print....
    Does this work?Process Process-1:
    Traceback (most recent call last):
      File "C:\Anaconda3\lib\multiprocessing\queues.py", line 241, in _feed
        obj = ForkingPickler.dumps(obj)
      File "C:\Anaconda3\lib\multiprocessing\reduction.py", line 50, in dumps
        cls(buf, protocol).dump(obj)
      File "C:\Anaconda3\lib\multiprocessing\process.py", line 287, in __reduce__
        'Pickling an AuthenticationString object is '
    TypeError: Pickling an AuthenticationString object is disallowed for security reasons
    Traceback (most recent call last):
      File "C:\Anaconda3\lib\multiprocessing\process.py", line 254, in _bootstrap
        self.run()
      File "C:\Anaconda3\lib\multiprocessing\process.py", line 93, in run
        self._target(*self._args, **self._kwargs)
      File "C:\Anaconda3\saved_programs\a_open_file4.py", line 20, in ask_input
        command = input(prompt)
    EOFError: EOF when reading a line
    Does this work?
    Through overhead
    I have no clue what happened that would cause this to print....
    Traceback (most recent call last):
      File "C:\Anaconda3\lib\multiprocessing\queues.py", line 241, in _feed
        obj = ForkingPickler.dumps(obj)
      File "C:\Anaconda3\lib\multiprocessing\reduction.py", line 50, in dumps
        cls(buf, protocol).dump(obj)
      File "C:\Anaconda3\lib\multiprocessing\queues.py", line 58, in __getstate__
        context.assert_spawning(self)
      File "C:\Anaconda3\lib\multiprocessing\context.py", line 347, in assert_spawning
        ' through inheritance' % type(obj).__name__
    RuntimeError: Queue objects should only be shared between processes through inheritance
    Process Process-2:
    Traceback (most recent call last):
      File "C:\Anaconda3\lib\multiprocessing\process.py", line 254, in _bootstrap
        self.run()
      File "C:\Anaconda3\lib\multiprocessing\process.py", line 93, in run
        self._target(*self._args, **self._kwargs)
      File "C:\Anaconda3\saved_programs\a_open_file4.py", line 16, in delay_terminate_process
        process.terminate()
      File "C:\Anaconda3\lib\multiprocessing\process.py", line 113, in terminate
        self._popen.terminate()
    AttributeError: 'NoneType' object has no attribute 'terminate'

I really don't understand the multiprocessing module well and although I have read the official docs am unsure why this error occurred or why it appears to have ran through the function call 3 times in the process. Any help on how to either resolve the error or achieve an optional user input in a cleaner manner will be much appreciated by a noob programmer. Thanks!

Community
  • 1
  • 1
Patrick
  • 121
  • 3

0 Answers0