From a16e0c468ae935bfbce19339295fd14121938d78 Mon Sep 17 00:00:00 2001 From: Ryan McCampbell Date: Sat, 3 Apr 2021 17:58:25 -0400 Subject: [PATCH 1/3] Rename _CursesWindow to window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name _CursesWindow is not exposed at runtime which makes explicit type annotation difficult. It has to be wrapped in quotes, and this doesn't seem to work for all type checkers: PyLance's typechecker accepts it but Jedi's doesn't (tested in VS Code). This is especially annoying because with curses.wrapper(callback) there is no way to infer the type of the passed window except with an explicit annotation. Experimentally, the type is exposed under the name "_curses.window" in Python 3.9 on both Ubuntu and Windows (via [windows-curses](https://pypi.org/project/windows-curses/)). While this is not explicitly documented as public, it is the name used for all the window method docs, and it is probably unlikely to change since some might interpret the lack of underscore as indicating it is public. Unfortunately it doesn't seem to be exposed as such in Python 2, but `¯\_(ツ)_/¯`. Using the runtime name should allow type checking to work with most typecheckers/platforms without quotes, and the old name can be kept as an alias for backwards compatibility. --- stdlib/_curses.pyi | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/stdlib/_curses.pyi b/stdlib/_curses.pyi index ae39ef512df4..ab76f3c07eef 100644 --- a/stdlib/_curses.pyi +++ b/stdlib/_curses.pyi @@ -288,7 +288,7 @@ def flash() -> None: ... def flushinp() -> None: ... def getmouse() -> Tuple[int, int, int, int, int]: ... def getsyx() -> Tuple[int, int]: ... -def getwin(__file: BinaryIO) -> _CursesWindow: ... +def getwin(__file: BinaryIO) -> window: ... def halfdelay(__tenths: int) -> None: ... def has_colors() -> bool: ... def has_ic() -> bool: ... @@ -296,7 +296,7 @@ def has_il() -> bool: ... def has_key(__key: int) -> bool: ... def init_color(__color_number: int, __r: int, __g: int, __b: int) -> None: ... def init_pair(__pair_number: int, __fg: int, __bg: int) -> None: ... -def initscr() -> _CursesWindow: ... +def initscr() -> window: ... def intrflush(__flag: bool) -> None: ... def is_term_resized(__nlines: int, __ncols: int) -> bool: ... def isendwin() -> bool: ... @@ -307,8 +307,8 @@ def meta(__yes: bool) -> None: ... def mouseinterval(__interval: int) -> None: ... def mousemask(__newmask: int) -> Tuple[int, int]: ... def napms(__ms: int) -> int: ... -def newpad(__nlines: int, __ncols: int) -> _CursesWindow: ... -def newwin(__nlines: int, __ncols: int, __begin_y: int = ..., __begin_x: int = ...) -> _CursesWindow: ... +def newpad(__nlines: int, __ncols: int) -> window: ... +def newwin(__nlines: int, __ncols: int, __begin_y: int = ..., __begin_x: int = ...) -> window: ... def nl(__flag: bool = ...) -> None: ... def nocbreak() -> None: ... def noecho() -> None: ... @@ -363,7 +363,7 @@ def use_env(__flag: bool) -> None: ... class error(Exception): ... -class _CursesWindow: +class window: if sys.version_info >= (3, 3): encoding: str @overload @@ -417,9 +417,9 @@ class _CursesWindow: def delch(self, y: int, x: int) -> None: ... def deleteln(self) -> None: ... @overload - def derwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + def derwin(self, begin_y: int, begin_x: int) -> window: ... @overload - def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... def echochar(self, ch: _chtype, attr: int = ...) -> None: ... def enclose(self, y: int, x: int) -> bool: ... def erase(self) -> None: ... @@ -489,16 +489,16 @@ class _CursesWindow: def notimeout(self, yes: bool) -> None: ... def noutrefresh(self) -> None: ... @overload - def overlay(self, destwin: _CursesWindow) -> None: ... + def overlay(self, destwin: window) -> None: ... @overload def overlay( - self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int ) -> None: ... @overload - def overwrite(self, destwin: _CursesWindow) -> None: ... + def overwrite(self, destwin: window) -> None: ... @overload def overwrite( - self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int ) -> None: ... def putwin(self, file: IO[Any]) -> None: ... def redrawln(self, beg: int, num: int) -> None: ... @@ -514,13 +514,13 @@ class _CursesWindow: def standend(self) -> None: ... def standout(self) -> None: ... @overload - def subpad(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subpad(self, begin_y: int, begin_x: int) -> window: ... @overload - def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... @overload - def subwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subwin(self, begin_y: int, begin_x: int) -> window: ... @overload - def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... + def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... def syncdown(self) -> None: ... def syncok(self, flag: bool) -> None: ... def syncup(self) -> None: ... @@ -533,6 +533,9 @@ class _CursesWindow: @overload def vline(self, y: int, x: int, ch: _chtype, n: int) -> None: ... +# Alias for backwards compatibility +_CursesWindow = window + if sys.version_info >= (3, 8): class _ncurses_version(NamedTuple): major: int From 9049a34506f8e24b7ceb2e347ff009f298309210 Mon Sep 17 00:00:00 2001 From: Ryan McCampbell Date: Sun, 4 Apr 2021 02:05:08 -0400 Subject: [PATCH 2/3] Moved window class name behind version check I discovered the name _curses.window is only actually exported in Python >= 3.8 so I moved the name behind a version check, and reverted the original class name to _CursesWindow --- stdlib/_curses.pyi | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/stdlib/_curses.pyi b/stdlib/_curses.pyi index ab76f3c07eef..224c8f523930 100644 --- a/stdlib/_curses.pyi +++ b/stdlib/_curses.pyi @@ -288,7 +288,7 @@ def flash() -> None: ... def flushinp() -> None: ... def getmouse() -> Tuple[int, int, int, int, int]: ... def getsyx() -> Tuple[int, int]: ... -def getwin(__file: BinaryIO) -> window: ... +def getwin(__file: BinaryIO) -> _CursesWindow: ... def halfdelay(__tenths: int) -> None: ... def has_colors() -> bool: ... def has_ic() -> bool: ... @@ -296,7 +296,7 @@ def has_il() -> bool: ... def has_key(__key: int) -> bool: ... def init_color(__color_number: int, __r: int, __g: int, __b: int) -> None: ... def init_pair(__pair_number: int, __fg: int, __bg: int) -> None: ... -def initscr() -> window: ... +def initscr() -> _CursesWindow: ... def intrflush(__flag: bool) -> None: ... def is_term_resized(__nlines: int, __ncols: int) -> bool: ... def isendwin() -> bool: ... @@ -307,8 +307,8 @@ def meta(__yes: bool) -> None: ... def mouseinterval(__interval: int) -> None: ... def mousemask(__newmask: int) -> Tuple[int, int]: ... def napms(__ms: int) -> int: ... -def newpad(__nlines: int, __ncols: int) -> window: ... -def newwin(__nlines: int, __ncols: int, __begin_y: int = ..., __begin_x: int = ...) -> window: ... +def newpad(__nlines: int, __ncols: int) -> _CursesWindow: ... +def newwin(__nlines: int, __ncols: int, __begin_y: int = ..., __begin_x: int = ...) -> _CursesWindow: ... def nl(__flag: bool = ...) -> None: ... def nocbreak() -> None: ... def noecho() -> None: ... @@ -363,7 +363,7 @@ def use_env(__flag: bool) -> None: ... class error(Exception): ... -class window: +class _CursesWindow: if sys.version_info >= (3, 3): encoding: str @overload @@ -417,9 +417,9 @@ class window: def delch(self, y: int, x: int) -> None: ... def deleteln(self) -> None: ... @overload - def derwin(self, begin_y: int, begin_x: int) -> window: ... + def derwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... @overload - def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... + def derwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... def echochar(self, ch: _chtype, attr: int = ...) -> None: ... def enclose(self, y: int, x: int) -> bool: ... def erase(self) -> None: ... @@ -489,16 +489,16 @@ class window: def notimeout(self, yes: bool) -> None: ... def noutrefresh(self) -> None: ... @overload - def overlay(self, destwin: window) -> None: ... + def overlay(self, destwin: _CursesWindow) -> None: ... @overload def overlay( - self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int ) -> None: ... @overload - def overwrite(self, destwin: window) -> None: ... + def overwrite(self, destwin: _CursesWindow) -> None: ... @overload def overwrite( - self, destwin: window, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int + self, destwin: _CursesWindow, sminrow: int, smincol: int, dminrow: int, dmincol: int, dmaxrow: int, dmaxcol: int ) -> None: ... def putwin(self, file: IO[Any]) -> None: ... def redrawln(self, beg: int, num: int) -> None: ... @@ -514,13 +514,13 @@ class window: def standend(self) -> None: ... def standout(self) -> None: ... @overload - def subpad(self, begin_y: int, begin_x: int) -> window: ... + def subpad(self, begin_y: int, begin_x: int) -> _CursesWindow: ... @overload - def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... + def subpad(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... @overload - def subwin(self, begin_y: int, begin_x: int) -> window: ... + def subwin(self, begin_y: int, begin_x: int) -> _CursesWindow: ... @overload - def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> window: ... + def subwin(self, nlines: int, ncols: int, begin_y: int, begin_x: int) -> _CursesWindow: ... def syncdown(self) -> None: ... def syncok(self, flag: bool) -> None: ... def syncup(self) -> None: ... @@ -533,12 +533,10 @@ class window: @overload def vline(self, y: int, x: int, ch: _chtype, n: int) -> None: ... -# Alias for backwards compatibility -_CursesWindow = window - if sys.version_info >= (3, 8): class _ncurses_version(NamedTuple): major: int minor: int patch: int ncurses_version: _ncurses_version + window = _CursesWindow From f8b525e47202ec2d57cd4c48170d270b4e205133 Mon Sep 17 00:00:00 2001 From: Ryan McCampbell Date: Mon, 5 Apr 2021 15:51:35 -0400 Subject: [PATCH 3/3] Added # undocumented comment as suggested Co-authored-by: Akuli --- stdlib/_curses.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/_curses.pyi b/stdlib/_curses.pyi index 224c8f523930..cf11bb40d2ee 100644 --- a/stdlib/_curses.pyi +++ b/stdlib/_curses.pyi @@ -539,4 +539,4 @@ if sys.version_info >= (3, 8): minor: int patch: int ncurses_version: _ncurses_version - window = _CursesWindow + window = _CursesWindow # undocumented