IngoMeyer441 / simple-term-menu

A Python package which creates simple interactive menus on the command line.
MIT License
492 stars 43 forks source link

Can't iterate terminal_menu.chosen_menu_entries #82

Closed steakhutzeee closed 9 months ago

steakhutzeee commented 10 months ago

Hi,

trying to iterate terminal_menu.chosen_menu_entries Pylance in VSCode complains that Object of type "None" cannot be used as iterable value

The code works fine, is it a false positive?

Full code:

from simple_term_menu import TerminalMenu

def menu():
    terminal_menu = TerminalMenu(
        [
            "option_1",
            "option_2",
            "option_3",
        ],
        multi_select=True,
        multi_select_select_on_accept=False,
        show_multi_select_hint=True,
        title=title,
    )
    terminal_menu.show()

    chosen_menu_entries_list = [
        "paperless-ngx" if i == "paperless-ngx - [postgres, redis]" else i
        for i in terminal_menu.chosen_menu_entries   <--- reportOptionalIterable error
    ]

    return chosen_menu_entries_list
IngoMeyer441 commented 10 months ago

chosen_menu_entries is declared as Optional[Tuple[str, ...]]. It is None before the show method is called, but Pylance does not know that it is not None anymore after the method was executed successfully. In order to satisfy Pylance (and to check if the user really selected an entry), you can add an if terminal_menu.chosen_menu_entries is not None: before creating your chosen_menu_entries_list.

steakhutzeee commented 10 months ago

Thanks, i edited the code to:

terminal_menu.py:

from simple_term_menu import TerminalMenu

def menu():
    terminal_menu = TerminalMenu(
        [
            "option_1",
            "option_2",
            "option_3",
        ],
        multi_select=True,
        multi_select_select_on_accept=False,
        show_multi_select_hint=True,
        title=title,
    )
    terminal_menu.show()

    if terminal_menu.chosen_menu_entries is not None:
        chosen_menu_entries_list = [
            "paperless-ngx" if i == "paperless-ngx - [postgres, redis]" else i
            for i in terminal_menu.chosen_menu_entries
        ]

        return chosen_menu_entries_list

solving the issue.

But now i have the same issue in another module for the same project:

Module1:

print("")
subprocess.run(
    f"{script_dir}/update_container.sh "
    + " ".join(str(i) for i in terminal_menu.menu()),  <--- reportOptionalIterable error
    stderr=subprocess.STDOUT,
    text=True,
    shell=True,
    encoding="utf-8",
)

Before terminal_menu.menu() resulted as str for return value, now it's str | None, so i suppose this is happening now because i'm not only returning a str now.

Tried this but issue persists:

Module1:

print("")
subprocess.run(
    f"{script_dir}/update_container.sh "
    + " ".join(
        str(i)
        for i in terminal_menu.menu()
        if terminal_menu.TerminalMenu.chosen_menu_entries is not None
    ),
    stderr=subprocess.STDOUT,
    text=True,
    shell=True,
    encoding="utf-8",
)

How can i solve?

IngoMeyer441 commented 10 months ago

Because of the new if statement, your menu function can return without explicitly returning anything. In this case, Python returns None implicitly. Therefore, you need to check for None before your subprocess.run call, something like this:

chosen_menu_entries = terminal_menu.menu()
if chosen_menu_entries is not None:
    subprocess.run(
        f"{script_dir}/update_container.sh "
        + " ".join(
            str(i)
            for i in chosen_menu_entries
        ),
        stderr=subprocess.STDOUT,
        text=True,
        shell=True,
        encoding="utf-8",
    )