[pypy-commit] pypy py3.6: fix _curses for py3.6

mattip pypy.commits at gmail.com
Sun Jan 26 04:26:26 EST 2020


Author: Matti Picus <matti.picus at gmail.com>
Branch: py3.6
Changeset: r98587:9265d2b9cef6
Date: 2020-01-26 11:25 +0200
http://bitbucket.org/pypy/pypy/changeset/9265d2b9cef6/

Log:	fix _curses for py3.6

diff --git a/lib-python/3/test/test_curses.py b/lib-python/3/test/test_curses.py
--- a/lib-python/3/test/test_curses.py
+++ b/lib-python/3/test/test_curses.py
@@ -15,7 +15,8 @@
 import tempfile
 import unittest
 
-from test.support import requires, import_module, verbose, SaveSignals
+from test.support import (requires, import_module, verbose, SaveSignals,
+        cpython_only)
 
 # Optionally test curses module.  This currently requires that the
 # 'curses' resource be given on the regrtest command line using the -u
@@ -315,6 +316,7 @@
                                msg='userptr should fail since not set'):
             p.userptr()
 
+    @cpython_only
     @requires_curses_func('panel')
     def test_userptr_memory_leak(self):
         w = curses.newwin(10, 10)
@@ -328,6 +330,7 @@
         self.assertEqual(sys.getrefcount(obj), nrefs,
                          "set_userptr leaked references")
 
+    @cpython_only
     @requires_curses_func('panel')
     def test_userptr_segfault(self):
         w = curses.newwin(10, 10)
@@ -420,20 +423,20 @@
         # we will need to rewrite this test.
         try:
             signature = inspect.signature(stdscr.addch)
-            self.assertFalse(signature)
         except ValueError:
-            # not generating a signature is fine.
-            pass
 
-        # So.  No signature for addch.
-        # But Argument Clinic gave us a human-readable equivalent
-        # as the first line of the docstring.  So we parse that,
-        # and ensure that the parameters appear in the correct order.
-        # Since this is parsing output from Argument Clinic, we can
-        # be reasonably certain the generated parsing code will be
-        # correct too.
-        human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
-        self.assertIn("[y, x,]", human_readable_signature)
+            # So.  No signature for addch.
+            # But Argument Clinic gave us a human-readable equivalent
+            # as the first line of the docstring.  So we parse that,
+            # and ensure that the parameters appear in the correct order.
+            # Since this is parsing output from Argument Clinic, we can
+            # be reasonably certain the generated parsing code will be
+            # correct too.
+            human_readable_signature = stdscr.addch.__doc__.split("\n")[0]
+            self.assertIn("[y, x,]", human_readable_signature)
+        else:
+            params = list(signature.parameters.keys())
+            self.assertTrue(params.index('y') < params.index('x'))
 
     def test_issue13051(self):
         stdscr = self.stdscr
diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py
--- a/lib_pypy/_curses.py
+++ b/lib_pypy/_curses.py
@@ -4,6 +4,7 @@
 if sys.platform == 'win32':
     #This module does not exist in windows
     raise ImportError('No module named _curses')
+import locale
 from functools import wraps
 
 from _curses_cffi import ffi, lib
@@ -175,6 +176,40 @@
         raise TypeError("bytes or str expected, got a '%s' object"
                         % (type(text).__name__,))
 
+def _convert_to_chtype(win, obj):
+    if isinstance(obj, bytes) and len(obj) == 1:
+        value = ord(obj)
+    elif isinstance(obj, str):
+        if len(obj) != 1:
+            raise TypeError("expect bytes or str of length 1 or int, "
+                            "got a str of length %d", len(obj))
+        value = ord(obj)
+        if (128 < value):
+            if win:
+                encoding = win.encoding
+            else:
+                encoding = screen_encoding
+            b = obj.encode(encoding)
+            if len(bytes) == 1:
+                value = ord(b)
+            else:
+                OverflowError("byte doesn't fit in chtype")
+    elif isinstance(obj, int):
+        value = obj
+    else:
+        raise TypeError('expect bytes or str of length 1, or int, got %s' % type(obj))
+    return value
+
+def _convert_to_string(win, obj):
+    if isinstance(obj, str):
+        value = obj.encode(win.encoding)
+    elif isinstance(obj, bytes):
+        value = obj
+    else:
+        raise TypeError('expect bytes or str, got %s' % type(obj))
+    if b'\0' in value:
+        raise ValueError('embedded null character') 
+    return value
 
 def _extract_yx(args):
     if len(args) >= 2:
