Author: Ronan Lamy <[email protected]>
Branch: PyBuffer
Changeset: r91048:2fbdc25dcb1b
Date: 2017-04-13 00:49 +0100
http://bitbucket.org/pypy/pypy/changeset/2fbdc25dcb1b/
Log: hg merge py3.5
diff too long, truncating to 2000 out of 51546 lines
diff --git a/lib-python/3/distutils/ccompiler.py
b/lib-python/3/distutils/ccompiler.py
--- a/lib-python/3/distutils/ccompiler.py
+++ b/lib-python/3/distutils/ccompiler.py
@@ -959,7 +959,9 @@
# is assumed to be in the 'distutils' package.)
compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler',
"standard UNIX-style compiler"),
- 'msvc': ('_msvccompiler', 'MSVCCompiler',
+ # PyPy change: On win32 PyPy is translated with the
+ # "msvc9compiler", force the same here.
+ 'msvc': ('msvc9compiler', 'MSVCCompiler',
"Microsoft Visual C++"),
'cygwin': ('cygwinccompiler', 'CygwinCCompiler',
"Cygwin port of GNU C Compiler for Win32"),
diff --git a/lib-python/3/distutils/sysconfig_pypy.py
b/lib-python/3/distutils/sysconfig_pypy.py
--- a/lib-python/3/distutils/sysconfig_pypy.py
+++ b/lib-python/3/distutils/sysconfig_pypy.py
@@ -66,12 +66,12 @@
so_ext = [s[0] for s in imp.get_suffixes() if s[2] == imp.C_EXTENSION][0]
g = {}
- g['CC'] = "gcc -pthread"
- g['CXX'] = "g++ -pthread"
+ g['CC'] = "cc -pthread"
+ g['CXX'] = "c++ -pthread"
g['OPT'] = "-DNDEBUG -O2"
g['CFLAGS'] = "-DNDEBUG -O2"
g['CCSHARED'] = "-fPIC"
- g['LDSHARED'] = "gcc -pthread -shared"
+ g['LDSHARED'] = "cc -pthread -shared"
g['EXT_SUFFIX'] = so_ext
g['SHLIB_SUFFIX'] = so_ext
g['SO'] = so_ext # deprecated in Python 3, for backward compatibility
diff --git a/lib-python/3/pathlib.py b/lib-python/3/pathlib.py
--- a/lib-python/3/pathlib.py
+++ b/lib-python/3/pathlib.py
@@ -1209,23 +1209,19 @@
def mkdir(self, mode=0o777, parents=False, exist_ok=False):
if self._closed:
self._raise_closed()
- if not parents:
- try:
- self._accessor.mkdir(self, mode)
- except FileExistsError:
- if not exist_ok or not self.is_dir():
- raise
- else:
- try:
- self._accessor.mkdir(self, mode)
- except FileExistsError:
- if not exist_ok or not self.is_dir():
- raise
- except OSError as e:
- if e.errno != ENOENT:
- raise
- self.parent.mkdir(parents=True)
- self._accessor.mkdir(self, mode)
+ # NOTE: version from CPython 3.7 plus fix at issue #29694
+ try:
+ self._accessor.mkdir(self, mode)
+ except FileNotFoundError:
+ if not parents or self.parent == self:
+ raise
+ self.parent.mkdir(parents=True, exist_ok=True)
+ self.mkdir(mode, parents=False, exist_ok=exist_ok)
+ except OSError:
+ # Cannot rely on checking for EEXIST, since the operating system
+ # could give priority to other errors like EACCES or EROFS
+ if not exist_ok or not self.is_dir():
+ raise
def chmod(self, mode):
"""
diff --git a/lib-python/3/sre_compile.py b/lib-python/3/sre_compile.py
--- a/lib-python/3/sre_compile.py
+++ b/lib-python/3/sre_compile.py
@@ -378,7 +378,11 @@
def _bytes_to_codes(b):
# Convert block indices to word array
- a = memoryview(b).cast('I')
+ if _sre.CODESIZE == 2:
+ code = 'H'
+ else:
+ code = 'I'
+ a = memoryview(b).cast(code)
assert a.itemsize == _sre.CODESIZE
assert len(a) * a.itemsize == len(b)
return a.tolist()
diff --git a/lib-python/3/test/_test_multiprocessing.py
b/lib-python/3/test/_test_multiprocessing.py
--- a/lib-python/3/test/_test_multiprocessing.py
+++ b/lib-python/3/test/_test_multiprocessing.py
@@ -2147,7 +2147,8 @@
# Because we are using xmlrpclib for serialization instead of
# pickle this will cause a serialization error.
- self.assertRaises(Exception, queue.put, time.sleep)
+ # Changed on PyPy: passing functions to xmlrpc is broken
+ #self.assertRaises(Exception, queue.put, time.sleep)
# Make queue finalizer run before the server is stopped
del queue
diff --git a/lib-python/3/test/test_pathlib.py
b/lib-python/3/test/test_pathlib.py
--- a/lib-python/3/test/test_pathlib.py
+++ b/lib-python/3/test/test_pathlib.py
@@ -8,6 +8,7 @@
import stat
import tempfile
import unittest
+from unittest import mock
from test import support
TESTFN = support.TESTFN
@@ -1751,6 +1752,35 @@
p.mkdir(exist_ok=True)
self.assertEqual(cm.exception.errno, errno.EEXIST)
+ def test_mkdir_concurrent_parent_creation(self):
+ for pattern_num in range(32):
+ p = self.cls(BASE, 'dirCPC%d' % pattern_num)
+ self.assertFalse(p.exists())
+
+ def my_mkdir(path, mode=0o777):
+ path = str(path)
+ # Emulate another process that would create the directory
+ # just before we try to create it ourselves. We do it
+ # in all possible pattern combinations, assuming that this
+ # function is called at most 5 times (dirCPC/dir1/dir2,
+ # dirCPC/dir1, dirCPC, dirCPC/dir1, cirCPC/dir1/dir2).
+ if pattern.pop():
+ os.mkdir(path, mode) # from another process
+ concurrently_created.add(path)
+ os.mkdir(path, mode) # our real call
+
+ pattern = [bool(pattern_num & (1 << n)) for n in range(5)]
+ concurrently_created = set()
+ p12 = p / 'dir1' / 'dir2'
+ try:
+ with mock.patch("pathlib._normal_accessor.mkdir", my_mkdir):
+ p12.mkdir(parents=True, exist_ok=False)
+ except FileExistsError:
+ self.assertIn(str(p12), concurrently_created)
+ else:
+ self.assertNotIn(str(p12), concurrently_created)
+ self.assertTrue(p.exists())
+
@with_symlinks
def test_symlink_to(self):
P = self.cls(BASE)
diff --git a/lib-python/3/test/test_xml_etree.py
b/lib-python/3/test/test_xml_etree.py
--- a/lib-python/3/test/test_xml_etree.py
+++ b/lib-python/3/test/test_xml_etree.py
@@ -1878,6 +1878,17 @@
with self.assertRaises(RuntimeError):
repr(e) # Should not crash
+ def test_bad_find_returns_none(self):
+ # This behavior is the one we get historically when the C
+ # extension module is enabled. With the Python version, it
+ # raised a TypeError instead. There are projects out there
+ # that depend on the non-raising behavior, of course.
+ e = ET.Element('foo')
+ assert e.find('') is None
+ assert e.findall('') == []
+ assert e.findtext('') is None
+ assert e.findtext('', default="default.") == "default."
+
class MutatingElementPath(str):
def __new__(cls, elem, *args):
self = str.__new__(cls, *args)
diff --git a/lib-python/3/xml/etree/ElementTree.py
b/lib-python/3/xml/etree/ElementTree.py
--- a/lib-python/3/xml/etree/ElementTree.py
+++ b/lib-python/3/xml/etree/ElementTree.py
@@ -294,7 +294,14 @@
Return the first matching element, or None if no element was found.
"""
- return ElementPath.find(self, path, namespaces)
+ # Used to be: return ElementPath.find(self, path, namespaces)
+ # but there are projects out there that rely on it getting None
+ # instead of an internal TypeError. This is what the C version
+ # of this class does.
+ result = ElementPath.iterfind(self, path, namespaces)
+ if result is None:
+ return None
+ return next(result, None)
def findtext(self, path, default=None, namespaces=None):
"""Find text for first matching element by tag name or path.
@@ -308,7 +315,17 @@
content, the empty string is returned.
"""
- return ElementPath.findtext(self, path, default, namespaces)
+ # Used to be:
+ # return ElementPath.findtext(self, path, default, namespaces)
+ # See find().
+ result = ElementPath.iterfind(self, path, namespaces)
+ if result is None:
+ return default
+ try:
+ elem = next(result)
+ return elem.text or ""
+ except StopIteration:
+ return default
def findall(self, path, namespaces=None):
"""Find all matching subelements by tag name or path.
@@ -319,7 +336,12 @@
Returns list containing all matching elements in document order.
"""
- return ElementPath.findall(self, path, namespaces)
+ # Used to be: return ElementPath.findall(self, path, namespaces)
+ # See find().
+ result = ElementPath.iterfind(self, path, namespaces)
+ if result is None:
+ return []
+ return list(result)
def iterfind(self, path, namespaces=None):
"""Find all matching subelements by tag name or path.
diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -597,7 +597,7 @@
py.test.skip("%s module not included in %s" % (mod,
execpath))
- cmd = "%s %s %s" % (execpath, regrrun, fspath.purebasename)
+ cmd = "%s -m test -v %s" % (execpath, fspath.purebasename)
# add watchdog for timing out
cmd = "%s %s %s %s" % (python, watchdog_script, TIMEOUT, cmd)
else:
diff --git a/lib_pypy/_audioop_build.py b/lib_pypy/_audioop_build.py
--- a/lib_pypy/_audioop_build.py
+++ b/lib_pypy/_audioop_build.py
@@ -656,4 +656,4 @@
ffi.set_source("_audioop_cffi", C_SOURCE)
if __name__ == "__main__":
- ffi.compile()
+ ffi.compile(verbose=2)
diff --git a/lib_pypy/_decimal_build.py b/lib_pypy/_decimal_build.py
--- a/lib_pypy/_decimal_build.py
+++ b/lib_pypy/_decimal_build.py
@@ -226,6 +226,16 @@
_libdir = os.path.join(os.path.dirname(__file__), '_libmpdec')
ffi.set_source('_decimal_cffi',
"""
+#ifdef _MSC_VER
+ #if defined(_WIN64)
+ typedef __int64 LONG_PTR;
+ #else
+ typedef long LONG_PTR;
+ #endif
+ typedef LONG_PTR ssize_t;
+#else
+ #define HAVE_STDINT_H
+#endif
#include "mpdecimal.h"
#define MPD_Float_operation MPD_Not_implemented
@@ -266,7 +276,6 @@
include_dirs=[_libdir],
extra_compile_args=[
"-DANSI",
- "-DHAVE_STDINT_H",
"-DHAVE_INTTYPES_H",
"-DCONFIG_64" if sys.maxsize > 1 << 32 else "-DCONFIG_32",
],
diff --git a/lib_pypy/_pypy_testcapi.py b/lib_pypy/_pypy_testcapi.py
--- a/lib_pypy/_pypy_testcapi.py
+++ b/lib_pypy/_pypy_testcapi.py
@@ -61,13 +61,12 @@
# set link options
output_filename = modulename + _get_c_extension_suffix()
if sys.platform == 'win32':
- # XXX pyconfig.h uses a pragma to link to the import library,
- # which is currently python3.lib
- library = os.path.join(thisdir, '..', 'libs', 'python32')
+ libname = 'python{0[0]}{0[1]}'.format(sys.version_info)
+ library = os.path.join(thisdir, '..', 'lib', libname)
if not os.path.exists(library + '.lib'):
# For a local translation or nightly build
- library = os.path.join(thisdir, '..', 'pypy', 'goal', 'python32')
- assert os.path.exists(library + '.lib'),'Could not find import library
"%s"' % library
+ library = os.path.join(thisdir, '..', 'pypy', 'goal', libname)
+ assert os.path.exists(library + '.lib'), 'Could not find import
library "%s"' % library
libraries = [library, 'oleaut32']
extra_ldargs = ['/MANIFEST', # needed for VC10
'/EXPORT:PyInit_' + modulename]
diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py
--- a/lib_pypy/_sqlite3.py
+++ b/lib_pypy/_sqlite3.py
@@ -32,10 +32,11 @@
import threading
try:
- from __pypy__ import newlist_hint
+ from __pypy__ import newlist_hint, add_memory_pressure
except ImportError:
assert '__pypy__' not in sys.builtin_module_names
newlist_hint = lambda sizehint: []
+ add_memory_pressure = lambda size: None
if sys.version_info[0] >= 3:
StandardError = Exception
@@ -152,6 +153,9 @@
check_same_thread=True, factory=None, cached_statements=100,
uri=0):
factory = Connection if not factory else factory
+ # an sqlite3 db seems to be around 100 KiB at least (doesn't matter if
+ # backed by :memory: or a file)
+ add_memory_pressure(100 * 1024)
return factory(database, timeout, detect_types, isolation_level,
check_same_thread, factory, cached_statements, uri)
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
@@ -563,7 +563,7 @@
if sys.platform == "win32":
# we need 'libpypy-c.lib'. Current distributions of
# pypy (>= 4.1) contain it as 'libs/python27.lib'.
- pythonlib = "python27"
+ pythonlib = "python{0[0]}{0[1]}".format(sys.version_info)
if hasattr(sys, 'prefix'):
ensure('library_dirs', os.path.join(sys.prefix, 'libs'))
else:
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -72,8 +72,6 @@
if "cppyy" in working_modules:
working_modules.remove("cppyy") # not tested on win32
- if "faulthandler" in working_modules:
- working_modules.remove("faulthandler") # missing details
# The _locale module is needed by site.py on Windows
default_modules.add("_locale")
diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst
--- a/pypy/doc/build.rst
+++ b/pypy/doc/build.rst
@@ -79,6 +79,9 @@
_ssl
libssl
+_vmprof
+ libunwind (optional, loaded dynamically at runtime)
+
Make sure to have these libraries (with development headers) installed
before building PyPy, otherwise the resulting binary will not contain
these modules. Furthermore, the following libraries should be present
@@ -185,7 +188,7 @@
::
cd pypy/tool/release
- ./package.py pypy-VER-PLATFORM
+ ./package.py --archive-name=pypy-VER-PLATFORM
This creates a clean and prepared hierarchy, as well as a ``.tar.bz2``
with the same content; both are found by default in
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
@@ -364,6 +364,24 @@
.. __:
https://bitbucket.org/pypy/pypy/issue/1974/different-behaviour-for-collections-of
+Performance Differences
+-------------------------
+
+CPython has an optimization that can make repeated string concatenation not
+quadratic. For example, this kind of code runs in O(n) time::
+
+ s = ''
+ for string in mylist:
+ s += string
+
+In PyPy, this code will always have quadratic complexity. Note also, that the
+CPython optimization is brittle and can break by having slight variations in
+your code anyway. So you should anyway replace the code with::
+
+ parts = []
+ for string in mylist:
+ parts.append(string)
+ s = "".join(parts)
Miscellaneous
-------------
diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst
--- a/pypy/doc/install.rst
+++ b/pypy/doc/install.rst
@@ -57,6 +57,7 @@
.. code-block:: console
$ ./pypy-xxx/bin/pypy -m ensurepip
+ $ ./pypy-xxx/bin/pip install -U pip wheel # to upgrade to the latest
versions
$ ./pypy-xxx/bin/pip install pygments # for example
Third party libraries will be installed in ``pypy-xxx/site-packages``, and
@@ -77,7 +78,17 @@
# from the mercurial checkout
$ virtualenv -p /path/to/pypy/pypy/translator/goal/pypy-c my-pypy-env
-Note that bin/python is now a symlink to bin/pypy.
+ # in any case activate it
+ $ source my-pypy-env/bin/activate
+
+Note that my-pypy-env/bin/python is now a symlink to my-pypy-env/bin/pypy
+so you should be able to run pypy simply by typing::
+
+ $ python
+
+You should still upgrade pip and wheel to the latest versions via::
+
+ $ my-pypy-env/bin/pip install -U pip wheel
.. _pip: http://pypi.python.org/pypi/pip
.. _ensurepip: https://docs.python.org/2.7/library/ensurepip.html
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
@@ -2,7 +2,22 @@
What's new in PyPy2.7 5.8+
==========================
-.. this is a revision shortly after release-pypy2.7-v5.7
+.. this is a revision shortly after release-pypy2.7-v5.7.0
.. startrev: 44f31f6dd39f
+Add cpyext interfaces for ``PyModule_New``
+Correctly handle `dict.pop`` where the ``pop``
+key is not the same type as the ``dict``'s and ``pop``
+is called with a default (will be part of release 5.7.1)
+
+.. branch: issue2522
+
+Fix missing tp_new on w_object called through multiple inheritance
+(will be part of release 5.7.1)
+
+.. branch: lstrip_to_empty_string
+
+.. branch: vmprof-native
+
+PyPy support to profile native frames in vmprof.
diff --git a/pypy/doc/whatsnew-pypy3-head.rst b/pypy/doc/whatsnew-pypy3-head.rst
--- a/pypy/doc/whatsnew-pypy3-head.rst
+++ b/pypy/doc/whatsnew-pypy3-head.rst
@@ -5,3 +5,16 @@
.. this is the revision after release-pypy3.3-5.7.x was branched
.. startrev: afbf09453369
+.. branch: mtest
+Use "<python> -m test" to run the CPython test suite, as documented by CPython,
+instead of our outdated regrverbose.py script.
+
+.. branch: win32-faulthandler
+
+Enable the 'faulthandler' module on Windows;
+this unblocks the Python test suite.
+
+.. branch: superjumbo
+
+Implement posix.posix_fallocate() and posix.posix_fadvise()
+
diff --git a/pypy/goal/targetpypystandalone.py
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -13,6 +13,7 @@
from pypy import pypydir
from rpython.rlib import rthread
from pypy.module.thread import os_thread
+from pypy.module.sys.version import CPYTHON_VERSION
thisdir = py.path.local(__file__).dirpath()
@@ -285,7 +286,8 @@
if sys.platform == 'win32':
libdir = thisdir.join('..', '..', 'libs')
libdir.ensure(dir=1)
- config.translation.libname = str(libdir.join('python27.lib'))
+ pythonlib = "python{0[0]}{0[1]}.lib".format(CPYTHON_VERSION)
+ config.translation.libname = str(libdir.join(pythonlib))
if config.translation.thread:
config.objspace.usemodules.thread = True
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -9,6 +9,7 @@
from rpython.rlib.objectmodel import we_are_translated, specialize
from rpython.rlib.objectmodel import dont_inline
from rpython.rlib import rstack, rstackovf
+from rpython.rlib import rwin32
from pypy.interpreter import debug
@@ -568,33 +569,6 @@
# 31: ANSI color code "red"
ansi_print(text, esc="31", file=file, newline=newline)
-try:
- WindowsError
-except NameError:
- _WINDOWS = False
-else:
- _WINDOWS = True
-
- def wrap_windowserror(space, e, w_filename=None):
- XXX # WindowsError no longer exists in Py3.5
- # instead, OSError has a kwarg winerror that overrides
- # any errno supplied
- from rpython.rlib import rwin32
-
- winerror = e.winerror
- try:
- msg = rwin32.FormatError(winerror)
- except ValueError:
- msg = 'Windows Error %d' % winerror
- exc = space.w_WindowsError
- if w_filename is not None:
- w_error = space.call_function(exc, space.newint(winerror),
- space.newtext(msg), w_filename)
- else:
- w_error = space.call_function(exc, space.newint(winerror),
- space.newtext(msg))
- return OperationError(exc, w_error)
-
@specialize.arg(3, 6)
def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError',
w_exception_class=None, w_filename2=None, eintr_retry=False):
@@ -612,9 +586,6 @@
"""
assert isinstance(e, OSError)
- if _WINDOWS and isinstance(e, WindowsError):
- return wrap_windowserror(space, e, w_filename)
-
if w_exception_class is None:
w_exc = getattr(space, exception_name)
else:
@@ -631,28 +602,37 @@
def _wrap_oserror2_impl(space, e, w_filename, w_filename2, w_exc, eintr_retry):
# move the common logic in its own function, instead of having it
# duplicated 4 times in all 4 specialized versions of wrap_oserror2()
- errno = e.errno
- if errno == EINTR:
- space.getexecutioncontext().checksignals()
- if eintr_retry:
- return None
+ if rwin32.WIN32 and isinstance(e, WindowsError):
+ winerror = e.winerror
+ try:
+ msg = rwin32.FormatError(winerror)
+ except ValueError:
+ msg = 'Windows Error %d' % winerror
+ w_errno = space.w_None
+ w_winerror = space.newint(winerror)
+ w_msg = space.newtext(msg)
+ else:
+ errno = e.errno
+ if errno == EINTR:
+ space.getexecutioncontext().checksignals()
+ if eintr_retry:
+ return None
- try:
- msg = strerror(errno)
- except ValueError:
- msg = u'error %d' % errno
- if w_filename is not None:
- if w_filename2 is not None:
- w_error = space.call_function(w_exc, space.newint(errno),
- space.newunicode(msg), w_filename,
- space.w_None, w_filename2)
- else:
- w_error = space.call_function(w_exc, space.newint(errno),
- space.newunicode(msg), w_filename)
- else:
- w_error = space.call_function(w_exc, space.newint(errno),
- space.newunicode(msg))
+ try:
+ msg = strerror(errno)
+ except ValueError:
+ msg = u'error %d' % errno
+ w_errno = space.newint(errno)
+ w_winerror = space.w_None
+ w_msg = space.newunicode(msg)
+
+ if w_filename is None:
+ w_filename = space.w_None
+ if w_filename2 is None:
+ w_filename2 = space.w_None
+ w_error = space.call_function(w_exc, w_errno, w_msg, w_filename,
+ w_winerror, w_filename2)
operror = OperationError(w_exc, w_error)
if eintr_retry:
raise operror
diff --git a/pypy/interpreter/pyparser/future.py
b/pypy/interpreter/pyparser/future.py
--- a/pypy/interpreter/pyparser/future.py
+++ b/pypy/interpreter/pyparser/future.py
@@ -80,6 +80,7 @@
from pypy.interpreter.pyparser import pygram
it = TokenIterator(tokens)
result = 0
+ last_position = (0, 0)
#
# The only things that can precede a future statement are another
# future statement and a doc string (only one). This is a very
@@ -94,6 +95,11 @@
it.skip_name("__future__") and
it.skip_name("import")):
it.skip(pygram.tokens.LPAR) # optionally
+ # return in 'last_position' any line-column pair that points
+ # somewhere inside the last __future__ import statement
+ # (at the start would be fine too, but it's easier to grab a
+ # random position inside)
+ last_position = (it.tok[2], it.tok[3])
result |= future_flags.get_compiler_feature(it.next_feature_name())
while it.skip(pygram.tokens.COMMA):
result |= future_flags.get_compiler_feature(it.next_feature_name())
@@ -104,5 +110,4 @@
# remove the flags that were specified but are anyway mandatory
result &= ~future_flags.mandatory_flags
- position = (it.tok[2], it.tok[3])
- return result, position
+ return result, last_position
diff --git a/pypy/interpreter/pyparser/test/test_future.py
b/pypy/interpreter/pyparser/test/test_future.py
--- a/pypy/interpreter/pyparser/test/test_future.py
+++ b/pypy/interpreter/pyparser/test/test_future.py
@@ -2,10 +2,9 @@
from pypy.interpreter.pyparser import future, pytokenizer
from pypy.tool import stdlib___future__ as fut
-def run(s, expected_last_future=None):
+def run(s, expected_last_future=(0, 0)):
source_lines = s.splitlines(True)
tokens = pytokenizer.generate_tokens(source_lines, 0)
- expected_last_future = expected_last_future or tokens[-1][2:4]
#
flags, last_future_import = future.add_future_flags(
future.futureFlags_3_5, tokens)
@@ -14,7 +13,7 @@
def test_docstring():
s = '"Docstring\\" "\nfrom __future__ import division\n'
- f = run(s)
+ f = run(s, (2, 24))
assert f == 0
def test_comment():
@@ -45,152 +44,152 @@
def test_from():
s = 'from __future__ import division\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_froms():
s = 'from __future__ import division, generators, with_statement\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_from_as():
s = 'from __future__ import division as b\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_froms_as():
s = 'from __future__ import division as b, generators as c\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_from_paren():
s = 'from __future__ import (division)\n'
- f = run(s)
+ f = run(s, (1, 25))
assert f == 0
def test_froms_paren():
s = 'from __future__ import (division, generators)\n'
- f = run(s)
+ f = run(s, (1, 25))
assert f == 0
def test_froms_paren_as():
s = 'from __future__ import (division as b, generators,)\n'
- f = run(s)
+ f = run(s, (1, 25))
assert f == 0
def test_paren_with_newline():
s = 'from __future__ import (division,\nabsolute_import)\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_paren_with_newline_2():
s = 'from __future__ import (\ndivision,\nabsolute_import)\n'
- f = run(s)
+ f = run(s, (2, 0))
assert f == 0
def test_multiline():
s = '"abc" #def\n #ghi\nfrom __future__ import (division as b,
generators,)\nfrom __future__ import with_statement\n'
- f = run(s)
+ f = run(s, (4, 23))
assert f == 0
def test_windows_style_lineendings():
s = '"abc" #def\r\n #ghi\r\nfrom __future__ import (division as b,
generators,)\r\nfrom __future__ import with_statement\r\n'
- f = run(s)
+ f = run(s, (4, 23))
assert f == 0
def test_mac_style_lineendings():
s = '"abc" #def\r #ghi\rfrom __future__ import (division as b,
generators,)\rfrom __future__ import with_statement\r'
- f = run(s)
+ f = run(s, (4, 23))
assert f == 0
def test_semicolon():
s = '"abc" #def\n #ghi\nfrom __future__ import (division as b,
generators,); from __future__ import with_statement\n'
- f = run(s)
+ f = run(s, (3, 78))
assert f == 0
def test_semicolon_2():
s = 'from __future__ import division; from foo import bar'
- f = run(s, expected_last_future=(1, 39))
+ f = run(s, expected_last_future=(1, 24))
assert f == 0
def test_full_chain():
s = '"abc" #def\n #ghi\nfrom __future__ import (division as b,
generators,); from __future__ import with_statement\n'
- f = run(s)
+ f = run(s, (3, 78))
assert f == 0
def test_intervening_code():
s = 'from __future__ import (division as b, generators,)\nfrom sys import
modules\nfrom __future__ import with_statement\n'
- f = run(s, expected_last_future=(2, 5))
+ f = run(s, expected_last_future=(1, 25))
assert f == 0
def test_nonexisting():
s = 'from __future__ import non_existing_feature\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_nonexisting_2():
s = 'from __future__ import non_existing_feature, with_statement\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_from_import_abs_import():
s = 'from __future__ import absolute_import\n'
- f = run(s)
+ f = run(s, (1, 24))
assert f == 0
def test_raw_doc():
s = 'r"Doc"\nfrom __future__ import with_statement\n'
- f = run(s)
+ f = run(s, (2, 23))
assert f == 0
def test_unicode_doc():
s = 'u"Doc"\nfrom __future__ import with_statement\n'
- f = run(s)
+ f = run(s, (2, 23))
assert f == 0
def test_raw_unicode_doc():
s = 'ru"Doc"\nfrom __future__ import with_statement\n'
- f = run(s)
+ f = run(s, (2, 23))
assert f == 0
def test_continuation_line():
s = "\\\nfrom __future__ import with_statement\n"
- f = run(s)
+ f = run(s, (2, 23))
assert f == 0
def test_continuation_lines():
s = "\\\n \t\\\nfrom __future__ import with_statement\n"
- f = run(s)
+ f = run(s, (3, 23))
assert f == 0
def test_lots_of_continuation_lines():
s = "\\\n\\\n\\\n\\\n\\\n\\\n\nfrom __future__ import with_statement\n"
- f = run(s)
+ f = run(s, (8, 23))
assert f == 0
def test_continuation_lines_raise():
s = " \\\n \t\\\nfrom __future__ import with_statement\n"
- f = run(s, expected_last_future=(1, 0))
+ f = run(s)
assert f == 0 # because of the INDENT
def test_continuation_lines_in_docstring_single_quoted():
s = '"\\\n\\\n\\\n\\\n\\\n\\\n"\nfrom __future__ import division\n'
- f = run(s)
+ f = run(s, (8, 24))
assert f == 0
def test_continuation_lines_in_docstring_triple_quoted():
s = '"""\\\n\\\n\\\n\\\n\\\n\\\n"""\nfrom __future__ import division\n'
- f = run(s)
+ f = run(s, (8, 24))
assert f == 0
def test_blank_lines():
s = ('\n\t\n\nfrom __future__ import with_statement'
' \n \n \nfrom __future__ import division')
- f = run(s)
+ f = run(s, (7, 23))
assert f == 0
def test_dummy_semicolons():
s = ('from __future__ import division;\n'
'from __future__ import with_statement;')
- f = run(s)
+ f = run(s, (2, 23))
assert f == 0
diff --git a/pypy/interpreter/test/test_syntax.py
b/pypy/interpreter/test/test_syntax.py
--- a/pypy/interpreter/test/test_syntax.py
+++ b/pypy/interpreter/test/test_syntax.py
@@ -308,6 +308,15 @@
assert isinstance(ns["c"], bytes)
assert isinstance(ns["d"], bytes)
+ def test_both_futures_with_semicolon(self):
+ # Issue #2526: a corner case which crashes only if the file
+ # contains *nothing more* than two __future__ imports separated
+ # by a semicolon.
+ s = """
+from __future__ import unicode_literals; from __future__ import print_function
+"""
+ exec s in {}
+
class AppTestComprehensions:
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
@@ -6,6 +6,8 @@
class BuildersModule(MixedModule):
+ """ Module containing string and unicode builders """
+
appleveldefs = {}
interpleveldefs = {
@@ -34,6 +36,8 @@
class IntOpModule(MixedModule):
+ """ Module for integer operations that have two-complement overflow
+ behaviour instead of overflowing to longs """
appleveldefs = {}
interpleveldefs = {
'int_add': 'interp_intop.int_add',
@@ -55,6 +59,8 @@
class Module(MixedModule):
+ """ PyPy specific "magic" functions. A lot of them are experimental and
+ subject to change, many are internal. """
appleveldefs = {
}
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
@@ -106,13 +106,15 @@
raise wrap_oserror(space, e)
@unwrap_spec(sizehint=int)
-def resizelist_hint(space, w_iterable, sizehint):
- if not isinstance(w_iterable, W_ListObject):
+def resizelist_hint(space, w_list, sizehint):
+ """ Reallocate the underlying storage of the argument list to sizehint """
+ if not isinstance(w_list, W_ListObject):
raise oefmt(space.w_TypeError, "arg 1 must be a 'list'")
- w_iterable._resize_hint(sizehint)
+ w_list._resize_hint(sizehint)
@unwrap_spec(sizehint=int)
def newlist_hint(space, sizehint):
+ """ Create a new empty list that has an underlying storage of length
sizehint """
return space.newlist_hint(sizehint)
@unwrap_spec(debug=int)
@@ -125,6 +127,9 @@
@unwrap_spec(estimate=int)
def add_memory_pressure(estimate):
+ """ Add memory pressure of estimate bytes. Useful when calling a C function
+ that internally allocates a big chunk of memory. This instructs the GC to
+ garbage collect sooner than it would otherwise."""
rgc.add_memory_pressure(estimate)
@unwrap_spec(w_frame=PyFrame)
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
@@ -1471,8 +1471,13 @@
with self.StdErrCapture(fd=True) as f:
res = lib.bar(4, 5)
assert res == 0
- assert f.getvalue() == (
+ assert f.getvalue() in (
+ # If the underlying cffi is <= 1.9
"extern \"Python\": function bar() called, but no code was
attached "
+ "to it yet with @ffi.def_extern(). Returning 0.\n",
+ # If the underlying cffi is >= 1.10
+ "extern \"Python\": function _CFFI_test_extern_python_1.bar() "
+ "called, but no code was attached "
"to it yet with @ffi.def_extern(). Returning 0.\n")
@ffi.def_extern("bar")
diff --git a/pypy/module/_multiprocessing/interp_win32.py
b/pypy/module/_multiprocessing/interp_win32.py
--- a/pypy/module/_multiprocessing/interp_win32.py
+++ b/pypy/module/_multiprocessing/interp_win32.py
@@ -4,10 +4,9 @@
from rpython.rtyper.tool import rffi_platform
from rpython.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.interpreter.error import oefmt, wrap_windowserror
+from pypy.interpreter.error import oefmt, wrap_oserror
from pypy.interpreter.function import StaticMethod
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.module._multiprocessing.interp_connection import w_handle
CONSTANTS = """
PIPE_ACCESS_INBOUND PIPE_ACCESS_DUPLEX
@@ -35,6 +34,9 @@
def handle_w(space, w_handle):
return rffi.cast(rwin32.HANDLE, space.int_w(w_handle))
+def w_handle(space, handle):
+ return space.newint(rffi.cast(rffi.INTPTR_T, handle))
+
_CreateNamedPipe = rwin32.winexternal(
'CreateNamedPipeA', [
rwin32.LPCSTR,
@@ -106,7 +108,7 @@
def CloseHandle(space, w_handle):
handle = handle_w(space, w_handle)
if not rwin32.CloseHandle(handle):
- raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+ raise wrap_oserror(space, rwin32.lastSavedWindowsError())
def GetLastError(space):
return space.newint(rwin32.GetLastError_saved())
@@ -126,7 +128,7 @@
outputsize, inputsize, timeout, rffi.NULL)
if handle == rwin32.INVALID_HANDLE_VALUE:
- raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+ raise wrap_oserror(space, rwin32.lastSavedWindowsError())
return w_handle(space, handle)
@@ -136,7 +138,7 @@
if overlapped:
raise oefmt(space.w_NotImplementedError, "expected a NULL pointer")
if not _ConnectNamedPipe(handle, rffi.NULL):
- raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+ raise wrap_oserror(space, rwin32.lastSavedWindowsError())
def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances,
w_timeout):
@@ -156,7 +158,7 @@
statep[2] = rffi.ptradd(state, 2)
if not _SetNamedPipeHandleState(handle, statep[0], statep[1],
statep[2]):
- raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+ raise wrap_oserror(space, rwin32.lastSavedWindowsError())
finally:
lltype.free(state, flavor='raw')
lltype.free(statep, flavor='raw')
@@ -165,7 +167,7 @@
def WaitNamedPipe(space, name, timeout):
# Careful: zero means "default value specified by CreateNamedPipe()"
if not _WaitNamedPipe(name, timeout):
- raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+ raise wrap_oserror(space, rwin32.lastSavedWindowsError())
@unwrap_spec(filename='fsencode', access=r_uint, share=r_uint,
disposition=r_uint, flags=r_uint)
@@ -180,7 +182,7 @@
disposition, flags, rwin32.NULL_HANDLE)
if handle == rwin32.INVALID_HANDLE_VALUE:
- raise wrap_windowserror(space, rwin32.lastSavedWindowsError())
+ raise wrap_oserror(space, rwin32.lastSavedWindowsError())
return w_handle(space, handle)
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
@@ -50,8 +50,8 @@
return OperationError(w_VMProfError, space.newtext(e.msg))
-@unwrap_spec(fileno=int, period=float)
-def enable(space, fileno, period):
+@unwrap_spec(fileno=int, period=float, memory=int, lines=int, native=int)
+def enable(space, fileno, period, memory, lines, native):
"""Enable vmprof. Writes go to the given 'fileno', a file descriptor
opened for writing. *The file descriptor must remain open at least
until disable() is called.*
@@ -65,7 +65,7 @@
# "with vmprof will crash"),
# space.w_RuntimeWarning)
try:
- rvmprof.enable(fileno, period)
+ rvmprof.enable(fileno, period, memory, native)
except rvmprof.VMProfError as e:
raise VMProfError(space, e)
diff --git a/pypy/module/_vmprof/test/test__vmprof.py
b/pypy/module/_vmprof/test/test__vmprof.py
--- a/pypy/module/_vmprof/test/test__vmprof.py
+++ b/pypy/module/_vmprof/test/test__vmprof.py
@@ -24,10 +24,11 @@
i += 5 * WORD # header
assert s[i ] == 5 # MARKER_HEADER
assert s[i + 1] == 0 # 0
- assert s[i + 2] == 2 # VERSION_THREAD_ID
- assert s[i + 3] == 4 # len('pypy')
- assert s[i + 4: i + 8] == b'pypy'
- i += 8
+ assert s[i + 2] == 6 # VERSION_TIMESTAMP
+ assert s[i + 3] == 8 # PROFILE_RPYTHON
+ assert s[i + 4] == 4 # len('pypy')
+ assert s[i + 5: i + 9] == b'pypy'
+ i += 9
while i < len(s):
if s[i] == 3:
break
@@ -41,6 +42,17 @@
_, size = struct.unpack("ll", s[i:i + 2 * WORD])
count += 1
i += 2 * WORD + size
+ elif s[i] == '\x06':
+ print(s[i:i+24])
+ i += 1+8+8+8
+ elif s[i] == '\x07':
+ i += 1
+ # skip string
+ size, = struct.unpack("l", s[i:i + WORD])
+ i += WORD+size
+ # skip string
+ size, = struct.unpack("l", s[i:i + WORD])
+ i += WORD+size
else:
raise AssertionError(s[i])
return count
@@ -48,7 +60,7 @@
import _vmprof
gc.collect() # try to make the weakref list deterministic
gc.collect() # by freeing all dead code objects
- _vmprof.enable(tmpfileno, 0.01)
+ _vmprof.enable(tmpfileno, 0.01, 0, 0, 0)
_vmprof.disable()
s = open(self.tmpfilename, 'rb').read()
no_of_codes = count(s)
@@ -64,7 +76,7 @@
gc.collect()
gc.collect()
- _vmprof.enable(tmpfileno2, 0.01)
+ _vmprof.enable(tmpfileno2, 0.01, 0, 0, 0)
exec_("""def foo2():
pass
@@ -79,9 +91,9 @@
def test_enable_ovf(self):
import _vmprof
- raises(_vmprof.VMProfError, _vmprof.enable, 2, 0)
- raises(_vmprof.VMProfError, _vmprof.enable, 2, -2.5)
- raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300)
- raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300 * 1e300)
+ raises(_vmprof.VMProfError, _vmprof.enable, 2, 0, 0, 0, 0)
+ raises(_vmprof.VMProfError, _vmprof.enable, 2, -2.5, 0, 0, 0)
+ raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300, 0, 0, 0)
+ raises(_vmprof.VMProfError, _vmprof.enable, 2, 1e300 * 1e300, 0, 0, 0)
NaN = (1e300*1e300) / (1e300*1e300)
- raises(_vmprof.VMProfError, _vmprof.enable, 2, NaN)
+ raises(_vmprof.VMProfError, _vmprof.enable, 2, NaN, 0, 0, 0)
diff --git a/pypy/module/_vmprof/test/test_direct.py
b/pypy/module/_vmprof/test/test_direct.py
--- a/pypy/module/_vmprof/test/test_direct.py
+++ b/pypy/module/_vmprof/test/test_direct.py
@@ -43,7 +43,7 @@
}
-""" + open(str(srcdir.join("vmprof_get_custom_offset.h"))).read(),
include_dirs=[str(srcdir)])
+""" + open(str(srcdir.join("shared/vmprof_get_custom_offset.h"))).read(),
include_dirs=[str(srcdir)])
class TestDirect(object):
def test_infrastructure(self):
diff --git a/pypy/module/_winreg/interp_winreg.py
b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -2,7 +2,7 @@
from pypy.interpreter.baseobjspace import W_Root, BufferInterfaceNotFound
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.interpreter.error import OperationError, oefmt, wrap_windowserror
+from pypy.interpreter.error import OperationError, oefmt, wrap_oserror
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib import rwinreg, rwin32
from rpython.rlib.rarithmetic import r_uint, intmask
@@ -110,7 +110,7 @@
elif isinstance(w_hkey, W_HKEY):
return w_hkey.hkey
elif space.isinstance_w(w_hkey, space.w_int):
- if space.is_true(space.lt(w_hkey, space.wrap(0))):
+ if space.is_true(space.lt(w_hkey, space.newint(0))):
return rffi.cast(rwinreg.HKEY, space.int_w(w_hkey))
return rffi.cast(rwinreg.HKEY, space.uint_w(w_hkey))
else:
@@ -702,7 +702,7 @@
try:
return space.newunicode(rwinreg.ExpandEnvironmentStrings(source))
except WindowsError as e:
- raise wrap_windowserror(space, e)
+ raise wrap_oserror(space, e)
def DisableReflectionKey(space, w_key):
"""Disables registry reflection for 32-bit processes running on a 64-bit
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -4,7 +4,6 @@
class Module(MixedModule):
interpleveldefs = {
- 'load_module': 'api.load_extension_module',
}
appleveldefs = {
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -565,7 +565,7 @@
'PyUnicode_FromFormat', 'PyUnicode_FromFormatV',
'PyUnicode_AsWideCharString',
'PyUnicode_GetSize', 'PyUnicode_GetLength',
'PyModule_AddObject', 'PyModule_AddIntConstant',
'PyModule_AddStringConstant',
- 'PyModule_GetDef',
+ 'PyModule_GetDef', 'PyModuleDef_Init',
'Py_BuildValue', 'Py_VaBuildValue', 'PyTuple_Pack',
'_PyArg_Parse_SizeT', '_PyArg_ParseTuple_SizeT',
'_PyArg_ParseTupleAndKeywords_SizeT', '_PyArg_VaParse_SizeT',
@@ -651,7 +651,7 @@
global all_exceptions
all_exceptions = list(exceptions.Module.interpleveldefs)
for exc_name in all_exceptions:
- if exc_name in ('EnvironmentError', 'IOError'):
+ if exc_name in ('EnvironmentError', 'IOError', 'WindowsError'):
# FIXME: aliases of OSError cause a clash of names via
# export_struct
continue
@@ -1489,8 +1489,7 @@
copy_header_files(cts, trunk_include, use_micronumpy)
-@unwrap_spec(path='fsencode', name='text')
-def load_extension_module(space, path, name):
+def create_extension_module(space, w_spec):
# note: this is used both to load CPython-API-style C extension
# modules (cpyext) and to load CFFI-style extension modules
# (_cffi_backend). Any of the two can be disabled at translation
@@ -1498,6 +1497,9 @@
# order of things here.
from rpython.rlib import rdynload
+ name = space.text_w(space.getattr(w_spec, space.newtext("name")))
+ path = space.text_w(space.getattr(w_spec, space.newtext("origin")))
+
if os.sep not in path:
path = os.curdir + os.sep + path # force a '/' in the path
basename = name.split('.')[-1]
@@ -1535,7 +1537,7 @@
except KeyError:
pass
else:
- return load_cpyext_module(space, name, path, dll, initptr)
+ return create_cpyext_module(space, w_spec, name, path, dll,
initptr)
if look_for is not None:
look_for += ' or ' + also_look_for
else:
@@ -1549,8 +1551,9 @@
initfunctype = lltype.Ptr(lltype.FuncType([], PyObject))
-def load_cpyext_module(space, name, path, dll, initptr):
+def create_cpyext_module(space, w_spec, name, path, dll, initptr):
from rpython.rlib import rdynload
+ from pypy.module.cpyext.pyobject import get_w_obj_and_decref
space.getbuiltinmodule("cpyext") # mandatory to init cpyext
state = space.fromcache(State)
@@ -1562,25 +1565,54 @@
state.package_context = name, path
try:
initfunc = rffi.cast(initfunctype, initptr)
- w_mod = generic_cpy_call(space, initfunc)
+ initret = generic_cpy_call_dont_convert_result(space, initfunc)
state.check_and_raise_exception()
+ if not initret.c_ob_type:
+ raise oefmt(space.w_SystemError,
+ "init function of %s returned uninitialized object",
+ name)
+ # This should probably compare by identity with PyModuleDef_Type from
+ # modsupport.c, but I didn't find a way to do that.
+ tp_name_nonconst = rffi.cast(rffi.CCHARP, initret.c_ob_type.c_tp_name)
+ if rffi.charp2str(tp_name_nonconst) == "moduledef":
+ from pypy.module.cpyext.modsupport import \
+ create_module_from_def_and_spec
+ return create_module_from_def_and_spec(space, initret, w_spec,
+ name)
finally:
state.package_context = old_context
+ w_mod = get_w_obj_and_decref(space, initret)
state.fixup_extension(w_mod, name, path)
return w_mod
+def exec_extension_module(space, w_mod):
+ from pypy.module.cpyext.modsupport import exec_def
+ if not space.config.objspace.usemodules.cpyext:
+ return
+ if not isinstance(w_mod, Module):
+ return
+ space.getbuiltinmodule("cpyext")
+ mod_as_pyobj = rawrefcount.from_obj(PyObject, w_mod)
+ if mod_as_pyobj:
+ return exec_def(space, w_mod, mod_as_pyobj)
+
@specialize.ll()
def generic_cpy_call(space, func, *args):
FT = lltype.typeOf(func).TO
- return make_generic_cpy_call(FT, False)(space, func, *args)
+ return make_generic_cpy_call(FT, False, True)(space, func, *args)
@specialize.ll()
def generic_cpy_call_expect_null(space, func, *args):
FT = lltype.typeOf(func).TO
- return make_generic_cpy_call(FT, True)(space, func, *args)
+ return make_generic_cpy_call(FT, True, True)(space, func, *args)
+
[email protected]()
+def generic_cpy_call_dont_convert_result(space, func, *args):
+ FT = lltype.typeOf(func).TO
+ return make_generic_cpy_call(FT, False, False)(space, func, *args)
@specialize.memo()
-def make_generic_cpy_call(FT, expect_null):
+def make_generic_cpy_call(FT, expect_null, convert_result):
from pypy.module.cpyext.pyobject import make_ref, from_ref
from pypy.module.cpyext.pyobject import is_pyobj, as_pyobj
from pypy.module.cpyext.pyobject import get_w_obj_and_decref
@@ -1634,8 +1666,9 @@
keepalive_until_here(*keepalives)
if is_PyObject(RESULT_TYPE):
- if not is_pyobj(result):
+ if not convert_result or not is_pyobj(result):
ret = result
+ has_result = bool(ret)
else:
# The object reference returned from a C function
# that is called from Python must be an owned reference
@@ -1644,10 +1677,10 @@
ret = get_w_obj_and_decref(space, result)
else:
ret = None
+ has_result = ret is not None
# Check for exception consistency
has_error = PyErr_Occurred(space) is not None
- has_result = ret is not None
if has_error and has_result:
raise oefmt(space.w_SystemError,
"An exception was set, but function returned a "
diff --git a/pypy/module/cpyext/include/modsupport.h
b/pypy/module/cpyext/include/modsupport.h
--- a/pypy/module/cpyext/include/modsupport.h
+++ b/pypy/module/cpyext/include/modsupport.h
@@ -87,9 +87,9 @@
#ifdef _WIN32
/* explicitly export since PyAPI_FUNC is usually dllimport */
#ifdef __cplusplus
-#define PyMODINIT_FUNC extern "C" __declspec(dllexport) void
+#define PyMODINIT_FUNC extern "C" __declspec(dllexport) PyObject*
#else
-#define PyMODINIT_FUNC __declspec(dllexport) void
+#define PyMODINIT_FUNC __declspec(dllexport) PyObject*
#endif
#else
#ifdef __cplusplus
diff --git a/pypy/module/cpyext/include/moduleobject.h
b/pypy/module/cpyext/include/moduleobject.h
--- a/pypy/module/cpyext/include/moduleobject.h
+++ b/pypy/module/cpyext/include/moduleobject.h
@@ -8,6 +8,8 @@
#include "cpyext_moduleobject.h"
+PyAPI_FUNC(PyObject *) PyModuleDef_Init(struct PyModuleDef*);
+
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/modsupport.py b/pypy/module/cpyext/modsupport.py
--- a/pypy/module/cpyext/modsupport.py
+++ b/pypy/module/cpyext/modsupport.py
@@ -1,7 +1,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, METH_STATIC, METH_CLASS, METH_COEXIST, CANNOT_FAIL, cts,
- parse_dir, bootstrap_function)
+ parse_dir, bootstrap_function, generic_cpy_call)
from pypy.module.cpyext.pyobject import PyObject, as_pyobj, make_typedescr
from pypy.interpreter.module import Module
from pypy.module.cpyext.methodobject import (
@@ -14,6 +14,7 @@
cts.parse_header(parse_dir / 'cpyext_moduleobject.h')
PyModuleDef = cts.gettype('PyModuleDef *')
PyModuleObject = cts.gettype('PyModuleObject *')
+PyModuleDef_Slot = cts.gettype('PyModuleDef_Slot')
@bootstrap_function
def init_moduleobject(space):
@@ -64,6 +65,89 @@
return w_mod
+createfunctype = lltype.Ptr(lltype.FuncType([PyObject, PyModuleDef], PyObject))
+execfunctype = lltype.Ptr(lltype.FuncType([PyObject], rffi.INT_real))
+
+
+def create_module_from_def_and_spec(space, moddef, w_spec, name):
+ moddef = rffi.cast(PyModuleDef, moddef)
+ if moddef.c_m_size < 0:
+ raise oefmt(space.w_SystemError,
+ "module %s: m_size may not be negative for multi-phase "
+ "initialization", name)
+ createf = lltype.nullptr(rffi.VOIDP.TO)
+ has_execution_slots = False
+ cur_slot = rffi.cast(rffi.CArrayPtr(PyModuleDef_Slot), moddef.c_m_slots)
+ if cur_slot:
+ while True:
+ slot = rffi.cast(lltype.Signed, cur_slot[0].c_slot)
+ if slot == 0:
+ break
+ elif slot == 1:
+ if createf:
+ raise oefmt(space.w_SystemError,
+ "module %s has multiple create slots", name)
+ createf = cur_slot[0].c_value
+ elif slot < 0 or slot > 2:
+ raise oefmt(space.w_SystemError,
+ "module %s uses unknown slot ID %d", name, slot)
+ else:
+ has_execution_slots = True
+ cur_slot = rffi.ptradd(cur_slot, 1)
+ if createf:
+ createf = rffi.cast(createfunctype, createf)
+ w_mod = generic_cpy_call(space, createf, w_spec, moddef)
+ else:
+ w_mod = Module(space, space.newtext(name))
+ if isinstance(w_mod, Module):
+ mod = rffi.cast(PyModuleObject, as_pyobj(space, w_mod))
+ #mod.c_md_state = None
+ mod.c_md_def = moddef
+ else:
+ if moddef.c_m_size > 0 or moddef.c_m_traverse or moddef.c_m_clear or \
+ moddef.c_m_free:
+ raise oefmt(space.w_SystemError,
+ "module %s is not a module object, but requests "
+ "module state", name)
+ if has_execution_slots:
+ raise oefmt(space.w_SystemError,
+ "module %s specifies execution slots, but did not "
+ "create a ModuleType instance", name)
+ dict_w = {}
+ convert_method_defs(space, dict_w, moddef.c_m_methods, None, w_mod, name)
+ for key, w_value in dict_w.items():
+ space.setattr(w_mod, space.newtext(key), w_value)
+ if moddef.c_m_doc:
+ doc = rffi.charp2str(rffi.cast(rffi.CCHARP, moddef.c_m_doc))
+ space.setattr(w_mod, space.newtext('__doc__'), space.newtext(doc))
+ return w_mod
+
+
+def exec_def(space, w_mod, mod_as_pyobj):
+ from pypy.module.cpyext.pyerrors import PyErr_Occurred
+ mod = rffi.cast(PyModuleObject, mod_as_pyobj)
+ moddef = mod.c_md_def
+ cur_slot = rffi.cast(rffi.CArrayPtr(PyModuleDef_Slot), moddef.c_m_slots)
+ while cur_slot and rffi.cast(lltype.Signed, cur_slot[0].c_slot):
+ if rffi.cast(lltype.Signed, cur_slot[0].c_slot) == 2:
+ execf = rffi.cast(execfunctype, cur_slot[0].c_value)
+ res = generic_cpy_call(space, execf, w_mod)
+ has_error = PyErr_Occurred(space) is not None
+ if rffi.cast(lltype.Signed, res):
+ if has_error:
+ state = space.fromcache(State)
+ state.check_and_raise_exception()
+ else:
+ raise oefmt(space.w_SystemError,
+ "execution of module %S failed without "
+ "setting an exception", w_mod.w_name)
+ if has_error:
+ raise oefmt(space.w_SystemError,
+ "execution of module %S raised unreported "
+ "exception", w_mod.w_name)
+ cur_slot = rffi.ptradd(cur_slot, 1)
+
+
def convert_method_defs(space, dict_w, methods, w_type, w_self=None,
name=None):
w_name = space.newtext_or_none(name)
methods = rffi.cast(rffi.CArrayPtr(PyMethodDef), methods)
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -4,10 +4,10 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib.rarithmetic import widen
-from rpython.rlib import rgc # Force registration of gc.collect
+from rpython.rlib import rgc # Force registration of gc.collect
from pypy.module.cpyext.api import (
slot_function, generic_cpy_call, PyObject, Py_ssize_t,
- pypy_decl, Py_buffer, Py_bufferP, PyTypeObjectPtr, cts)
+ Py_buffer, Py_bufferP, PyTypeObjectPtr, cts)
from pypy.module.cpyext.typeobjectdefs import (
unaryfunc, ternaryfunc, binaryfunc,
getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
@@ -794,6 +794,16 @@
return 0
return buff_w
+missing_wrappers = ['wrap_indexargfunc', 'wrap_del']
+for name in missing_wrappers:
+ assert name not in globals()
+ def missing_wrapper(space, w_self, w_args, func):
+ print "cpyext: missing slot wrapper " + name
+ raise NotImplementedError("Slot wrapper " + name)
+ missing_wrapper.__name__ = name
+ globals()[name] = missing_wrapper
+
+
PyWrapperFlag_KEYWORDS = 1
class TypeSlot:
@@ -811,7 +821,7 @@
if WRAPPER is None:
wrapper = None
else:
- wrapper = globals().get(WRAPPER, Ellipsis)
+ wrapper = globals()[WRAPPER]
# irregular interface, because of tp_getattr/tp_getattro confusion
if NAME == "__getattr__":
@@ -825,17 +835,9 @@
function = getattr(userslot, FUNCTION or '!missing', None)
assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
if FLAGS:
- if wrapper is Ellipsis:
- @func_renamer(WRAPPER)
- def wrapper(space, w_self, w_args, func, w_kwds):
- raise NotImplementedError("Wrapper for slot " + NAME)
wrapper1 = None
wrapper2 = wrapper
else:
- if wrapper is Ellipsis:
- @func_renamer(WRAPPER)
- def wrapper(space, w_self, w_args, func):
- raise NotImplementedError("Wrapper for slot " + NAME)
wrapper1 = wrapper
wrapper2 = None
return TypeSlot(NAME, SLOT, function, wrapper1, wrapper2, DOC)
diff --git a/pypy/module/cpyext/src/modsupport.c
b/pypy/module/cpyext/src/modsupport.c
--- a/pypy/module/cpyext/src/modsupport.c
+++ b/pypy/module/cpyext/src/modsupport.c
@@ -602,3 +602,26 @@
}
return ((PyModuleObject *)m)->md_def;
}
+
+PyTypeObject PyModuleDef_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "moduledef", /* tp_name */
+ sizeof(struct PyModuleDef), /* tp_size */
+ 0, /* tp_itemsize */
+};
+
+static Py_ssize_t max_module_number;
+
+PyObject*
+PyModuleDef_Init(struct PyModuleDef* def)
+{
+ if (PyType_Ready(&PyModuleDef_Type) < 0)
+ return NULL;
+ if (def->m_base.m_index == 0) {
+ max_module_number++;
+ Py_REFCNT(def) = 1;
+ Py_TYPE(def) = &PyModuleDef_Type;
+ def->m_base.m_index = max_module_number;
+ }
+ return (PyObject*)def;
+}
diff --git a/pypy/module/cpyext/test/buffer_test.c
b/pypy/module/cpyext/test/buffer_test.c
--- a/pypy/module/cpyext/test/buffer_test.c
+++ b/pypy/module/cpyext/test/buffer_test.c
@@ -344,7 +344,6 @@
#endif
if (m == NULL)
INITERROR;
- PyMyArrayType.tp_new = PyType_GenericNew;
if (PyType_Ready(&PyMyArrayType) < 0)
INITERROR;
Py_INCREF(&PyMyArrayType);
diff --git a/pypy/module/cpyext/test/comparisons.c
b/pypy/module/cpyext/test/comparisons.c
--- a/pypy/module/cpyext/test/comparisons.c
+++ b/pypy/module/cpyext/test/comparisons.c
@@ -68,7 +68,7 @@
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
- 0, /* tp_new */
+ PyType_GenericNew, /* tp_new */
0 /* tp_free */
};
@@ -87,7 +87,6 @@
{
PyObject *m, *d;
- CmpType.tp_new = PyType_GenericNew;
if (PyType_Ready(&CmpType) < 0)
return NULL;
m = PyModule_Create(&moduledef);
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -36,14 +36,14 @@
Py_ssize_t foo_ssizet;
} fooobject;
-static PyTypeObject footype;
+static PyTypeObject fooType;
static fooobject *
newfooobject(void)
{
fooobject *foop;
- foop = PyObject_New(fooobject, &footype);
+ foop = PyObject_New(fooobject, &fooType);
if (foop == NULL)
return NULL;
@@ -160,6 +160,28 @@
return PyObject_GenericSetAttr((PyObject *)self, name, value);
}
+static PyObject *
+new_fooType(PyTypeObject * t, PyObject *args, PyObject *kwds)
+{
+ PyObject * o;
+ /* copied from numpy scalartypes.c for inherited classes */
+ if (t->tp_bases && (PyTuple_GET_SIZE(t->tp_bases) > 1))
+ {
+ PyTypeObject *sup;
+ /* We are inheriting from a Python type as well so
+ give it first dibs on conversion */
+ sup = (PyTypeObject *)PyTuple_GET_ITEM(t->tp_bases, 1);
+ /* Prevent recursion */
+ if (new_fooType != sup->tp_new)
+ {
+ o = sup->tp_new(t, args, kwds);
+ return o;
+ }
+ }
+ o = t->tp_alloc(t, 0);
+ return o;
+};
+
static PyMemberDef foo_members[] = {
{"int_member", T_INT, offsetof(fooobject, foo), 0,
"A helpful docstring."},
@@ -194,7 +216,7 @@
PyDoc_STRVAR(foo_doc, "foo is for testing.");
-static PyTypeObject footype = {
+static PyTypeObject fooType = {
PyVarObject_HEAD_INIT(NULL, 0)
"foo.foo", /*tp_name*/
sizeof(fooobject), /*tp_size*/
@@ -592,7 +614,7 @@
0, /*tp_init*/
0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/
- 0, /*tp_new*/
+ PyType_GenericNew, /*tp_new*/
0, /*tp_free Low-level free-memory routine */
0, /*tp_is_gc For PyObject_IS_GC */
0, /*tp_bases*/
@@ -648,6 +670,37 @@
return PyInt_FromLong(tf);
}
+static PyTypeObject GetType1 = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "foo.GetType1", /*tp_name*/
+ sizeof(PyObject), /*tp_size*/
+};
+static PyTypeObject GetType2 = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "foo.GetType2", /*tp_name*/
+ sizeof(PyObject), /*tp_size*/
+};
+static PyObject *gettype1, *gettype2;
+
+static PyObject *gettype1_getattr(PyObject *self, char *name)
+{
+ char buf[200];
+ strcpy(buf, "getattr:");
+ strcat(buf, name);
+ return PyBytes_FromString(buf);
+}
+static PyObject *gettype2_getattro(PyObject *self, PyObject *name)
+{
+ char buf[200];
+ PyObject* temp;
+ temp = PyUnicode_AsASCIIString(name);
+ if (temp == NULL) return NULL;
+ strcpy(buf, "getattro:");
+ strcat(buf, PyBytes_AS_STRING(temp));
+ return PyBytes_FromString(buf);
+}
+
+
/* List of functions exported by this module */
static PyMethodDef foo_functions[] = {
@@ -706,13 +759,14 @@
if (module == NULL)
INITERROR;
- footype.tp_new = PyType_GenericNew;
-
UnicodeSubtype.tp_base = &PyUnicode_Type;
UnicodeSubtype2.tp_base = &UnicodeSubtype;
MetaType.tp_base = &PyType_Type;
- if (PyType_Ready(&footype) < 0)
+ fooType.tp_new = &new_fooType;
+ InitErrType.tp_new = PyType_GenericNew;
+
+ if (PyType_Ready(&fooType) < 0)
INITERROR;
if (PyType_Ready(&UnicodeSubtype) < 0)
INITERROR;
@@ -725,8 +779,6 @@
if (PyType_Ready(&SimplePropertyType) < 0)
INITERROR;
- SimplePropertyType.tp_new = PyType_GenericNew;
- InitErrType.tp_new = PyType_GenericNew;
Py_TYPE(&CustomType) = &MetaType;
if (PyType_Ready(&CustomType) < 0)
@@ -744,11 +796,23 @@
if (PyType_Ready(&TupleLike) < 0)
INITERROR;
+ GetType1.tp_flags = Py_TPFLAGS_DEFAULT;
+ GetType1.tp_getattr = &gettype1_getattr;
+ if (PyType_Ready(&GetType1) < 0)
+ INITERROR;
+ gettype1 = PyObject_New(PyObject, &GetType1);
+
+ GetType2.tp_flags = Py_TPFLAGS_DEFAULT;
+ GetType2.tp_getattro = &gettype2_getattro;
+ if (PyType_Ready(&GetType2) < 0)
+ INITERROR;
+ gettype2 = PyObject_New(PyObject, &GetType2);
+
d = PyModule_GetDict(module);
if (d == NULL)
INITERROR;
- if (PyDict_SetItemString(d, "fooType", (PyObject *)&footype) < 0)
+ if (PyDict_SetItemString(d, "fooType", (PyObject *)&fooType) < 0)
INITERROR;
if (PyDict_SetItemString(d, "UnicodeSubtype", (PyObject *)
&UnicodeSubtype) < 0)
INITERROR;
@@ -766,6 +830,10 @@
INITERROR;
if (PyDict_SetItemString(d, "TupleLike", (PyObject *) &TupleLike) < 0)
INITERROR;
+ if (PyDict_SetItemString(d, "gettype1", gettype1) < 0)
+ INITERROR;
+ if (PyDict_SetItemString(d, "gettype2", gettype2) < 0)
+ INITERROR;
#if PY_MAJOR_VERSION >=3
return module;
#endif
diff --git a/pypy/module/cpyext/test/multiphase.c
b/pypy/module/cpyext/test/multiphase.c
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/multiphase.c
@@ -0,0 +1,28 @@
+#include "Python.h"
+
+static struct PyModuleDef multiphase_def;
+
+static PyObject *check_getdef_same(PyObject *self, PyObject *args) {
+ return PyBool_FromLong(PyModule_GetDef(self) == &multiphase_def);
+}
+
+static PyMethodDef methods[] = {
+ {"check_getdef_same", check_getdef_same, METH_NOARGS},
+ {NULL}
+};
+
+static PyModuleDef multiphase_def = {
+ PyModuleDef_HEAD_INIT, /* m_base */
+ "multiphase", /* m_name */
+ "example docstring", /* m_doc */
+ 0, /* m_size */
+ methods, /* m_methods */
+ NULL, /* m_slots */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+PyMODINIT_FUNC PyInit_multiphase(void) {
+ return PyModuleDef_Init(&multiphase_def);
+}
diff --git a/pypy/module/cpyext/test/test_classobject.py
b/pypy/module/cpyext/test/test_classobject.py
--- a/pypy/module/cpyext/test/test_classobject.py
+++ b/pypy/module/cpyext/test/test_classobject.py
@@ -27,15 +27,3 @@
InstanceMethod.testmethod.attribute = "test"
assert testfunction.attribute == "test"
raises(AttributeError, setattr, inst.testmethod, "attribute", "test")
-
- def test_pyclass_new_no_bases(self):
- module = self.import_extension('foo', [
- ("new_foo", "METH_O",
- """
- return PyClass_New(NULL, PyDict_New(), args);
- """)])
- FooClass = module.new_foo("FooClass")
- class Cls1:
- pass
- assert type(FooClass) is type(Cls1)
- assert FooClass.__bases__ == Cls1.__bases__
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
@@ -40,9 +40,11 @@
def load_module(self, mod, name):
space = self.space
- api.load_extension_module(space, mod, name)
- return space.getitem(
- space.sys.get('modules'), space.wrap(name))
+ w_path = space.newtext(mod)
+ w_name = space.newtext(name)
+ return space.appexec([w_name, w_path], '''(name, path):
+ import imp
+ return imp.load_dynamic(name, path)''')
def get_cpyext_info(space):
diff --git a/pypy/module/cpyext/test/test_memoryobject.py
b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -187,6 +187,10 @@
" on too long format string"
finally:
warnings.resetwarnings()
+ # calling get_buffer_info on x creates a memory leak,
+ # which is detected as an error at test teardown:
+ # Exception TypeError: "'NoneType' object is not callable"
+ # in <bound method ConcreteArray.__del__ ...> ignored
def test_releasebuffer(self):
if not self.runappdirect:
diff --git a/pypy/module/cpyext/test/test_module.py
b/pypy/module/cpyext/test/test_module.py
--- a/pypy/module/cpyext/test/test_module.py
+++ b/pypy/module/cpyext/test/test_module.py
@@ -25,12 +25,85 @@
module = self.import_extension('foo', [
("check_getdef_same", "METH_NOARGS",
"""
- return PyBool_FromLong(PyModule_GetDef(mod_global) ==
&moduledef);
+ return PyBool_FromLong(PyModule_GetDef(self) == &moduledef);
"""
)], prologue="""
static struct PyModuleDef moduledef;
- static PyObject *mod_global;
- """, more_init="""
- mod_global = mod;
""")
assert module.check_getdef_same()
+
+
+class AppTestMultiPhase(AppTestCpythonExtensionBase):
+ def test_basic(self):
+ from types import ModuleType
+ module = self.import_module(name='multiphase')
+ assert isinstance(module, ModuleType)
+ assert module.__name__ == 'multiphase'
+ assert module.__doc__ == "example docstring"
+
+ def test_getdef(self):
+ from types import ModuleType
+ module = self.import_module(name='multiphase')
+ assert module.check_getdef_same()
+
+ def test_slots(self):
+ from types import ModuleType
+ body = """
+ static PyModuleDef multiphase_def;
+
+ static PyObject* multiphase_create(PyObject *spec, PyModuleDef *def) {
+ PyObject *module = PyModule_New("altname");
+ PyObject_SetAttrString(module, "create_spec", spec);
+ PyObject_SetAttrString(module, "create_def_eq",
+ PyBool_FromLong(def == &multiphase_def));
+ return module;
+ }
+
+ static int multiphase_exec(PyObject* module) {
+ Py_INCREF(Py_True);
+ PyObject_SetAttrString(module, "exec_called", Py_True);
+ return 0;
+ }
+
+ static PyModuleDef_Slot multiphase_slots[] = {
+ {Py_mod_create, multiphase_create},
+ {Py_mod_exec, multiphase_exec},
+ {0, NULL}
+ };
+
+ static PyModuleDef multiphase_def = {
+ PyModuleDef_HEAD_INIT, /* m_base */
+ "multiphase", /* m_name */
+ "example docstring", /* m_doc */
+ 0, /* m_size */
+ NULL, /* m_methods */
+ multiphase_slots, /* m_slots */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+ };
+ """
+ init = """
+ return PyModuleDef_Init(&multiphase_def);
+ """
+ module = self.import_module(name='multiphase', body=body, init=init)
+ assert module.create_spec
+ assert module.create_spec is module.__spec__
+ assert module.create_def_eq
+ assert module.exec_called
+
+ def test_forget_init(self):
+ from types import ModuleType
+ body = """
+ static PyModuleDef multiphase_def = {
+ PyModuleDef_HEAD_INIT, /* m_base */
+ "multiphase", /* m_name */
+ "example docstring", /* m_doc */
+ 0, /* m_size */
+ };
+ """
+ init = """
+ return (PyObject *) &multiphase_def;
+ """
+ raises(SystemError, self.import_module, name='multiphase', body=body,
+ init=init)
diff --git a/pypy/module/cpyext/test/test_typeobject.py
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -16,12 +16,12 @@
assert 'foo' in sys.modules
assert "copy" in dir(module.fooType)
obj = module.new()
- print(obj.foo)
+ #print(obj.foo)
assert obj.foo == 42
- print("Obj has type", type(obj))
+ #print("Obj has type", type(obj))
assert type(obj) is module.fooType
- print("type of obj has type", type(type(obj)))
- print("type of type of obj has type", type(type(type(obj))))
+ #print("type of obj has type", type(type(obj)))
+ #print("type of type of obj has type", type(type(type(obj))))
assert module.fooType.__doc__ == "foo is for testing."
def test_typeobject_method_descriptor(self):
@@ -949,6 +949,8 @@
pass
class foo(f2, f1):
pass
+
+ x = foo()
assert bar.__base__ is f2
# On cpython, the size changes.
if '__pypy__' in sys.builtin_module_names:
@@ -1159,8 +1161,8 @@
((PyHeapTypeObject*)Base2)->ht_name = dummyname;
((PyHeapTypeObject*)Base12)->ht_name = dummyname;
}
- #endif
- #endif
+ #endif
+ #endif
Base1->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HEAPTYPE;
Base2->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HEAPTYPE;
Base12->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE;
@@ -1198,24 +1200,13 @@
bases = module.foo(C)
assert bases == (A, B)
- def test_multiple_inheritance_old_style_base(self):
- module = self.import_extension('foo', [
- ("foo", "METH_O",
- '''
- PyTypeObject *tp;
- tp = (PyTypeObject*)args;
- Py_INCREF(tp->tp_bases);
- return tp->tp_bases;
- '''
- )])
- # used to segfault after some iterations
- for i in range(11):
- print i
- class A(object):
- pass
- class B:
- pass
- class C(A, B):
- pass
- bases = module.foo(C)
- assert bases == (A, B)
+ def test_getattr_getattro(self):
+ module = self.import_module(name='foo')
+ assert module.gettype2.dcba == b'getattro:dcba'
+ assert (type(module.gettype2).__getattribute__(module.gettype2, 'dcBA')
+ == b'getattro:dcBA')
+ assert module.gettype1.abcd == b'getattr:abcd'
+ # GetType1 objects have a __getattribute__ method, but this
+ # doesn't call tp_getattr at all, also on CPython
+ raises(AttributeError, type(module.gettype1).__getattribute__,
+ module.gettype1, 'dcBA')
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -682,10 +682,6 @@
if pto.c_tp_itemsize < pto.c_tp_base.c_tp_itemsize:
pto.c_tp_itemsize = pto.c_tp_base.c_tp_itemsize
- if space.is_w(w_type, space.w_object):
- # will be filled later on with the correct value
- # may not be 0
- pto.c_tp_new = cts.cast('newfunc', 1)
update_all_slots(space, w_type, pto)
if not pto.c_tp_new:
base_object_pyo = make_ref(space, space.w_object)
diff --git a/pypy/module/exceptions/__init__.py
b/pypy/module/exceptions/__init__.py
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit