From 8d1e192499d475f70eab27fe6c8c4fad510ac1ad Mon Sep 17 00:00:00 2001 From: Valentin Sulzer Date: Fri, 18 Oct 2024 14:14:17 -0400 Subject: [PATCH] don't use inputimeout --- pyproject.toml | 1 - src/pybamm/config.py | 33 ++++++++--------- tests/unit/test_config.py | 76 ++++++++++++++++++++++++++++++++------- 3 files changed, 78 insertions(+), 32 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3eae1d9411..be07105f75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,6 @@ dependencies = [ "pandas>=1.5.0", "pooch>=1.8.1", "posthog", - "inputimeout", ] [project.urls] diff --git a/src/pybamm/config.py b/src/pybamm/config.py index 222b1d8da2..ee08ef6774 100644 --- a/src/pybamm/config.py +++ b/src/pybamm/config.py @@ -3,7 +3,8 @@ import platformdirs from pathlib import Path import pybamm -from inputimeout import inputimeout, TimeoutOccurred +import select +import sys def is_running_tests(): # pragma: no cover @@ -48,7 +49,7 @@ def ask_user_opt_in(timeout=10): Parameters ---------- - timeout: float, optional + timeout : float, optional The timeout for the user to respond to the prompt. Default is 10 seconds. Returns @@ -67,25 +68,21 @@ def ask_user_opt_in(timeout=10): ) while True: - try: - user_input = ( - inputimeout( - prompt="Do you want to enable telemetry? (Y/n): ", timeout=timeout - ) - .strip() - .lower() - ) - except TimeoutOccurred: + print("Do you want to enable telemetry? (Y/n): ", end="", flush=True) + + rlist, _, _ = select.select([sys.stdin], [], [], timeout) + if rlist: + user_input = sys.stdin.readline().strip().lower() + if user_input in ["yes", "y", ""]: + return True + elif user_input in ["no", "n"]: + return False + else: + print("Invalid input. Please enter 'yes/y' for yes or 'no/n' for no.") + else: print("\nTimeout reached. Defaulting to not enabling telemetry.") return False - if user_input in ["yes", "y", ""]: - return True - elif user_input in ["no", "n"]: - return False - else: - print("\nInvalid input. Please enter 'yes'/'y' or 'no'/'n'.") - def generate(): # pragma: no cover if is_running_tests(): diff --git a/tests/unit/test_config.py b/tests/unit/test_config.py index 6e262fb011..65d42bf168 100644 --- a/tests/unit/test_config.py +++ b/tests/unit/test_config.py @@ -1,5 +1,6 @@ import pytest -from inputimeout import TimeoutOccurred +import select +import sys import pybamm import uuid @@ -33,24 +34,73 @@ def test_write_read_uuid(self, tmp_path, write_opt_in): assert config_dict["enable_telemetry"] is False @pytest.mark.parametrize("user_opted_in, user_input", [(True, "y"), (False, "n")]) - def test_ask_user_opt_in(self, monkeypatch, user_opted_in, user_input): - # Mock the inputimeout function to return invalid input first, then valid input - inputs = iter(["invalid", user_input]) - monkeypatch.setattr( - "pybamm.config.inputimeout", lambda prompt, timeout: next(inputs) - ) + def test_ask_user_opt_in(self, monkeypatch, capsys, user_opted_in, user_input): + # Mock select.select to simulate user input + def mock_select(*args, **kwargs): + return [sys.stdin], [], [] + + monkeypatch.setattr(select, "select", mock_select) + + # Mock sys.stdin.readline to return the desired input + monkeypatch.setattr(sys.stdin, "readline", lambda: user_input + "\n") # Call the function to ask the user if they want to opt in opt_in = pybamm.config.ask_user_opt_in() + + # Check the result assert opt_in is user_opted_in - def test_ask_user_opt_in_timeout(self, monkeypatch): - # Mock the inputimeout function to raise a TimeoutOccurred exception - def mock_inputimeout(*args, **kwargs): - raise TimeoutOccurred + # Check that the prompt was printed + captured = capsys.readouterr() + assert "Do you want to enable telemetry? (Y/n):" in captured.out + + def test_ask_user_opt_in_invalid_input(self, monkeypatch, capsys): + # Mock select.select to simulate user input and then timeout + def mock_select(*args, **kwargs): + nonlocal call_count + if call_count == 0: + call_count += 1 + return [sys.stdin], [], [] + else: + return [], [], [] - monkeypatch.setattr("pybamm.config.inputimeout", mock_inputimeout) + monkeypatch.setattr(select, "select", mock_select) + + # Mock sys.stdin.readline to return invalid input + monkeypatch.setattr(sys.stdin, "readline", lambda: "invalid\n") + + # Initialize call count + call_count = 0 # Call the function to ask the user if they want to opt in - opt_in = pybamm.config.ask_user_opt_in() + opt_in = pybamm.config.ask_user_opt_in(timeout=1) + + # Check the result (should be False for timeout after invalid input) assert opt_in is False + + # Check that the prompt, invalid input message, and timeout message were printed + captured = capsys.readouterr() + assert "Do you want to enable telemetry? (Y/n):" in captured.out + assert ( + "Invalid input. Please enter 'yes/y' for yes or 'no/n' for no." + in captured.out + ) + assert "Timeout reached. Defaulting to not enabling telemetry." in captured.out + + def test_ask_user_opt_in_timeout(self, monkeypatch, capsys): + # Mock select.select to simulate a timeout + def mock_select(*args, **kwargs): + return [], [], [] + + monkeypatch.setattr(select, "select", mock_select) + + # Call the function to ask the user if they want to opt in + opt_in = pybamm.config.ask_user_opt_in(timeout=1) + + # Check the result (should be False for timeout) + assert opt_in is False + + # Check that the prompt and timeout message were printed + captured = capsys.readouterr() + assert "Do you want to enable telemetry? (Y/n):" in captured.out + assert "Timeout reached. Defaulting to not enabling telemetry." in captured.out