From 7bd1a946edbb5d41ee036449975aeffcc261ddfa Mon Sep 17 00:00:00 2001 From: Paolo Lammens Date: Wed, 8 Jun 2022 11:29:27 +0200 Subject: [PATCH] fix: Clear O_NONBLOCK flag after using ainput() This is to ensure we can still use regular blocking IO such as input() and print() after using ainput. Fixes #17, #19 --- src/loveletter_cli/session.py | 2 +- src/loveletter_cli/ui/input.py | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/loveletter_cli/session.py b/src/loveletter_cli/session.py index 3915ecc..1a603fe 100644 --- a/src/loveletter_cli/session.py +++ b/src/loveletter_cli/session.py @@ -9,7 +9,6 @@ import more_itertools as mitt import valid8 -from aioconsole import ainput from multimethod import multimethod import loveletter.game @@ -22,6 +21,7 @@ from loveletter_cli.exceptions import Restart from loveletter_cli.server_process import ServerProcess from loveletter_cli.ui import ( + ainput, async_ask_valid_input, draw_game, pause, diff --git a/src/loveletter_cli/ui/input.py b/src/loveletter_cli/ui/input.py index b1cdcf3..1d588d2 100644 --- a/src/loveletter_cli/ui/input.py +++ b/src/loveletter_cli/ui/input.py @@ -1,11 +1,12 @@ import enum import functools +import sys import textwrap from typing import Callable, Tuple, Type, TypeVar +import aioconsole import more_itertools import valid8 -from aioconsole import ainput from .misc import printable_width @@ -14,6 +15,22 @@ _DEFAULT = object() +# Define ainput() based on OS: if the OS uses the O_NONBLOCK flag, we have to +# clear it after every call to ainput() to ensure compatibility with blocking +# IO such as print() and input(). +try: + import fcntl # noqa +except ImportError: + ainput = aioconsole.ainput +else: + + @functools.wraps(aioconsole.ainput) + async def ainput(*args, **kwargs): + result = await aioconsole.ainput(*args, **kwargs) + fcntl.fcntl(sys.stdin.fileno(), fcntl.F_SETFL, 0) + return result + + def ask_valid_input(*args, **kwargs) -> _T: error_message, parser, prompt, validation_errors = _ask_valid_input_parse_args( *args, **kwargs @@ -162,4 +179,6 @@ async def pause() -> None: # the user has to enter twice before input is detected; # but the asynchronous nature is needed to ensure other events are handled in time # (e.g. when the connection is lost). + # Also caused trouble on Linux and Unix regarding the O_NONBLOCK flag + # (see #17 and #19) but this has been fixed. await ainput("Enter something to continue... ")