0

Using a library that when I call a certain function that I will call foo() , I am prompted for input as such:

def foo():
   if input("Proceed?") == 'yes':
        take_action()

I am required to pass in an answer to continue.

But I would like to be able to loop over foo() with a default value to feed the prompt.

The problem is the developers did not provide an option to supply a default value for the prompt.

Ideally they would have written foo() like this:

def foo(default_response=None):
    if default_response == 'yes':
        take_action()
    elif input("Proceed?") == 'yes':
        take_action()

Given that they did not supply an option for a default response, is there a way for me to loop over foo() and provide the input automatically without changing the source code?

spapadop
  • 51
  • 5
  • Why can't you just write your own function that does only what you need? A messy solution might be to run it in a subprocess and provide the input as shown here https://stackoverflow.com/questions/8475290/how-do-i-write-to-a-python-subprocess-stdin – Stuart Mar 13 '22 at 23:53
  • That's why [yes](https://en.wikipedia.org/wiki/Yes_(Unix)) exists :-) – Kelly Bundy Mar 14 '22 at 00:03
  • 1
    Ideally, the function wouldn't call `input` *at all*, and rely entirely on the caller to provide the necessary input. I/O should happen as close to the "edge" of the program as possible. – chepner Mar 14 '22 at 00:13
  • @Stuart Writing my own function would really just be duplicating most of their original function in my library. Trying to avoid copying code when I just need to change a small part of it. – spapadop Mar 14 '22 at 00:25
  • @KellyBundy trying to avoid OS specific solutions – spapadop Mar 14 '22 at 00:25

1 Answers1

1

One solution is to monkey patch the library to temporarily replace the input function. For example, if I have module foo.py that looks like this:

def take_action():
    print("doing something")


def foo():
    if input("Proceed? ") == "yes":
        take_action()

I can write bar.py like this:

import foo
from unittest import mock


def fake_input(default_response=None):
    '''Creates a replacement for the `input` function that will
    return a default response if one was provided.'''

    def _input(prompt):
        return default_response if default_response else input(prompt)

    return _input


with mock.patch("foo.input", new=fake_input("yes")):
    foo.foo()

foo.foo()

If you run this code, you'll see that the first call to foo.foo() uses a default input, and proceeds without prompting. The second call to foo.foo() will prompt normally.

larsks
  • 277,717
  • 41
  • 399
  • 399