curses: get_wch return value inconsistent with cpython

Create issue
Issue #3064 resolved
Anthony Sottile created an issue
import curses

def c_main(stdscr):
    ch = stdscr.get_wch()
    assert isinstance(ch, str), ch


curses.wrapper(c_main)

Run this and type “a” on the keyboard

In CPython this does nothing

In pypy3.6 I get:

$ pypy3 t.py
Traceback (most recent call last):
  File "t.py", line 8, in <module>
    curses.wrapper(c_main)
  File "/home/asottile/opt/pypy3.6-v7.1.1-linux64/lib-python/3/curses/__init__.py", line 94, in wrapper
    return func(stdscr, *args, **kwds)
  File "t.py", line 5, in c_main
    assert isinstance(ch, str), ch
AssertionError: 97

$ pypy3 --version
Python 3.6.1 (784b254d6699, Apr 14 2019, 10:22:42)
[PyPy 7.1.1-beta0 with GCC 6.2.0 20160901]

Comments (5)

  1. Anthony Sottile reporter

    Seems a patch like this would work, though I don’t see KEY_CODE_YES in the cffi module 🤔

    -            return wch[0]
    +        if val == lib.KEY_CODE_YES:
    +            return wch[0]
    +        else:
    +            return chr(wch[0])
    

    I’m not too familiar with cffi but I assume it would be adding another constant to _curses_build.py?

  2. Anthony Sottile reporter

    I need to re-learn mercurial, but this is my guess at a functional patch:

    $ git diff
    diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py
    index df6d8aa..b310293 100644
    --- a/lib_pypy/_curses.py
    +++ b/lib_pypy/_curses.py
    @@ -412,7 +412,10 @@ class Window(object):
             else:
                 raise error("get_wch requires 0 or 2 arguments")
             _check_ERR(val, "get_wch")
    -        return wch[0]
    +        if val == lib.KEY_CODE_YES:
    +            return wch[0]
    +        else:
    +            return chr(wch[0])
    
         def getkey(self, *args):
             if len(args) == 0:
    diff --git a/lib_pypy/_curses_build.py b/lib_pypy/_curses_build.py
    index 81b5e68..9985cee 100644
    --- a/lib_pypy/_curses_build.py
    +++ b/lib_pypy/_curses_build.py
    @@ -89,6 +89,7 @@ MEVENT;
    
     static const int ERR, OK;
     static const int TRUE, FALSE;
    +static const int KEY_CODE_YES;
     static const int KEY_MIN, KEY_MAX;
    
     static const int COLOR_BLACK;
    
  3. mattip

    Looks good to me, it makes the logic in that function much more like `PyCursesWindow_Get_WCh` in cpython. Commited in 1e244de6b3ad, thanks

  4. Anthony Sottile reporter

    can confirm this is fixed! thanks again:

    pypy3 run-test: commands[1] | coverage run -m pytest tests
    ============================= test session starts ==============================
    platform linux -- Python 3.6.9[pypy-7.2.0-alpha], pytest-5.1.2, py-1.8.0, pluggy-0.12.0
    cachedir: .tox/pypy3/.pytest_cache
    rootdir: /tmp/x/babi
    collected 36 items                                                             
    
    tests/babi_test.py ....................................                  [100%]
    
    ============================= 36 passed in 36.44s ==============================
    pypy3 run-test: commands[2] | coverage combine
    pypy3 run-test: commands[3] | coverage report --fail-under 100
    Name    Stmts   Miss Branch BrPart  Cover   Missing
    ---------------------------------------------------
    ---------------------------------------------------
    TOTAL     670      0    162      0   100%
    
    3 files skipped due to complete coverage.
    ___________________________________ summary ____________________________________
      pypy3: commands succeeded
      congratulations :)
    
  5. Log in to comment