[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