Skip to main content
Became Hot Network Question
List item continuation paragraphs
Source Link
Toby Speight
  • 81.7k
  • 14
  • 101
  • 308

currentInitial code

ideasIdeas how to handle args.assume

  1. replace interactive.confirm with another function dynamically

    replace interactive.confirm with another function dynamically

    # insert this into cli.py
        if args.assume is not None:
            import interactive
            interactive.confirm = lambda _, __=None: args.assume
    

    I do not like this because it changes a function on the fly. I like it because I can forget the args.assume thing in the rest of my application. It does not show up in the unit tests of interactive.confirm.

  2. add an extra argument to all functions that call interactive.confirm and to the function itself:

    # in interactive.py
    def confirm(message: str, assume: bool|None, accept_enter_key: bool = True) -> bool:
        if assume is not None:
            return assume
        ...
    # in main.py
    def work(foo, assume):
        if interactive.confirm(f"do you want {foo}", assume):
        ...
    
    if __name__ == "__main__":
        args = cli.parse()
        work(args.foo, args.assume)
    

    I don't like this because I have to change the signature of many functions in my program and the new argument has to be tested in the unittest of interactive.confirm.

  3. save the value of args.assume to a global variable that is read by interactive.confirm:

    # insert this into cli.py
        if args.assume is not None:
            import interactive
            interactive.assume = args.assume
    # and in interactive.py
    def confirm(message: str, accept_enter_key: bool = True) -> bool:
        if assume is not None:
            return assume
        ...
    

    This (nearly) has the advantage of (1) because it does not touch any other code but the command line parser and confirm. But it uses a global mutable variable to toggle program behaviour which I thought was bad style.

# insert this into cli.py
    if args.assume is not None:
        import interactive
        interactive.confirm = lambda _, __=None: args.assume

I do not like this because it changes a function on the fly. I like it because I can forget the args.assume thing in the rest of my application. It does not show up in the unit tests of interactive.confirm.

  1. add an extra argument to all functions that call interactive.confirm and to the function itself:
# in interactive.py
def confirm(message: str, assume: bool|None, accept_enter_key: bool = True) -> bool:
    if assume is not None:
        return assume
    ...
# in main.py
def work(foo, assume):
    if interactive.confirm(f"do you want {foo}", assume):
    ...

if __name__ == "__main__":
    args = cli.parse()
    work(args.foo, args.assume)

I don't like this because I have to change the signature of many functions in my program and the new argument has to be tested in the unittest of interactive.confirm.

  1. save the value of args.assume to a global variable that is read by interactive.confirm:
# insert this into cli.py
    if args.assume is not None:
        import interactive
        interactive.assume = args.assume
# and in interactive.py
def confirm(message: str, accept_enter_key: bool = True) -> bool:
    if assume is not None:
        return assume
    ...

This (nearly) has the advantage of (1) because it does not touch any other code but the command line parser and confirm. But it uses a global mutable variable to toggle program behaviour which I thought was bad style.

questionQuestion

backgroundBackground

current code

ideas how to handle args.assume

  1. replace interactive.confirm with another function dynamically
# insert this into cli.py
    if args.assume is not None:
        import interactive
        interactive.confirm = lambda _, __=None: args.assume

I do not like this because it changes a function on the fly. I like it because I can forget the args.assume thing in the rest of my application. It does not show up in the unit tests of interactive.confirm.

  1. add an extra argument to all functions that call interactive.confirm and to the function itself:
# in interactive.py
def confirm(message: str, assume: bool|None, accept_enter_key: bool = True) -> bool:
    if assume is not None:
        return assume
    ...
# in main.py
def work(foo, assume):
    if interactive.confirm(f"do you want {foo}", assume):
    ...

if __name__ == "__main__":
    args = cli.parse()
    work(args.foo, args.assume)

I don't like this because I have to change the signature of many functions in my program and the new argument has to be tested in the unittest of interactive.confirm.

  1. save the value of args.assume to a global variable that is read by interactive.confirm:
# insert this into cli.py
    if args.assume is not None:
        import interactive
        interactive.assume = args.assume
# and in interactive.py
def confirm(message: str, accept_enter_key: bool = True) -> bool:
    if assume is not None:
        return assume
    ...

This (nearly) has the advantage of (1) because it does not touch any other code but the command line parser and confirm. But it uses a global mutable variable to toggle program behaviour which I thought was bad style.

question

background

Initial code

