[pypy-svn] r79326 - in pypy/branch/psycopg2compatibility/pypy: module/cpyext module/cpyext/test tool

dan at codespeak.net dan at codespeak.net
Mon Nov 22 01:36:16 CET 2010


Author: dan
Date: Mon Nov 22 01:36:13 2010
New Revision: 79326

Added:
   pypy/branch/psycopg2compatibility/pypy/tool/call_logger.py
Modified:
   pypy/branch/psycopg2compatibility/pypy/module/cpyext/api.py
   pypy/branch/psycopg2compatibility/pypy/module/cpyext/intobject.py
   pypy/branch/psycopg2compatibility/pypy/module/cpyext/pyobject.py
   pypy/branch/psycopg2compatibility/pypy/module/cpyext/pystate.py
   pypy/branch/psycopg2compatibility/pypy/module/cpyext/stubs.py
   pypy/branch/psycopg2compatibility/pypy/module/cpyext/test/test_pystate.py
Log:
Importing my changes from before.

Modified: pypy/branch/psycopg2compatibility/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/psycopg2compatibility/pypy/module/cpyext/api.py	(original)
+++ pypy/branch/psycopg2compatibility/pypy/module/cpyext/api.py	Mon Nov 22 01:36:13 2010
@@ -36,6 +36,42 @@
 
 DEBUG_WRAPPER = True
 
+if not we_are_translated() and DEBUG_WRAPPER:
+    from functools import wraps
+else:
+    def wraps(f): return lambda f: f
+
+from pypy.tool.call_logger import CallLogger, SkipArgument
+
+class CPyExtCallLogger(CallLogger):
+    def format_arg(self, arg, args, kwargs, name=''):
+        from pypy.module.cpyext.object import PyObject_Repr
+        from pypy.rpython.lltypesystem.rffi import charp2str, unicode_from_buffer
+        from pypy.rpython.lltypesystem.lltype import direct_arrayitems
+        from pypy.module.cpyext.pyobject import from_ref, InvalidPointerException
+        from pypy.objspace.std.model import UnwrapError
+
+        if isinstance(arg, ObjSpace):
+            raise SkipArgument()
+
+        if is_PyObject(arg):
+            space = args[0]
+            return space.unwrap(PyObject_Repr(space, arg))
+
+        return repr(arg)
+
+    def log(self, logstr, depth=0):
+        from sys import stderr
+        print >>stderr, (' ' * depth) + logstr
+
+    def log_call(self, f):
+        if not we_are_translated() and DEBUG_WRAPPER:
+            return CallLogger.log_call(self, f)
+        else:
+            return f
+
+log_call = CPyExtCallLogger().log_call
+
 # update these for other platforms
 Py_ssize_t = lltype.Signed
 Py_ssize_tP = rffi.CArrayPtr(Py_ssize_t)
@@ -321,6 +357,8 @@
     'PyCObject_Type', 'init_pycobject',
 
     'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
+    'PyThread_Get',
+    'PyInterpreter_Head', 'PyInterpreter_Next',
 ]
 TYPES = {}
 GLOBALS = { # this needs to include all prebuilt pto, otherwise segfaults occur
@@ -470,7 +508,10 @@
         [name.startswith("w_") for name in names])))
     fatal_value = callable.api_func.restype._defl()
 
+    logged_callable = log_call(callable)
+
     @specialize.ll()
+    @wraps(callable)
     def wrapper(*args):
         from pypy.module.cpyext.pyobject import make_ref, from_ref
         from pypy.module.cpyext.pyobject import Reference
@@ -481,8 +522,6 @@
         retval = fatal_value
         boxed_args = ()
         try:
-            if not we_are_translated() and DEBUG_WRAPPER:
-                print >>sys.stderr, callable,
             assert len(args) == len(callable.api_func.argtypes)
             for i, (typ, is_wrapped) in argtypes_enum_ui:
                 arg = args[i]
@@ -496,9 +535,7 @@
                 boxed_args += (arg_conv, )
             state = space.fromcache(State)
             try:
