[pypy-svn] r43966 - in pypy/branch/kill-ctypes/pypy/module/_curses: . test

fijal at codespeak.net fijal at codespeak.net
Fri Jun 1 07:49:46 CEST 2007


Author: fijal
Date: Fri Jun  1 07:49:45 2007
New Revision: 43966

Added:
   pypy/branch/kill-ctypes/pypy/module/_curses/   (props changed)
   pypy/branch/kill-ctypes/pypy/module/_curses/__init__.py
   pypy/branch/kill-ctypes/pypy/module/_curses/app_curses.py
   pypy/branch/kill-ctypes/pypy/module/_curses/fficurses.py
   pypy/branch/kill-ctypes/pypy/module/_curses/interp_curses.py
   pypy/branch/kill-ctypes/pypy/module/_curses/test/   (props changed)
   pypy/branch/kill-ctypes/pypy/module/_curses/test/__init__.py
   pypy/branch/kill-ctypes/pypy/module/_curses/test/test_curses.py
Log:
Add a dummy _curses module, just enough to run pyrepl. Still, there
are major concerns about merging this branch:

* storing annotations on __class__ of ExtFunc
* termios exception hacks (annotation)
* seems that lltype.free has some problems with exception_is_here()
  (fficurses.py/tigetstr_llimpl)
* we_are_translated in interp_termios, which is ugly.



Added: pypy/branch/kill-ctypes/pypy/module/_curses/__init__.py
==============================================================================
--- (empty file)
+++ pypy/branch/kill-ctypes/pypy/module/_curses/__init__.py	Fri Jun  1 07:49:45 2007
@@ -0,0 +1,35 @@
+
+from pypy.interpreter.mixedmodule import MixedModule
+from pypy.module._curses import fficurses
+from pypy.module._curses import interp_curses
+from pypy.rlib.nonconst import NonConstant
+import _curses
+
+class Module(MixedModule):
+    """ Low-level interface for curses module,
+    not meant to be used directly
+    """
+    applevel_name = "_curses"
+
+    appleveldefs = {
+        'error'          : 'app_curses.error',
+    }
+    
+    interpleveldefs = {
+        'setupterm'      : 'interp_curses.setupterm',
+        'tigetstr'       : 'interp_curses.tigetstr',
+        'tparm'          : 'interp_curses.tparm',
+    }
+
+    def startup(self, space):
+        # XXX nasty annotation trick
+        try:
+            raise interp_curses.curses_error(NonConstant("xxx"))
+        except _curses.error, e:
+            pass
+
+import _curses
+for i in dir(_curses):
+    val = getattr(_curses, i)
+    if i.isupper() and type(val) is int:
+        Module.interpleveldefs[i] = "space.wrap(%s)" % val

Added: pypy/branch/kill-ctypes/pypy/module/_curses/app_curses.py
==============================================================================
--- (empty file)
+++ pypy/branch/kill-ctypes/pypy/module/_curses/app_curses.py	Fri Jun  1 07:49:45 2007
@@ -0,0 +1,3 @@
+
+class error(Exception):
+    pass

Added: pypy/branch/kill-ctypes/pypy/module/_curses/fficurses.py
==============================================================================
--- (empty file)
+++ pypy/branch/kill-ctypes/pypy/module/_curses/fficurses.py	Fri Jun  1 07:49:45 2007
@@ -0,0 +1,101 @@
+
+""" The ffi for rpython, need to be imported for side effects
+"""
+
+import sys
+from pypy.rpython.lltypesystem import rffi
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.extfunc import register_external
+from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.module._curses import interp_curses
+from pypy.rpython.lltypesystem import llmemory
+
+# waaa...
+includes = ['curses.h', 'term.h']
+libs = ['curses']
+
+INT = rffi.INT
+INTP = lltype.Ptr(lltype.Array(INT, hints={'nolength':True}))
+c_setupterm = rffi.llexternal('setupterm', [rffi.CCHARP, INT, INTP], INT,
+                              includes=includes, libraries=libs)
+c_tigetstr = rffi.llexternal('tigetstr', [rffi.CCHARP], rffi.CCHARP,
+                             includes=includes, libraries=libs)
+c_tparm = rffi.llexternal('tparm', [rffi.CCHARP, INT, INT, INT, INT, INT,
+                                    INT, INT, INT, INT, INT], rffi.CCHARP,
+                          includes=includes, libraries=libs)
+
+ERR = rffi.CConstant('ERR', INT)
+OK = rffi.CConstant('OK', INT)
+
+def curses_setupterm(term, fd):
+    intp = lltype.malloc(INTP.TO, 1, flavor='raw')
+    err = c_setupterm(term, fd, intp)
+    try:
+        if err == ERR:
+            if intp[0] == 0:
+                msg = "setupterm: could not find terminal"
+            elif intp[0] == -1:
+                msg = "setupterm: could not find terminfo database"
+            else:
+                msg = "setupterm: unknown error"
+            raise interp_curses.curses_error(msg)
+        interp_curses.module_info.setupterm_called = True
+    finally:
+        lltype.free(intp, flavor='raw')
+
+def curses_setupterm_null_llimpl(fd):
+    curses_setupterm(lltype.nullptr(rffi.CCHARP.TO), fd)
+
+def curses_setupterm_llimpl(term, fd):
+    ll_s = rffi.str2charp(term)
+    try:
+        curses_setupterm(ll_s, fd)
+    finally:
+        lltype.free(ll_s, flavor='raw')
+
+register_external(interp_curses._curses_setupterm_null,
+                  [int], llimpl=curses_setupterm_null_llimpl,
+                  export_name='_curses.setupterm_null')
+register_external(interp_curses._curses_setupterm,
+                  [str, int], llimpl=curses_setupterm_llimpl,
+                  export_name='_curses.setupterm')
+
+def check_setup_invoked():
+    if not interp_curses.module_info.setupterm_called:
+        raise interp_curses.curses_error("must call (at least) setupterm() first")
+
+def tigetstr_llimpl(cap):
+    check_setup_invoked()
+    ll_cap = rffi.str2charp(cap)
+    try:
+        ll_res = c_tigetstr(ll_cap)
+        num = lltype.cast_ptr_to_int(ll_res)
+        if num == 0 or num == -1:
+            raise interp_curses.TermError()
+        res = rffi.charp2str(ll_res)
+        # XXX - how to avoid a problem with leaking stuff here???
+        #lltype.free(ll_res, flavor='raw')
+        return res
+    finally:
+        lltype.free(ll_cap, flavor='raw')
+    
+register_external(interp_curses._curses_tigetstr, [str], str,
+                  export_name='_curses.tigetstr', llimpl=tigetstr_llimpl)
+
+def tparm_llimpl(s, args):
+    check_setup_invoked()
+    l = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+    for i in range(min(len(args), 10)):
+        l[i] = args[i]
+    ll_s = rffi.str2charp(s)
+    # XXX nasty trick stolen from CPython
+    ll_res = c_tparm(ll_s, l[0], l[1], l[2], l[3], l[4], l[5], l[6],
+                     l[7], l[8], l[9])
+    lltype.free(ll_s, flavor='raw')
+    # XXX - how to make this happy?
+    # lltype.free(ll_res, flavor.raw)
+    return rffi.charp2str(ll_res)
+
+register_external(interp_curses._curses_tparm, [str, [int]], str,
+                  export_name='_curses.tparm', llimpl=tparm_llimpl)
+

Added: pypy/branch/kill-ctypes/pypy/module/_curses/interp_curses.py
==============================================================================
--- (empty file)
+++ pypy/branch/kill-ctypes/pypy/module/_curses/interp_curses.py	Fri Jun  1 07:49:45 2007
@@ -0,0 +1,77 @@
+
+from pypy.interpreter.baseobjspace import ObjSpace, W_Root
+from pypy.interpreter.error import OperationError
+
+import _curses
+
+class ModuleInfo:
+    def __init__(self):
+        self.setupterm_called = False
+
+module_info = ModuleInfo()
+
+class curses_error(_curses.error):
+    def __init__(self, msg):
+        self.args = [msg]
+
+def convert_error(space, error):
+    msg = error.args[0]
+    w_module = space.getbuiltinmodule('_curses')
+    w_exception_class = space.getattr(w_module, space.wrap('error'))
+    w_exception = space.call_function(w_exception_class, space.wrap(msg))
+    return OperationError(w_exception_class, w_exception)
+
+def _curses_setupterm_null(fd):
+    # NOT_RPYTHON
+    _curses.setupterm(None, fd)
+
+def _curses_setupterm(termname, fd):
+    # NOT_RPYTHON
+    _curses.setupterm(termname, fd)
+
+def setupterm(space, w_termname=None, fd=-1):
+    if fd == -1:
+        w_stdout = space.getattr(space.getbuiltinmodule('sys'),
+                                 space.wrap('stdout'))
+        fd = space.int_w(space.call_function(space.getattr(w_stdout,
+                                             space.wrap('fileno'))))
+    try:
+        if space.is_w(w_termname, space.w_None) or w_termname is None:
+            _curses_setupterm_null(fd)
+        else:
+            _curses_setupterm(space.str_w(w_termname), fd)
+    except _curses.error, e:
+        raise convert_error(space, e)
+setupterm.unwrap_spec = [ObjSpace, W_Root, int]
+
+class TermError(Exception):
+    pass
+
+def _curses_tigetstr(capname):
+    # NOT_RPYTHON
+    res = _curses.tigetstr(capname)
+    if res is None:
+        raise TermError
+    return res
+
+def _curses_tparm(s, args):
+    # NOT_RPYTHON
+    return _curses.tparm(s, *args)
+
+def tigetstr(space, capname):
+    try:
+        result = _curses_tigetstr(capname)
+    except TermError:
+        return space.w_None
+    except _curses.error, e:
+        raise convert_error(space, e)
+    return space.wrap(result)
+tigetstr.unwrap_spec = [ObjSpace, str]
+
+def tparm(space, s, args_w):
+    args = [space.int_w(a) for a in args_w]
+    try:
+        return space.wrap(_curses_tparm(s, args))
+    except _curses.error, e:
+        raise convert_error(space, e)
+tparm.unwrap_spec = [ObjSpace, str, 'args_w']

Added: pypy/branch/kill-ctypes/pypy/module/_curses/test/__init__.py
==============================================================================

Added: pypy/branch/kill-ctypes/pypy/module/_curses/test/test_curses.py
==============================================================================
--- (empty file)
+++ pypy/branch/kill-ctypes/pypy/module/_curses/test/test_curses.py	Fri Jun  1 07:49:45 2007
@@ -0,0 +1,89 @@
+
+from pypy.translator.c.test.test_genc import compile
+from pypy.module._curses import interp_curses
+from pypy.module._curses import fficurses        
+from pypy.conftest import gettestobjspace
+from pypy.tool.autopath import pypydir
+from pypy.tool.udir import udir
+import py
+import sys
+
+class AppTestCurses(object):
+    def setup_class(cls): 
+        cls.space = gettestobjspace(usemodules=['_curses'])
+
+    def test_tigetstr(self):
+        import _curses
+        _curses.setupterm()
+        assert _curses.tigetstr('cup') == '\x1b[%i%p1%d;%p2%dH'
+
+    def test_tparm(self):
+        import _curses
+        _curses.setupterm()
+        assert _curses.tparm(_curses.tigetstr('cup'), 5, 3) == '\033[6;4H'
+
+class TestCurses(object):
+    """ We need to fork here, to prevent
+    the setup to be done
+    """
+    def _spawn(self, *args, **kwds):
+        import pexpect
+        print 'SPAWN:', args, kwds
+        child = pexpect.spawn(*args, **kwds)
+        child.logfile = sys.stdout
+        return child
+
+    def spawn(self, argv):
+        py_py = py.path.local(pypydir).join('bin', 'py.py')
+        return self._spawn(sys.executable, [str(py_py)] + argv)
+
+    def setup_class(self):
+        try:
+            import pexpect
+        except ImportError:
+            py.test.skip('pexpect not found')
+
+    def test_setupterm(self):
+        source = py.code.Source("""
+        import _curses
+        try:
+            _curses.tigetstr('cup')
+        except _curses.error:
+            print 'ok!'
+        """)
+        f = udir.join("test_setupterm.py")
+        f.write(source)
+        child = self.spawn(['--withmod-_curses', str(f)])
+        child.expect('ok!')
+
+# XXX probably we need to run all the stuff here in pexpect anyway...
+
+class TestCCurses(object):
+    """ Test compiled version
+    """
+    def test_csetupterm(self):
+        def runs_setupterm():
+            interp_curses._curses_setupterm_null(1)
+
+        fn = compile(runs_setupterm, [])
+        fn()
+
+    def test_ctgetstr(self):
+        def runs_ctgetstr():
+            interp_curses._curses_setupterm("xterm", 1)
+            res = interp_curses._curses_tigetstr('cup')
+            assert res == '\x1b[%i%p1%d;%p2%dH'
+
+        fn = compile(runs_ctgetstr, [])
+        fn()
+
+    def test_ctparm(self):
+        def runs_tparm():
+            interp_curses._curses_setupterm("xterm", 1)
+            cup = interp_curses._curses_tigetstr('cup')
+            res = interp_curses._curses_tparm(cup, [5, 3])
+            assert res == '\033[6;4H'
+
+        fn = compile(runs_tparm, [])
+        fn()
+    


More information about the pypy-svn mailing list