Ideas how to handle args.assume

  1. replace interactive.confirm with another function dynamically

    # insert this into cli.py
        if args.assume is not None:
            import interactive
            interactive.confirm = lambda _, __=None: args.assume
    

    I do not like this because it changes a function on the fly. I like it because I can forget the args.assume thing in the rest of my application. It does not show up in the unit tests of interactive.confirm.

  2. add an extra argument to all functions that call interactive.confirm and to the function itself:

    # in interactive.py
    def confirm(message: str, assume: bool|None, accept_enter_key: bool = True) -> bool:
        if assume is not None:
            return assume
        ...
    # in main.py
    def work(foo, assume):
        if interactive.confirm(f"do you want {foo}", assume):
        ...
    
    if __name__ == "__main__":
        args = cli.parse()
        work(args.foo, args.assume)
    

    I don't like this because I have to change the signature of many functions in my program and the new argument has to be tested in the unittest of interactive.confirm.

  3. save the value of args.assume to a global variable that is read by interactive.confirm:

    # insert this into cli.py
        if args.assume is not None:
            import interactive
            interactive.assume = args.assume
    # and in interactive.py
    def confirm(message: str, accept_enter_key: bool = True) -> bool:
        if assume is not None:
            return assume
        ...
    

    This (nearly) has the advantage of (1) because it does not touch any other code but the command line parser and confirm. But it uses a global mutable variable to toggle program behaviour which I thought was bad style.

Question

Background

deleted 1 character in body
Source Link
Lucas
  • 161
  • 3

I came up with three ideas but I can find something about both ideaseach idea that I don't like:

I came up with three ideas but I can find something about both ideas that I don't like:

I came up with three ideas but I can find something about each idea that I don't like:

Source Link
Lucas
  • 161
  • 3

Implementing a --assume-yes/--assume-no command line flag to affect a `input()` based `confirm()` function

I have a Python command line application that needs to ask the user for confirmation at some point. I want to add a --assume-yes/--assume-no command line flag to skip the confirmation. I have several ideas how to handle this flag and am not sure which is good/best/terrible.

current code

# main.py, this file is simplified, "work" knows nothing about the structure of "args"
import cli, interactive

def work(foo):
    if interactive.confirm(f"do you want {foo}"):
        print("ok, I will do it")
    else:
        print("skipping")

if __name__ == "__main__":
    args = cli.parse()
    work(args.foo)
# cli.py, this is simplified
import argparse

def parse():
    parser = argparse.ArgumentParser()
    parser.add_argument("--foo")
    parser.add_argument("--assume-yes", action="store_true", dest="assume",
                        default=None)
    parser.add_argument("--assume-no", action="store_false", dest="assume")
    args = parser.parse_args()
    # how to handle args.assume at this point? see below for my ideas
    return args
# interactive.py, this is the original function from my project
def confirm(message: str, accept_enter_key: bool = True) -> bool:
    """Ask the user for confirmation on the terminal.

    :param message: the question to print
    :param accept_enter_key: Accept ENTER as alternative for "n"
    :returns: the answer of the user
    """
    while True:
        answer = input(message + ' (y/N) ')
        answer = answer.lower()
        if answer == 'y':
            return True
        if answer == 'n':
            return False
        if answer == '' and accept_enter_key:
            return False
        print('Please answer with "y" for yes or "n" for no.')

ideas how to handle args.assume

I came up with three ideas but I can find something about both ideas that I don't like:

  1. replace interactive.confirm with another function dynamically
# insert this into cli.py
    if args.assume is not None:
        import interactive
        interactive.confirm = lambda _, __=None: args.assume

I do not like this because it changes a function on the fly. I like it because I can forget the args.assume thing in the rest of my application. It does not show up in the unit tests of interactive.confirm.

  1. add an extra argument to all functions that call interactive.confirm and to the function itself:
# in interactive.py
def confirm(message: str, assume: bool|None, accept_enter_key: bool = True) -> bool:
    if assume is not None:
        return assume
    ...
# in main.py
def work(foo, assume):
    if interactive.confirm(f"do you want {foo}", assume):
    ...

if __name__ == "__main__":
    args = cli.parse()
    work(args.foo, args.assume)

I don't like this because I have to change the signature of many functions in my program and the new argument has to be tested in the unittest of interactive.confirm.

  1. save the value of args.assume to a global variable that is read by interactive.confirm:
# insert this into cli.py
    if args.assume is not None:
        import interactive
        interactive.assume = args.assume
# and in interactive.py
def confirm(message: str, accept_enter_key: bool = True) -> bool:
    if assume is not None:
        return assume
    ...

This (nearly) has the advantage of (1) because it does not touch any other code but the command line parser and confirm. But it uses a global mutable variable to toggle program behaviour which I thought was bad style.

question

What do you think about my ideas to implement the assume logic? What pros and cons did I forget? Do you know another way to implement it?

background

The console application is khard. confirm is called directly in nine places by six other functions. Some of these get called by other functions in turn.