@@ -218,8 +253,17 @@
 
 
 class Window(object):
-    def __init__(self, window):
+    def __init__(self, window, encoding=None):
+        if encoding is None:
+            # CPython has a win32 branch here, but _curses is not supported
+            # on win32
+            codeset = locale.nl_langinfo(locale.CODESET)
+            if codeset:
+                encoding = codeset
+            else:
+                encoding = 'utf-8'
         self._win = window
+        self._encoding = encoding
 
     def __del__(self):
         if self._win != lib.stdscr:
@@ -288,7 +332,7 @@
 
     @_argspec(1, 1, 2)
     def addstr(self, y, x, text, attr=None):
-        text = _bytestype(text)
+        text = _convert_to_string(self, text)
         if attr is not None:
             attr_old = lib.getattrs(self._win)
             lib.wattrset(self._win, attr)
@@ -302,7 +346,7 @@
 
     @_argspec(2, 1, 2)
     def addnstr(self, y, x, text, n, attr=None):
-        text = _bytestype(text)
+        text = _convert_to_string(self, text)
         if attr is not None:
             attr_old = lib.getattrs(self._win)
             lib.wattrset(self._win, attr)
@@ -335,7 +379,15 @@
                     _chtype(tl), _chtype(tr), _chtype(bl), _chtype(br))
         return None
 
-    def box(self, vertint=0, horint=0):
+    def box(self, *args):
+        if len(args) == 0:
+            vertint = 0
+            horint = 0
+        elif len(args) == 2:
+            vertint = _convert_to_chtype(self, args[0])
+            horint = _convert_to_chtype(self, args[1])
+        else:
+            raise TypeError('verch,horch required')
         lib.box(self._win, vertint, horint)
         return None
 
@@ -502,7 +554,7 @@
 
     @_argspec(1, 1, 2)
     def insstr(self, y, x, text, attr=None):
-        text = _bytestype(text)
+        text = _convert_to_string(self, text)
         if attr is not None:
             attr_old = lib.getattrs(self._win)
             lib.wattrset(self._win, attr)
@@ -516,7 +568,7 @@
 
     @_argspec(2, 1, 2)
     def insnstr(self, y, x, text, n, attr=None):
-        text = _bytestype(text)
+        text = _convert_to_string(self, text)
         if attr is not None:
             attr_old = lib.getattrs(self._win)
             lib.wattrset(self._win, attr)
@@ -610,7 +662,7 @@
             win = lib.subpad(self._win, nlines, ncols, begin_y, begin_x)
         else:
             win = lib.subwin(self._win, nlines, ncols, begin_y, begin_x)
-        return Window(_check_NULL(win))
+        return Window(_check_NULL(win), self.encoding)
 
     def scroll(self, nlines=None):
         if nlines is None:
@@ -634,6 +686,23 @@
             _check_ERR(lib.wmove(self._win, y, x), "wmove")
         return _check_ERR(lib.wvline(self._win, ch | attr, n), "vline")
 
+    @property
+    def encoding(self):
+        return self._encoding
+
+    @encoding.setter
+    def encoding(self, val):
+        if not val:
+            raise TypeError('encoding may not be deleted')
+        if not isinstance(val, str):
+            raise TypeError('setting encoding to a non-string')
+        encoding = val.encode('ascii')
+        self._encoding = val 
+
+    @encoding.deleter
+    def encoding(self):
+        raise TypeError('encoding may not be deleted')
+        
 
 beep = _mk_no_return("beep")
 def_prog_mode = _mk_no_return("def_prog_mode")
@@ -821,7 +890,9 @@
     globals()["LINES"] = lib.LINES
     globals()["COLS"] = lib.COLS
 
-    return Window(win)
+    window = Window(win)
+    globals()['screen_encoding'] = window.encoding
+    return window
 
 
 def setupterm(term=None, fd=-1):
@@ -1030,7 +1101,13 @@
 
 def unget_wch(ch):
     _ensure_initialised()
-    return _check_ERR(lib.unget_wch(_chtype(ch)), "unget_wch")
+    if isinstance(ch, str):
+        if len(ch) != 1:
+            raise TypeError("expect bytes or str of length1, or int, "
+                            "got a str of length %d" % len(ch))
+    elif isinstance(ch, int): 
+        ch = chr(ch)
+    return _check_ERR(lib.unget_wch(ch), "unget_wch")
 
 
 def use_env(flag):


More information about the pypy-commit mailing list