[pypy-commit] pypy cffi-callback-onerror: hg merge default
arigo
noreply at buildbot.pypy.org
Sat Jul 4 23:30:28 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-callback-onerror
Changeset: r78432:088ea8f70900
Date: 2015-07-04 23:19 +0200
http://bitbucket.org/pypy/pypy/changeset/088ea8f70900/
Log: hg merge default
diff too long, truncating to 2000 out of 4366 lines
diff --git a/lib-python/2.7/test/test_urllib2.py b/lib-python/2.7/test/test_urllib2.py
--- a/lib-python/2.7/test/test_urllib2.py
+++ b/lib-python/2.7/test/test_urllib2.py
@@ -291,6 +291,7 @@
self.req_headers = []
self.data = None
self.raise_on_endheaders = False
+ self.sock = None
self._tunnel_headers = {}
def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
diff --git a/lib-python/2.7/urllib2.py b/lib-python/2.7/urllib2.py
--- a/lib-python/2.7/urllib2.py
+++ b/lib-python/2.7/urllib2.py
@@ -1200,6 +1200,12 @@
r = h.getresponse(buffering=True)
except TypeError: # buffering kw not supported
r = h.getresponse()
+ # If the server does not send us a 'Connection: close' header,
+ # HTTPConnection assumes the socket should be left open. Manually
+ # mark the socket to be closed when this response object goes away.
+ if h.sock:
+ h.sock.close()
+ h.sock = None
# Pick apart the HTTPResponse object to get the addinfourl
# object initialized properly.
diff --git a/lib_pypy/_tkinter/tclobj.py b/lib_pypy/_tkinter/tclobj.py
--- a/lib_pypy/_tkinter/tclobj.py
+++ b/lib_pypy/_tkinter/tclobj.py
@@ -108,6 +108,8 @@
return value.internalRep.doubleValue
if value.typePtr == typeCache.IntType:
return value.internalRep.longValue
+ if value.typePtr == typeCache.WideIntType:
+ return FromWideIntObj(app, value)
if value.typePtr == typeCache.BigNumType and tklib.HAVE_LIBTOMMATH:
return FromBignumObj(app, value)
if value.typePtr == typeCache.ListType:
diff --git a/lib_pypy/_tkinter/tklib_build.py b/lib_pypy/_tkinter/tklib_build.py
--- a/lib_pypy/_tkinter/tklib_build.py
+++ b/lib_pypy/_tkinter/tklib_build.py
@@ -179,6 +179,7 @@
typedef int... Tcl_WideInt;
int Tcl_GetWideIntFromObj(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_WideInt *value);
+Tcl_Obj *Tcl_NewWideIntObj(Tcl_WideInt value);
""")
if HAVE_LIBTOMMATH:
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cffi
-Version: 1.1.2
+Version: 1.2.0
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
from .api import FFI, CDefError, FFIError
from .ffiplatform import VerificationError, VerificationMissing
-__version__ = "1.1.2"
-__version_info__ = (1, 1, 2)
+__version__ = "1.2.0"
+__version_info__ = (1, 2, 0)
# The verifier module file names are based on the CRC32 of a string that
# contains the following version number. It may be older than __version__
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -328,6 +328,13 @@
data. Later, when this new cdata object is garbage-collected,
'destructor(old_cdata_object)' will be called.
"""
+ try:
+ gcp = self._backend.gcp
+ except AttributeError:
+ pass
+ else:
+ return gcp(cdata, destructor)
+ #
with self._lock:
try:
gc_weakrefs = self.gc_weakrefs
@@ -429,6 +436,8 @@
raise TypeError("ffi.include() expects an argument that is also of"
" type cffi.FFI, not %r" % (
type(ffi_to_include).__name__,))
+ if ffi_to_include is self:
+ raise ValueError("self.include(self)")
with ffi_to_include._lock:
with self._lock:
self._parser.include(ffi_to_include._parser)
diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py
--- a/lib_pypy/cffi/cffi_opcode.py
+++ b/lib_pypy/cffi/cffi_opcode.py
@@ -53,6 +53,7 @@
OP_GLOBAL_VAR = 33
OP_DLOPEN_FUNC = 35
OP_DLOPEN_CONST = 37
+OP_GLOBAL_VAR_F = 39
PRIM_VOID = 0
PRIM_BOOL = 1
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -633,6 +633,8 @@
def include(self, other):
for name, tp in other._declarations.items():
+ if name.startswith('anonymous $enum_$'):
+ continue # fix for test_anonymous_enum_include
kind = name.split(' ', 1)[0]
if kind in ('struct', 'union', 'enum', 'anonymous'):
self._declare(name, tp, included=True)
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -35,9 +35,6 @@
def is_integer_type(self):
return False
- def sizeof_enabled(self):
- return False
-
def get_cached_btype(self, ffi, finishlist, can_delay=False):
try:
BType = ffi._cached_btypes[self]
@@ -80,8 +77,7 @@
class BasePrimitiveType(BaseType):
- def sizeof_enabled(self):
- return True
+ pass
class PrimitiveType(BasePrimitiveType):
@@ -205,9 +201,6 @@
class FunctionPtrType(BaseFunctionType):
_base_pattern = '(*&)(%s)'
- def sizeof_enabled(self):
- return True
-
def build_backend_type(self, ffi, finishlist):
result = self.result.get_cached_btype(ffi, finishlist)
args = []
@@ -233,9 +226,6 @@
extra = self._base_pattern
self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
- def sizeof_enabled(self):
- return True
-
def build_backend_type(self, ffi, finishlist):
BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True)
return global_cache(self, ffi, 'new_pointer_type', BItem)
@@ -276,9 +266,6 @@
self.c_name_with_marker = (
self.item.c_name_with_marker.replace('&', brackets))
- def sizeof_enabled(self):
- return self.item.sizeof_enabled() and self.length is not None
-
def resolve_length(self, newlength):
return ArrayType(self.item, newlength)
@@ -433,9 +420,6 @@
from . import ffiplatform
raise ffiplatform.VerificationMissing(self._get_c_name())
- def sizeof_enabled(self):
- return self.fldtypes is not None
-
def build_backend_type(self, ffi, finishlist):
self.check_not_partial()
finishlist.append(self)
@@ -464,9 +448,6 @@
self.baseinttype = baseinttype
self.build_c_name_with_marker()
- def sizeof_enabled(self):
- return True # not strictly true, but external enums are obscure
-
def force_the_name(self, forcename):
StructOrUnionOrEnum.force_the_name(self, forcename)
if self.forcename is None:
diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h
--- a/lib_pypy/cffi/parse_c_type.h
+++ b/lib_pypy/cffi/parse_c_type.h
@@ -26,6 +26,7 @@
#define _CFFI_OP_GLOBAL_VAR 33
#define _CFFI_OP_DLOPEN_FUNC 35
#define _CFFI_OP_DLOPEN_CONST 37
+#define _CFFI_OP_GLOBAL_VAR_F 39
#define _CFFI_PRIM_VOID 0
#define _CFFI_PRIM_BOOL 1
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -981,10 +981,6 @@
if not self.target_is_python and tp.is_integer_type():
type_op = CffiOp(OP_CONSTANT_INT, -1)
else:
- if not tp.sizeof_enabled():
- raise ffiplatform.VerificationError(
- "constant '%s' is of type '%s', whose size is not known"
- % (name, tp._get_c_name()))
if self.target_is_python:
const_kind = OP_DLOPEN_CONST
else:
@@ -1069,18 +1065,36 @@
self._do_collect_type(self._global_type(tp, name))
def _generate_cpy_variable_decl(self, tp, name):
- pass
+ prnt = self._prnt
+ tp = self._global_type(tp, name)
+ if isinstance(tp, model.ArrayType) and tp.length is None:
+ tp = tp.item
+ ampersand = ''
+ else:
+ ampersand = '&'
+ # This code assumes that casts from "tp *" to "void *" is a
+ # no-op, i.e. a function that returns a "tp *" can be called
+ # as if it returned a "void *". This should be generally true
+ # on any modern machine. The only exception to that rule (on
+ # uncommon architectures, and as far as I can tell) might be
+ # if 'tp' were a function type, but that is not possible here.
+ # (If 'tp' is a function _pointer_ type, then casts from "fn_t
+ # **" to "void *" are again no-ops, as far as I can tell.)
+ prnt('static ' + tp.get_c_name('*_cffi_var_%s(void)' % (name,)))
+ prnt('{')
+ prnt(' return %s(%s);' % (ampersand, name))
+ prnt('}')
+ prnt()
def _generate_cpy_variable_ctx(self, tp, name):
tp = self._global_type(tp, name)
type_index = self._typesdict[tp]
- type_op = CffiOp(OP_GLOBAL_VAR, type_index)
- if tp.sizeof_enabled():
- size = "sizeof(%s)" % (name,)
+ if self.target_is_python:
+ op = OP_GLOBAL_VAR
else:
- size = 0
+ op = OP_GLOBAL_VAR_F
self._lsts["global"].append(
- GlobalExpr(name, '&%s' % name, type_op, size))
+ GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))
# ----------
# emitting the opcodes for individual types
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -135,7 +135,7 @@
Here are some more technical details. This issue affects the precise
time at which ``__del__`` methods are called, which
is not reliable in PyPy (nor Jython nor IronPython). It also means that
-weak references may stay alive for a bit longer than expected. This
+**weak references** may stay alive for a bit longer than expected. This
makes "weak proxies" (as returned by ``weakref.proxy()``) somewhat less
useful: they will appear to stay alive for a bit longer in PyPy, and
suddenly they will really be dead, raising a ``ReferenceError`` on the
@@ -143,6 +143,24 @@
``ReferenceError`` at any place that uses them. (Or, better yet, don't use
``weakref.proxy()`` at all; use ``weakref.ref()``.)
+Note a detail in the `documentation for weakref callbacks`__:
+
+ If callback is provided and not None, *and the returned weakref
+ object is still alive,* the callback will be called when the object
+ is about to be finalized.
+
+There are cases where, due to CPython's refcount semantics, a weakref
+dies immediately before or after the objects it points to (typically
+with some circular reference). If it happens to die just after, then
+the callback will be invoked. In a similar case in PyPy, both the
+object and the weakref will be considered as dead at the same time,
+and the callback will not be invoked. (Issue `#2030`__)
+
+.. __: https://docs.python.org/2/library/weakref.html
+.. __: https://bitbucket.org/pypy/pypy/issue/2030/
+
+---------------------------------
+
There are a few extra implications from the difference in the GC. Most
notably, if an object has a ``__del__``, the ``__del__`` is never called more
than once in PyPy; but CPython will call the same ``__del__`` several times
@@ -321,9 +339,8 @@
Miscellaneous
-------------
-* Hash randomization (``-R``) is ignored in PyPy. As documented in
- http://bugs.python.org/issue14621, some of us believe it has no
- purpose in CPython either.
+* Hash randomization (``-R``) `is ignored in PyPy`_. In CPython
+ before 3.4 it has `little point`_.
* You can't store non-string keys in type objects. For example::
@@ -338,7 +355,8 @@
for about 1400 calls.
* since the implementation of dictionary is different, the exact number
- which ``__hash__`` and ``__eq__`` are called is different. Since CPython
+ of times that ``__hash__`` and ``__eq__`` are called is different.
+ Since CPython
does not give any specific guarantees either, don't rely on it.
* assignment to ``__class__`` is limited to the cases where it
@@ -395,3 +413,12 @@
interactive mode. In a released version, this behaviour is suppressed, but
setting the environment variable PYPY_IRC_TOPIC will bring it back. Note that
downstream package providers have been known to totally disable this feature.
+
+* PyPy's readline module was rewritten from scratch: it is not GNU's
+ readline. It should be mostly compatible, and it adds multiline
+ support (see ``multiline_input()``). On the other hand,
+ ``parse_and_bind()`` calls are ignored (issue `#2072`_).
+
+.. _`is ignored in PyPy`: http://bugs.python.org/issue14621
+.. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html
+.. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/
diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -6,15 +6,9 @@
C. It was developed in collaboration with Roberto De Ioris from the `uwsgi`_
project. The `PyPy uwsgi plugin`_ is a good example of using the embedding API.
-**NOTE**: As of 1st of December, PyPy comes with ``--shared`` by default
-on linux, linux64 and windows. We will make it the default on all platforms
-by the time of the next release.
-
-The first thing that you need is to compile PyPy yourself with the option
-``--shared``. We plan to make ``--shared`` the default in the future. Consult
-the `how to compile PyPy`_ doc for details. This will result in ``libpypy.so``
-or ``pypy.dll`` file or something similar, depending on your platform. Consult
-your platform specification for details.
+**NOTE**: You need a PyPy compiled with the option ``--shared``, i.e.
+with a ``libpypy-c.so`` or ``pypy-c.dll`` file. This is the default in
+recent versions of PyPy.
The resulting shared library exports very few functions, however they are
enough to accomplish everything you need, provided you follow a few principles.
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -70,6 +70,20 @@
.. _`use virtualenv (as documented here)`: getting-started.html#installing-using-virtualenv
+Module xyz does not work in the sandboxed PyPy?
+-----------------------------------------------
+
+You cannot import *any* extension module in a `sandboxed PyPy`_,
+sorry. Even the built-in modules available are very limited.
+Sandboxing in PyPy is a good proof of concept, really safe IMHO, but
+it is only a proof of concept. It seriously requires someone working
+on it. Before this occurs, it can only be used it for "pure Python"
+examples: programs that import mostly nothing (or only pure Python
+modules, recursively).
+
+.. _`sandboxed PyPy`: sandbox.html
+
+
.. _`See below.`:
Do CPython Extension modules work with PyPy?
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -11,3 +11,14 @@
.. branch: stdlib-2.7.10
Update stdlib to version 2.7.10
+
+.. branch: issue2062
+
+.. branch: disable-unroll-for-short-loops
+The JIT no longer performs loop unrolling if the loop compiles to too much code.
+
+.. branch: run-create_cffi_imports
+
+Build cffi import libraries as part of translation by monkey-patching an
+aditional task into translation
+
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -1,6 +1,6 @@
import py
-import os, sys
+import os, sys, subprocess
import pypy
from pypy.interpreter import gateway
@@ -298,6 +298,44 @@
wrapstr = 'space.wrap(%r)' % (options)
pypy.module.sys.Module.interpleveldefs['pypy_translation_info'] = wrapstr
+ # HACKHACKHACK
+ # ugly hack to modify target goal from compile_c to build_cffi_imports
+ # this should probably get cleaned up and merged with driver.create_exe
+ from rpython.translator.driver import taskdef
+ import types
+
+ class Options(object):
+ pass
+
+
+ def mkexename(name):
+ if sys.platform == 'win32':
+ name = name.new(ext='exe')
+ return name
+
+ @taskdef(['compile_c'], "Create cffi bindings for modules")
+ def task_build_cffi_imports(self):
+ from pypy.tool.build_cffi_imports import create_cffi_import_libraries
+ ''' Use cffi to compile cffi interfaces to modules'''
+ exename = mkexename(driver.compute_exe_name())
+ basedir = exename
+ while not basedir.join('include').exists():
+ _basedir = basedir.dirpath()
+ if _basedir == basedir:
+ raise ValueError('interpreter %s not inside pypy repo',
+ str(exename))
+ basedir = _basedir
+ modules = self.config.objspace.usemodules.getpaths()
+ options = Options()
+ # XXX possibly adapt options using modules
+ failures = create_cffi_import_libraries(exename, options, basedir)
+ # if failures, they were already printed
+ print >> sys.stderr, str(exename),'successfully built, but errors while building the above modules will be ignored'
+ driver.task_build_cffi_imports = types.MethodType(task_build_cffi_imports, driver)
+ driver.tasks['build_cffi_imports'] = driver.task_build_cffi_imports, ['compile_c']
+ driver.default_goal = 'build_cffi_imports'
+ # HACKHACKHACK end
+
return self.get_entry_point(config)
def jitpolicy(self, driver):
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -40,6 +40,11 @@
PYPYLOG: If set to a non-empty value, enable logging.
"""
+try:
+ from __pypy__ import get_hidden_tb, hidden_applevel
+except ImportError:
+ get_hidden_tb = lambda: sys.exc_info()[2]
+ hidden_applevel = lambda f: f
import sys
DEBUG = False # dump exceptions before calling the except hook
@@ -63,6 +68,7 @@
exitcode = 1
raise SystemExit(exitcode)
+ at hidden_applevel
def run_toplevel(f, *fargs, **fkwds):
"""Calls f() and handles all OperationErrors.
Intended use is to run the main program or one interactive statement.
@@ -87,13 +93,13 @@
except SystemExit as e:
handle_sys_exit(e)
- except:
- display_exception()
+ except BaseException as e:
+ display_exception(e)
return False
return True # success
-def display_exception():
- etype, evalue, etraceback = sys.exc_info()
+def display_exception(e):
+ etype, evalue, etraceback = type(e), e, get_hidden_tb()
try:
# extra debugging info in case the code below goes very wrong
if DEBUG and hasattr(sys, 'stderr'):
@@ -119,11 +125,11 @@
hook(etype, evalue, etraceback)
return # done
- except:
+ except BaseException as e:
try:
stderr = sys.stderr
print >> stderr, 'Error calling sys.excepthook:'
- originalexcepthook(*sys.exc_info())
+ originalexcepthook(type(e), e, e.__traceback__)
print >> stderr
print >> stderr, 'Original exception was:'
except:
@@ -509,6 +515,7 @@
return options
+ at hidden_applevel
def run_command_line(interactive,
inspect,
run_command,
@@ -597,6 +604,7 @@
# Put '' on sys.path
sys.path.insert(0, '')
+ @hidden_applevel
def run_it():
exec run_command in mainmodule.__dict__
success = run_toplevel(run_it)
@@ -634,6 +642,7 @@
print >> sys.stderr, "Could not open PYTHONSTARTUP"
print >> sys.stderr, "IOError:", e
else:
+ @hidden_applevel
def run_it():
co_python_startup = compile(startup,
python_startup,
@@ -650,6 +659,7 @@
inspect = True
else:
# If not interactive, just read and execute stdin normally.
+ @hidden_applevel
def run_it():
co_stdin = compile(sys.stdin.read(), '<stdin>', 'exec',
PyCF_ACCEPT_NULL_BYTES)
@@ -689,7 +699,7 @@
except SystemExit as e:
status = e.code
if inspect_requested():
- display_exception()
+ display_exception(e)
else:
status = not success
@@ -743,6 +753,7 @@
# This is important for py3k
sys.executable = executable
+ at hidden_applevel
def entry_point(executable, argv):
# note that before calling setup_bootstrap_path, we are limited because we
# cannot import stdlib modules. In particular, we cannot use unicode
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -1,6 +1,7 @@
import sys
from pypy.interpreter.error import OperationError, get_cleared_operation_error
from rpython.rlib.unroll import unrolling_iterable
+from rpython.rlib.objectmodel import specialize
from rpython.rlib import jit
TICK_COUNTER_STEP = 100
@@ -214,13 +215,21 @@
self._trace(frame, 'exception', None, operationerr)
#operationerr.print_detailed_traceback(self.space)
- def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!!
+ @specialize.arg(1)
+ def sys_exc_info(self, for_hidden=False):
"""Implements sys.exc_info().
- Return an OperationError instance or None."""
+ Return an OperationError instance or None.
+
+ Ignores exceptions within hidden frames unless for_hidden=True
+ is specified.
+
+ # NOTE: the result is not the wrapped sys.exc_info() !!!
+
+ """
frame = self.gettopframe()
while frame:
if frame.last_exception is not None:
- if (not frame.hide() or
+ if ((for_hidden or not frame.hide()) or
frame.last_exception is
get_cleared_operation_error(self.space)):
return frame.last_exception
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -15,7 +15,10 @@
self.running = False
def descr__repr__(self, space):
- code_name = self.pycode.co_name
+ if self.pycode is None:
+ code_name = '<finished>'
+ else:
+ code_name = self.pycode.co_name
addrstring = self.getaddrstring(space)
return space.wrap("<generator object %s at 0x%s>" %
(code_name, addrstring))
@@ -45,6 +48,8 @@
w_framestate, w_running = args_w
if space.is_w(w_framestate, space.w_None):
self.frame = None
+ self.space = space
+ self.pycode = None
else:
frame = instantiate(space.FrameClass) # XXX fish
frame.descr__setstate__(space, w_framestate)
@@ -62,9 +67,10 @@
def send_ex(self, w_arg, operr=None):
pycode = self.pycode
- if jit.we_are_jitted() and should_not_inline(pycode):
- generatorentry_driver.jit_merge_point(gen=self, w_arg=w_arg,
- operr=operr, pycode=pycode)
+ if pycode is not None:
+ if jit.we_are_jitted() and should_not_inline(pycode):
+ generatorentry_driver.jit_merge_point(gen=self, w_arg=w_arg,
+ operr=operr, pycode=pycode)
return self._send_ex(w_arg, operr)
def _send_ex(self, w_arg, operr):
@@ -158,7 +164,10 @@
return self.pycode
def descr__name__(self, space):
- code_name = self.pycode.co_name
+ if self.pycode is None:
+ code_name = '<finished>'
+ else:
+ code_name = self.pycode.co_name
return space.wrap(code_name)
# Results can be either an RPython list of W_Root, or it can be an
diff --git a/pypy/interpreter/pytraceback.py b/pypy/interpreter/pytraceback.py
--- a/pypy/interpreter/pytraceback.py
+++ b/pypy/interpreter/pytraceback.py
@@ -60,7 +60,6 @@
def check_traceback(space, w_tb, msg):
- from pypy.interpreter.typedef import PyTraceback
if w_tb is None or not space.isinstance_w(w_tb, space.gettypeobject(PyTraceback.typedef)):
raise OperationError(space.w_TypeError, space.wrap(msg))
return w_tb
diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py
--- a/pypy/interpreter/test/test_zzpickle_and_slow.py
+++ b/pypy/interpreter/test/test_zzpickle_and_slow.py
@@ -491,6 +491,22 @@
assert pack.mod is result
+ def test_pickle_generator_crash(self):
+ import pickle
+
+ def f():
+ yield 0
+
+ x = f()
+ x.next()
+ try:
+ x.next()
+ except StopIteration:
+ y = pickle.loads(pickle.dumps(x))
+ assert 'finished' in y.__name__
+ assert 'finished' in repr(y)
+ assert y.gi_code is None
+
class AppTestGeneratorCloning:
def setup_class(cls):
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -71,6 +71,8 @@
'debug_print_once' : 'interp_debug.debug_print_once',
'debug_flush' : 'interp_debug.debug_flush',
'builtinify' : 'interp_magic.builtinify',
+ 'hidden_applevel' : 'interp_magic.hidden_applevel',
+ 'get_hidden_tb' : 'interp_magic.get_hidden_tb',
'lookup_special' : 'interp_magic.lookup_special',
'do_what_I_mean' : 'interp_magic.do_what_I_mean',
'validate_fd' : 'interp_magic.validate_fd',
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -59,6 +59,20 @@
bltn = BuiltinFunction(func)
return space.wrap(bltn)
+def hidden_applevel(space, w_func):
+ """Decorator that hides a function's frame from app-level"""
+ from pypy.interpreter.function import Function
+ func = space.interp_w(Function, w_func)
+ func.getcode().hidden_applevel = True
+ return w_func
+
+def get_hidden_tb(space):
+ """Return the traceback of the current exception being handled by a
+ frame hidden from applevel.
+ """
+ operr = space.getexecutioncontext().sys_exc_info(for_hidden=True)
+ return space.w_None if operr is None else space.wrap(operr.get_traceback())
+
@unwrap_spec(meth=str)
def lookup_special(space, w_obj, meth):
"""Lookup up a special method on an object."""
diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py
--- a/pypy/module/__pypy__/test/test_special.py
+++ b/pypy/module/__pypy__/test/test_special.py
@@ -27,6 +27,52 @@
assert A.a is not A.__dict__['a']
assert A.b is A.__dict__['b']
+ def test_hidden_applevel(self):
+ import __pypy__
+ import sys
+
+ @__pypy__.hidden_applevel
+ def sneak(): (lambda: 1/0)()
+ try:
+ sneak()
+ except ZeroDivisionError as e:
+ tb = sys.exc_info()[2]
+ assert tb.tb_frame == sys._getframe()
+ assert tb.tb_next.tb_frame.f_code.co_name == '<lambda>'
+ else:
+ assert False, 'Expected ZeroDivisionError'
+
+ def test_hidden_applevel_frames(self):
+ import __pypy__
+ import sys
+
+ @__pypy__.hidden_applevel
+ def test_hidden():
+ assert sys._getframe().f_code.co_name != 'test_hidden'
+ def e(): 1/0
+ try: e()
+ except ZeroDivisionError as e:
+ assert sys.exc_info() == (None, None, None)
+ else: assert False
+ return 2
+ assert test_hidden() == 2
+
+ def test_get_hidden_tb(self):
+ import __pypy__
+ import sys
+
+ @__pypy__.hidden_applevel
+ def test_hidden_with_tb():
+ def not_hidden(): 1/0
+ try: not_hidden()
+ except ZeroDivisionError as e:
+ assert sys.exc_info() == (None, None, None)
+ tb = __pypy__.get_hidden_tb()
+ assert tb.tb_frame.f_code.co_name == 'not_hidden'
+ return True
+ else: return False
+ assert test_hidden_with_tb()
+
def test_lookup_special(self):
from __pypy__ import lookup_special
class X(object):
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -2,7 +2,7 @@
from pypy.interpreter.mixedmodule import MixedModule
from rpython.rlib import rdynload
-VERSION = "1.1.2"
+VERSION = "1.2.0"
class Module(MixedModule):
@@ -37,6 +37,7 @@
'from_handle': 'handle.from_handle',
'_get_types': 'func._get_types',
'from_buffer': 'func.from_buffer',
+ 'gcp': 'func.gcp',
'string': 'func.string',
'buffer': 'cbuffer.buffer',
diff --git a/pypy/module/_cffi_backend/cdlopen.py b/pypy/module/_cffi_backend/cdlopen.py
--- a/pypy/module/_cffi_backend/cdlopen.py
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -36,7 +36,10 @@
self.libname)
try:
cdata = dlsym(self.libhandle, name)
+ found = bool(cdata)
except KeyError:
+ found = False
+ if not found:
raise oefmt(self.ffi.w_FFIError,
"symbol '%s' not found in library '%s'",
name, self.libname)
diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py
--- a/pypy/module/_cffi_backend/cffi_opcode.py
+++ b/pypy/module/_cffi_backend/cffi_opcode.py
@@ -53,6 +53,7 @@
OP_GLOBAL_VAR = 33
OP_DLOPEN_FUNC = 35
OP_DLOPEN_CONST = 37
+OP_GLOBAL_VAR_F = 39
PRIM_VOID = 0
PRIM_BOOL = 1
diff --git a/pypy/module/_cffi_backend/cglob.py b/pypy/module/_cffi_backend/cglob.py
--- a/pypy/module/_cffi_backend/cglob.py
+++ b/pypy/module/_cffi_backend/cglob.py
@@ -2,23 +2,38 @@
from pypy.interpreter.typedef import TypeDef
from pypy.module._cffi_backend.cdataobj import W_CData
from pypy.module._cffi_backend import newtype
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+FNPTR = rffi.CCallback([], rffi.VOIDP)
class W_GlobSupport(W_Root):
- def __init__(self, space, w_ctype, ptr):
+ _immutable_fields_ = ['w_ctype', 'ptr', 'fetch_addr']
+
+ def __init__(self, space, w_ctype, ptr=lltype.nullptr(rffi.CCHARP.TO),
+ fetch_addr=lltype.nullptr(rffi.VOIDP.TO)):
self.space = space
self.w_ctype = w_ctype
self.ptr = ptr
+ self.fetch_addr = rffi.cast(FNPTR, fetch_addr)
+
+ def fetch_global_var_addr(self):
+ if self.ptr:
+ return self.ptr
+ result = self.fetch_addr()
+ return rffi.cast(rffi.CCHARP, result)
def read_global_var(self):
- return self.w_ctype.convert_to_object(self.ptr)
+ return self.w_ctype.convert_to_object(self.fetch_global_var_addr())
def write_global_var(self, w_newvalue):
- self.w_ctype.convert_from_object(self.ptr, w_newvalue)
+ self.w_ctype.convert_from_object(self.fetch_global_var_addr(),
+ w_newvalue)
def address(self):
w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype)
- return W_CData(self.space, self.ptr, w_ctypeptr)
+ return W_CData(self.space, self.fetch_global_var_addr(), w_ctypeptr)
W_GlobSupport.typedef = TypeDef("FFIGlobSupport")
W_GlobSupport.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -143,7 +143,7 @@
@jit.unroll_safe
def _call(self, funcaddr, args_w):
space = self.space
- cif_descr = self.cif_descr
+ cif_descr = self.cif_descr # 'self' should have been promoted here
size = cif_descr.exchange_size
mustfree_max_plus_1 = 0
buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -134,8 +134,7 @@
def convert_to_object(self, cdata):
unichardata = rffi.cast(rffi.CWCHARP, cdata)
- s = rffi.wcharpsize2unicode(unichardata, 1)
- return self.space.wrap(s)
+ return self.space.wrap(unichardata[0])
def string(self, cdataobj, maxlen):
with cdataobj as ptr:
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -223,9 +223,13 @@
if (isinstance(w_cdata, cdataobj.W_CDataNewOwning) or
isinstance(w_cdata, cdataobj.W_CDataPtrToStructOrUnion)):
if i != 0:
- space = self.space
- raise oefmt(space.w_IndexError,
+ raise oefmt(self.space.w_IndexError,
"cdata '%s' can only be indexed by 0", self.name)
+ else:
+ if not w_cdata.unsafe_escaping_ptr():
+ raise oefmt(self.space.w_RuntimeError,
+ "cannot dereference null pointer from cdata '%s'",
+ self.name)
return self
def _check_slice_index(self, w_cdata, start, stop):
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -542,13 +542,18 @@
@jit.dont_look_inside
-def W_FFIObject___new__(space, w_subtype, __args__):
- r = space.allocate_instance(W_FFIObject, w_subtype)
+def make_plain_ffi_object(space, w_ffitype=None):
+ if w_ffitype is None:
+ w_ffitype = space.gettypefor(W_FFIObject)
+ r = space.allocate_instance(W_FFIObject, w_ffitype)
# get in 'src_ctx' a NULL which translation doesn't consider to be constant
src_ctx = rffi.cast(parse_c_type.PCTX, 0)
r.__init__(space, src_ctx)
return space.wrap(r)
+def W_FFIObject___new__(space, w_subtype, __args__):
+ return make_plain_ffi_object(space, w_subtype)
+
def make_CData(space):
return space.gettypefor(W_CData)
diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py
--- a/pypy/module/_cffi_backend/func.py
+++ b/pypy/module/_cffi_backend/func.py
@@ -105,3 +105,18 @@
"raw address on PyPy", w_x)
#
return cdataobj.W_CDataFromBuffer(space, _cdata, w_ctype, buf, w_x)
+
+# ____________________________________________________________
+
+class ConstantFFI:
+ ffi1 = None
+ def _cleanup_(self):
+ self.ffi1 = None
+constant_ffi = ConstantFFI()
+
+ at unwrap_spec(w_cdata=cdataobj.W_CData)
+def gcp(space, w_cdata, w_destructor):
+ if constant_ffi.ffi1 is None:
+ from pypy.module._cffi_backend import ffi_obj
+ constant_ffi.ffi1 = ffi_obj.make_plain_ffi_object(space)
+ return constant_ffi.ffi1.descr_gc(w_cdata, w_destructor)
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -60,12 +60,12 @@
self.ffi, self.ctx.c_types, getarg(g.c_type_op))
assert isinstance(rawfunctype, realize_c_type.W_RawFuncType)
#
- w_ct, locs = rawfunctype.unwrap_as_nostruct_fnptr(self.ffi)
+ rawfunctype.prepare_nostruct_fnptr(self.ffi)
#
ptr = rffi.cast(rffi.CCHARP, g.c_address)
assert ptr
- return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn, w_ct,
- locs, rawfunctype, fnname, self.libname)
+ return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn,
+ rawfunctype, fnname, self.libname)
@jit.elidable_promote()
def _get_attr_elidable(self, attr):
@@ -102,6 +102,8 @@
#
elif op == cffi_opcode.OP_GLOBAL_VAR:
# A global variable of the exact type specified here
+ # (nowadays, only used by the ABI mode or backend
+ # compatibility; see OP_GLOBAL_F for the API mode
w_ct = realize_c_type.realize_c_type(
self.ffi, self.ctx.c_types, getarg(g.c_type_op))
g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn)
@@ -113,7 +115,13 @@
ptr = rffi.cast(rffi.CCHARP, g.c_address)
if not ptr: # for dlopen() style
ptr = self.cdlopen_fetch(attr)
- w_result = cglob.W_GlobSupport(space, w_ct, ptr)
+ w_result = cglob.W_GlobSupport(space, w_ct, ptr=ptr)
+ #
+ elif op == cffi_opcode.OP_GLOBAL_VAR_F:
+ w_ct = realize_c_type.realize_c_type(
+ self.ffi, self.ctx.c_types, getarg(g.c_type_op))
+ w_result = cglob.W_GlobSupport(space, w_ct,
+ fetch_addr=g.c_address)
#
elif (op == cffi_opcode.OP_CONSTANT_INT or
op == cffi_opcode.OP_ENUM):
@@ -131,6 +139,9 @@
realize_c_type.FUNCPTR_FETCH_CHARP,
g.c_address)
if w_ct.size <= 0:
+ raise oefmt(self.ffi.w_FFIError,
+ "constant '%s' is of type '%s', "
+ "whose size is not known", attr, w_ct.name)
raise oefmt(space.w_SystemError,
"constant has no known size")
if not fetch_funcptr: # for dlopen() style
@@ -172,7 +183,11 @@
w_value = self._build_attr(attr)
if w_value is None:
if is_getattr and attr == '__all__':
- return self.dir1(ignore_type=cffi_opcode.OP_GLOBAL_VAR)
+ return self.dir1(ignore_global_vars=True)
+ if is_getattr and attr == '__dict__':
+ return self.full_dict_copy()
+ if is_getattr and attr == '__name__':
+ return self.descr_repr()
raise oefmt(self.space.w_AttributeError,
"cffi library '%s' has no function, constant "
"or global variable named '%s'",
@@ -202,16 +217,31 @@
def descr_dir(self):
return self.dir1()
- def dir1(self, ignore_type=-1):
+ def dir1(self, ignore_global_vars=False):
space = self.space
total = rffi.getintfield(self.ctx, 'c_num_globals')
g = self.ctx.c_globals
names_w = []
for i in range(total):
- if getop(g[i].c_type_op) != ignore_type:
- names_w.append(space.wrap(rffi.charp2str(g[i].c_name)))
+ if ignore_global_vars:
+ op = getop(g[i].c_type_op)
+ if (op == cffi_opcode.OP_GLOBAL_VAR or
+ op == cffi_opcode.OP_GLOBAL_VAR_F):
+ continue
+ names_w.append(space.wrap(rffi.charp2str(g[i].c_name)))
return space.newlist(names_w)
+ def full_dict_copy(self):
+ space = self.space
+ total = rffi.getintfield(self.ctx, 'c_num_globals')
+ g = self.ctx.c_globals
+ w_result = space.newdict()
+ for i in range(total):
+ w_attr = space.wrap(rffi.charp2str(g[i].c_name))
+ w_value = self._get_attr(w_attr)
+ space.setitem(w_result, w_attr, w_value)
+ return w_result
+
def address_of_func_or_global_var(self, varname):
# rebuild a string object from 'varname', to do typechecks and
# to force a unicode back to a plain string
@@ -224,7 +254,8 @@
if isinstance(w_value, W_FunctionWrapper):
# '&func' returns a regular cdata pointer-to-function
if w_value.directfnptr:
- return W_CData(space, w_value.directfnptr, w_value.ctype)
+ ctype = w_value.typeof(self.ffi)
+ return W_CData(space, w_value.directfnptr, ctype)
else:
return w_value # backward compatibility
#
diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py
--- a/pypy/module/_cffi_backend/realize_c_type.py
+++ b/pypy/module/_cffi_backend/realize_c_type.py
@@ -1,4 +1,5 @@
import sys
+from rpython.rlib import jit
from rpython.rlib.rarithmetic import intmask
from rpython.rlib.objectmodel import specialize
from rpython.rtyper.lltypesystem import lltype, rffi
@@ -135,8 +136,12 @@
class W_RawFuncType(W_Root):
"""Temporary: represents a C function type (not a function pointer)"""
+
+ _immutable_fields_ = ['nostruct_ctype', 'nostruct_locs', 'nostruct_nargs']
_ctfuncptr = None
- _nostruct_ctfuncptr = (None, None)
+ nostruct_ctype = None
+ nostruct_locs = None
+ nostruct_nargs = 0
def __init__(self, opcodes, base_index):
self.opcodes = opcodes
@@ -168,14 +173,16 @@
assert self._ctfuncptr is not None
return self._ctfuncptr
- def unwrap_as_nostruct_fnptr(self, ffi):
- # tweaked version: instead of returning the ctfuncptr corresponding
- # exactly to the OP_FUNCTION ... OP_FUNCTION_END opcodes, return
- # another one in which the struct args are replaced with ptr-to-
- # struct, and a struct return value is replaced with a hidden first
- # arg of type ptr-to-struct. This is how recompiler.py produces
+ @jit.dont_look_inside
+ def prepare_nostruct_fnptr(self, ffi):
+ # tweaked version: instead of returning the ctfuncptr
+ # corresponding exactly to the OP_FUNCTION ... OP_FUNCTION_END
+ # opcodes, this builds in self.nostruct_ctype another one in
+ # which the struct args are replaced with ptr-to- struct, and
+ # a struct return value is replaced with a hidden first arg of
+ # type ptr-to-struct. This is how recompiler.py produces
# trampoline functions for PyPy.
- if self._nostruct_ctfuncptr[0] is None:
+ if self.nostruct_ctype is None:
fargs, fret, ellipsis = self._unpack(ffi)
# 'locs' will be a string of the same length as the final fargs,
# containing 'A' where a struct argument was detected, and 'R'
@@ -198,8 +205,10 @@
locs = None
else:
locs = ''.join(locs)
- self._nostruct_ctfuncptr = (ctfuncptr, locs)
- return self._nostruct_ctfuncptr
+ self.nostruct_ctype = ctfuncptr
+ self.nostruct_locs = locs
+ self.nostruct_nargs = len(ctfuncptr.fargs) - (locs is not None and
+ locs[0] == 'R')
def unexpected_fn_type(self, ffi):
fargs, fret, ellipsis = self._unpack(ffi)
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.c b/pypy/module/_cffi_backend/src/parse_c_type.c
--- a/pypy/module/_cffi_backend/src/parse_c_type.c
+++ b/pypy/module/_cffi_backend/src/parse_c_type.c
@@ -362,7 +362,7 @@
case TOK_INTEGER:
errno = 0;
-#ifndef MS_WIN32
+#ifndef _MSC_VER
if (sizeof(length) > sizeof(unsigned long))
length = strtoull(tok->p, &endptr, 0);
else
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -2099,8 +2099,7 @@
p = cast(BVoidP, 123456)
py.test.raises(TypeError, "p[0]")
p = cast(BVoidP, 0)
- if 'PY_DOT_PY' in globals(): py.test.skip("NULL crashes early on py.py")
- py.test.raises(TypeError, "p[0]")
+ py.test.raises((TypeError, RuntimeError), "p[0]")
def test_iter():
BInt = new_primitive_type("int")
@@ -3333,6 +3332,15 @@
check(4 | 8, "CHB", "GTB")
check(4 | 16, "CHB", "ROB")
+def test_dereference_null_ptr():
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ p = cast(BIntPtr, 0)
+ py.test.raises(RuntimeError, "p[0]")
+ py.test.raises(RuntimeError, "p[0] = 42")
+ py.test.raises(RuntimeError, "p[42]")
+ py.test.raises(RuntimeError, "p[42] = -1")
+
def test_version():
# this test is here mostly for PyPy
- assert __version__ == "1.1.2"
+ assert __version__ == "1.2.0"
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -4,6 +4,8 @@
spaceconfig = dict(usemodules=('_cffi_backend', 'array'))
def teardown_method(self, meth):
+ from pypy.module._cffi_backend.func import constant_ffi
+ constant_ffi._cleanup_()
_clean_cache(self.space)
def test_ffi_new(self):
@@ -234,9 +236,10 @@
assert p1[0] == 123
seen.append(1)
ffi.gc(p, destructor=destructor) # instantly forgotten
+ _cffi1_backend.gcp(p, destructor=destructor)
for i in range(5):
if seen:
break
import gc
gc.collect()
- assert seen == [1]
+ assert seen == [1, 1]
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -16,8 +16,8 @@
from cffi import ffiplatform
except ImportError:
py.test.skip("system cffi module not found or older than 1.0.0")
- if cffi.__version_info__ < (1, 0, 4):
- py.test.skip("system cffi module needs to be at least 1.0.4")
+ if cffi.__version_info__ < (1, 2, 0):
+ py.test.skip("system cffi module needs to be at least 1.2.0")
space.appexec([], """():
import _cffi_backend # force it to be initialized
""")
@@ -276,6 +276,15 @@
""")
lib.aa = 5
assert dir(lib) == ['aa', 'ff', 'my_constant']
+ #
+ aaobj = lib.__dict__['aa']
+ assert not isinstance(aaobj, int) # some internal object instead
+ assert lib.__dict__ == {
+ 'ff': lib.ff,
+ 'aa': aaobj,
+ 'my_constant': -45}
+ lib.__dict__['ff'] = "??"
+ assert lib.ff(10) == 15
def test_verify_opaque_struct(self):
ffi, lib = self.prepare(
@@ -491,28 +500,33 @@
"int foo(int x) { return x + 32; }")
assert lib.foo(10) == 42
- def test_bad_size_of_global_1(self):
- ffi, lib = self.prepare(
- "short glob;",
- "test_bad_size_of_global_1",
- "long glob;")
- raises(ffi.error, getattr, lib, "glob")
-
- def test_bad_size_of_global_2(self):
- ffi, lib = self.prepare(
- "int glob[10];",
- "test_bad_size_of_global_2",
- "int glob[9];")
- e = raises(ffi.error, getattr, lib, "glob")
- assert str(e.value) == ("global variable 'glob' should be 40 bytes "
- "according to the cdef, but is actually 36")
-
- def test_unspecified_size_of_global(self):
+ def test_unspecified_size_of_global_1(self):
ffi, lib = self.prepare(
"int glob[];",
- "test_unspecified_size_of_global",
+ "test_unspecified_size_of_global_1",
"int glob[10];")
- lib.glob # does not crash
+ assert ffi.typeof(lib.glob) == ffi.typeof("int *")
+
+ def test_unspecified_size_of_global_2(self):
+ ffi, lib = self.prepare(
+ "int glob[][5];",
+ "test_unspecified_size_of_global_2",
+ "int glob[10][5];")
+ assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+ def test_unspecified_size_of_global_3(self):
+ ffi, lib = self.prepare(
+ "int glob[][...];",
+ "test_unspecified_size_of_global_3",
+ "int glob[10][5];")
+ assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+ def test_unspecified_size_of_global_4(self):
+ ffi, lib = self.prepare(
+ "int glob[...][...];",
+ "test_unspecified_size_of_global_4",
+ "int glob[10][5];")
+ assert ffi.typeof(lib.glob) == ffi.typeof("int[10][5]")
def test_include_1(self):
ffi1, lib1 = self.prepare(
@@ -819,6 +833,22 @@
assert isinstance(addr, ffi.CData)
assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
+ def test_address_of_function_with_struct(self):
+ ffi, lib = self.prepare(
+ "struct foo_s { int x; }; long myfunc(struct foo_s);",
+ "test_addressof_function_with_struct", """
+ struct foo_s { int x; };
+ char myfunc(struct foo_s input) { return (char)(input.x + 42); }
+ """)
+ s = ffi.new("struct foo_s *", [5])[0]
+ assert lib.myfunc(s) == 47
+ assert not isinstance(lib.myfunc, ffi.CData)
+ assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)")
+ addr = ffi.addressof(lib, 'myfunc')
+ assert addr(s) == 47
+ assert isinstance(addr, ffi.CData)
+ assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)")
+
def test_issue198(self):
ffi, lib = self.prepare("""
typedef struct{...;} opaque_t;
@@ -844,11 +874,22 @@
""")
assert lib.almost_forty_two == 42.25
+ def test_constant_of_unknown_size(self):
+ ffi, lib = self.prepare(
+ "typedef ... opaque_t;"
+ "const opaque_t CONSTANT;",
+ 'test_constant_of_unknown_size',
+ "typedef int opaque_t;"
+ "const int CONSTANT = 42;")
+ e = raises(ffi.error, getattr, lib, 'CONSTANT')
+ assert str(e.value) == ("constant 'CONSTANT' is of "
+ "type 'opaque_t', whose size is not known")
+
def test_variable_of_unknown_size(self):
ffi, lib = self.prepare("""
typedef ... opaque_t;
opaque_t globvar;
- """, 'test_constant_of_unknown_size', """
+ """, 'test_variable_of_unknown_size', """
typedef char opaque_t[6];
opaque_t globvar = "hello";
""")
@@ -984,5 +1025,35 @@
assert sys.modules['_CFFI_test_import_from_lib.lib'] is lib
from _CFFI_test_import_from_lib.lib import MYFOO
assert MYFOO == 42
- assert not hasattr(lib, '__dict__')
+ assert hasattr(lib, '__dict__')
assert lib.__all__ == ['MYFOO', 'mybar'] # but not 'myvar'
+ assert lib.__name__ == repr(lib)
+
+ def test_macro_var_callback(self):
+ ffi, lib = self.prepare(
+ "int my_value; int *(*get_my_value)(void);",
+ 'test_macro_var_callback',
+ "int *(*get_my_value)(void);\n"
+ "#define my_value (*get_my_value())")
+ #
+ values = ffi.new("int[50]")
+ def it():
+ for i in range(50):
+ yield i
+ it = it()
+ #
+ @ffi.callback("int *(*)(void)")
+ def get_my_value():
+ return values + it.next()
+ lib.get_my_value = get_my_value
+ #
+ values[0] = 41
+ assert lib.my_value == 41 # [0]
+ p = ffi.addressof(lib, 'my_value') # [1]
+ assert p == values + 1
+ assert p[-1] == 41
+ assert p[+1] == 0
+ lib.my_value = 42 # [2]
+ assert values[2] == 42
+ assert p[-1] == 41
+ assert p[+1] == 42
diff --git a/pypy/module/_cffi_backend/wrapper.py b/pypy/module/_cffi_backend/wrapper.py
--- a/pypy/module/_cffi_backend/wrapper.py
+++ b/pypy/module/_cffi_backend/wrapper.py
@@ -19,12 +19,20 @@
wrapper is callable, and the arguments it expects and returns
are directly the struct/union. Calling ffi.typeof(wrapper)
also returns the original struct/union signature.
+
+ This class cannot be used for variadic functions.
"""
_immutable_ = True
common_doc_str = 'direct call to the C function of the same name'
- def __init__(self, space, fnptr, directfnptr, ctype,
- locs, rawfunctype, fnname, modulename):
+ def __init__(self, space, fnptr, directfnptr,
+ rawfunctype, fnname, modulename):
+ # everything related to the type of the function is accessed
+ # as immutable attributes of the 'rawfunctype' object, which
+ # is a W_RawFuncType. This gives us an obvious thing to
+ # promote in order to do the call.
+ ctype = rawfunctype.nostruct_ctype
+ locs = rawfunctype.nostruct_locs
assert isinstance(ctype, W_CTypeFunc)
assert ctype.cif_descr is not None # not for '...' functions
assert locs is None or len(ctype.fargs) == len(locs)
@@ -32,83 +40,86 @@
self.space = space
self.fnptr = fnptr
self.directfnptr = directfnptr
- self.ctype = ctype
- self.locs = locs
self.rawfunctype = rawfunctype
self.fnname = fnname
self.modulename = modulename
- self.nargs_expected = len(ctype.fargs) - (locs is not None and
- locs[0] == 'R')
def typeof(self, ffi):
return self.rawfunctype.unwrap_as_fnptr(ffi)
- @jit.unroll_safe
- def _prepare(self, args_w, start_index):
- # replaces struct/union arguments with ptr-to-struct/union arguments
+ def descr_call(self, args_w):
space = self.space
- locs = self.locs
- fargs = self.ctype.fargs
- for i in range(start_index, len(locs)):
- if locs[i] != 'A':
- continue
- w_arg = args_w[i]
- farg = fargs[i] # <ptr to struct/union>
- assert isinstance(farg, W_CTypePtrOrArray)
- if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem:
- # fast way: we are given a W_CData "struct", so just make
- # a new W_CData "ptr-to-struct" which points to the same
- # raw memory. We use unsafe_escaping_ptr(), so we have to
- # make sure the original 'w_arg' stays alive; the easiest
- # is to build an instance of W_CDataPtrToStructOrUnion.
- w_arg = W_CDataPtrToStructOrUnion(
- space, w_arg.unsafe_escaping_ptr(), farg, w_arg)
- else:
- # slow way: build a new "ptr to struct" W_CData by calling
- # the equivalent of ffi.new()
- if space.is_w(w_arg, space.w_None):
- continue
- w_arg = farg.newp(w_arg)
- args_w[i] = w_arg
-
- def descr_call(self, args_w):
- if len(args_w) != self.nargs_expected:
- space = self.space
- if self.nargs_expected == 0:
+ rawfunctype = jit.promote(self.rawfunctype)
+ ctype = rawfunctype.nostruct_ctype
+ locs = rawfunctype.nostruct_locs
+ nargs_expected = rawfunctype.nostruct_nargs
+ #
+ if len(args_w) != nargs_expected:
+ if nargs_expected == 0:
raise oefmt(space.w_TypeError,
"%s() takes no arguments (%d given)",
self.fnname, len(args_w))
- elif self.nargs_expected == 1:
+ elif nargs_expected == 1:
raise oefmt(space.w_TypeError,
"%s() takes exactly one argument (%d given)",
self.fnname, len(args_w))
else:
raise oefmt(space.w_TypeError,
"%s() takes exactly %d arguments (%d given)",
- self.fnname, self.nargs_expected, len(args_w))
+ self.fnname, nargs_expected, len(args_w))
#
- if self.locs is not None:
+ if locs is not None:
# This case is if there are structs as arguments or return values.
# If the result we want to present to the user is "returns struct",
# then internally allocate the struct and pass a pointer to it as
# a first argument.
- if self.locs[0] == 'R':
- w_result_cdata = self.ctype.fargs[0].newp(self.space.w_None)
+ if locs[0] == 'R':
+ w_result_cdata = ctype.fargs[0].newp(space.w_None)
args_w = [w_result_cdata] + args_w
- self._prepare(args_w, 1)
- self.ctype._call(self.fnptr, args_w) # returns w_None
+ prepare_args(space, rawfunctype, args_w, 1)
+ #
+ ctype._call(self.fnptr, args_w) # returns w_None
+ #
assert isinstance(w_result_cdata, W_CDataPtrToStructOrUnion)
return w_result_cdata.structobj
else:
args_w = args_w[:]
- self._prepare(args_w, 0)
+ prepare_args(space, rawfunctype, args_w, 0)
#
- return self.ctype._call(self.fnptr, args_w)
+ return ctype._call(self.fnptr, args_w)
def descr_repr(self, space):
return space.wrap("<FFIFunctionWrapper for %s()>" % (self.fnname,))
+ at jit.unroll_safe
+def prepare_args(space, rawfunctype, args_w, start_index):
+ # replaces struct/union arguments with ptr-to-struct/union arguments
+ locs = rawfunctype.nostruct_locs
+ fargs = rawfunctype.nostruct_ctype.fargs
+ for i in range(start_index, len(locs)):
+ if locs[i] != 'A':
+ continue
+ w_arg = args_w[i]
+ farg = fargs[i] # <ptr to struct/union>
+ assert isinstance(farg, W_CTypePtrOrArray)
+ if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem:
+ # fast way: we are given a W_CData "struct", so just make
+ # a new W_CData "ptr-to-struct" which points to the same
+ # raw memory. We use unsafe_escaping_ptr(), so we have to
+ # make sure the original 'w_arg' stays alive; the easiest
+ # is to build an instance of W_CDataPtrToStructOrUnion.
+ w_arg = W_CDataPtrToStructOrUnion(
+ space, w_arg.unsafe_escaping_ptr(), farg, w_arg)
+ else:
+ # slow way: build a new "ptr to struct" W_CData by calling
+ # the equivalent of ffi.new()
+ if space.is_w(w_arg, space.w_None):
+ continue
+ w_arg = farg.newp(w_arg)
+ args_w[i] = w_arg
+
+
W_FunctionWrapper.typedef = TypeDef(
'FFIFunctionWrapper',
__repr__ = interp2app(W_FunctionWrapper.descr_repr),
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -613,7 +613,7 @@
# ____________________________________________________________
def wrap_list_of_str(space, lst):
- return space.newlist([space.wrap(s) for s in lst])
+ return space.newlist_bytes(lst)
class FileState:
def __init__(self, space):
diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py
--- a/pypy/module/_io/interp_textio.py
+++ b/pypy/module/_io/interp_textio.py
@@ -600,6 +600,7 @@
def read_w(self, space, w_size=None):
self._check_attached(space)
+ self._check_closed(space)
if not self.w_decoder:
raise OperationError(space.w_IOError, space.wrap("not readable"))
@@ -641,6 +642,7 @@
def readline_w(self, space, w_limit=None):
self._check_attached(space)
+ self._check_closed(space)
self._writeflush(space)
limit = convert_size(space, w_limit)
@@ -736,7 +738,7 @@
def write_w(self, space, w_text):
self._check_attached(space)
- # self._check_closed(space)
+ self._check_closed(space)
if not self.w_encoder:
raise OperationError(space.w_IOError, space.wrap("not writable"))
diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py
--- a/pypy/module/_io/test/test_io.py
+++ b/pypy/module/_io/test/test_io.py
@@ -391,3 +391,57 @@
f.seek(1, 0)
f.read(buffer_size * 2)
assert f.tell() == 1 + buffer_size * 2
+
+
+class AppTestIoAferClose:
+ spaceconfig = dict(usemodules=['_io'])
+
+ def setup_class(cls):
+ tmpfile = udir.join('tmpfile').ensure()
+ cls.w_tmpfile = cls.space.wrap(str(tmpfile))
+
+ def test_io_after_close(self):
+ import _io
+ for kwargs in [
+ {"mode": "w"},
+ {"mode": "wb"},
+ {"mode": "w", "buffering": 1},
+ {"mode": "w", "buffering": 2},
+ {"mode": "wb", "buffering": 0},
+ {"mode": "r"},
+ {"mode": "rb"},
+ {"mode": "r", "buffering": 1},
+ {"mode": "r", "buffering": 2},
+ {"mode": "rb", "buffering": 0},
+ {"mode": "w+"},
+ {"mode": "w+b"},
+ {"mode": "w+", "buffering": 1},
+ {"mode": "w+", "buffering": 2},
+ {"mode": "w+b", "buffering": 0},
+ ]:
+ print kwargs
+ if "b" not in kwargs["mode"]:
+ kwargs["encoding"] = "ascii"
+ f = _io.open(self.tmpfile, **kwargs)
+ f.close()
+ raises(ValueError, f.flush)
+ raises(ValueError, f.fileno)
+ raises(ValueError, f.isatty)
+ raises(ValueError, f.__iter__)
+ if hasattr(f, "peek"):
+ raises(ValueError, f.peek, 1)
+ raises(ValueError, f.read)
+ if hasattr(f, "read1"):
+ raises(ValueError, f.read1, 1024)
+ if hasattr(f, "readall"):
+ raises(ValueError, f.readall)
+ if hasattr(f, "readinto"):
+ raises(ValueError, f.readinto, bytearray(1024))
+ raises(ValueError, f.readline)
+ raises(ValueError, f.readlines)
+ raises(ValueError, f.seek, 0)
+ raises(ValueError, f.tell)
+ raises(ValueError, f.truncate)
+ raises(ValueError, f.write, b"" if "b" in kwargs['mode'] else u"")
+ raises(ValueError, f.writelines, [])
+ raises(ValueError, next, f)
diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py
--- a/pypy/module/_rawffi/callback.py
+++ b/pypy/module/_rawffi/callback.py
@@ -27,8 +27,10 @@
callback_ptr = global_counter.get(userdata.addarg)
w_callable = callback_ptr.w_callable
argtypes = callback_ptr.argtypes
+ must_leave = False
space = callback_ptr.space
try:
+ must_leave = space.threadlocals.try_enter_thread(space)
args_w = [None] * len(argtypes)
for i in range(len(argtypes)):
argtype = argtypes[i]
@@ -50,6 +52,8 @@
resshape = letter2tp(space, callback_ptr.result)
for i in range(resshape.size):
ll_res[i] = '\x00'
+ if must_leave:
+ space.threadlocals.leave_thread(space)
class W_CallbackPtr(W_DataInstance):
@@ -75,6 +79,14 @@
if tracker.DO_TRACING:
addr = rffi.cast(lltype.Signed, self.ll_callback.ll_closure)
tracker.trace_allocation(addr, self)
+ #
+ # We must setup the GIL here, in case the callback is invoked in
+ # some other non-Pythonic thread. This is the same as ctypes on
+ # CPython (but only when creating a callback; on CPython it occurs
+ # as soon as we import _ctypes)
+ if space.config.translation.thread:
+ from pypy.module.thread.os_thread import setup_threads
+ setup_threads(space)
def free(self):
if tracker.DO_TRACING:
diff --git a/pypy/module/_socket/__init__.py b/pypy/module/_socket/__init__.py
--- a/pypy/module/_socket/__init__.py
+++ b/pypy/module/_socket/__init__.py
@@ -18,6 +18,10 @@
from rpython.rlib.rsocket import rsocket_startup
rsocket_startup()
+ def shutdown(self, space):
+ from pypy.module._socket.interp_socket import close_all_sockets
+ close_all_sockets(space)
+
def buildloaders(cls):
from rpython.rlib import rsocket
for name in """
diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py
--- a/pypy/module/_socket/interp_func.py
+++ b/pypy/module/_socket/interp_func.py
@@ -142,7 +142,7 @@
sock = rsocket.fromfd(fd, family, type, proto)
except SocketError, e:
raise converted_error(space, e)
- return space.wrap(W_Socket(sock))
+ return space.wrap(W_Socket(space, sock))
@unwrap_spec(family=int, type=int, proto=int)
def socketpair(space, family=rsocket.socketpair_default_family,
@@ -160,8 +160,8 @@
except SocketError, e:
raise converted_error(space, e)
return space.newtuple([
- space.wrap(W_Socket(sock1)),
- space.wrap(W_Socket(sock2))
+ space.wrap(W_Socket(space, sock1)),
+ space.wrap(W_Socket(space, sock2))
])
# The following 4 functions refuse all negative numbers, like CPython 2.6.
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -1,4 +1,5 @@
-from rpython.rlib import rsocket
+import sys
+from rpython.rlib import rsocket, rweaklist
from rpython.rlib.rarithmetic import intmask
from rpython.rlib.rsocket import (
RSocket, AF_INET, SOCK_STREAM, SocketError, SocketErrorWithErrno,
@@ -153,8 +154,9 @@
class W_Socket(W_Root):
- def __init__(self, sock):
+ def __init__(self, space, sock):
self.sock = sock
+ register_socket(space, sock)
def get_type_w(self, space):
return space.wrap(self.sock.type)
@@ -183,7 +185,7 @@
fd, addr = self.sock.accept()
sock = rsocket.make_socket(
fd, self.sock.family, self.sock.type, self.sock.proto)
- return space.newtuple([space.wrap(W_Socket(sock)),
+ return space.newtuple([space.wrap(W_Socket(space, sock)),
addr_as_object(addr, sock.fd, space)])
except SocketError as e:
raise converted_error(space, e)
@@ -248,7 +250,7 @@
def dup_w(self, space):
try:
sock = self.sock.dup()
- return W_Socket(sock)
+ return W_Socket(space, sock)
except SocketError as e:
raise converted_error(space, e)
@@ -592,10 +594,50 @@
sock = RSocket(family, type, proto)
except SocketError as e:
raise converted_error(space, e)
- W_Socket.__init__(self, sock)
+ W_Socket.__init__(self, space, sock)
return space.wrap(self)
descr_socket_new = interp2app(newsocket)
+
+# ____________________________________________________________
+# Automatic shutdown()/close()
+
+# On some systems, the C library does not guarantee that when the program
+# finishes, all data sent so far is really sent even if the socket is not
+# explicitly closed. This behavior has been observed on Windows but not
+# on Linux, so far.
+NEED_EXPLICIT_CLOSE = (sys.platform == 'win32')
+
+class OpenRSockets(rweaklist.RWeakListMixin):
+ pass
+class OpenRSocketsState:
+ def __init__(self, space):
+ self.openrsockets = OpenRSockets()
+ self.openrsockets.initialize()
+
+def getopenrsockets(space):
+ if NEED_EXPLICIT_CLOSE and space.config.translation.rweakref:
+ return space.fromcache(OpenRSocketsState).openrsockets
+ else:
+ return None
+
+def register_socket(space, socket):
+ openrsockets = getopenrsockets(space)
+ if openrsockets is not None:
+ openrsockets.add_handle(socket)
+
+def close_all_sockets(space):
+ openrsockets = getopenrsockets(space)
+ if openrsockets is not None:
+ for sock_wref in openrsockets.get_all_handles():
+ sock = sock_wref()
+ if sock is not None:
+ try:
+ sock.close()
+ except SocketError:
+ pass
+
+
# ____________________________________________________________
# Error handling
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -309,10 +309,16 @@
class AppTestSocket:
+ spaceconfig = dict(usemodules=['_socket', '_weakref', 'struct'])
+
def setup_class(cls):
cls.space = space
cls.w_udir = space.wrap(str(udir))
+ def teardown_class(cls):
+ if not cls.runappdirect:
+ cls.space.sys.getmodule('_socket').shutdown(cls.space)
+
def test_module(self):
import _socket
assert _socket.socket.__name__ == 'socket'
@@ -614,6 +620,12 @@
finally:
os.chdir(oldcwd)
+ def test_automatic_shutdown(self):
+ # doesn't really test anything, but at least should not explode
+ # in close_all_sockets()
+ import _socket
+ self.foo = _socket.socket()
+
class AppTestPacket:
def setup_class(cls):
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -136,7 +136,7 @@
def __init__(self, ctx, protos):
self.protos = protos
self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos)
- NPN_STORAGE.set(r_uint(rffi.cast(rffi.UINT, self.buf)), self)
+ NPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self)
# set both server and client callbacks, because the context
# can be used to create both types of sockets
@@ -151,7 +151,7 @@
@staticmethod
def advertiseNPN_cb(s, data_ptr, len_ptr, args):
- npn = NPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args)))
+ npn = NPN_STORAGE.get(rffi.cast(lltype.Unsigned, args))
if npn and npn.protos:
data_ptr[0] = npn.buf
len_ptr[0] = rffi.cast(rffi.UINT, len(npn.protos))
@@ -163,7 +163,7 @@
@staticmethod
def selectNPN_cb(s, out_ptr, outlen_ptr, server, server_len, args):
- npn = NPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args)))
+ npn = NPN_STORAGE.get(rffi.cast(lltype.Unsigned, args))
if npn and npn.protos:
client = npn.buf
client_len = len(npn.protos)
@@ -182,7 +182,7 @@
def __init__(self, ctx, protos):
self.protos = protos
self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos)
- ALPN_STORAGE.set(r_uint(rffi.cast(rffi.UINT, self.buf)), self)
+ ALPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self)
with rffi.scoped_str2charp(protos) as protos_buf:
if libssl_SSL_CTX_set_alpn_protos(
@@ -197,7 +197,7 @@
@staticmethod
def selectALPN_cb(s, out_ptr, outlen_ptr, client, client_len, args):
- alpn = ALPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args)))
+ alpn = ALPN_STORAGE.get(rffi.cast(lltype.Unsigned, args))
if alpn and alpn.protos:
server = alpn.buf
server_len = len(alpn.protos)
diff --git a/pypy/module/_vmprof/interp_vmprof.py b/pypy/module/_vmprof/interp_vmprof.py
--- a/pypy/module/_vmprof/interp_vmprof.py
+++ b/pypy/module/_vmprof/interp_vmprof.py
@@ -26,7 +26,7 @@
eci_kwds = dict(
include_dirs = [SRC],
includes = ['vmprof.h', 'trampoline.h'],
- separate_module_files = [SRC.join('trampoline.asmgcc.s')],
+ separate_module_files = [SRC.join('trampoline.vmprof.s')],
libraries = ['dl'],
post_include_bits=["""
diff --git a/pypy/module/_vmprof/src/trampoline.asmgcc.s b/pypy/module/_vmprof/src/trampoline.vmprof.s
rename from pypy/module/_vmprof/src/trampoline.asmgcc.s
rename to pypy/module/_vmprof/src/trampoline.vmprof.s
--- a/pypy/module/_vmprof/src/trampoline.asmgcc.s
+++ b/pypy/module/_vmprof/src/trampoline.vmprof.s
@@ -1,7 +1,6 @@
// NOTE: you need to use TABs, not spaces!
.text
- .p2align 4,,-1
.globl pypy_execute_frame_trampoline
.type pypy_execute_frame_trampoline, @function
pypy_execute_frame_trampoline:
diff --git a/pypy/module/_vmprof/src/vmprof.c b/pypy/module/_vmprof/src/vmprof.c
--- a/pypy/module/_vmprof/src/vmprof.c
+++ b/pypy/module/_vmprof/src/vmprof.c
@@ -305,7 +305,6 @@
static int remove_sigprof_timer(void) {
static struct itimerval timer;
- last_period_usec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
timer.it_value.tv_sec = 0;
@@ -317,11 +316,15 @@
}
static void atfork_disable_timer(void) {
- remove_sigprof_timer();
+ if (last_period_usec) {
+ remove_sigprof_timer();
+ }
}
static void atfork_enable_timer(void) {
- install_sigprof_timer(last_period_usec);
+ if (last_period_usec) {
+ install_sigprof_timer(last_period_usec);
+ }
}
static int install_pthread_atfork_hooks(void) {
@@ -412,6 +415,7 @@
if (remove_sigprof_timer() == -1) {
return -1;
}
+ last_period_usec = 0;
if (remove_sigprof_handler() == -1) {
return -1;
}
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -38,4 +38,4 @@
'C') or Fortran-style (fortran is 'F') contiguous or either one
(fortran is 'A'). Return 0 otherwise."""
# PyPy only supports contiguous Py_buffers for now.
- return space.wrap(1)
+ return 1
diff --git a/pypy/module/cpyext/test/test_version.py b/pypy/module/cpyext/test/test_version.py
--- a/pypy/module/cpyext/test/test_version.py
+++ b/pypy/module/cpyext/test/test_version.py
@@ -16,7 +16,7 @@
}
"""
module = self.import_module(name='foo', init=init)
- assert module.py_version == sys.version[:5]
+ assert module.py_version == '%d.%d.%d' % sys.version_info[:3]
assert module.py_major_version == sys.version_info.major
assert module.py_minor_version == sys.version_info.minor
assert module.py_micro_version == sys.version_info.micro
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -349,6 +349,11 @@
w_all = try_getattr(space, w_mod, space.wrap('__all__'))
if w_all is not None:
fromlist_w = space.fixedview(w_all)
+ else:
+ fromlist_w = []
+ # "from x import *" with x already imported and no x.__all__
+ # always succeeds without doing more imports. It will
+ # just copy everything from x.__dict__ as it is now.
for w_name in fromlist_w:
if try_getattr(space, w_mod, w_name) is None:
return None
@@ -389,6 +394,8 @@
w_all = try_getattr(space, w_mod, w('__all__'))
if w_all is not None:
fromlist_w = space.fixedview(w_all)
+ else:
+ fromlist_w = []
for w_name in fromlist_w:
if try_getattr(space, w_mod, w_name) is None:
load_part(space, w_path, prefix, space.str0_w(w_name),
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -66,6 +66,14 @@
b = "insubpackage = 1",
)
setuppkg("pkg.pkg2", a='', b='')
+ setuppkg("pkg.withall",
+ __init__ = "__all__ = ['foobar']",
+ foobar = "found = 123")
+ setuppkg("pkg.withoutall",
+ __init__ = "",
+ foobar = "found = 123")
+ setuppkg("pkg.bogusall",
+ __init__ = "__all__ = 42")
setuppkg("pkg_r", inpkg = "import x.y")
setuppkg("pkg_r.x")
setuppkg("x", y='')
@@ -677,6 +685,32 @@
import imp
raises(ValueError, imp.load_module, "", "", "", [1, 2, 3, 4])
+ def test_import_star_finds_submodules_with___all__(self):
+ for case in ["not-imported-yet", "already-imported"]:
+ d = {}
+ exec "from pkg.withall import *" in d
+ assert d["foobar"].found == 123
More information about the pypy-commit
mailing list