-                result = callable(space, *boxed_args)
-                if not we_are_translated() and DEBUG_WRAPPER:
-                    print >>sys.stderr, " DONE"
+                result = logged_callable(space, *boxed_args)
             except OperationError, e:
                 failed = True
                 state.set_exception(e)

Modified: pypy/branch/psycopg2compatibility/pypy/module/cpyext/intobject.py
==============================================================================
--- pypy/branch/psycopg2compatibility/pypy/module/cpyext/intobject.py	(original)
+++ pypy/branch/psycopg2compatibility/pypy/module/cpyext/intobject.py	Mon Nov 22 01:36:13 2010
@@ -3,7 +3,6 @@
 from pypy.module.cpyext.api import (cpython_api, PyObject, CANNOT_FAIL,
                                     build_type_checkers, Py_ssize_t)
 
-
 PyInt_Check, PyInt_CheckExact = build_type_checkers("Int")
 
 @cpython_api([lltype.Signed], PyObject)
@@ -49,3 +48,31 @@
     """
     return space.wrap(ival) # XXX this is wrong on win64
 
+ at cpython_api([rffi.CCHARP, rffi.CCHARPP, rffi.INT_real], PyObject)
+def PyInt_FromString(space, str, pend, base):
+    """Return a new PyIntObject or PyLongObject based on the string
+    value in str, which is interpreted according to the radix in base.  If
+    pend is non-NULL, *pend will point to the first character in str which
+    follows the representation of the number.  If base is 0, the radix will be
+    determined based on the leading characters of str: if str starts with
+    '0x' or '0X', radix 16 will be used; if str starts with '0', radix
+    8 will be used; otherwise radix 10 will be used.  If base is not 0, it
+    must be between 2 and 36, inclusive.  Leading spaces are ignored.  If
+    there are no digits, ValueError will be raised.  If the string represents
+    a number too large to be contained within the machine's long int type
+    and overflow warnings are being suppressed, a PyLongObject will be
+    returned.  If overflow warnings are not being suppressed, NULL will be
+    returned in this case."""
+    # TODO: test!
+    if pend:
+        raise NotImplementedError
+        len = pend - str # FIXME: can sub pointers? right function name?
+        str = rffi.charp2strn(str, len)
+    else:
+        str = rffi.charp2str(str)
+
+    base = int(base)
+
+    value = int(str, base)
+
+    return space.wrap(value)

Modified: pypy/branch/psycopg2compatibility/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/psycopg2compatibility/pypy/module/cpyext/pyobject.py	(original)
+++ pypy/branch/psycopg2compatibility/pypy/module/cpyext/pyobject.py	Mon Nov 22 01:36:13 2010
@@ -171,7 +171,7 @@
         lifeline = self.lifeline_dict.get(w_obj)
         if lifeline is not None: # make old PyObject ready for use in C code
             py_obj = lifeline.pyo
-            assert py_obj.c_ob_refcnt == 0
+            assert py_obj.c_ob_refcnt == 0, "%r refcount %d" % (py_obj, py_obj.c_ob_refcnt)
             return py_obj
         else:
             return lltype.nullptr(PyObject.TO)

Modified: pypy/branch/psycopg2compatibility/pypy/module/cpyext/pystate.py
==============================================================================
--- pypy/branch/psycopg2compatibility/pypy/module/cpyext/pystate.py	(original)
+++ pypy/branch/psycopg2compatibility/pypy/module/cpyext/pystate.py	Mon Nov 22 01:36:13 2010
@@ -3,8 +3,8 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 
 
-PyThreadState = lltype.Ptr(cpython_struct("PyThreadState", ()))
 PyInterpreterState = lltype.Ptr(cpython_struct("PyInterpreterState", ()))
+PyThreadState = lltype.Ptr(cpython_struct("PyThreadState", [('interp', PyInterpreterState)]))
 
 @cpython_api([], PyThreadState, error=CANNOT_FAIL)
 def PyEval_SaveThread(space):
@@ -35,4 +35,55 @@
 def PyEval_ThreadsInitialized(space):
     return 1
 
+# XXX: might be generally useful
+def encapsulator(T, flavor='raw'):
+    class MemoryCapsule(object):
+        def __init__(self):
+            self.memory = lltype.malloc(T, flavor=flavor)
+        def __del__(self):
+            lltype.free(self.memory, flavor=flavor)
+    return MemoryCapsule
+
+ThreadStateCapsule = encapsulator(PyThreadState.TO)
+
+class InterpreterState(object):
+    def __init__(self, space):
+        self.interpreter_state = lltype.malloc(PyInterpreterState.TO, flavor='raw', immortal=True)
+
+    def new_thread_state(self):
+        capsule = ThreadStateCapsule()
+        ts = capsule.memory
+        ts.c_interp = self.interpreter_state
+        return capsule
+
+    def get_thread_state(self, space):
+        ec = space.getexecutioncontext()
+        return self._get_thread_state(ec).memory
+
+    def _get_thread_state(self, ec):
+        try:
+            ts = ec.cpyext_threadstate
+            if not ts:
+                ec.cpyext_threadstate = self.new_thread_state()
+        except AttributeError, e:
+            ec.cpyext_threadstate = self.new_thread_state()
 
+        return ec.cpyext_threadstate
+
+ at cpython_api([], PyThreadState, error=CANNOT_FAIL)
+def PyThreadState_Get(space, ):
+    state = space.fromcache(InterpreterState)
+    return state.get_thread_state(space)
+
+ at cpython_api([], PyInterpreterState, error=CANNOT_FAIL)
+def PyInterpreterState_Head(space, ):
+    """Return the interpreter state object at the head of the list of all such objects.
+    """
+    return space.fromcache(InterpreterState).interpreter_state
+
+ at cpython_api([PyInterpreterState], PyInterpreterState, error=CANNOT_FAIL)
+def PyInterpreterState_Next(space, interp):
+    """Return the next interpreter state object after interp from the list of all
+    such objects.
+    """
+    return lltype.nullptr(PyInterpreterState.TO)

Modified: pypy/branch/psycopg2compatibility/pypy/module/cpyext/stubs.py
==============================================================================
--- pypy/branch/psycopg2compatibility/pypy/module/cpyext/stubs.py	(original)
+++ pypy/branch/psycopg2compatibility/pypy/module/cpyext/stubs.py	Mon Nov 22 01:36:13 2010
@@ -1679,13 +1679,6 @@
     PyInterpreterState_Clear()."""
     raise NotImplementedError
 
- at cpython_api([], PyThreadState)
-def PyThreadState_Get(space, ):
-    """Return the current thread state.  The global interpreter lock must be held.
-    When the current thread state is NULL, this issues a fatal error (so that
-    the caller needn't check for NULL)."""
-    raise NotImplementedError
-
 @cpython_api([], PyObject)
 def PyThreadState_GetDict(space, ):
     """Return a dictionary in which extensions can store thread-specific state
@@ -1822,19 +1815,6 @@
     defined."""
     raise NotImplementedError
 
- at cpython_api([], PyInterpreterState)
-def PyInterpreterState_Head(space, ):
-    """Return the interpreter state object at the head of the list of all such objects.
-    """
-    raise NotImplementedError
-
- at cpython_api([PyInterpreterState], PyInterpreterState)
-def PyInterpreterState_Next(space, interp):
-    """Return the next interpreter state object after interp from the list of all
-    such objects.
-    """
-    raise NotImplementedError
-
 @cpython_api([PyInterpreterState], PyThreadState)
 def PyInterpreterState_ThreadHead(space, interp):
     """Return the a pointer to the first PyThreadState object in the list of
@@ -1849,23 +1829,6 @@
     """
     raise NotImplementedError
 
- at cpython_api([rffi.CCHARP, rffi.CCHARPP, rffi.INT_real], PyObject)
-def PyInt_FromString(space, str, pend, base):
-    """Return a new PyIntObject or PyLongObject based on the string
-    value in str, which is interpreted according to the radix in base.  If
-    pend is non-NULL, *pend will point to the first character in str which
-    follows the representation of the number.  If base is 0, the radix will be
-    determined based on the leading characters of str: if str starts with
-    '0x' or '0X', radix 16 will be used; if str starts with '0', radix
-    8 will be used; otherwise radix 10 will be used.  If base is not 0, it
-    must be between 2 and 36, inclusive.  Leading spaces are ignored.  If
-    there are no digits, ValueError will be raised.  If the string represents
-    a number too large to be contained within the machine's long int type
-    and overflow warnings are being suppressed, a PyLongObject will be
-    returned.  If overflow warnings are not being suppressed, NULL will be
-    returned in this case."""
-    raise NotImplementedError
-
 @cpython_api([rffi.SIZE_T], PyObject)
 def PyInt_FromSize_t(space, ival):
     """Create a new integer object with a value of ival. If the value exceeds

Modified: pypy/branch/psycopg2compatibility/pypy/module/cpyext/test/test_pystate.py
==============================================================================
--- pypy/branch/psycopg2compatibility/pypy/module/cpyext/test/test_pystate.py	(original)
+++ pypy/branch/psycopg2compatibility/pypy/module/cpyext/test/test_pystate.py	Mon Nov 22 01:36:13 2010
@@ -1,4 +1,7 @@
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.rpython.lltypesystem.lltype import nullptr
+from pypy.module.cpyext.pystate import PyInterpreterState, PyThreadState
 
 class AppTestThreads(AppTestCpythonExtensionBase):
     def test_allow_threads(self):
@@ -17,3 +20,26 @@
         # Should compile at least
         module.test()
 
+class TestInterpreterState(BaseApiTest):
+    def test_interpreter_head(self, space, api):
+        state = api.PyInterpreterState_Head()
+        assert state != nullptr(PyInterpreterState.TO)
+
+    def test_interpreter_next(self, space, api):
+        state = api.PyInterpreterState_Head()
+        assert nullptr(PyInterpreterState.TO) == api.PyInterpreterState_Next(state)
+
+def clear_threadstate(space):
+    # XXX: this should collect the ThreadState memory
+    del space.getexecutioncontext().cpyext_threadstate
+
+class TestThreadState(BaseApiTest):
+    def test_thread_state_get(self, space, api):
+        ts = api.PyThreadState_Get()
+        assert ts != nullptr(PyThreadState.TO)
+        clear_threadstate(space)
+
+    def test_thread_state_interp(self, space, api):
+        ts = api.PyThreadState_Get()
+        assert ts.c_interp == api.PyInterpreterState_Head()
+        clear_threadstate(space)

Added: pypy/branch/psycopg2compatibility/pypy/tool/call_logger.py
==============================================================================
--- (empty file)
+++ pypy/branch/psycopg2compatibility/pypy/tool/call_logger.py	Mon Nov 22 01:36:13 2010
@@ -0,0 +1,47 @@
+from functools import wraps
+
+class SkipArgument(Exception): pass
+
+class CallLogger(object):
+    def __init__(self):
+        self.indentation = 0
+    
+    def format_arg(self, arg, args=[], kwargs={}, name=''):
+        return repr(arg)
+
+    def argstrs(self, args, kwargs):
+        argstrs = []
+        for arg in args:
+            try:
+                argstrs.append(self.format_arg(arg, args, kwargs))
+            except SkipArgument, e: continue
+        argstr = ', '.join(argstrs)
+
+        kwargstrs = []
+        for name, arg in kwargs.iteritems():
+            try:
+                kwargstrs.append("%s=%s" % (name, self.format_arg(arg, args, kwargs, name=name)))
+            except SkipArgument, e: continue
+        kwargstr = ', '.join(kwargstrs)
+
+        if argstr and kwargstr:
+            return ', '.join([argstr, kwargstr])
+        elif argstr:
+            return argstr
+        else:
+            return kwargstr
+
+    def log(self, logstr, depth=0):
+        print (' ' * depth) + logstr
+
+    def log_call(self, f):
+        @wraps(f)
+        def wrapped(*args, **kwargs):
+            argstr = self.argstrs(args, kwargs)
+            self.log("%s(%s)" % (f.__name__, argstr), depth=self.indentation)
+            self.indentation += 1
+            result = f(*args, **kwargs)
+            self.indentation -= 1
+            self.log("%s(%s)->%r" % (f.__name__, argstr, result), depth=self.indentation)
+            return result
+        return wrapped



More information about the Pypy-commit mailing list