Author: Ronan Lamy <[email protected]>
Branch: _py3k-cpyext-A
Changeset: r87012:b8bcaa6c2cfb
Date: 2016-09-11 21:17 +0100
http://bitbucket.org/pypy/pypy/changeset/b8bcaa6c2cfb/
Log: Merge test-cpyext
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -43,16 +43,20 @@
def PySequence_Fast(space, w_obj, m):
"""Returns the sequence o as a tuple, unless it is already a tuple or
list, in
which case o is returned. Use PySequence_Fast_GET_ITEM() to access the
- members of the result. Returns NULL on failure. If the object is not a
- sequence, raises TypeError with m as the message text."""
+ members of the result. Returns NULL on failure. If the object cannot be
+ converted to a sequence, and raises a TypeError, raise a new TypeError with
+ m as the message text. If the conversion otherwise, fails, reraise the
+ original exception"""
if isinstance(w_obj, W_ListObject):
# make sure we can return a borrowed obj from PySequence_Fast_GET_ITEM
w_obj.convert_to_cpy_strategy(space)
return w_obj
try:
return W_ListObject.newlist_cpyext(space, space.listview(w_obj))
- except OperationError:
- raise OperationError(space.w_TypeError, space.wrap(rffi.charp2str(m)))
+ except OperationError as e:
+ if e.match(space, space.w_TypeError):
+ raise OperationError(space.w_TypeError,
space.wrap(rffi.charp2str(m)))
+ raise e
@cpython_api([rffi.VOIDP, Py_ssize_t], PyObject, result_borrowed=True)
def PySequence_Fast_GET_ITEM(space, w_obj, index):
diff --git a/pypy/module/cpyext/test/test_cpyext.py
b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -42,19 +42,6 @@
files.append(filename)
return files
-def create_so(modname, include_dirs, source_strings=None, source_files=None,
- compile_extra=None, link_extra=None, libraries=None):
- dirname = (udir/uniquemodulename('module')).ensure(dir=1)
- if source_strings:
- assert not source_files
- files = convert_sources_to_files(source_strings, dirname)
- source_files = files
- soname = c_compile(source_files, outputfilename=str(dirname/modname),
- compile_extra=compile_extra, link_extra=link_extra,
- include_dirs=include_dirs,
- libraries=libraries)
- return soname
-
class SystemCompilationInfo(object):
"""Bundles all the generic information required to compile extensions.
@@ -68,6 +55,33 @@
self.extra_libs = extra_libs
self.ext = ext
+ def compile_extension_module(self, name, include_dirs=[],
+ source_files=None, source_strings=None):
+ """
+ Build an extension module and return the filename of the resulting
+ native code file.
+
+ name is the name of the module, possibly including dots if it is a
+ module inside a package.
+
+ Any extra keyword arguments are passed on to ExternalCompilationInfo to
+ build the module (so specify your source with one of those).
+ """
+ modname = name.split('.')[-1]
+ dirname = (udir/uniquemodulename('module')).ensure(dir=1)
+ if source_strings:
+ assert not source_files
+ files = convert_sources_to_files(source_strings, dirname)
+ source_files = files
+ soname = c_compile(source_files, outputfilename=str(dirname/modname),
+ compile_extra=self.compile_extra,
+ link_extra=self.link_extra,
+ include_dirs=self.include_extra + include_dirs,
+ libraries=self.extra_libs)
+ pydname = soname.new(purebasename=modname, ext=self.ext)
+ soname.rename(pydname)
+ return str(pydname)
+
def get_cpyext_info(space):
from pypy.module.imp.importing import get_so_extension
state = space.fromcache(State)
@@ -96,30 +110,6 @@
ext=get_so_extension(space))
-def compile_extension_module(sys_info, modname, include_dirs=[],
- source_files=None, source_strings=None):
- """
- Build an extension module and return the filename of the resulting native
- code file.
-
- modname is the name of the module, possibly including dots if it is a
module
- inside a package.
-
- Any extra keyword arguments are passed on to ExternalCompilationInfo to
- build the module (so specify your source with one of those).
- """
- modname = modname.split('.')[-1]
- soname = create_so(modname,
- include_dirs=sys_info.include_extra + include_dirs,
- source_files=source_files,
- source_strings=source_strings,
- compile_extra=sys_info.compile_extra,
- link_extra=sys_info.link_extra,
- libraries=sys_info.extra_libs)
- pydname = soname.new(purebasename=modname, ext=sys_info.ext)
- soname.rename(pydname)
- return str(pydname)
-
def get_so_suffix():
from imp import get_suffixes, C_EXTENSION
for suffix, mode, typ in get_suffixes():
@@ -148,6 +138,35 @@
link_extra=link_extra,
ext=get_so_suffix())
+def make_methods(functions, modname):
+ methods_table = []
+ codes = []
+ for funcname, flags, code in functions:
+ cfuncname = "%s_%s" % (modname, funcname)
+ methods_table.append("{\"%s\", %s, %s}," %
+ (funcname, cfuncname, flags))
+ func_code = """
+ static PyObject* %s(PyObject* self, PyObject* args)
+ {
+ %s
+ }
+ """ % (cfuncname, code)
+ codes.append(func_code)
+
+ body = "\n".join(codes) + """
+ static PyMethodDef methods[] = {
+ %(methods)s
+ { NULL }
+ };
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "%(modname)s", /* m_name */
+ NULL, /* m_doc */
+ -1, /* m_size */
+ methods, /* m_methods */
+ };
+ """ % dict(methods='\n'.join(methods_table), modname=modname)
+ return body
def freeze_refcnts(self):
rawrefcount._dont_free_any_more()
@@ -168,6 +187,7 @@
return arg
listview = passthrough
str_w = passthrough
+ wrap = passthrough
def unwrap(self, args):
try:
@@ -308,6 +328,15 @@
if not cls.runappdirect:
cls.w_runappdirect = space.wrap(cls.runappdirect)
+ def record_imported_module(self, name):
+ """
+ Record a module imported in a test so that it can be cleaned up in
+ teardown before the check for leaks is done.
+
+ name gives the name of the module in the space's sys.modules.
+ """
+ self.imported_module_names.append(name)
+
def setup_method(self, func):
@gateway.unwrap_spec(name=str)
def compile_module(space, name,
@@ -324,16 +353,20 @@
source_strings = space.listview_bytes(w_source_strings)
else:
source_strings = None
- pydname = compile_extension_module(
- self.sys_info, name,
+ pydname = self.sys_info.compile_extension_module(
+ name,
source_files=source_files,
source_strings=source_strings)
+
+ # hackish, but tests calling compile_module() always end up
+ # importing the result
+ self.record_imported_module(name)
+
return space.wrap(pydname)
@gateway.unwrap_spec(name=str, init='str_or_None', body=str,
- load_it=bool, filename='str_or_None',
- PY_SSIZE_T_CLEAN=bool)
- def import_module(space, name, init=None, body='', load_it=True,
+ filename='str_or_None', PY_SSIZE_T_CLEAN=bool)
+ def import_module(space, name, init=None, body='',
filename=None, w_include_dirs=None,
PY_SSIZE_T_CLEAN=False):
"""
@@ -378,69 +411,30 @@
filename = py.path.local(pypydir) / 'module' \
/ 'cpyext'/ 'test' / (filename + ".c")
kwds = dict(source_files=[filename])
- mod = compile_extension_module(self.sys_info, name,
- include_dirs=include_dirs, **kwds)
+ mod = self.sys_info.compile_extension_module(
+ name, include_dirs=include_dirs, **kwds)
+ w_result = load_module(space, mod, name)
+ if not self.runappdirect:
+ self.record_imported_module(name)
+ return w_result
- if load_it:
- if self.runappdirect:
- import imp
- return imp.load_dynamic(name, mod)
- else:
- api.load_extension_module(space, mod, name)
- self.imported_module_names.append(name)
- return space.getitem(
- space.sys.get('modules'),
- space.wrap(name))
- else:
- path = os.path.dirname(mod)
- if self.runappdirect:
- return path
- else:
- return space.wrap(path)
@gateway.unwrap_spec(mod=str, name=str)
- def reimport_module(space, mod, name):
+ def load_module(space, mod, name):
if self.runappdirect:
import imp
return imp.load_dynamic(name, mod)
else:
api.load_extension_module(space, mod, name)
- return space.getitem(
- space.sys.get('modules'),
- space.wrap(name))
+ return space.getitem(
+ space.sys.get('modules'), space.wrap(name))
@gateway.unwrap_spec(modname=str, prologue=str,
more_init=str, PY_SSIZE_T_CLEAN=bool)
def import_extension(space, modname, w_functions, prologue="",
w_include_dirs=None, more_init="",
PY_SSIZE_T_CLEAN=False):
functions = space.unwrap(w_functions)
- methods_table = []
- codes = []
- for funcname, flags, code in functions:
- cfuncname = "%s_%s" % (modname, funcname)
- methods_table.append("{\"%s\", %s, %s}," %
- (funcname, cfuncname, flags))
- func_code = """
- static PyObject* %s(PyObject* self, PyObject* args)
- {
- %s
- }
- """ % (cfuncname, code)
- codes.append(func_code)
-
- body = prologue + "\n".join(codes) + """
- static PyMethodDef methods[] = {
- %(methods)s
- { NULL }
- };
- static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "%(modname)s", /* m_name */
- NULL, /* m_doc */
- -1, /* m_size */
- methods, /* m_methods */
- };
- """ % dict(methods='\n'.join(methods_table), modname=modname)
+ body = prologue + make_methods(functions, modname)
init = """PyObject *mod = PyModule_Create(&moduledef);"""
if more_init:
init += more_init
@@ -449,16 +443,6 @@
w_include_dirs=w_include_dirs,
PY_SSIZE_T_CLEAN=PY_SSIZE_T_CLEAN)
- @gateway.unwrap_spec(name=str)
- def record_imported_module(name):
- """
- Record a module imported in a test so that it can be cleaned up in
- teardown before the check for leaks is done.
-
- name gives the name of the module in the space's sys.modules.
- """
- self.imported_module_names.append(name)
-
def debug_collect(space):
rawrefcount._collect()
@@ -479,15 +463,15 @@
def wrap(func):
return func
self.sys_info = get_sys_info_app()
+ self.compile_module = self.sys_info.compile_extension_module
else:
interp2app = gateway.interp2app
wrap = self.space.wrap
self.sys_info = get_cpyext_info(self.space)
- self.w_compile_module = wrap(interp2app(compile_module))
+ self.w_compile_module = wrap(interp2app(compile_module))
self.w_import_module = wrap(interp2app(import_module))
- self.w_reimport_module = wrap(interp2app(reimport_module))
+ self.w_load_module = wrap(interp2app(load_module))
self.w_import_extension = wrap(interp2app(import_extension))
- self.w_record_imported_module =
wrap(interp2app(record_imported_module))
self.w_here = wrap(str(py.path.local(pypydir)) +
'/module/cpyext/test/')
self.w_debug_collect = wrap(interp2app(debug_collect))
@@ -628,15 +612,11 @@
If `cherry.date` is an extension module which imports `apple.banana`,
the latter is added to `sys.modules` for the `"apple.banana"` key.
"""
- if self.runappdirect:
- skip('record_imported_module not supported in runappdirect mode')
# Build the extensions.
banana = self.compile_module(
"apple.banana", source_files=[self.here + 'banana.c'])
- self.record_imported_module("apple.banana")
date = self.compile_module(
"cherry.date", source_files=[self.here + 'date.c'])
- self.record_imported_module("cherry.date")
# Set up some package state so that the extensions can actually be
# imported.
@@ -648,7 +628,6 @@
apple.__path__ = [os.path.dirname(banana)]
import cherry.date
- import apple.banana
assert sys.modules['apple.banana'].__name__ == 'apple.banana'
assert sys.modules['cherry.date'].__name__ == 'cherry.date'
@@ -1004,7 +983,7 @@
f.write('not again!\n')
f.close()
m1 = sys.modules['foo']
- m2 = self.reimport_module(m1.__file__, name='foo')
+ m2 = self.load_module(m1.__file__, name='foo')
assert m1 is m2
assert m1 is sys.modules['foo']
diff --git a/pypy/module/cpyext/test/test_import.py
b/pypy/module/cpyext/test/test_import.py
--- a/pypy/module/cpyext/test/test_import.py
+++ b/pypy/module/cpyext/test/test_import.py
@@ -1,6 +1,6 @@
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.lltypesystem import rffi
class TestImport(BaseApiTest):
def test_import(self, space, api):
@@ -39,9 +39,9 @@
class AppTestImportLogic(AppTestCpythonExtensionBase):
def test_import_logic(self):
- path = self.import_module(name='test_import_module', load_it=False)
- import sys
- sys.path.append(path)
+ import sys, os
+ path = self.compile_module('test_import_module',
+ source_files=[os.path.join(self.here, 'test_import_module.c')])
+ sys.path.append(os.path.dirname(path))
import test_import_module
assert test_import_module.TEST is None
-
diff --git a/pypy/module/cpyext/test/test_sequence.py
b/pypy/module/cpyext/test/test_sequence.py
--- a/pypy/module/cpyext/test/test_sequence.py
+++ b/pypy/module/cpyext/test/test_sequence.py
@@ -267,3 +267,31 @@
assert module.test_fast_sequence(s[0:-1])
assert module.test_fast_sequence(s[::-1])
+ def test_fast_keyerror(self):
+ module = self.import_extension('foo', [
+ ("test_fast_sequence", "METH_VARARGS",
+ """
+ PyObject *foo;
+ PyObject * seq = PyTuple_GetItem(args, 0);
+ if (seq == NULL)
+ Py_RETURN_NONE;
+ foo = PySequence_Fast(seq, "Could not convert object to
sequence");
+ if (foo != NULL)
+ {
+ return foo;
+ }
+ if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ return PyBool_FromLong(1);
+ }
+ return NULL;
+ """)])
+ class Map(object):
+ def __len__(self):
+ return 1
+
+ def __getitem__(self, index):
+ raise KeyError()
+
+ assert module.test_fast_sequence(Map()) is True
+
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit