From c8239fe3dcf07bf8101d9feb07b5a5b64c5c95a3 Mon Sep 17 00:00:00 2001 From: Christian Monch Date: Tue, 9 Apr 2024 16:13:04 +0200 Subject: [PATCH] fail if `ui` asks for input without a terminal This commit attempts to fix the issue where `get` stalls if an annex remote tries to ask for credentials in a process that has no terminal attached. --- datalad/ui/dialog.py | 26 ++++++++++++++++++++++++++ datalad/ui/utils.py | 14 +++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/datalad/ui/dialog.py b/datalad/ui/dialog.py index ceef68c447..f43d6cc2b3 100644 --- a/datalad/ui/dialog.py +++ b/datalad/ui/dialog.py @@ -31,6 +31,7 @@ from ..utils import auto_repr from ..utils import on_windows from .base import InteractiveUI +from .utils import has_terminal from datalad.support.exceptions import CapturedException # Example APIs which might be useful to look for "inspiration" @@ -357,6 +358,31 @@ def get_progressbar(self, *args, **kwargs): return super(UnderAnnexUI, self).get_progressbar( *args, **kwargs) + def input(self, prompt, hidden=False): + if not has_terminal(): + # we are not interactive + raise RuntimeError('Interactive input not available for `ui.input()` in annex remotes') + return super(UnderAnnexUI, self).input(prompt, hidden) + + def question(self, + text, + title=None, + choices=None, + default=None, + hidden=False, + repeat=None): + if not has_terminal(): + # we are not interactive + raise RuntimeError('Interactive input not available for `ui.question()` in annex remotes') + return super(UnderAnnexUI, self).question( + text, + title=title, + choices=choices, + default=default, + hidden=hidden, + repeat=repeat + ) + @auto_repr class UnderTestsUI(DialogUI): diff --git a/datalad/ui/utils.py b/datalad/ui/utils.py index 2e64c2321d..abb70b4683 100644 --- a/datalad/ui/utils.py +++ b/datalad/ui/utils.py @@ -73,4 +73,16 @@ def show_hint(msg): ui.message("{}".format( ansi_colors.color_word( msg, - ansi_colors.YELLOW))) \ No newline at end of file + ansi_colors.YELLOW))) + + +def has_terminal(): + """Return True if the process has a controlling terminal + + This checks for a controlling terminal on Linux + """ + try: + open('/dev/tty', 'r').close() + return True + except IOError as exc: + return False