aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2022-02-10 16:52:01 +0200
committerMatti Picus <matti.picus@gmail.com>2022-02-10 16:52:01 +0200
commita61bea0c175e3135b7bd6e6f08720766ceff9dda (patch)
tree8be3536a8b769c5bed3025632b11080f305c2727
parentstart a pypy3.9 release branch (diff)
parentavoid possible deadlocks by creating ProcessPoolExecutor processes earlier (i... (diff)
downloadpypy-a61bea0c175e3135b7bd6e6f08720766ceff9dda.tar.gz
pypy-a61bea0c175e3135b7bd6e6f08720766ceff9dda.tar.bz2
pypy-a61bea0c175e3135b7bd6e6f08720766ceff9dda.zip
merge py3.9 into release
-rw-r--r--.hgtags4
-rw-r--r--LICENSE38
-rw-r--r--extra_tests/ctypes_tests/test_structures.py16
-rw-r--r--extra_tests/test_modules.py14
-rw-r--r--lib-python/3/concurrent/futures/process.py21
-rw-r--r--lib-python/3/test/test_call.py2
-rw-r--r--lib-python/3/test/test_eof.py13
-rw-r--r--lib-python/3/test/test_exceptions.py1
-rw-r--r--lib-python/3/test/test_future.py5
-rw-r--r--lib-python/3/test/test_os.py3
-rw-r--r--lib-python/3/test/test_threading.py1
-rw-r--r--lib-python/stdlib-upgrade.txt6
-rw-r--r--lib_pypy/__init__.py2
-rw-r--r--lib_pypy/_cffi_ssl/_stdssl/__init__.py2
-rw-r--r--lib_pypy/_crypt/__init__.py2
-rw-r--r--lib_pypy/_ctypes_test.py2
-rw-r--r--lib_pypy/_curses.py2
-rw-r--r--lib_pypy/_dbm.py2
-rw-r--r--lib_pypy/_hashlib/__init__.py5
-rw-r--r--lib_pypy/_overlapped.py2
-rw-r--r--lib_pypy/_scproxy.py2
-rw-r--r--lib_pypy/_sysconfigdata.py17
-rw-r--r--lib_pypy/_testcapimodule.c10
-rw-r--r--lib_pypy/_testmultiphase.c.h101
-rw-r--r--lib_pypy/_testmultiphase.py4
-rw-r--r--lib_pypy/_winapi.py2
-rw-r--r--lib_pypy/cffi.dist-info/METADATA1
-rw-r--r--lib_pypy/msvcrt.py2
-rw-r--r--lib_pypy/pyrepl/_minimal_curses.py2
-rw-r--r--lib_pypy/readline.py4
-rw-r--r--lib_pypy/syslog.py2
-rw-r--r--pypy/doc/contributor.rst38
-rw-r--r--pypy/doc/release-v7.3.8.rst66
-rw-r--r--pypy/doc/tool/makecontributor.py16
-rw-r--r--pypy/interpreter/astcompiler/codegen.py5
-rw-r--r--pypy/interpreter/astcompiler/test/test_compiler.py21
-rw-r--r--pypy/interpreter/baseobjspace.py19
-rw-r--r--pypy/interpreter/error.py19
-rw-r--r--pypy/interpreter/function.py24
-rw-r--r--pypy/interpreter/generator.py5
-rw-r--r--pypy/interpreter/pyframe.py15
-rw-r--r--pypy/interpreter/pyopcode.py36
-rw-r--r--pypy/interpreter/pyparser/baserpypeg.py8
-rw-r--r--pypy/interpreter/pyparser/error.py31
-rw-r--r--pypy/interpreter/test/apptest_pyframe.py56
-rw-r--r--pypy/interpreter/test/test_compiler.py5
-rw-r--r--pypy/interpreter/test/test_objspace.py6
-rw-r--r--pypy/interpreter/test/test_pyframe.py14
-rw-r--r--pypy/interpreter/test/test_raise.py61
-rw-r--r--pypy/interpreter/test/test_unicodehelper.py11
-rw-r--r--pypy/interpreter/unicodehelper.py7
-rw-r--r--pypy/module/_locale/moduledef.py2
-rw-r--r--pypy/module/_posixsubprocess/_posixsubprocess.c36
-rw-r--r--pypy/module/_posixsubprocess/test/apptest_subprocess.py140
-rw-r--r--pypy/module/cpyext/api.py70
-rw-r--r--pypy/module/cpyext/cdatetime.py3
-rw-r--r--pypy/module/cpyext/classobject.py3
-rw-r--r--pypy/module/cpyext/include/Python.h1
-rw-r--r--pypy/module/cpyext/include/methodobject.h22
-rw-r--r--pypy/module/cpyext/include/modsupport.h104
-rw-r--r--pypy/module/cpyext/include/object.h117
-rw-r--r--pypy/module/cpyext/include/pystate.h21
-rw-r--r--pypy/module/cpyext/include/tupleobject.h1
-rw-r--r--pypy/module/cpyext/methodobject.py121
-rw-r--r--pypy/module/cpyext/modsupport.py12
-rw-r--r--pypy/module/cpyext/parse/cpyext_object.h6
-rw-r--r--pypy/module/cpyext/pystate.py55
-rw-r--r--pypy/module/cpyext/src/call.c2
-rw-r--r--pypy/module/cpyext/src/getargs.c1494
-rw-r--r--pypy/module/cpyext/src/modsupport.c60
-rw-r--r--pypy/module/cpyext/test/foo.c1
-rw-r--r--pypy/module/cpyext/test/multiphase2.c7
-rw-r--r--pypy/module/cpyext/test/test_module.py8
-rw-r--r--pypy/module/cpyext/test/test_typeobject.py15
-rw-r--r--pypy/module/cpyext/test/test_unicodeobject.py20
-rw-r--r--pypy/module/cpyext/typeobject.py21
-rw-r--r--pypy/module/cpyext/unicodeobject.py57
-rw-r--r--pypy/module/posix/interp_posix.py15
-rw-r--r--pypy/module/posix/interp_scandir.py10
-rw-r--r--pypy/module/posix/test/test_posix2.py46
-rw-r--r--pypy/module/pyexpat/interp_pyexpat.py55
-rw-r--r--pypy/module/pyexpat/test/test_build.py2
-rw-r--r--pypy/module/select/interp_epoll.py102
-rw-r--r--pypy/module/thread/os_thread.py4
-rw-r--r--pypy/objspace/std/intobject.py22
-rw-r--r--pypy/objspace/std/proxyobject.py3
-rw-r--r--pypy/objspace/std/test/test_bytesobject.py1
-rw-r--r--pypy/objspace/std/transparent.py5
-rw-r--r--pypy/tool/pytest/apptest.py2
-rw-r--r--pypy/tool/release/check_versions.py5
-rwxr-xr-xpypy/tool/release/package.py3
-rw-r--r--pypy/tool/release/repackage.sh6
-rw-r--r--pypy/tool/release/versions.json176
-rw-r--r--rpython/rlib/_rsocket_rffi.py6
-rw-r--r--rpython/rlib/ropenssl.py2
-rw-r--r--rpython/rlib/rvmprof/src/shared/vmprof_getpc.h2
-rw-r--r--rpython/translator/c/src/dtoa.c6
-rw-r--r--rpython/translator/c/src/support.c2
-rw-r--r--rpython/translator/c/test/test_extfunc.py4
-rw-r--r--rpython/translator/platform/windows.py2
-rw-r--r--rpython/translator/tool/cbuild.py4
101 files changed, 3014 insertions, 623 deletions
diff --git a/.hgtags b/.hgtags
index ac5b2a2fc4..aa442b9a7d 100644
--- a/.hgtags
+++ b/.hgtags
@@ -129,3 +129,7 @@ cc3911ab8fcd509143c64012cc7067d75ab4b6ac release-pypy3.7-v7.3.6
279d80ac20791479931c3e105755c8453f5f527c release-pypy3.8-v7.3.6
9ef55f6fc3697bf8d85334ce2d70fdbba888e3ab release-pypy3.8-v7.3.7
44db26267d0a38e51a7e8490983ed7e7bcb84b74 release-pypy3.7-v7.3.7
+6f82fdd0ce3c822780c99642e620260f2d93daa4 release-pypy2.7-v7.3.8rc1
+0e322cb44401d19c73b3c3862bcd86bf56ff69ae release-pypy3.7-v7.3.8rc1
+67f1b98040bad2f1241e4e1ebde6051a505f628a release-pypy3.8-v7.3.8rc1
+307e102d7222131fee14073e8856df773627186c release-pypy3.9-v7.3.8rc1
diff --git a/LICENSE b/LICENSE
index bdc91a4153..cb7f7fd534 100644
--- a/LICENSE
+++ b/LICENSE
@@ -39,9 +39,9 @@ the beginning of each file) the files in the 'pypy' directory are each
copyrighted by one or more of the following people and organizations:
Armin Rigo
- Maciej Fijalkowski
- Carl Friedrich Bolz-Tereick
+ Maciej Fijałkowski
Matti Picus
+ Carl Friedrich Bolz-Tereick
Antonio Cuni
Amaury Forgeot d'Arc
Ronan Lamy
@@ -55,7 +55,7 @@ copyrighted by one or more of the following people and organizations:
David Schneider
Holger Krekel
Christian Tismer
- Hakan Ardo
+ Håkan Ardö
Benjamin Peterson
Wim Lavrijsen
Anders Chrigstrom
@@ -67,6 +67,7 @@ copyrighted by one or more of the following people and organizations:
Lukas Diekmann
Sven Hager
Anders Lehmann
+ Edd Barrett
Aurelien Campeas
Niklaus Haldimann
Camillo Bruni
@@ -106,10 +107,10 @@ copyrighted by one or more of the following people and organizations:
Stefan Beyer
Tyler Wade
Vincent Legoll
+ Simon Cross
Michael Foord
- Stephan Diehl
muke101
- Simon Cross
+ Stephan Diehl
Jean-Paul Calderone
Stefan Schwarzer
Tomek Meka
@@ -122,7 +123,6 @@ copyrighted by one or more of the following people and organizations:
Yannick Jadoul
Squeaky
Timo Paulssen
- Edd Barrett
Marius Gedminas
Laurence Tratt
Alexandre Fayolle
@@ -134,6 +134,7 @@ copyrighted by one or more of the following people and organizations:
John Witulski
Jeremy Thurgood
Julian Berman
+ Adrian Kuhn
Dario Bertini
Greg Price
Ivan Sichmann Freitas
@@ -151,17 +152,17 @@ copyrighted by one or more of the following people and organizations:
Tobias Oberstein
marky1991
Boris Feigin
- Adrian Kuhn
tav
Taavi Burns
Joannah Nanjekye
Georg Brandl
+ Michał Górny
quejebo
Vanessa Freudenberg
- Michał Górny
Gerald Klix
Wanja Saatkamp
Mike Blume
+ olliemath
Oscar Nierstrasz
Rami Chowdhury
Stefan H. Muller
@@ -178,7 +179,6 @@ copyrighted by one or more of the following people and organizations:
Lukas Renggli
Dusty Phillips
Guenter Jantzen
- Bert Freudenberg
Amit Regmi
Ned Batchelder
Jasper Schulz
@@ -201,7 +201,6 @@ copyrighted by one or more of the following people and organizations:
Lucian Branescu Mihaila
anatoly techtonik
Mariano Anaya
- olliemath
Olivier Dormond
Jared Grubb
Karl Bartel
@@ -219,6 +218,7 @@ copyrighted by one or more of the following people and organizations:
Aaron Iles
Christian Hudon
Daniel Patrick
+ Ricky Zhou
Justas Sadzevicius
Gasper Zejn
Neil Shepperd
@@ -228,7 +228,6 @@ copyrighted by one or more of the following people and organizations:
Berkin Ilbeyi
Mihnea Saracin
Matt Jackson
- Ricky Zhou
Jonathan David Riehl
Anders Qvist
Beatrice During
@@ -326,8 +325,6 @@ copyrighted by one or more of the following people and organizations:
Dan Colish
Akira Li
Bobby Impollonia
- roberto@goyle
- Roberto De Ioris
timo
Anna Katrina Dominguez
Juan Francisco Cantero Hurtado
@@ -354,7 +351,6 @@ copyrighted by one or more of the following people and organizations:
afteryu
Andrew Stepanov
Radu Ciorba
- Ian Clester
Carl Bordum Hansen
Paul Ganssle
Michal Kuffa
@@ -367,8 +363,8 @@ copyrighted by one or more of the following people and organizations:
dakarpov@gmail.com
Sreepathi Pai
Georges Racinet
- Bolutife Ogunsola
ashwinahuja
+ Bolutife Ogunsola
cjmcdonald@google.com
Alex Orange
alexprengere
@@ -466,21 +462,23 @@ copyrighted by one or more of the following people and organizations:
paugier
bernd.schoeller@inf.ethz.ch
Sam Edwards
- Ihar Shabes
- kotus9
- mark doerr
- Tomas Hrnciar
Joannah Nanjekye nanjekyejoannah@gmail.com
Alex Kashirin
+ Ihar Shabes
+ kotus9
Mike Kaplinskiy
Henri Tuhola
+ mark doerr
+ Tomas Hrnciar
shaolo1
Chris AtLee
Christoph Reiter
Chris Burr
Brad Kish
- David Hewitt
Michael Cho
+ Ian Clester
+ David Hewitt
+ h-vetinari
Isuru Fernando
Heinrich-Heine University, Germany
diff --git a/extra_tests/ctypes_tests/test_structures.py b/extra_tests/ctypes_tests/test_structures.py
index 96531ddf3c..6ec11e69b8 100644
--- a/extra_tests/ctypes_tests/test_structures.py
+++ b/extra_tests/ctypes_tests/test_structures.py
@@ -31,7 +31,6 @@ def test___init__():
class Person(Structure):
_fields_ = (("name", c_char*10),
("age", c_int))
-
def __init__(self, name, surname, age):
self.name = name + b' ' + surname
self.age = age
@@ -221,3 +220,18 @@ def test_memoryview_endian():
mv = memoryview(c_les)
assert mv.format == 'B'
+def test_deepcopy_struct():
+ # issue 3022: missing __new__ on StructureInstanceAutoFree
+ import copy
+
+ class struct_a(Structure):
+ pass
+
+ class struct_b(Structure):
+ pass
+
+ struct_a._fields_ = [('first',struct_b)]
+
+ a = struct_a()
+ b = copy.deepcopy(a)
+ assert isinstance(b.first, struct_b)
diff --git a/extra_tests/test_modules.py b/extra_tests/test_modules.py
new file mode 100644
index 0000000000..a383bc763a
--- /dev/null
+++ b/extra_tests/test_modules.py
@@ -0,0 +1,14 @@
+import pytest
+import sys
+
+@pytest.mark.skipif(sys.platform == 'win32', reason="works on win32")
+def test_cant_import_msvcrt():
+ with pytest.raises(ModuleNotFoundError) as info:
+ import msvcrt
+ assert info.value.name == "msvcrt"
+
+@pytest.mark.skipif(sys.platform != 'win32', reason="test only for win32")
+def test_cant_import_readline():
+ with pytest.raises(ModuleNotFoundError) as info:
+ import readline
+ assert info.value.name == "readline"
diff --git a/lib-python/3/concurrent/futures/process.py b/lib-python/3/concurrent/futures/process.py
index a29e5247ab..e956df50c1 100644
--- a/lib-python/3/concurrent/futures/process.py
+++ b/lib-python/3/concurrent/futures/process.py
@@ -659,13 +659,28 @@ class ProcessPoolExecutor(_base.Executor):
_threads_wakeups[self._executor_manager_thread] = \
self._executor_manager_thread_wakeup
- def _adjust_process_count(self):
+ def _adjust_process_count_cpython(self):
# if there's an idle process, we don't need to spawn a new one.
if self._idle_worker_semaphore.acquire(blocking=False):
- return
-
+ return
process_count = len(self._processes)
if process_count < self._max_workers:
+ # for process_count in range(len(self._processes), self._max_workers):
+ print('starting process', process_count)
+ p = self._mp_context.Process(
+ target=_process_worker,
+ args=(self._call_queue,
+ self._result_queue,
+ self._initializer,
+ self._initargs))
+ p.start()
+ self._processes[p.pid] = p
+
+ def _adjust_process_count(self):
+ # PyPy: create all the processes in the first call to avoid hanging
+ # after using os.fork. See unused _adjust_process_count_cpython above
+ process_count = len(self._processes)
+ for _ in range(process_count, self._max_workers):
p = self._mp_context.Process(
target=_process_worker,
args=(self._call_queue,
diff --git a/lib-python/3/test/test_call.py b/lib-python/3/test/test_call.py
index 451a7170c3..0f9944cf23 100644
--- a/lib-python/3/test/test_call.py
+++ b/lib-python/3/test/test_call.py
@@ -548,6 +548,7 @@ def testfunction_kw(self, *, kw):
class TestPEP590(unittest.TestCase):
+ @cpython_only
def test_method_descriptor_flag(self):
import functools
cached = functools.lru_cache(1)(testfunction)
@@ -567,6 +568,7 @@ class TestPEP590(unittest.TestCase):
pass
self.assertFalse(MethodDescriptorHeap.__flags__ & Py_TPFLAGS_METHOD_DESCRIPTOR)
+ @cpython_only
def test_vectorcall_flag(self):
self.assertTrue(_testcapi.MethodDescriptorBase.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
self.assertTrue(_testcapi.MethodDescriptorDerived.__flags__ & Py_TPFLAGS_HAVE_VECTORCALL)
diff --git a/lib-python/3/test/test_eof.py b/lib-python/3/test/test_eof.py
index 2c78c3f36e..c95c7af547 100644
--- a/lib-python/3/test/test_eof.py
+++ b/lib-python/3/test/test_eof.py
@@ -37,7 +37,10 @@ class EOFTestCase(unittest.TestCase):
def test_line_continuation_EOF(self):
"""A continuation at the end of input must be an error; bpo2180."""
- expect = 'unexpected EOF while parsing (<string>, line 1)'
+ if sys.implementation.name == 'pypy':
+ expect = "end of file (EOF) in multi-line statement (<string>, line 2)"
+ else:
+ expect = "unexpected EOF while parsing (<string>, line 1)"
with self.assertRaises(SyntaxError) as excinfo:
exec('x = 5\\')
self.assertEqual(str(excinfo.exception), expect)
@@ -48,16 +51,20 @@ class EOFTestCase(unittest.TestCase):
@unittest.skipIf(not sys.executable, "sys.executable required")
def test_line_continuation_EOF_from_file_bpo2180(self):
"""Ensure tok_nextc() does not add too many ending newlines."""
+ if sys.implementation.name == 'pypy':
+ msg = b"end of file (EOF) in multi-line statement"
+ else:
+ msg = b"unexpected EOF while parsing"
with support.temp_dir() as temp_dir:
file_name = script_helper.make_script(temp_dir, 'foo', '\\')
rc, out, err = script_helper.assert_python_failure(file_name)
- self.assertIn(b'unexpected EOF while parsing', err)
+ self.assertIn(msg, err)
self.assertIn(b'line 2', err)
self.assertIn(b'\\', err)
file_name = script_helper.make_script(temp_dir, 'foo', 'y = 6\\')
rc, out, err = script_helper.assert_python_failure(file_name)
- self.assertIn(b'unexpected EOF while parsing', err)
+ self.assertIn(msg, err)
self.assertIn(b'line 2', err)
self.assertIn(b'y = 6\\', err)
diff --git a/lib-python/3/test/test_exceptions.py b/lib-python/3/test/test_exceptions.py
index 0edef19af3..306af0a676 100644
--- a/lib-python/3/test/test_exceptions.py
+++ b/lib-python/3/test/test_exceptions.py
@@ -1246,6 +1246,7 @@ class ExceptionTests(unittest.TestCase):
b'while normalizing an exception', err)
self.assertIn(b'Done.', out)
+ @cpython_only
def test_recursion_in_except_handler(self):
def set_relative_recursion_limit(n):
diff --git a/lib-python/3/test/test_future.py b/lib-python/3/test/test_future.py
index c6da835997..0f94add4f5 100644
--- a/lib-python/3/test/test_future.py
+++ b/lib-python/3/test/test_future.py
@@ -60,7 +60,10 @@ class FutureTest(unittest.TestCase):
def test_badfuture7(self):
with self.assertRaises(SyntaxError) as cm:
from test import badsyntax_future7
- self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 53)
+ # PyPy reports 54, which puts the caret under the f in from __future__
+ # CPython reports 53, which puts the caret just befort the f
+ # self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 53)
+ self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 54)
def test_badfuture8(self):
with self.assertRaises(SyntaxError) as cm:
diff --git a/lib-python/3/test/test_os.py b/lib-python/3/test/test_os.py
index 59ddf9e0b3..3ce147a0c4 100644
--- a/lib-python/3/test/test_os.py
+++ b/lib-python/3/test/test_os.py
@@ -481,7 +481,8 @@ class StatAttributeTests(unittest.TestCase):
self.assertTrue(isinstance(result.f_fsid, int))
# Test that the size of the tuple doesn't change
- self.assertEqual(len(result), 10)
+ # PyPy - structseq does not hide f_fsid
+ # self.assertEqual(len(result), 10)
# Make sure that assignment really fails
try:
diff --git a/lib-python/3/test/test_threading.py b/lib-python/3/test/test_threading.py
index 2222fa793e..42811b72d6 100644
--- a/lib-python/3/test/test_threading.py
+++ b/lib-python/3/test/test_threading.py
@@ -803,6 +803,7 @@ class ThreadTests(BaseTestCase):
# Daemon threads must never add it to _shutdown_locks.
self.assertNotIn(tstate_lock, threading._shutdown_locks)
+ @cpython_only
def test_locals_at_exit(self):
# bpo-19466: thread locals must not be deleted before destructors
# are called
diff --git a/lib-python/stdlib-upgrade.txt b/lib-python/stdlib-upgrade.txt
index c061fa7454..f0ce3e8fcf 100644
--- a/lib-python/stdlib-upgrade.txt
+++ b/lib-python/stdlib-upgrade.txt
@@ -10,7 +10,11 @@ Process for upgrading the stdlib to a new cpython version
2. upgrade the files there
2a. `rm -rf lib-python/3/*`
2b. copy the files from the cpython repo
- 2c. copy `Modules/_ctypes/_ctypes_test.c` and `Modules/_testcapimodule.c` to `lib_pypy/`
+ 2c. copy to `lib_pypy`
+ - `Modules/_ctypes/_ctypes_test.c`
+ - `Modules/_testcapimodule.c`
+ - `Modules/_testmultiphase.c`
+ - `Modules/_testmultiphase.c.h`
2d. `hg add lib-python/3/`
2e. `hg remove --after`
2f. show copied files in cpython repo by running appropriate git commands
diff --git a/lib_pypy/__init__.py b/lib_pypy/__init__.py
index 5747a91294..dad4526e1f 100644
--- a/lib_pypy/__init__.py
+++ b/lib_pypy/__init__.py
@@ -1,4 +1,4 @@
# This __init__.py shows up in PyPy's app-level standard library.
# Let's try to prevent that confusion...
if __name__ != 'lib_pypy':
- raise ImportError('__init__')
+ raise ModuleNotFoundError('__init__', name='__init__')
diff --git a/lib_pypy/_cffi_ssl/_stdssl/__init__.py b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
index b87ff68038..bbf721c649 100644
--- a/lib_pypy/_cffi_ssl/_stdssl/__init__.py
+++ b/lib_pypy/_cffi_ssl/_stdssl/__init__.py
@@ -13,7 +13,7 @@ except ImportError as e:
"If you have a compiler installed, you can try to rebuild it by running:\n" + \
"cd %s\n" % os.path.abspath(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) + \
"%s _ssl_build.py\n" % sys.executable
- raise ImportError(str(e) + msg)
+ raise ModuleNotFoundError(str(e) + msg, name='_cffi_ssl')
from _cffi_ssl._stdssl.certificate import (_test_decode_cert,
_decode_certificate, _certificate_to_der)
diff --git a/lib_pypy/_crypt/__init__.py b/lib_pypy/_crypt/__init__.py
index d81ea545ff..4e295f89eb 100644
--- a/lib_pypy/_crypt/__init__.py
+++ b/lib_pypy/_crypt/__init__.py
@@ -19,7 +19,7 @@ ffi.cdef('char *crypt(char *word, char *salt);')
try:
lib = ffi.dlopen('crypt')
except OSError:
- raise ImportError('crypt not available')
+ raise ModuleNotFoundError('crypt not available', name='crypt')
@builtinify
diff --git a/lib_pypy/_ctypes_test.py b/lib_pypy/_ctypes_test.py
index 1889a21765..75dadd4d56 100644
--- a/lib_pypy/_ctypes_test.py
+++ b/lib_pypy/_ctypes_test.py
@@ -4,7 +4,7 @@ import os
try:
import cpyext
except ImportError:
- raise ImportError("No module named '_ctypes_test'")
+ raise ModuleNotFoundError("No module named '_ctypes_test'", name='_ctypes_test')
try:
import _ctypes
_ctypes.PyObj_FromPtr = None
diff --git a/lib_pypy/_curses.py b/lib_pypy/_curses.py
index 64fea97393..1fc079673b 100644
--- a/lib_pypy/_curses.py
+++ b/lib_pypy/_curses.py
@@ -3,7 +3,7 @@
import sys
if sys.platform == 'win32':
#This module does not exist in windows
- raise ImportError('No module named _curses')
+ raise ModuleNotFoundError('No module named _curses', name='_curses')
import locale
from functools import wraps
diff --git a/lib_pypy/_dbm.py b/lib_pypy/_dbm.py
index fab08524cc..c64f541b40 100644
--- a/lib_pypy/_dbm.py
+++ b/lib_pypy/_dbm.py
@@ -152,7 +152,7 @@ if sys.platform != 'darwin':
if libpath:
break
else:
- raise ImportError("Cannot find dbm library")
+ raise ModuleNotFoundError("Cannot find dbm library", name='_dbm')
lib = CDLL(libpath) # Linux
_platform = 'bdb'
else:
diff --git a/lib_pypy/_hashlib/__init__.py b/lib_pypy/_hashlib/__init__.py
index db8b13b41f..3f2c03b503 100644
--- a/lib_pypy/_hashlib/__init__.py
+++ b/lib_pypy/_hashlib/__init__.py
@@ -64,6 +64,11 @@ class HASH(object):
return "<%s HASH object at 0x%s>" % (self.name, id(self))
def update(self, string):
+ if isinstance(string, str):
+ raise TypeError("Unicode-objects must be encoded before hashing")
+ elif isinstance(string, memoryview):
+ # issue 2756: ffi.from_buffer() cannot handle memoryviews
+ string = string.tobytes()
buf = ffi.from_buffer(string)
with self.lock:
# XXX try to not release the GIL for small requests
diff --git a/lib_pypy/_overlapped.py b/lib_pypy/_overlapped.py
index a5fdf83767..56397a127e 100644
--- a/lib_pypy/_overlapped.py
+++ b/lib_pypy/_overlapped.py
@@ -10,7 +10,7 @@ import _winapi
from _winapi import _Z, RaiseFromWindowsErr
if sys.platform != 'win32':
- raise ImportError("The '_overlapped' module is only available on Windows")
+ raise ModuleNotFoundError("The '_overlapped' module is only available on Windows", name='_overlapped')
# Declare external Win32 functions
diff --git a/lib_pypy/_scproxy.py b/lib_pypy/_scproxy.py
index 1f4299ffff..64478f0d49 100644
--- a/lib_pypy/_scproxy.py
+++ b/lib_pypy/_scproxy.py
@@ -4,7 +4,7 @@ the SystemConfiguration framework.
"""
import sys
if sys.platform != 'darwin':
- raise ImportError('Requires Mac OS X')
+ raise ModuleNotFoundError('Requires Mac OS X', name='_scproxy')
from ctypes import c_int32, c_int64, c_void_p, c_char_p, c_int, cdll
from ctypes import pointer, create_string_buffer
diff --git a/lib_pypy/_sysconfigdata.py b/lib_pypy/_sysconfigdata.py
index 33fbfd6b6d..8deb672ef1 100644
--- a/lib_pypy/_sysconfigdata.py
+++ b/lib_pypy/_sysconfigdata.py
@@ -52,6 +52,23 @@ else:
build_time_vars['LDLIBRARY'] = 'libpypy3-c.so'
build_time_vars['INCLUDEPY'] = os.path.join(mybase, 'include', 'pypy' + pydot)
build_time_vars['LIBDIR'] = os.path.join(mybase, 'bin')
+ # try paths relative to sys.base_prefix first
+ tzpaths = [
+ os.path.join(mybase, 'share', 'zoneinfo'),
+ os.path.join(mybase, 'lib', 'zoneinfo'),
+ os.path.join(mybase, 'share', 'lib', 'zoneinfo'),
+ os.path.join(mybase, '..', 'etc', 'zoneinfo'),
+ ]
+ # add absolute system paths if sys.base_prefix != "/usr"
+ # (then we'd be adding duplicates)
+ if mybase != '/usr':
+ tzpaths.extend([
+ '/usr/share/zoneinfo',
+ '/usr/lib/zoneinfo',
+ '/usr/share/lib/zoneinfo',
+ '/etc/zoneinfo',
+ ])
+ build_time_vars['TZPATH'] = ':'.join(tzpaths)
if find_executable("gcc"):
build_time_vars.update({
diff --git a/lib_pypy/_testcapimodule.c b/lib_pypy/_testcapimodule.c
index 88e8a6bc0f..fca51fe409 100644
--- a/lib_pypy/_testcapimodule.c
+++ b/lib_pypy/_testcapimodule.c
@@ -2724,7 +2724,6 @@ test_PyDateTime_DELTA_GET(PyObject *self, PyObject *obj)
return Py_BuildValue("(lll)", days, seconds, microseconds);
}
-#ifndef PYPY_VERSION
/* test_thread_state spawns a thread of its own, and that thread releases
* `thread_done` when it's finished. The driver code has to know when the
* thread finishes, because the thread uses a PyObject (the callable) that
@@ -2805,9 +2804,7 @@ test_thread_state(PyObject *self, PyObject *args)
return NULL;
Py_RETURN_NONE;
}
-#endif
-#ifndef PYPY_VERSION
/* test Py_AddPendingCalls using threads */
static int _pending_callback(void *arg)
{
@@ -2843,7 +2840,6 @@ pending_threadfunc(PyObject *self, PyObject *arg)
}
Py_RETURN_TRUE;
}
-#endif /* PYPY_VERSION */
/* Some tests of PyUnicode_FromFormat(). This needs more tests. */
static PyObject *
@@ -2852,10 +2848,6 @@ test_string_from_format(PyObject *self, PyObject *Py_UNUSED(ignored))
PyObject *result;
char *msg;
-#ifdef PYPY_VERSION
-#define _PyUnicode_EqualToASCIIString(a, b) (PyUnicode_CompareWithASCIIString(a, b) == 0)
-#endif
-
#define CHECK_1_FORMAT(FORMAT, TYPE) \
result = PyUnicode_FromFormat(FORMAT, (TYPE)1); \
if (result == NULL) \
@@ -5541,10 +5533,8 @@ static PyMethodDef TestMethods[] = {
{"unicode_encodedecimal", unicode_encodedecimal, METH_VARARGS},
{"unicode_transformdecimaltoascii", unicode_transformdecimaltoascii, METH_VARARGS},
{"unicode_legacy_string", unicode_legacy_string, METH_VARARGS},
-#ifndef PYPY_VERSION
{"_test_thread_state", test_thread_state, METH_VARARGS},
{"_pending_threadfunc", pending_threadfunc, METH_VARARGS},
-#endif // ifndef PYPY_VERSION
#ifdef HAVE_GETTIMEOFDAY
{"profile_int", profile_int, METH_NOARGS},
#endif
diff --git a/lib_pypy/_testmultiphase.c.h b/lib_pypy/_testmultiphase.c.h
new file mode 100644
index 0000000000..0d38c230f7
--- /dev/null
+++ b/lib_pypy/_testmultiphase.c.h
@@ -0,0 +1,101 @@
+/*[clinic input]
+preserve
+[clinic start generated code]*/
+
+PyDoc_STRVAR(_testmultiphase_StateAccessType_get_defining_module__doc__,
+"get_defining_module($self, /)\n"
+"--\n"
+"\n"
+"Return the module of the defining class.");
+
+#define _TESTMULTIPHASE_STATEACCESSTYPE_GET_DEFINING_MODULE_METHODDEF \
+ {"get_defining_module", (PyCFunction)(void(*)(void))_testmultiphase_StateAccessType_get_defining_module, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _testmultiphase_StateAccessType_get_defining_module__doc__},
+
+static PyObject *
+_testmultiphase_StateAccessType_get_defining_module_impl(StateAccessTypeObject *self,
+ PyTypeObject *cls);
+
+static PyObject *
+_testmultiphase_StateAccessType_get_defining_module(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = { NULL};
+ static _PyArg_Parser _parser = {":get_defining_module", _keywords, 0};
+
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
+ )) {
+ goto exit;
+ }
+ return_value = _testmultiphase_StateAccessType_get_defining_module_impl(self, cls);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_testmultiphase_StateAccessType_increment_count_clinic__doc__,
+"increment_count_clinic($self, /, n=1, *, twice=False)\n"
+"--\n"
+"\n"
+"Add \'n\' from the module-state counter.\n"
+"\n"
+"Pass \'twice\' to double that amount.\n"
+"\n"
+"This tests Argument Clinic support for defining_class.");
+
+#define _TESTMULTIPHASE_STATEACCESSTYPE_INCREMENT_COUNT_CLINIC_METHODDEF \
+ {"increment_count_clinic", (PyCFunction)(void(*)(void))_testmultiphase_StateAccessType_increment_count_clinic, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _testmultiphase_StateAccessType_increment_count_clinic__doc__},
+
+static PyObject *
+_testmultiphase_StateAccessType_increment_count_clinic_impl(StateAccessTypeObject *self,
+ PyTypeObject *cls,
+ int n, int twice);
+
+static PyObject *
+_testmultiphase_StateAccessType_increment_count_clinic(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = {"n", "twice", NULL};
+ static _PyArg_Parser _parser = {"|i$p:increment_count_clinic", _keywords, 0};
+ int n = 1;
+ int twice = 0;
+
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
+ &n, &twice)) {
+ goto exit;
+ }
+ return_value = _testmultiphase_StateAccessType_increment_count_clinic_impl(self, cls, n, twice);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(_testmultiphase_StateAccessType_get_count__doc__,
+"get_count($self, /)\n"
+"--\n"
+"\n"
+"Return the value of the module-state counter.");
+
+#define _TESTMULTIPHASE_STATEACCESSTYPE_GET_COUNT_METHODDEF \
+ {"get_count", (PyCFunction)(void(*)(void))_testmultiphase_StateAccessType_get_count, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, _testmultiphase_StateAccessType_get_count__doc__},
+
+static PyObject *
+_testmultiphase_StateAccessType_get_count_impl(StateAccessTypeObject *self,
+ PyTypeObject *cls);
+
+static PyObject *
+_testmultiphase_StateAccessType_get_count(StateAccessTypeObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ PyObject *return_value = NULL;
+ static const char * const _keywords[] = { NULL};
+ static _PyArg_Parser _parser = {":get_count", _keywords, 0};
+
+ if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
+ )) {
+ goto exit;
+ }
+ return_value = _testmultiphase_StateAccessType_get_count_impl(self, cls);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=39eea487e94e7f5d input=a9049054013a1b77]*/
diff --git a/lib_pypy/_testmultiphase.py b/lib_pypy/_testmultiphase.py
index e10e9996f5..d24cdea434 100644
--- a/lib_pypy/_testmultiphase.py
+++ b/lib_pypy/_testmultiphase.py
@@ -4,13 +4,13 @@ import os
try:
import cpyext
except ImportError:
- raise ImportError("No module named '_testmultiphase'")
+ raise ModuleNotFoundError("No module named '_testmultiphase'", name='_testmultiphase')
import _pypy_testcapi
cfile = '_testmultiphase.c'
thisdir = os.path.dirname(__file__)
output_dir = _pypy_testcapi.get_hashed_dir(os.path.join(thisdir, cfile))
try:
- fp, filename, description = imp.find_module('_test_multiphase', path=[output_dir])
+ fp, filename, description = imp.find_module('_testmultiphase', path=[output_dir])
with fp:
imp.load_module('_testmultiphase', fp, filename, description)
except ImportError:
diff --git a/lib_pypy/_winapi.py b/lib_pypy/_winapi.py
index ef31b9c161..0285801e5c 100644
--- a/lib_pypy/_winapi.py
+++ b/lib_pypy/_winapi.py
@@ -7,7 +7,7 @@ modules on Windows.
import sys
if sys.platform != 'win32':
- raise ImportError("The '_winapi' module is only available on Windows")
+ raise ImportError("The '_winapi' module is only available on Windows", name="_winapi")
# Declare external Win32 functions
diff --git a/lib_pypy/cffi.dist-info/METADATA b/lib_pypy/cffi.dist-info/METADATA
index 723deb6630..1e9927006d 100644
--- a/lib_pypy/cffi.dist-info/METADATA
+++ b/lib_pypy/cffi.dist-info/METADATA
@@ -20,7 +20,6 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: License :: OSI Approved :: MIT License
License-File: LICENSE
-Requires-Dist: pycparser
CFFI
diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py
index 5437b0e156..e567081dc5 100644
--- a/lib_pypy/msvcrt.py
+++ b/lib_pypy/msvcrt.py
@@ -11,7 +11,7 @@ still useful routines.
import sys
if sys.platform != 'win32':
- raise ModuleNotFoundError("The 'msvcrt' module is only available on Windows")
+ raise ModuleNotFoundError("The 'msvcrt' module is only available on Windows", name="msvcrt")
import _rawffi
if sys.maxsize > 2 ** 31:
diff --git a/lib_pypy/pyrepl/_minimal_curses.py b/lib_pypy/pyrepl/_minimal_curses.py
index bc0dd4231f..fc51679815 100644
--- a/lib_pypy/pyrepl/_minimal_curses.py
+++ b/lib_pypy/pyrepl/_minimal_curses.py
@@ -22,7 +22,7 @@ def _find_clib():
path = ctypes.util.find_library(lib)
if path:
return path
- raise ImportError("curses library not found")
+ raise ModuleNotFoundError("curses library not found", name="_minimal_curses")
_clibpath = _find_clib()
clib = ctypes.cdll.LoadLibrary(_clibpath)
diff --git a/lib_pypy/readline.py b/lib_pypy/readline.py
index e08747acf4..34b326518f 100644
--- a/lib_pypy/readline.py
+++ b/lib_pypy/readline.py
@@ -11,6 +11,6 @@ try:
except ImportError:
import sys
if sys.platform == 'win32':
- raise ImportError("the 'readline' module is not available on Windows"
- " (on either PyPy or CPython)")
+ raise ModuleNotFoundError("the 'readline' module is not available on Windows"
+ " (on either PyPy or CPython)", name="readline")
raise
diff --git a/lib_pypy/syslog.py b/lib_pypy/syslog.py
index e9b25342e7..6a778596e6 100644
--- a/lib_pypy/syslog.py
+++ b/lib_pypy/syslog.py
@@ -8,7 +8,7 @@ syslog facility.
import sys
if sys.platform == 'win32':
- raise ImportError("No syslog on Windows")
+ raise ModuleNotFoundError("No syslog on Windows", name="syslog")
try: from __pypy__ import builtinify
except ImportError: builtinify = lambda f: f
diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst
index 4b92725090..3b7e80597e 100644
--- a/pypy/doc/contributor.rst
+++ b/pypy/doc/contributor.rst
@@ -5,9 +5,9 @@ Contributors
::
Armin Rigo
- Maciej Fijalkowski
- Carl Friedrich Bolz-Tereick
+ Maciej Fijałkowski
Matti Picus
+ Carl Friedrich Bolz-Tereick
Antonio Cuni
Amaury Forgeot d'Arc
Ronan Lamy
@@ -21,7 +21,7 @@ Contributors
David Schneider
Holger Krekel
Christian Tismer
- Hakan Ardo
+ Håkan Ardö
Benjamin Peterson
Wim Lavrijsen
Anders Chrigstrom
@@ -33,6 +33,7 @@ Contributors
Lukas Diekmann
Sven Hager
Anders Lehmann
+ Edd Barrett
Aurelien Campeas
Niklaus Haldimann
Camillo Bruni
@@ -72,10 +73,10 @@ Contributors
Stefan Beyer
Tyler Wade
Vincent Legoll
+ Simon Cross
Michael Foord
- Stephan Diehl
muke101
- Simon Cross
+ Stephan Diehl
Jean-Paul Calderone
Stefan Schwarzer
Tomek Meka
@@ -88,7 +89,6 @@ Contributors
Yannick Jadoul
Squeaky
Timo Paulssen
- Edd Barrett
Marius Gedminas
Laurence Tratt
Alexandre Fayolle
@@ -100,6 +100,7 @@ Contributors
John Witulski
Jeremy Thurgood
Julian Berman
+ Adrian Kuhn
Dario Bertini
Greg Price
Ivan Sichmann Freitas
@@ -117,17 +118,17 @@ Contributors
Tobias Oberstein
marky1991
Boris Feigin
- Adrian Kuhn
tav
Taavi Burns
Joannah Nanjekye
Georg Brandl
+ Michał Górny
quejebo
Vanessa Freudenberg
- Michał Górny
Gerald Klix
Wanja Saatkamp
Mike Blume
+ olliemath
Oscar Nierstrasz
Rami Chowdhury
Stefan H. Muller
@@ -144,7 +145,6 @@ Contributors
Lukas Renggli
Dusty Phillips
Guenter Jantzen
- Bert Freudenberg
Amit Regmi
Ned Batchelder
Jasper Schulz
@@ -167,7 +167,6 @@ Contributors
Lucian Branescu Mihaila
anatoly techtonik
Mariano Anaya
- olliemath
Olivier Dormond
Jared Grubb
Karl Bartel
@@ -185,6 +184,7 @@ Contributors
Aaron Iles
Christian Hudon
Daniel Patrick
+ Ricky Zhou
Justas Sadzevicius
Gasper Zejn
Neil Shepperd
@@ -194,7 +194,6 @@ Contributors
Berkin Ilbeyi
Mihnea Saracin
Matt Jackson
- Ricky Zhou
Jonathan David Riehl
Anders Qvist
Beatrice During
@@ -292,8 +291,6 @@ Contributors
Dan Colish
Akira Li
Bobby Impollonia
- roberto@goyle
- Roberto De Ioris
timo
Anna Katrina Dominguez
Juan Francisco Cantero Hurtado
@@ -320,7 +317,6 @@ Contributors
afteryu
Andrew Stepanov
Radu Ciorba
- Ian Clester
Carl Bordum Hansen
Paul Ganssle
Michal Kuffa
@@ -333,8 +329,8 @@ Contributors
dakarpov@gmail.com
Sreepathi Pai
Georges Racinet
- Bolutife Ogunsola
ashwinahuja
+ Bolutife Ogunsola
cjmcdonald@google.com
Alex Orange
alexprengere
@@ -432,19 +428,21 @@ Contributors
paugier
bernd.schoeller@inf.ethz.ch
Sam Edwards
- Ihar Shabes
- kotus9
- mark doerr
- Tomas Hrnciar
Joannah Nanjekye nanjekyejoannah@gmail.com
Alex Kashirin
+ Ihar Shabes
+ kotus9
Mike Kaplinskiy
Henri Tuhola
+ mark doerr
+ Tomas Hrnciar
shaolo1
Chris AtLee
Christoph Reiter
Chris Burr
Brad Kish
- David Hewitt
Michael Cho
+ Ian Clester
+ David Hewitt
+ h-vetinari
Isuru Fernando
diff --git a/pypy/doc/release-v7.3.8.rst b/pypy/doc/release-v7.3.8.rst
index f02b468328..332eb8e99b 100644
--- a/pypy/doc/release-v7.3.8.rst
+++ b/pypy/doc/release-v7.3.8.rst
@@ -3,7 +3,7 @@ PyPy v7.3.8: release of python 2.7, 3.7, 3.8, and 3.9-beta
==========================================================
..
- Changelog up to commit c859fcd9d243
+ Changelog up to commit 0360402c9455
.. note::
This is a pre-release announcement. When the release actually happens, it
@@ -20,7 +20,8 @@ wish to share. The release includes four different interpreters:
backported security updates)
- PyPy3.7, which is an interpreter supporting the syntax and the features of
- Python 3.7, including the stdlib for CPython 3.7.12.
+ Python 3.7, including the stdlib for CPython 3.7.12. This will be the last
+ release of PyPy3.7.
- PyPy3.8, which is an interpreter supporting the syntax and the features of
Python 3.8, including the stdlib for CPython 3.8.12. This is our third
@@ -29,25 +30,28 @@ wish to share. The release includes four different interpreters:
- PyPy3.9, which is an interpreter supporting the syntax and the features of
Python 3.9, including the stdlib for CPython 3.9.10. As this is our first
release of this interpreter, we relate to this as "beta" quality. We
- welcome testing of this version, if you discover incompatibilites, please
- report them so we can gain confidence in the version.
+ welcome testing of this version, if you discover incompatibilities, please
+ report them so we can gain confidence in the version. There is still a known
+ `speed regression`_ around ``**kwargs`` handling in 3.9.
The interpreters are based on much the same codebase, thus the multiple
release. This is a micro release, all APIs are compatible with the other 7.3
releases. Highlights of the release, since the release of 7.3.7 in late October 2021,
include:
- - Improvement in ssl's use of CFFI buffers to speed up ``recv`` and ``recvinto``
- - PyPy3.9 uses a python version of the peg parser which brought with it a
+ - PyPy3.9 uses an RPython version of the PEG parser which brought with it a
cleanup of the lexer and parser in general
- Fixed a regression in PyPy3.8 when JITting empty list comprehenshions
- Tweaked some issues around changing the file layout after packaging to make
- PyPy more compatible with CPython
+ the on-disk layout of PyPy3.8 more compatible with CPython. This requires
+ ``setuptools>=58.1.0``
- RPython now allows the target executable to have a ``.`` in its name, so
PyPy3.9 will produce a ``pypy3.9-c`` and ``libpypy3.9-c.so``. Changing the
name of the shared object to be version-specific (it used to be
``libpypy3-c.so``) will allow it to live alongside other versions.
- Building PyPy3.9+ accepts a ``--platlibdir`` argument like CPython.
+ - Improvement in ssl's use of CFFI buffers to speed up ``recv`` and ``recvinto``
+ - Update the packaged OpenSSL to 1.1.1m
We recommend updating. You can find links to download the v7.3.8 releases here:
@@ -121,10 +125,14 @@ Bugfixes shared across versions
- Copy ``dtoa`` changes from CPython (bpo40780_)
- Use ``symtable`` to improve the position of "duplicate argument" errors
- Add ``__builtins__`` to globals ``dict`` when calling ``eval`` (issue 3584_)
+- Update embedded OpenSSL to 1.1.1m (bpo43522_)
+- Avoid using ``epoll_event`` directly from RPython since it is a ``packed struct``
+- Clean up some compilation warnings around `const char *`` conversions to
+ ``char *``
Speedups and enhancements shared across versions
------------------------------------------------
-- Add unicodedata version 13, use 3.2 by default
+- Add unicodedata version 13, make 3.2 the basis of unicodedata compression
- Use 10.9 as a minimum ``MACOSX_DEPLOYMENT_TARGET`` to match CPython
- Only compute the ``Some*`` annotation types once, not every time we call a
type checked function
@@ -134,9 +142,11 @@ Speedups and enhancements shared across versions
- Stop doing guard strengthening with guards that come from inlining the short
preamble. doing that can lead to endless bridges (issue 3598_)
- Split `__pypy__.do_what_I_mean()`` into the original plus ``__pypy__._internal_crash``
- to make the meaning more clear. These are functions useful for internal
+ to make the meaning more clear. These are functions only useful for internal
testing (issue 3617_).
- Prepare ``_ssl`` for OpenSSL3
+- Improve ``x << y`` where ``x`` and ``y`` are ints but the results doesn't fit
+ into a machine word: don't convert ``y`` to ``rbigint`` and back to int
C-API (cpyext) and C-extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -169,7 +179,22 @@ Python 3.7+ bugfixes
segfault
- Detail about ``PYTHONIOENCODING``: if the encoding or the error is ommitted,
always use ``utf-8/strict`` (instead of asking the locale)
-- Fix for bpo43522_, use embedded OpenSSL to 1.1.1m
+- Disallow overriding the ``__context__`` descriptor from ``BaseException``
+ when chaining exceptions (issue 3644_)
+- Replace ``raise ImportError`` with ``raise ModuleNotFoundError`` where
+ appropriate in pure-python equivalents of CPython builtin modules
+- Add missing ``rewinddir()`` at the end of ``os.scandir``
+- ``os.dup2`` now returns ``fd2``
+- Make ``__fspath__`` errors compatible with CPython
+- Fix handling of backslash in raw unicode escape decoders that don't
+ start valid escape sequences (issue 3652_)
+- Add missing equivalent of ``_Py_RestoreSignals()`` call in ``fork_exec``
+- Catch exceptions in ``atexit`` functions to avoid crashing the interpreter at
+ shutdown
+- Update ``fast2locals`` to deal with the fact that it's now possible to
+ delete cell vars (was forbidden in python2) (issue 3656_)
+delete cell vars (was forbidden in python2).
+- Allow hashing memoryviews (issue 2756_)
Python 3.7+ speedups and enhancements
-------------------------------------
@@ -185,13 +210,14 @@ Python 3.7+ speedups and enhancements
- Fix the ctypes errcheck_ protocol
- Various fixes in the windows-only ``_overlapped`` module (issue 3625_)
- Implement ``-X utf8``
+- Add ``WITH_DYLD`` to ``sysconfig`` for darwin
Python 3.7 C-API
~~~~~~~~~~~~~~~~
- Added ``PyDescr_NewGetSet``, ``PyModule_NewObject``, ``PyModule_ExecDef``,
``PyCodec_Decode``, ``PyCodec_Encode``, ``PyErr_WarnExplicit``,
- ``PyDateTime_TimeZone_UTC``
+ ``PyDateTime_TimeZone_UTC``, ``PyUnicode_DecodeLocaleAndSize``
- Fix segfault when using format strings in ``PyUnicode_FromFormat`` and
``PyErr_Format`` (issue 3593_)
- ``_PyObject_LookupAttrId`` does not raise ``AttributeError``
@@ -202,10 +228,10 @@ Python 3.7 C-API
- Alias ``PyDateTime_DATE_GET_FOLD``, which CPython uses instead of the
documented ``PyDateTime_GET_FOLD`` (issue 3627_)
- Add some ``_PyHASH*`` macros (issue 3590_)
+- Fix signature of ``PyUnicode_DecodeLocale`` (issue 3661_)
Python 3.8+ bugfixes
--------------------
-- Fixed a regression when JITting empty list comprehenshions (issue 3598_)
- Unwrapping an unsigned short raises ``ValueError`` on negative numbers
- Make properties unpicklable
- When packaging, fix finding dependencies of shared objects for portable
@@ -217,16 +243,19 @@ Python 3.8+ bugfixes
stdlib tests to allow PyPy's repr. bpo35545_ touches on this. (issue 3628_)
- Fix small bugs when raising errors in various stdlib modules that caused
stdlib test failures
+- Update bundled ``setuptools`` to ``58.1.0`` to get the fix for the new PyPy
+ layout
Python 3.8+ speedups and enhancements
-------------------------------------
- Implement reversed items and values iterator pickling, fix reversed keys
iterator pickling
- Add more auditing events, while skipping CPython-specific tracing and
- attribute-modifaction tracing
+ attribute-modification tracing
+- Fixed a speed regression when JITting empty list comprehensions (issue
+ 3598_)
- Make sure that all bytecodes that can close a loop go via ``jump_absolute``,
so the JIT can trace them
-- Add more auditing events
Python 3.8 C-API
~~~~~~~~~~~~~~~~
@@ -237,7 +266,10 @@ Python 3.8 C-API
``tp_pypy_flags`` slot. Users should upgrade Cython to 0.2.26 to avoid a
compiler warning.
- Add ``PyCompilerFlags.cf_feature_version`` (bpo35766_)
+- Distinguish between a c-api ``CMethod`` and an app-level ``Method``, which
+ is important for obscure reasons
+.. _2756: https://foss.heptapod.net/pypy/pypy/-/issues/2756
.. _3589: https://foss.heptapod.net/pypy/pypy/-/issues/3589
.. _3584: https://foss.heptapod.net/pypy/pypy/-/issues/3584
.. _3598: https://foss.heptapod.net/pypy/pypy/-/issues/3598
@@ -256,6 +288,11 @@ Python 3.8 C-API
.. _3628: https://foss.heptapod.net/pypy/pypy/-/issues/3628
.. _3627: https://foss.heptapod.net/pypy/pypy/-/issues/3627
.. _3630: https://foss.heptapod.net/pypy/pypy/-/issues/3630
+.. _3644: https://foss.heptapod.net/pypy/pypy/-/issues/3644
+.. _3642: https://foss.heptapod.net/pypy/pypy/-/issues/3642
+.. _3652: https://foss.heptapod.net/pypy/pypy/-/issues/3652
+.. _3656: https://foss.heptapod.net/pypy/pypy/-/issues/3656
+.. _3661: https://foss.heptapod.net/pypy/pypy/-/issues/3661
.. _bpo35883: https://bugs.python.org/issue35883
.. _bpo44954: https://bugs.python.org/issue44954
.. _bpo40780: https://bugs.python.org/issue40780
@@ -263,3 +300,4 @@ Python 3.8 C-API
.. _bpo43522: https://bugs.python.org/issue43522
.. _bpo35545: https://bugs.python.org/issue35545
.. _errcheck: https://docs.python.org/3/library/ctypes.html#ctypes._FuncPtr.errcheck
+.. _`speed regression`_: https://foss.heptapod.net/pypy/pypy/-/issues/3649
diff --git a/pypy/doc/tool/makecontributor.py b/pypy/doc/tool/makecontributor.py
index d30c5d8640..b318770132 100644
--- a/pypy/doc/tool/makecontributor.py
+++ b/pypy/doc/tool/makecontributor.py
@@ -14,26 +14,26 @@ import mercurial.ui
ROOT = py.path.local(__file__).join('..', '..', '..', '..')
author_re = re.compile('(.*) <.*>')
pair_programming_re = re.compile(r'^\((.*?)\)')
-excluded = set(["pypy", "convert-repo", "hgattic"])
+excluded = set(["pypy", "convert-repo", "hgattic", '"Miss Islington (bot)"'])
alias = {
'Anders Chrigstrom': ['arre'],
'Antonio Cuni': ['antocuni', 'anto'],
'Armin Rigo': ['arigo', 'arfigo', 'armin', 'arigato'],
- 'Maciej Fijalkowski': ['fijal'],
+ 'Maciej Fijałkowski': ['fijal', 'Maciej Fijalkowski'],
'Carl Friedrich Bolz-Tereick': ['Carl Friedrich Bolz', 'cfbolz', 'cf', 'cbolz'],
'Samuele Pedroni': ['pedronis', 'samuele', 'samule'],
'Richard Plangger': ['planrich', 'plan_rich'],
'Remi Meier': ['remi'],
'Michael Hudson-Doyle': ['mwh', 'Michael Hudson'],
'Holger Krekel': ['hpk', 'holger krekel', 'holger', 'hufpk'],
- "Amaury Forgeot d'Arc": ['afa', 'amauryfa@gmail.com'],
+ "Amaury Forgeot d'Arc": ['afa', 'amauryfa@gmail.com', 'amaury'],
'Alex Gaynor': ['alex', 'agaynor'],
'David Schneider': ['bivab', 'david'],
'Christian Tismer': ['chris', 'christian', 'tismer',
'tismer@christia-wjtqxl.localdomain'],
'Benjamin Peterson': ['benjamin'],
- 'Hakan Ardo': ['hakan', 'hakanardo'],
+ 'Håkan Ardö': ['hakan', 'hakanardo', 'Hakan Ardo'],
'Niklaus Haldimann': ['nik'],
'Alexander Schremmer': ['xoraxax'],
'Anders Hammarquist': ['iko'],
@@ -46,7 +46,7 @@ alias = {
'Eric van Riet Paap': ['ericvrp'],
'Jacob Hallen': ['jacob', 'jakob', 'jacob hallen'],
'Anders Lehmann': ['ale', 'anders'],
- 'Vanessa Freudenberg': ['bert'],
+ 'Vanessa Freudenberg': ['bert', 'Bert Freudenberg'],
'Boris Feigin': ['boris', 'boria'],
'Valentino Volonghi': ['valentino', 'dialtone'],
'Aurelien Campeas': ['aurelien', 'aureliene'],
@@ -96,6 +96,10 @@ alias = {
'Brad Kish': ['rtkbkish'],
'Michał Górny': ['mgorny'],
'David Hewitt': ['davidhewitt'],
+ 'Adrian Kuhn': ['akuhn'],
+ 'David Malcolm': ['dmalcolm'],
+ 'Simon Cross': ['hodgestar'],
+ 'Łukasz Langa': ['ambv'],
}
alias_map = {}
@@ -150,7 +154,7 @@ def main(show_numbers):
# uncomment the next lines to get the list of nicknamed which could not be
# parsed from commit logs
- ## items = ignored_nicknames.items()
+ ## items = list(ignored_nicknames.items())
## items.sort(key=operator.itemgetter(1), reverse=True)
## for name, n in items:
## if show_numbers:
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
index 89d65c2a7d..0b20d09d75 100644
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -418,6 +418,8 @@ class PythonCodeGenerator(assemble.PythonCodeMaker):
if doc_expr is not None:
start = 1
doc_expr.walkabout(self)
+ if doc_expr.lineno > 0:
+ self.update_position(doc_expr.lineno)
self.name_op("__doc__", ast.Store, doc_expr)
self.scope.doc_removable = True
self._visit_body(body, start)
@@ -551,6 +553,9 @@ class PythonCodeGenerator(assemble.PythonCodeMaker):
self.update_position(dec.lineno)
dec.walkabout(self)
+ if func.lineno > 0:
+ self.update_position(func.lineno)
+
args = func.args
assert isinstance(args, ast.arguments)
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py
index a50580482b..63f9aabc97 100644
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -2037,6 +2037,27 @@ x = [c for c in expr_lines.__code__.co_lnotab]
"""
self.st(func, "x", [0, 1, 2, 1, 2, 255])
+ def test_lineno_docstring_class(self):
+ func = """
+def expr_lines(x):
+ class A:
+ "abc"
+x = [c for c in expr_lines.__code__.co_consts[1].co_lnotab]
+"""
+ self.st(func, "x", [8, 1])
+
+ def test_lineno_funcdef(self):
+ func = '''def f():
+ @decorator
+ def my_function(
+ x=x
+ ):
+ pass
+x = [c for c in f.__code__.co_lnotab]
+'''
+ self.st(func, 'x', [0, 1, 2, 2, 2, 255])
+
+
def test_revdb_metavar(self):
self.error_test("7 * $0", SyntaxError)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
index 9ed8eee5b5..309dae4e0d 100644
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -464,7 +464,12 @@ class ObjSpace(object):
ret = 0
self.wait_for_thread_shutdown()
w_atexit = self.getbuiltinmodule('atexit')
- self.call_method(w_atexit, '_run_exitfuncs')
+ try:
+ self.call_method(w_atexit, '_run_exitfuncs')
+ except OperationError:
+ # discard exceptions, see call_py_exitfuncs in pylifecycle.c in
+ # CPython
+ pass
self.sys.finalizing = True
if self.sys.flush_std_files(self) < 0:
ret = -1
@@ -1198,8 +1203,8 @@ class ObjSpace(object):
return self.call_args(w_callable, args)
def _try_fetch_pycode(self, w_func):
- from pypy.interpreter.function import Function, Method
- if isinstance(w_func, Method):
+ from pypy.interpreter.function import Function, _Method
+ if isinstance(w_func, _Method):
w_func = w_func.w_function
if isinstance(w_func, Function):
return w_func.code
@@ -1209,8 +1214,8 @@ class ObjSpace(object):
nargs = len(args_w) # used for pruning funccall versions
if not self.config.objspace.disable_call_speedhacks and nargs < 5:
# start of hack for performance
- from pypy.interpreter.function import Function, Method
- if isinstance(w_func, Method):
+ from pypy.interpreter.function import Function, _Method
+ if isinstance(w_func, _Method):
if nargs < 4:
func = w_func.w_function
if isinstance(func, Function):
@@ -1225,7 +1230,7 @@ class ObjSpace(object):
def call_valuestack(self, w_func, nargs, frame, methodcall=False):
# methodcall is only used for better error messages in argument.py
- from pypy.interpreter.function import Function, Method, is_builtin_code
+ from pypy.interpreter.function import Function, _Method, is_builtin_code
if frame.get_is_being_profiled() and is_builtin_code(w_func):
# XXX: this code is copied&pasted :-( from the slow path below
# call_valuestack().
@@ -1234,7 +1239,7 @@ class ObjSpace(object):
if not self.config.objspace.disable_call_speedhacks:
# start of hack for performance
- if isinstance(w_func, Method):
+ if isinstance(w_func, _Method):
# reuse callable stack place for w_inst
frame.settopvalue(w_func.w_instance, nargs)
nargs += 1
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
index 01120d756d..2abd10b6e3 100644
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -416,13 +416,16 @@ class OperationError(Exception):
def chain_exceptions(self, space, context):
"""Attach another OperationError as __context__."""
+ from pypy.module.exceptions.interp_exceptions import W_BaseException
self.normalize_exception(space)
w_value = self.get_w_value(space)
context.normalize_exception(space)
w_context = context.get_w_value(space)
if not space.is_w(w_value, w_context):
+ if not isinstance(w_value, W_BaseException):
+ raise oefmt(space.w_SystemError, "not an instance of Exception: %T", w_value)
_break_context_cycle(space, w_value, w_context)
- space.setattr(w_value, space.newtext('__context__'), w_context)
+ w_value.descr_setcontext(space, w_context)
def chain_exceptions_from_cause(self, space, exception):
# XXX does this code really make sense?
@@ -474,17 +477,19 @@ def _break_context_cycle(space, w_value, w_context):
This is O(chain length) but context chains are usually very short. Uses
Floyd's cycle algorithm.
"""
+ from pypy.module.exceptions.interp_exceptions import W_BaseException
w_rabbit = w_context
w_tortoise = w_context
update_tortoise_toggle = False
- w_attrname_context = space.newtext('__context__')
while True:
- w_next = space.getattr(w_rabbit, w_attrname_context)
- if space.is_w(w_next, space.w_None):
+ if not isinstance(w_rabbit, W_BaseException):
+ raise oefmt(space.w_SystemError, "not an instance of Exception: %T", w_rabbit)
+ w_next = w_rabbit.descr_getcontext(space)
+ if space.is_none(w_next):
break
if space.is_w(w_next, w_value):
- space.setattr(w_rabbit, w_attrname_context, space.w_None)
+ w_rabbit.descr_setcontext(space, space.w_None)
break
w_rabbit = w_next
if space.is_w(w_rabbit, w_tortoise):
@@ -492,7 +497,9 @@ def _break_context_cycle(space, w_value, w_context):
break
if update_tortoise_toggle:
# every other iteration
- w_tortoise = space.getattr(w_rabbit, w_attrname_context)
+ if not isinstance(w_tortoise, W_BaseException):
+ raise oefmt(space.w_SystemError, "not an instance of Exception: %T", w_tortoise)
+ w_tortoise = w_tortoise.descr_getcontext(space)
update_tortoise_toggle = not update_tortoise_toggle
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
index c4c832cc01..a4e88a5404 100644
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -530,7 +530,7 @@ def descr_function_get(space, w_function, w_obj, w_cls=None):
return Method(space, w_function, w_obj)
-class Method(W_Root):
+class _Method(W_Root):
"""A method is a function bound to a specific instance."""
_immutable_fields_ = ['w_function', 'w_instance']
@@ -540,15 +540,6 @@ class Method(W_Root):
self.w_function = w_function
self.w_instance = w_instance
- def descr_method__new__(space, w_subtype, w_function, w_instance):
- if space.is_w(w_instance, space.w_None):
- w_instance = None
- if w_instance is None:
- raise oefmt(space.w_TypeError, "self must not be None")
- method = space.allocate_instance(Method, w_subtype)
- Method.__init__(method, space, w_function, w_instance)
- return method
-
def __repr__(self):
return u"bound method %s" % (self.w_function.getname(self.space),)
@@ -592,7 +583,7 @@ class Method(W_Root):
def descr_method_eq(self, w_other):
space = self.space
- if not isinstance(w_other, Method):
+ if not isinstance(w_other, _Method):
return space.w_NotImplemented
if not space.is_w(self.w_instance, w_other.w_instance):
return space.w_False
@@ -621,6 +612,15 @@ class Method(W_Root):
tup = [w_instance, space.newtext(w_function.getname(space))]
return space.newtuple([new_inst, space.newtuple(tup)])
+class Method(_Method):
+ def descr_method__new__(space, w_subtype, w_function, w_instance):
+ if space.is_w(w_instance, space.w_None):
+ w_instance = None
+ if w_instance is None:
+ raise oefmt(space.w_TypeError, "self must not be None")
+ method = space.allocate_instance(Method, w_subtype)
+ _Method.__init__(method, space, w_function, w_instance)
+ return method
class StaticMethod(W_Root):
"""The staticmethod objects."""
@@ -730,7 +730,7 @@ class BuiltinFunction(Function):
def is_builtin_code(w_func):
from pypy.interpreter.gateway import BuiltinCode
- if isinstance(w_func, Method):
+ if isinstance(w_func, _Method):
w_func = w_func.w_function
if isinstance(w_func, Function):
code = w_func.getcode()
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
index d4169b7c81..95181cf7e8 100644
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -123,6 +123,11 @@ return next yielded value or raise StopIteration."""
if self.saved_operr is not None:
ec.set_sys_exc_info(self.saved_operr)
self.saved_operr = None
+ d = frame.getdebug()
+ if d is not None:
+ # on CPython, those don't live on the frame and start with default
+ # value when running execute_frame
+ d.instr_lb = d.instr_ub = d.instr_prev_plus_one = 0
self.running = True
try:
w_result = frame.execute_frame(w_arg_or_err)
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
index 0e2333ed7a..77af215611 100644
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -517,14 +517,14 @@ class PyFrame(W_Root):
'Classname object'"""
# XXX this is super annoying to compute every time we do a function call!
# CPython has a similar function, PyEval_GetFuncName
- from pypy.interpreter.function import Function, Method
+ from pypy.interpreter.function import Function, _Method
if fnname is not None:
return fnname + '()'
if w_function is None:
return None
if isinstance(w_function, Function):
return w_function.name + '()'
- if isinstance(w_function, Method):
+ if isinstance(w_function, _Method):
return self._guess_function_name_parens(None, w_function.w_function)
return self.space.type(w_function).getname(self.space) + ' object'
@@ -604,7 +604,12 @@ class PyFrame(W_Root):
try:
w_value = cell.get()
except ValueError:
- pass
+ w_name = self.space.newtext(name)
+ try:
+ self.space.delitem(d.w_locals, w_name)
+ except OperationError as e:
+ if not e.match(self.space, self.space.w_KeyError):
+ raise
else:
self.space.setitem_str(d.w_locals, name, w_value)
@@ -643,6 +648,8 @@ class PyFrame(W_Root):
w_value = self.space.finditem_str(w_locals, name)
if w_value is not None:
cell.set(w_value)
+ else:
+ cell.set(None)
@jit.unroll_safe
def init_cells(self):
@@ -842,6 +849,8 @@ class PyFrame(W_Root):
for i in range(len(self.locals_cells_stack_w)):
w_oldvalue = self.locals_cells_stack_w[i]
if isinstance(w_oldvalue, Cell):
+ # we can't mutate w_oldvalue here, because that could still be
+ # shared by an inner/outer function
w_newvalue = Cell(
None, w_oldvalue.family)
else:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
index 34fd986285..1d8f13617f 100644
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -3,6 +3,7 @@ Implementation of a part of the standard Python opcodes.
The rest, dealing with variables in optimized ways, is in nestedscope.py.
"""
+import sys
from rpython.rlib import jit, rstackovf, rstring
from rpython.rlib.debug import check_nonneg
@@ -71,7 +72,21 @@ class __extend__(pyframe.PyFrame):
try:
next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
except OperationError as operr:
- operr.record_context(self.space, ec)
+ try:
+ operr.record_context(self.space, ec)
+ except OperationError as operr2:
+ # this should be unreachable! but we don't want to crash if it
+ # still happens
+ operr.normalize_exception(self.space)
+ operr2.normalize_exception(self.space)
+ # NB: don't *raise* it, it's handled by the
+ # handle_operation_error call below (otherwise some higher up
+ # except block handles it)
+ operr = oefmt(
+ self.space.w_TypeError,
+ "couldn't record exception context for exception '%T', got: %R",
+ operr.get_w_value(self.space),
+ operr2.get_w_value(self.space))
next_instr = self.handle_operation_error(ec, operr)
except RaiseWithExplicitTraceback as e:
next_instr = self.handle_operation_error(ec, e.operr,
@@ -1846,14 +1861,17 @@ class FinallyBlock(FrameBlock):
# set the current value of sys_exc_info to operationerr,
# saving the old value in a custom type of FrameBlock
frame.save_and_change_sys_exc_info(operationerr)
- if frame.get_w_f_trace() is not None:
- # force a line trace event next, by setting instr_prev_plus_one to
- # a high value, simulating a backward jump to the line trace logic
- # in executioncontext (CPython has the same code, see
- # test_trace_generator_finalisation for why it's needed)
- debugdata = frame.getdebug()
- assert debugdata is not None
- debugdata.instr_prev_plus_one = len(frame.pycode.co_code) + 1
+ d = frame.getdebug()
+ if d is not None and d.w_f_trace is not None:
+ needs_new_execution_window = not (d.instr_lb <= frame.last_instr < d.instr_ub)
+ needs_line_update = d.instr_lb == frame.last_instr or frame.last_instr < d.instr_prev_plus_one
+ # logic taken from CPython, see test_trace_generator_finalisation
+
+ # Make sure that we trace line after exception if we are in a new execution
+ # window or we don't need a line update and we are not in the first instruction
+ # of the line.
+ if needs_new_execution_window or (not needs_line_update and d.instr_lb > 0):
+ d.instr_prev_plus_one = sys.maxint
return r_uint(self.handlerposition) # jump to the handler
def pop_block(self, frame):
diff --git a/pypy/interpreter/pyparser/baserpypeg.py b/pypy/interpreter/pyparser/baserpypeg.py
index 0f6b60d91b..62b1bfc0d0 100644
--- a/pypy/interpreter/pyparser/baserpypeg.py
+++ b/pypy/interpreter/pyparser/baserpypeg.py
@@ -759,8 +759,12 @@ class Parser:
start_lineno = tok.lineno
start_col_offset = tok.column
if end_lineno == -1:
- end_lineno = tok.end_lineno
- end_column = tok.end_column
+ if tok.end_lineno != -1:
+ end_lineno = tok.end_lineno
+ end_column = tok.end_column
+ else:
+ end_lineno = start_lineno
+ end_column = start_col_offset
if line_from_token:
line = tok.line
diff --git a/pypy/interpreter/pyparser/error.py b/pypy/interpreter/pyparser/error.py
index 110452ed42..f981586b3a 100644
--- a/pypy/interpreter/pyparser/error.py
+++ b/pypy/interpreter/pyparser/error.py
@@ -6,7 +6,7 @@ class SyntaxError(Exception):
lastlineno=0):
self.msg = msg
self.lineno = lineno
- # NB: offset is a 1-based index!
+ # NB: offset is a 1-based index into the bytes source
self.offset = offset
self.text = text
self.filename = filename
@@ -38,7 +38,7 @@ class SyntaxError(Exception):
except: # we can't allow any exceptions here!
return None""")
elif text is not None:
- from rpython.rlib.runicode import str_decode_utf_8_impl
+ from pypy.interpreter.unicodehelper import _str_decode_utf8_slowpath
# text may not be UTF-8 in case of decoding errors.
# adjust the encoded text offset to a decoded offset
# XXX do the right thing about continuation lines, which
@@ -49,19 +49,24 @@ class SyntaxError(Exception):
# codepoint-based index into the decoded unicode-version of
# self.text
- # XXX stop using runicode here!
def replace_error_handler(errors, encoding, msg, s, startpos, endpos):
- # must return unicode
- return u'\ufffd', endpos
+ return b'\xef\xbf\xbd', endpos, 'b', s
+
+ replacedtext, unilength, _ = _str_decode_utf8_slowpath(
+ text, 'replace', False, replace_error_handler, True)
if offset > len(text):
- offset = len(text)
- replacedtext, _ = str_decode_utf_8_impl(text, offset,
- 'replace', False, replace_error_handler, True)
- offset = len(replacedtext)
- if len(text) != offset:
- replacedtext, _ = str_decode_utf_8_impl(text, len(text),
- 'replace', False, replace_error_handler, True)
- w_text = space.newtext(replacedtext.encode('utf8'), len(replacedtext))
+ offset = unilength
+ elif offset >= 1:
+ offset = offset - 1 # 1-based to 0-based
+ assert offset >= 0
+ # slightly inefficient, call the decoder for text[:offset] too
+ _, offset, _ = _str_decode_utf8_slowpath(
+ text[:offset], 'replace', False, replace_error_handler,
+ True)
+ offset += 1 # convert to 1-based
+ else:
+ offset = 0
+ w_text = space.newutf8(replacedtext, unilength)
return space.newtuple([
space.newtext(self.msg),
space.newtuple([
diff --git a/pypy/interpreter/test/apptest_pyframe.py b/pypy/interpreter/test/apptest_pyframe.py
index f2c30afc6f..37f5dced02 100644
--- a/pypy/interpreter/test/apptest_pyframe.py
+++ b/pypy/interpreter/test/apptest_pyframe.py
@@ -545,6 +545,7 @@ def test_trace_generator_finalisation():
(6, 'return'),
(12, 'return')]
+
def test_dont_trace_on_reraise():
import sys
l = []
@@ -567,6 +568,40 @@ def test_dont_trace_on_reraise():
assert len(l) == 1
assert issubclass(l[0][0], Exception)
+def test_dont_trace_on_reraise2():
+ import sys
+ l = []
+ got_exc = []
+ def trace(frame, event, arg):
+ l.append((frame.f_lineno, event))
+ if event == 'exception':
+ got_exc.append(arg)
+ return trace
+
+
+ d = {}
+ exec("""
+def b(reraise): # line 2
+ try:
+ try:
+ raise Exception(exc)
+ except Exception as e:
+ if reraise:
+ raise
+ print("after raise") # Not run, line 9
+ except:
+ pass
+ """, d)
+
+ sys.settrace(trace)
+ d['b'](True)
+ sys.settrace(None)
+ assert l == [(2, 'call'), (3, 'line'), (4, 'line'),
+ (5, 'line'), (5, 'exception'), (6, 'line'),
+ (7, 'line'), (8, 'line'), # not 9!
+ (10, 'line'), (11, 'line'),
+ (11, 'return')]
+
def test_trace_changes_locals():
import sys
def trace(frame, what, arg):
@@ -949,3 +984,24 @@ def test_clear_locals():
inner.clear()
assert not outer.f_locals
assert not inner.f_locals
+
+
+def test_locals2fast_del_cell_var():
+ import sys
+ def t(frame, event, *args):
+ if 'a' in frame.f_locals:
+ del frame.f_locals['a']
+ return t
+ def f():
+ def g(): a
+ a = 1
+ a = 2
+ return a
+
+ sys.settrace(t)
+ try:
+ with pytest.raises(UnboundLocalError):
+ f()
+ finally:
+ sys.settrace(None)
+
diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py
index ef193bc8e1..1536a0ce23 100644
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -959,6 +959,11 @@ class AppTestCompiler(object):
raises(SyntaxError, eval, b'\xff\x20')
raises(SyntaxError, eval, b'\xef\xbb\x20')
+ def test_unicode_identifier_error_offset(self):
+ info = raises(SyntaxError, eval, b'\xe2\x82\xac = 1')
+ assert info.value.offset == 1
+ assert raises(SyntaxError, eval, b'\xc3\xa4 + \xe2\x82\xac').value.offset == 5
+
def test_import_nonascii(self):
c = compile('from os import 日本', '', 'exec')
assert ('日本',) in c.co_consts
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
index 16b713ab29..756bcd16c1 100644
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -444,12 +444,12 @@ class TestModuleMinimal:
w2 = space.new_interned_w_str(w0)
assert w2 is w0
- def test_exitfunc_catches_exceptions(self):
+ def test_atexit_catches_exceptions(self):
from pypy.tool.pytest.objspace import maketestobjspace
space = maketestobjspace()
space.appexec([], """():
- import sys
- sys.exitfunc = lambda: this_is_an_unknown_name
+ import atexit
+ atexit.register(lambda: this_is_an_unknown_name)
""")
ret = space.finish()
assert ret == 0
diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py
index 14c82c8ec6..38da26a916 100644
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -137,6 +137,20 @@ class AppTestPyFrame:
if hasattr(self, "check_no_w_locals"): # not appdirect
assert self.check_no_w_locals(fh.frame)
+ def test_del_cell_locals_bug(self):
+ """
+ def f():
+ x = object()
+
+ def foo():
+ print(x)
+
+ locals()
+ del x
+ assert "x" not in locals()
+ f()
+ """
+
def test_repr(self):
import sys
def a_name(a, b, c):
diff --git a/pypy/interpreter/test/test_raise.py b/pypy/interpreter/test/test_raise.py
index a7f3ebc0bb..862132186a 100644
--- a/pypy/interpreter/test/test_raise.py
+++ b/pypy/interpreter/test/test_raise.py
@@ -385,18 +385,47 @@ class AppTestRaiseContext:
fail("No exception raised")
def test_preexisting_cycle(self):
- def chain(e):
- res = Exception()
+ def chain(e, i=0):
+ res = Exception(i)
res.__context__ = e
return res
def cycle():
try:
raise ValueError(1)
except ValueError as ex:
- ex.__context__ = chain(chain(chain(ex))) # make cycle ourselves
+ start = curr = Exception()
+ for i in range(chainlength):
+ curr = chain(curr, i) # make cycle ourselves
+ start.__context__ = curr
+ for i in range(prelength):
+ curr = chain(curr, i + chainlength)
+ ex.__context__ = curr
raise TypeError(2) # shouldn't hang here
-
- raises(TypeError, cycle)
+ for chainlength in range(2, 7):
+ for prelength in range(2, 7):
+ print(chainlength, prelength)
+ raises(TypeError, cycle)
+
+ def test_long_cycle_broken(self):
+ def chain(e, i=0):
+ res = Exception(i)
+ res.__context__ = e
+ return res
+ def cycle():
+ try:
+ raise ValueError(1)
+ except ValueError as ex:
+ start = curr = TypeError()
+ for i in range(chainlength):
+ curr = chain(curr, i) # make cycle ourselves
+ ex.__context__ = curr
+ raise start
+ for chainlength in range(2, 7):
+ print(chainlength)
+ exc = raises(TypeError, cycle).value
+ for i in range(chainlength + 1):
+ exc = exc.__context__
+ assert exc.__context__ is None # got broken
def test_reraise_cycle_broken(self):
try:
@@ -519,6 +548,28 @@ class AppTestRaiseContext:
else:
assert False, "should have raised"
+ def test_context_setter_ignored(self):
+ class MyExc(Exception):
+ def __setattr__(self, name, value):
+ assert name != "__context__"
+
+ with raises(MyExc) as excinfo:
+ try:
+ raise KeyError
+ except KeyError:
+ raise MyExc
+ assert isinstance(excinfo.value.__context__, KeyError)
+
+ def test_context_getter_ignored(self):
+ class MyExc(Exception):
+ __context__ = property(None, None, None)
+
+ with raises(KeyError):
+ try:
+ raise MyExc
+ except MyExc:
+ raise KeyError
+
class AppTestTraceback:
diff --git a/pypy/interpreter/test/test_unicodehelper.py b/pypy/interpreter/test/test_unicodehelper.py
index d05c6dff02..4e120ed79e 100644
--- a/pypy/interpreter/test/test_unicodehelper.py
+++ b/pypy/interpreter/test/test_unicodehelper.py
@@ -84,7 +84,7 @@ def test_latin1_shortcut_bug(space):
sin = u"a\xac\u1234\u20ac\u8000"
assert utf8_encode_latin_1(sin.encode("utf-8"), "backslashreplace", handler) == sin.encode("latin-1", "backslashreplace")
-def test_unicode_escape_incremental_bug(space):
+def test_unicode_escape_incremental_bug():
class FakeUnicodeDataHandler:
def call(self, name):
assert name == "QUESTION MARK"
@@ -98,7 +98,7 @@ def test_unicode_escape_incremental_bug(space):
assert lgt1 + lgt2 == len(data)
assert input == (result1 + result2).decode("utf-8")
-def test_raw_unicode_escape_incremental_bug(space):
+def test_raw_unicode_escape_incremental_bug():
input = u"xҰa𐀂"
data = b'x\\u04b0a\\U00010002'
for i in range(1, len(data)):
@@ -106,3 +106,10 @@ def test_raw_unicode_escape_incremental_bug(space):
result2, _, lgt2 = str_decode_raw_unicode_escape(data[lgt1:i] + data[i:], 'strict', True, None)
assert lgt1 + lgt2 == len(data)
assert input == (result1 + result2).decode("utf-8")
+
+def test_raw_unicode_escape_backslash_without_escape():
+ data = b'[:/?#[\\]@]\\'
+ result, _, l = str_decode_raw_unicode_escape(data, 'strict', True, None)
+ assert l == len(data)
+ assert result == data
+
diff --git a/pypy/interpreter/unicodehelper.py b/pypy/interpreter/unicodehelper.py
index 63c2d6d238..b67b70e3e3 100644
--- a/pypy/interpreter/unicodehelper.py
+++ b/pypy/interpreter/unicodehelper.py
@@ -773,9 +773,14 @@ def str_decode_raw_unicode_escape(s, errors, final=False,
if s[pos] == 'u':
digits = 4
message = "truncated \\uXXXX escape"
- else:
+ elif s[pos] == 'U':
digits = 8
message = "truncated \\UXXXXXXXX escape"
+ else:
+ builder.append_char('\\')
+ builder.append_char(ch)
+ pos += 1
+ continue
pos += 1
if pos + digits > len(s) and not final:
pos -= 2
diff --git a/pypy/module/_locale/moduledef.py b/pypy/module/_locale/moduledef.py
index 6d91bf3718..550f8e8b4d 100644
--- a/pypy/module/_locale/moduledef.py
+++ b/pypy/module/_locale/moduledef.py
@@ -22,7 +22,7 @@ class Module(MixedModule):
interpleveldefs.update({
'nl_langinfo': 'interp_locale.nl_langinfo',
})
- if rlocale.HAVE_LIBINTL:
+ if rlocale.HAVE_LIBINTL and not sys.platform == 'darwin':
interpleveldefs.update({
'gettext': 'interp_locale.gettext',
'dgettext': 'interp_locale.dgettext',
diff --git a/pypy/module/_posixsubprocess/_posixsubprocess.c b/pypy/module/_posixsubprocess/_posixsubprocess.c
index d301576794..ccaa14c781 100644
--- a/pypy/module/_posixsubprocess/_posixsubprocess.c
+++ b/pypy/module/_posixsubprocess/_posixsubprocess.c
@@ -9,6 +9,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <signal.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -54,7 +55,6 @@
#define POSIX_CALL(call) do { if ((call) == -1) goto error; } while (0)
-
/* Convert ASCII to a positive int, no libc call. no overflow. -1 on error. */
static int
_pos_int_from_ascii(char *name)
@@ -69,6 +69,24 @@ _pos_int_from_ascii(char *name)
return num;
}
+static
+void local_pypysig_default(int signum)
+{
+ /* copied from pyypsig_default */
+#ifdef SA_RESTART
+ /* assume sigaction exists */
+ struct sigaction context;
+ context.sa_handler = SIG_DFL;
+ sigemptyset(&context.sa_mask);
+ context.sa_flags = 0;
+ sigaction(signum, &context, NULL);
+#else
+ signal(signum, SIG_DFL);
+#endif
+#ifdef HAVE_SIGINTERRUPT
+ siginterrupt(signum, 1);
+#endif
+}
#if defined(__FreeBSD__)
/* When /dev/fd isn't mounted it is often a static directory populated
@@ -452,9 +470,19 @@ pypy_subprocess_child_exec(
if (child_umask >= 0)
umask(child_umask); /* umask() always succeeds. */
- /* PyPy change: moved this call to the preexec callback */
- /* if (restore_signals) */
- /* _Py_RestoreSignals(); */
+ if (restore_signals) {
+ /* inline _Py_RestoreSignals(); */
+#ifdef SIGPIPE
+ local_pypysig_default(SIGPIPE);
+#endif
+#ifdef SIGXFZ
+ local_pypysig_default(SIGXFZ);
+#endif
+#ifdef SIGXFSZ
+ local_pypysig_default(SIGXFSZ);
+#endif
+ }
+
#ifdef HAVE_SETSID
if (call_setsid)
diff --git a/pypy/module/_posixsubprocess/test/apptest_subprocess.py b/pypy/module/_posixsubprocess/test/apptest_subprocess.py
index 33b44a5717..5368d2cd09 100644
--- a/pypy/module/_posixsubprocess/test/apptest_subprocess.py
+++ b/pypy/module/_posixsubprocess/test/apptest_subprocess.py
@@ -152,3 +152,143 @@ def test_umask():
finally:
if tmpdir is not None:
shutil.rmtree(tmpdir)
+
+def test_issue_3630():
+ import time
+ # Make sure the registered callback functions are not called unless
+ # fork_exec has a preexec_fn
+
+ tmpfile = 'fork_exec.txt'
+ with open(tmpfile, 'w'):
+ pass
+
+
+ # from multiprocessing.util.py
+ def spawnv_passfds(path, args, passfds, preexec_fn=None):
+ passfds = tuple(sorted(map(int, fds_to_pass)))
+ errpipe_read, errpipe_write = os.pipe()
+ try:
+ return _posixsubprocess.fork_exec(
+ args, [os.fsencode(path)], True, passfds, None, None,
+ -1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
+ False, False,
+ None, None, None, -1,
+ preexec_fn)
+ finally:
+ os.close(errpipe_read)
+ os.close(errpipe_write)
+
+ def preexec_fn():
+ pass
+
+ def before():
+ with open(tmpfile, mode='a') as fid:
+ fid.write('before\n')
+ print('before hook done')
+
+ def parent():
+ print('parent hook')
+ for i in range(10):
+ time.sleep(0.1)
+ with open(tmpfile, mode='r') as fid:
+ if 'child' in fid.read():
+ break
+ else:
+ print('tmpfile not updated')
+ with open(tmpfile, mode='a') as fid:
+ fid.write('parent\n')
+ print('parent hook done')
+
+ def child():
+ with open(tmpfile, mode='a') as fid:
+ fid.write('child\n')
+ print('child hook done')
+
+ os.register_at_fork(before=before, after_in_parent=parent, after_in_child=child)
+ fds_to_pass = []
+ try:
+ fds_to_pass.append(sys.stderr.fileno())
+ except Exception:
+ pass
+
+ r, w = os.pipe()
+ fds_to_pass.append(r)
+ args = ['ls', '.']
+
+ try:
+ spawnv_passfds('ls', args, fds_to_pass)
+ with open(tmpfile, mode='r') as fid:
+ contents = fid.read()
+ assert len(contents) == 0
+
+ spawnv_passfds('ls', args, fds_to_pass, preexec_fn=preexec_fn)
+ with open(tmpfile, mode='r') as fid:
+ contents = fid.read()
+ assert 'child' in contents
+ assert 'parent' in contents
+ assert 'before' in contents
+ finally:
+ os.remove(tmpfile)
+
+def test_restore_signals():
+ import posix as os
+ # Copied from lib-python/3/subprocess._execute_child
+ # when calling subprocess.check_output(['cat', '/proc/self/status'],
+ # restore_signals=True, universal_newlines=True)
+ def check_output(restore_signals):
+ c2pread, c2pwrite = os.pipe()
+ errpipe_read, errpipe_write = os.pipe()
+ try:
+ low_fds_to_close = []
+ while errpipe_write < 3:
+ low_fds_to_close.append(errpipe_write)
+ errpipe_write = os.dup(errpipe_write)
+ for low_fd in low_fds_to_close:
+ os.close(low_fd)
+ args = [b'cat', b'/proc/self/status']
+ executable_list=[b'/usr/bin/cat']
+ close_fds = True
+ fds_to_keep = (errpipe_write,)
+ cwd = None
+ env_list = None
+ p2cread = p2cwrite = -1
+ errread = errwrite = umask = -1
+ call_setsid = False
+ preexec_fn = None
+ gid = gids = uid = None
+ pid = _posixsubprocess.fork_exec(args, executable_list, close_fds,
+ fds_to_keep, cwd, env_list, p2cread, p2cwrite, c2pread,
+ c2pwrite, errread, errwrite, errpipe_read,
+ errpipe_write, restore_signals, call_setsid,
+ gid, gids, uid, umask,
+ preexec_fn)
+ os.close(errpipe_write)
+ # Wait for exec to fail or succeed; possibly raising an
+ # exception (limited in size)
+ errpipe_data = bytearray()
+ while True:
+ part = os.read(errpipe_read, 50000)
+ errpipe_data += part
+ if not part or len(errpipe_data) > 50000:
+ break
+ if errpipe_data:
+ newpid, sts = os.waitpid(pid, 0)
+ raise RuntimeError('running commande returned %s' % sts)
+ out = os.read(c2pread, 50000)
+ finally:
+ os.close(c2pwrite)
+ os.close(c2pread)
+ os.close(errpipe_read)
+ return out
+
+ sig_ign_mask1 = ''
+ sig_ign_mask2 = ''
+ for line in check_output(True).splitlines():
+ if line.startswith(b'SigIgn'):
+ sig_ign_mask1 = line
+ for line in check_output(False).splitlines():
+ if line.startswith(b'SigIgn'):
+ sig_ign_mask2 = line
+ assert b'1' not in sig_ign_mask1
+ assert sig_ign_mask2
+ assert sig_ign_mask1 != sig_ign_mask2
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
index d36fc49be4..b4ee19ac7f 100644
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -132,12 +132,13 @@ udir.join(pypy_decl).write("/* Will be filled later */\n")
udir.join('pypy_structmember_decl.h').write("/* Will be filled later */\n")
udir.join('pypy_marshal_decl.h').write("/* Will be filled later */\n")
udir.join('pypy_macros.h').write("/* Will be filled later */\n")
+udir.join('genericaliasobject.h').write("/* Will be filled later */\n")
constant_names = """
Py_TPFLAGS_READY Py_TPFLAGS_READYING
METH_COEXIST METH_STATIC METH_CLASS Py_TPFLAGS_BASETYPE
METH_NOARGS METH_VARARGS METH_KEYWORDS METH_FASTCALL METH_O
-Py_TPFLAGS_HEAPTYPE
+Py_TPFLAGS_HEAPTYPE METH_METHOD
Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_MAX_NDIMS
Py_CLEANUP_SUPPORTED PyBUF_READ
PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES PyBUF_WRITABLE PyBUF_SIMPLE PyBUF_WRITE
@@ -586,7 +587,7 @@ FUNCTIONS_BY_HEADER = defaultdict(dict)
# These are C symbols which cpyext will export, but which are defined in .c
# files somewhere in the implementation of cpyext (rather than being defined in
-# RPython).
+# RPython). Their name will be mangled by a #define
SYMBOLS_C = [
'Py_FatalError', 'PyOS_snprintf', 'PyOS_vsnprintf', 'PyArg_Parse',
'PyArg_ParseTuple', 'PyArg_UnpackTuple', 'PyArg_ParseTupleAndKeywords',
@@ -650,7 +651,7 @@ SYMBOLS_C = [
'PyTraceMalloc_Track', 'PyTraceMalloc_Untrack',
'PyBytes_FromFormat', 'PyBytes_FromFormatV',
- 'PyType_FromSpec',
+ 'PyType_FromSpec', 'PyType_GetModule', 'PyType_GetModuleState',
'Py_IncRef', 'Py_DecRef', 'PyObject_Free', 'PyObject_GC_Del', 'PyType_GenericAlloc',
'_PyObject_New', '_PyObject_NewVar',
'_PyObject_GC_Malloc', '_PyObject_GC_New', '_PyObject_GC_NewVar',
@@ -806,6 +807,7 @@ PyTypeObject = cts.gettype('PyTypeObject')
PyTypeObjectPtr = cts.gettype('PyTypeObject *')
PyObjectStruct = cts.gettype('PyObject')
PyObject = cts.gettype('PyObject *')
+PyObjectC = cts.gettype('PyObject const *')
PyObjectFields = (("ob_refcnt", lltype.Signed),
("ob_pypy_link", lltype.Signed),
("ob_type", PyTypeObjectPtr))
@@ -1257,7 +1259,7 @@ def attach_c_functions(space, eci, prefix):
)
state.C.flag_setters = {}
for c_name, attr in _flags:
- _, setter = rffi.CExternVariable(rffi.SIGNED, c_name, eci_flags,
+ _, setter = rffi.CExternVariable(rffi.INT_real, c_name, eci_flags,
_nowrapper=True, c_type='int')
state.C.flag_setters[attr] = setter
@@ -1279,7 +1281,7 @@ def init_flags(space):
state = space.fromcache(State)
for _, attr in _flags:
f = state.C.flag_setters[attr]
- f(space.sys.get_flag(attr))
+ f(rffi.cast(rffi.INT_real, space.sys.get_flag(attr)))
#_____________________________________________________
# Build the bridge DLL, Allow extension DLLs to call
@@ -1472,23 +1474,42 @@ def mangle_name(prefix, name):
else:
raise ValueError("Error converting '%s'" % name)
-def write_header(header_name, decls):
- lines = [
- '#include "cpyext_object.h"',
- '''
-#ifdef _WIN64
-#define Signed Py_ssize_t /* xxx temporary fix */
-#define Unsigned unsigned long long /* xxx temporary fix */
-#else
-#define Signed Py_ssize_t /* xxx temporary fix */
-#define Unsigned unsigned long /* xxx temporary fix */
-#endif
- '''] + decls + [
- '',
- '#undef Signed /* xxx temporary fix */',
- '#undef Unsigned /* xxx temporary fix */',
- '']
+def write_header(header_name, decls, needs_signed=True, add_guards=False):
decl_h = udir.join(header_name)
+ lines = []
+ if add_guards:
+ guard = 'Py_' + header_name.replace('.', '_').upper()
+ lines += ['#ifndef ' + guard,
+ '#define ' + guard,
+ '#ifdef __cplusplus',
+ 'extern "C" {',
+ '#endif', ''
+ ]
+ if needs_signed:
+ lines += [
+ '',
+ '#include "cpyext_object.h"',
+ '',
+ '#ifdef _WIN64',
+ '#define Signed Py_ssize_t /* xxx temporary fix */',
+ '#define Unsigned unsigned long long /* xxx temporary fix */',
+ '#else',
+ '#define Signed Py_ssize_t /* xxx temporary fix */',
+ '#define Unsigned unsigned long /* xxx temporary fix */',
+ '#endif',
+ ] + decls + [
+ '',
+ '#undef Signed /* xxx temporary fix */',
+ '#undef Unsigned /* xxx temporary fix */',
+ '']
+ else:
+ lines += decls
+ if add_guards:
+ lines += ['#ifdef __cplusplus',
+ '}',
+ '#endif',
+ '#endif /* !' + guard + ' */',
+ ]
decl_h.write('\n'.join(lines))
def generate_decls_and_callbacks(db, prefix=''):
@@ -1554,7 +1575,12 @@ static int PySlice_GetIndicesEx(PyObject *arg0, Py_ssize_t arg1,
decls[header].append('PyAPI_DATA(%s) %s;' % (typ, name))
for header_name, header_decls in decls.iteritems():
- write_header(header_name, header_decls)
+ # Hardcoded :(
+ if header_name in ('genericaliasobject.h',):
+ write_header(header_name, header_decls,
+ needs_signed=False, add_guards=True)
+ else:
+ write_header(header_name, header_decls)
# generate graminit.h
graminit_h = udir.join('graminit.h')
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
index 88dbc9442d..3dc98603dc 100644
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -1,8 +1,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rtyper.annlowlevel import llhelper
from rpython.rlib.rarithmetic import widen
-from pypy.module.cpyext.pyobject import (PyObject, make_ref, make_typedescr,
- decref, as_pyobj, incref)
+from pypy.module.cpyext.pyobject import (PyObject, make_ref, make_typedescr, decref)
from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, cpython_struct,
PyObjectFields, cts, parse_dir, bootstrap_function, slot_function,
Py_TPFLAGS_HEAPTYPE)
diff --git a/pypy/module/cpyext/classobject.py b/pypy/module/cpyext/classobject.py
index e065a4a9ec..4a30ce624a 100644
--- a/pypy/module/cpyext/classobject.py
+++ b/pypy/module/cpyext/classobject.py
@@ -40,7 +40,8 @@ class InstanceMethod(W_Root):
return self.getrepr(space, '<instancemethod %s>' %
(self.w_function.getname(space),))
-InstanceMethod.typedef = TypeDef("instancemethod",
+InstanceMethod.typedef = TypeDef(
+ "cinstancemethod",
__new__ = interp2app(InstanceMethod.descr_new),
__call__ = interp2app(InstanceMethod.descr_call,
descrmismatch='__call__'),
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
index 67861e7845..8505e4c4c4 100644
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -108,6 +108,7 @@
#include "pythread.h"
#include "traceback.h"
#include "pylifecycle.h"
+#include "genericaliasobject.h"
/* Missing definitions */
#include "missing.h"
diff --git a/pypy/module/cpyext/include/methodobject.h b/pypy/module/cpyext/include/methodobject.h
index f7f6bf5e23..7a3c0dca20 100644
--- a/pypy/module/cpyext/include/methodobject.h
+++ b/pypy/module/cpyext/include/methodobject.h
@@ -31,16 +31,34 @@ extern "C" {
#define METH_FASTCALL 0x0080
#endif
+/* METH_METHOD means the function stores an
+ * additional reference to the class that defines it;
+ * both self and class are passed to it.
+ * It uses PyCMethodObject instead of PyCFunctionObject.
+ * May not be combined with METH_NOARGS, METH_O, METH_CLASS or METH_STATIC.
+ */
+
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03090000
+#define METH_METHOD 0x0200
+#endif
+
+
#define PyCFunction_New(ml, self) PyCFunction_NewEx((ml), (self), NULL)
+#define PyCFunction_NewEx(ML, SELF, MOD) PyCMethod_New((ML), (SELF), (MOD), NULL)
+
/* Macros for direct access to these values. Type checks are *not*
done, so use with care. */
#define PyCFunction_GET_FUNCTION(func) \
(((PyCFunctionObject *)func) -> m_ml -> ml_meth)
#define PyCFunction_GET_SELF(func) \
- (((PyCFunctionObject *)func) -> m_self)
+ (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_STATIC ? \
+ NULL : ((PyCFunctionObject *)func) -> m_self)
#define PyCFunction_GET_FLAGS(func) \
- (((PyCFunctionObject *)func) -> m_ml -> ml_flags)
+ (((PyCFunctionObject *)func) -> m_ml -> ml_flags)
+#define PyCFunction_GET_CLASS(func) \
+ (((PyCFunctionObject *)func) -> m_ml -> ml_flags & METH_METHOD ? \
+ ((PyCMethodObject *)func) -> mm_class : NULL)
#ifdef __cplusplus
}
diff --git a/pypy/module/cpyext/include/modsupport.h b/pypy/module/cpyext/include/modsupport.h
index 57015deb8d..f29cadb991 100644
--- a/pypy/module/cpyext/include/modsupport.h
+++ b/pypy/module/cpyext/include/modsupport.h
@@ -30,8 +30,19 @@ extern "C" {
#define _Py_VaBuildStack _Py_VaBuildStack_SizeT
#endif
#else
+#ifndef Py_LIMITED_API
+PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list);
+PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT(
+ PyObject **small_stack,
+ Py_ssize_t small_stack_len,
+ const char *format,
+ va_list va,
+ Py_ssize_t *p_nargs);
+#endif /* !Py_LIMITED_API */
#endif
+/* Due to a glitch in 3.2, the _SizeT versions weren't exported from the DLL. */
+#if !defined(PY_SSIZE_T_CLEAN) || !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...);
PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...);
PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
@@ -39,14 +50,99 @@ PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list);
PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
const char *, char **, va_list);
+#endif
+PyAPI_FUNC(int) PyArg_ValidateKeywordArguments(PyObject *);
+PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...);
PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
-PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list);
-PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kw);
-PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...);
+
+#ifndef Py_LIMITED_API
+PyAPI_FUNC(int) _PyArg_UnpackStack(
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ const char *name,
+ Py_ssize_t min,
+ Py_ssize_t max,
+ ...);
+
+#undef _PyArg_NoKeywords
+PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kwargs);
+PyAPI_FUNC(int) _PyArg_NoKwnames(const char *funcname, PyObject *kwnames);
+PyAPI_FUNC(int) _PyArg_NoPositional(const char *funcname, PyObject *args);
+#define _PyArg_NoKeywords(funcname, kwargs) \
+ ((kwargs) == NULL || _PyArg_NoKeywords((funcname), (kwargs)))
+#define _PyArg_NoKwnames(funcname, kwnames) \
+ ((kwnames) == NULL || _PyArg_NoKwnames((funcname), (kwnames)))
+#define _PyArg_NoPositional(funcname, args) \
+ ((args) == NULL || _PyArg_NoPositional((funcname), (args)))
+
+PyAPI_FUNC(void) _PyArg_BadArgument(const char *, const char *, const char *, PyObject *);
+PyAPI_FUNC(int) _PyArg_CheckPositional(const char *, Py_ssize_t,
+ Py_ssize_t, Py_ssize_t);
+#define _PyArg_CheckPositional(funcname, nargs, min, max) \
+ (((min) <= (nargs) && (nargs) <= (max)) \
+ || _PyArg_CheckPositional((funcname), (nargs), (min), (max)))
+
+#endif
PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list);
+#ifndef Py_LIMITED_API
+PyAPI_FUNC(PyObject **) _Py_VaBuildStack(
+ PyObject **small_stack,
+ Py_ssize_t small_stack_len,
+ const char *format,
+ va_list va,
+ Py_ssize_t *p_nargs);
+#endif
+
+#ifndef Py_LIMITED_API
+typedef struct _PyArg_Parser {
+ const char *format;
+ const char * const *keywords;
+ const char *fname;
+ const char *custom_msg;
+ int pos; /* number of positional-only arguments */
+ int min; /* minimal number of arguments */
+ int max; /* maximal number of positional arguments */
+ PyObject *kwtuple; /* tuple of keyword parameter names */
+ struct _PyArg_Parser *next;
+} _PyArg_Parser;
+#ifdef PY_SSIZE_T_CLEAN
+#define _PyArg_ParseTupleAndKeywordsFast _PyArg_ParseTupleAndKeywordsFast_SizeT
+#define _PyArg_ParseStack _PyArg_ParseStack_SizeT
+#define _PyArg_ParseStackAndKeywords _PyArg_ParseStackAndKeywords_SizeT
+#define _PyArg_VaParseTupleAndKeywordsFast _PyArg_VaParseTupleAndKeywordsFast_SizeT
+#endif
+PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, ...);
+PyAPI_FUNC(int) _PyArg_ParseStack(
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ const char *format,
+ ...);
+PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords(
+ PyObject *const *args,
+ Py_ssize_t nargs,
+ PyObject *kwnames,
+ struct _PyArg_Parser *,
+ ...);
+PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list);
+PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords(
+ PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ int minpos, int maxpos, int minkw,
+ PyObject **buf);
+#define _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, parser, minpos, maxpos, minkw, buf) \
+ (((minkw) == 0 && (kwargs) == NULL && (kwnames) == NULL && \
+ (minpos) <= (nargs) && (nargs) <= (maxpos) && args != NULL) ? (args) : \
+ _PyArg_UnpackKeywords((args), (nargs), (kwargs), (kwnames), (parser), \
+ (minpos), (maxpos), (minkw), (buf)))
+
+void _PyArg_Fini(void);
+#endif /* Py_LIMITED_API */
PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *);
PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);
@@ -85,7 +181,9 @@ PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*,
+#ifndef Py_LIMITED_API
PyAPI_DATA(const char *) _Py_PackageContext;
+#endif
#ifdef __cplusplus
}
diff --git a/pypy/module/cpyext/include/object.h b/pypy/module/cpyext/include/object.h
index 4342be5610..7edfd58d29 100644
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -13,8 +13,6 @@ extern "C" {
#define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1)
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
-#define Py_RETURN_NOTIMPLEMENTED \
- return Py_INCREF(Py_NotImplemented), Py_NotImplemented
/*
CPython has this for backwards compatibility with really old extensions, and now
@@ -28,6 +26,38 @@ we have it for compatibility with CPython.
#define PyVarObject_HEAD_INIT(type, size) \
PyObject_HEAD_INIT(type) size,
+/* Cast argument to PyVarObject* type. */
+#define _PyVarObject_CAST(op) ((PyVarObject*)(op))
+/* Cast argument to PyObject* type. */
+#define _PyObject_CAST(op) ((PyObject*)(op))
+#define _PyObject_CAST_CONST(op) ((const PyObject*)(op))
+
+#define Py_REFCNT(ob) (_PyObject_CAST(ob)->ob_refcnt)
+#define Py_TYPE(ob) (_PyObject_CAST(ob)->ob_type)
+#define Py_SIZE(ob) (_PyVarObject_CAST(ob)->ob_size)
+
+static inline int _Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) {
+ return ob->ob_type == type;
+}
+#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST_CONST(ob), type)
+
+static inline void _Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
+ ob->ob_refcnt = refcnt;
+}
+#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt)
+
+static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
+ ob->ob_type = type;
+}
+#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type)
+
+static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
+ ob->ob_size = size;
+}
+#define Py_SET_SIZE(ob, size) _Py_SET_SIZE(_PyVarObject_CAST(ob), size)
+
+PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
+
#ifdef PYPY_DEBUG_REFCOUNT
/* Slow version, but useful for debugging */
#define Py_INCREF(ob) (Py_IncRef((PyObject *)(ob)))
@@ -36,64 +66,73 @@ we have it for compatibility with CPython.
#define Py_XDECREF(ob) (Py_DecRef((PyObject *)(ob)))
#else
/* Fast version */
-#define Py_INCREF(ob) (((PyObject *)(ob))->ob_refcnt++)
-#define Py_DECREF(op) \
- do { \
- PyObject *_py_decref_tmp = (PyObject *)(op); \
- if (--(_py_decref_tmp)->ob_refcnt != 0) \
- ; \
- else \
- _Py_Dealloc(_py_decref_tmp); \
- } while (0)
+static inline void _Py_INCREF(PyObject *op)
+{
+ op->ob_refcnt++;
+}
-#define Py_XINCREF(op) \
- do { \
- PyObject *_py_xincref_tmp = (PyObject *)(op); \
- if (_py_xincref_tmp != NULL) \
- Py_INCREF(_py_xincref_tmp); \
- } while (0)
+#define Py_INCREF(op) _Py_INCREF(_PyObject_CAST(op))
-#define Py_XDECREF(op) \
- do { \
- PyObject *_py_xdecref_tmp = (PyObject *)(op); \
- if (_py_xdecref_tmp != NULL) \
- Py_DECREF(_py_xdecref_tmp); \
- } while (0)
+static inline void _Py_DECREF(PyObject *op)
+{
+ if (--op->ob_refcnt != 0) {
+ }
+ else {
+ _Py_Dealloc(op);
+ }
+}
+
+#define Py_DECREF(op) _Py_DECREF(_PyObject_CAST(op))
+
+/* Function to use in case the object pointer can be NULL: */
+static inline void _Py_XINCREF(PyObject *op)
+{
+ if (op != NULL) {
+ Py_INCREF(op);
+ }
+}
+
+#define Py_XINCREF(op) _Py_XINCREF(_PyObject_CAST(op))
+
+static inline void _Py_XDECREF(PyObject *op)
+{
+ if (op != NULL) {
+ Py_DECREF(op);
+ }
+}
+
+#define Py_XDECREF(op) _Py_XDECREF(_PyObject_CAST(op))
-#endif
PyAPI_FUNC(void) Py_IncRef(PyObject *);
PyAPI_FUNC(void) Py_DecRef(PyObject *);
extern void *_pypy_rawrefcount_w_marker_deallocating;
-PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
#define Py_CLEAR(op) \
do { \
- PyObject *_py_tmp = (PyObject *)(op); \
+ PyObject *_py_tmp = _PyObject_CAST(op); \
if (_py_tmp != NULL) { \
(op) = NULL; \
Py_DECREF(_py_tmp); \
} \
} while (0)
+#endif
+#ifndef Py_LIMITED_API
#define Py_SETREF(op, op2) \
do { \
- PyObject *_py_tmp = (PyObject *)(op); \
+ PyObject *_py_tmp = _PyObject_CAST(op); \
(op) = (op2); \
Py_DECREF(_py_tmp); \
} while (0)
#define Py_XSETREF(op, op2) \
do { \
- PyObject *_py_tmp = (PyObject *)(op); \
+ PyObject *_py_tmp = _PyObject_CAST(op); \
(op) = (op2); \
Py_XDECREF(_py_tmp); \
} while (0)
-#define Py_REFCNT(ob) (((PyObject*)(ob))->ob_refcnt)
-#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
-#define Py_SIZE(ob) (((PyVarObject*)(ob))->ob_size)
-
#define _Py_NewReference(op) \
( ((PyObject *)(op))->ob_refcnt = 1, \
((PyObject *)(op))->ob_pypy_link = 0 )
@@ -101,12 +140,7 @@ PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
#define _Py_ForgetReference(ob) /* nothing */
#define Py_None (&_Py_NoneStruct)
-
-
-static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type) {
- ob->ob_type = type;
-}
-#define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type)
+#endif
/*
@@ -115,6 +149,10 @@ not implemented for a given type combination.
*/
#define Py_NotImplemented (&_Py_NotImplementedStruct)
+/* Macro for returning Py_NotImplemented from a function */
+#define Py_RETURN_NOTIMPLEMENTED \
+ return Py_INCREF(Py_NotImplemented), Py_NotImplemented
+
/* Rich comparison opcodes */
/*
XXX: Also defined in slotdefs.py
@@ -160,6 +198,9 @@ not implemented for a given type combination.
PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*);
+PyAPI_FUNC(PyObject *) PyType_GetModule(struct _typeobject *);
+PyAPI_FUNC(void *) PyType_GetModuleState(struct _typeobject *);
+
/* Flag bits for printing: */
diff --git a/pypy/module/cpyext/include/pystate.h b/pypy/module/cpyext/include/pystate.h
index 194d6b0782..d0b467d285 100644
--- a/pypy/module/cpyext/include/pystate.h
+++ b/pypy/module/cpyext/include/pystate.h
@@ -1,11 +1,24 @@
+/* Thread and interpreter state structures and their interfaces */
+
+
#ifndef Py_PYSTATE_H
#define Py_PYSTATE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This limitation is for performance and simplicity. If needed it can be
+removed (with effort). */
+#define MAX_CO_EXTRA_USERS 255
-struct _ts; /* Forward */
-struct _is; /* Forward */
+/* Forward declarations for PyFrameObject, PyThreadState
+ and PyInterpreterState */
+struct _ts;
+struct _is;
typedef struct _is {
struct _is *next;
+ PyObject * modules_by_index;
} PyInterpreterState;
typedef struct _ts {
@@ -25,5 +38,9 @@ enum {PyGILState_LOCKED, PyGILState_UNLOCKED};
typedef int PyGILState_STATE;
#define PyThreadState_GET() PyThreadState_Get()
+PyAPI_FUNC(PyObject*) PyState_FindModule(struct PyModuleDef*);
+#ifdef __cplusplus
+}
+#endif
#endif /* !Py_PYSTATE_H */
diff --git a/pypy/module/cpyext/include/tupleobject.h b/pypy/module/cpyext/include/tupleobject.h
index abb345b533..b2f73cec72 100644
--- a/pypy/module/cpyext/include/tupleobject.h
+++ b/pypy/module/cpyext/include/tupleobject.h
@@ -36,7 +36,6 @@ PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
#define PyTuple_CheckExact(op) (Py_TYPE(op) == &PyTuple_Type)
#define _PyTuple_CAST(op) (assert(PyTuple_Check(op)), (PyTupleObject *)(op))
-#define _PyTuple_ITEMS(op) (_PyTuple_CAST(op)->ob_item)
#ifdef __cplusplus
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
index c494d6b33d..92aa788117 100644
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -3,14 +3,15 @@ from rpython.rlib import jit
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
-from pypy.interpreter.function import ClassMethod, Method, StaticMethod
+from pypy.interpreter.function import ClassMethod, _Method, StaticMethod
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import (
- GetSetProperty, TypeDef, interp_attrproperty, interp_attrproperty_w)
+ GetSetProperty, TypeDef, interp_attrproperty, interp_attrproperty_w,
+ descr_generic_ne, make_weakref_descr)
from pypy.objspace.std.typeobject import W_TypeObject
from pypy.module.cpyext.api import (
CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_FASTCALL,
- METH_NOARGS, METH_O, METH_STATIC, METH_VARARGS,
+ METH_NOARGS, METH_O, METH_STATIC, METH_VARARGS, METH_METHOD,
PyObject, bootstrap_function, cpython_api, generic_cpy_call,
CANNOT_FAIL, slot_function, cts, build_type_checkers,
PyObjectP, Py_ssize_t)
@@ -25,14 +26,22 @@ PyCFunctionFast = cts.gettype('_PyCFunctionFast')
PyCFunctionKwArgs = cts.gettype('PyCFunctionWithKeywords')
PyCFunctionKwArgsFast = cts.gettype('_PyCFunctionFastWithKeywords')
PyCFunctionObject = cts.gettype('PyCFunctionObject*')
+PyCMethodObject = cts.gettype('PyCMethodObject*')
@bootstrap_function
-def init_methodobject(space):
+def init_functionobject(space):
make_typedescr(W_PyCFunctionObject.typedef,
basestruct=PyCFunctionObject.TO,
attach=cfunction_attach,
dealloc=cfunction_dealloc)
+@bootstrap_function
+def init_methodobject(space):
+ make_typedescr(W_PyCMethodObject.typedef,
+ basestruct=PyCMethodObject.TO,
+ attach=cmethod_attach,
+ dealloc=cmethod_dealloc)
+
def cfunction_attach(space, py_obj, w_obj, w_userdata=None):
assert isinstance(w_obj, W_PyCFunctionObject)
py_func = rffi.cast(PyCFunctionObject, py_obj)
@@ -48,6 +57,25 @@ def cfunction_dealloc(space, py_obj):
from pypy.module.cpyext.object import _dealloc
_dealloc(space, py_obj)
+def cmethod_attach(space, py_obj, w_obj, w_userdata=None):
+ assert isinstance(w_obj, W_PyCMethodObject)
+ py_func = rffi.cast(PyCFunctionObject, py_obj)
+ py_func.c_m_ml = w_obj.ml
+ py_func.c_m_self = make_ref(space, w_obj.w_self)
+ py_func.c_m_module = make_ref(space, w_obj.w_module)
+ py_meth = rffi.cast(PyCMethodObject, py_obj)
+ py_meth.c_mm_class = w_obj.w_objclass
+
+@slot_function([PyObject], lltype.Void)
+def cmethod_dealloc(space, py_obj):
+ py_func = rffi.cast(PyCFunctionObject, py_obj)
+ decref(space, py_func.c_func)
+ decref(space, py_func.c_m_module)
+ py_meth = rffi.cast(PyCMethodObject, py_obj)
+ decref(space, py_meth.c_mm_class)
+ from pypy.module.cpyext.object import _dealloc
+ _dealloc(space, py_obj)
+
def w_kwargs_from_args(space, __args__):
if __args__.keywords is None:
return None
@@ -129,6 +157,8 @@ class W_PyCFunctionObject(W_Root):
"%s() takes no keyword arguments", self.name)
elif flags & METH_FASTCALL:
if flags & METH_KEYWORDS:
+ if flags & METH_METHOD:
+ return self.call_keywords_fastcall_method(space, w_self, __args__)
return self.call_keywords_fastcall(space, w_self, __args__)
return self.call_varargs_fastcall(space, w_self, __args__)
elif flags & METH_KEYWORDS:
@@ -194,6 +224,16 @@ class W_PyCFunctionObject(W_Root):
finally:
decref(space, py_args)
+ def call_keywords_fastcall_method(self, space, w_self, __args__):
+ func = rffi.cast(PyCFunctionKwArgsFast, self.ml.c_ml_meth)
+ py_args, len_args, w_kwnames = w_fastcall_args_from_args(space, __args__)
+ try:
+ return generic_cpy_call(space, func, w_self,
+ py_args.c_ob_item, len_args, w_kwnames)
+ finally:
+ decref(space, py_args)
+
+
def get_doc(self, space):
c_doc = self.ml.c_ml_doc
if c_doc:
@@ -225,8 +265,8 @@ class W_PyCFunctionObject(W_Root):
class W_PyCMethodObject(W_PyCFunctionObject):
- def __init__(self, space, ml, w_type):
- W_PyCFunctionObject.__init__(self, space, ml, w_self=None)
+ def __init__(self, space, ml, w_self, w_module, w_type):
+ W_PyCFunctionObject.__init__(self, space, ml, w_self, w_module)
self.space = space
self.w_objclass = w_type
@@ -344,17 +384,51 @@ class W_PyCWrapperObject(W_Root):
(self.method_name,
self.w_objclass.name))
+class CMethod(_Method):
+ # Differentiate this from an app-level class Method
+ # so isinstance(c-class-meth, type(app-class-method)) is False
+ def descr_method__new__(space, w_subtype, w_function, w_instance):
+ if space.is_w(w_instance, space.w_None):
+ w_instance = None
+ if w_instance is None:
+ raise oefmt(space.w_TypeError, "self must not be None")
+ method = space.allocate_instance(CMethod, w_subtype)
+ _Method.__init__(method, space, w_function, w_instance)
+ return method
+
+ pass
+
+CMethod.typedef = TypeDef(
+ "builtin method",
+ __doc__ = """instancemethod(function, instance, class)
+
+Create an instance method object.""",
+ __new__ = interp2app(CMethod.descr_method__new__.im_func),
+ __call__ = interp2app(CMethod.descr_method_call),
+ __get__ = interp2app(CMethod.descr_method_get),
+ __func__ = interp_attrproperty_w('w_function', cls=CMethod),
+ __self__ = interp_attrproperty_w('w_instance', cls=CMethod),
+ __getattribute__ = interp2app(CMethod.descr_method_getattribute),
+ __eq__ = interp2app(CMethod.descr_method_eq),
+ __ne__ = descr_generic_ne,
+ __hash__ = interp2app(CMethod.descr_method_hash),
+ __repr__ = interp2app(CMethod.descr_method_repr),
+ __reduce__ = interp2app(CMethod.descr_method__reduce__),
+ __weakref__ = make_weakref_descr(CMethod),
+ )
+CMethod.typedef.acceptable_as_base_class = False
+
def cmethod_descr_get(space, w_function, w_obj, w_cls=None):
if w_obj is None or space.is_w(w_obj, space.w_None):
return w_function
else:
- return Method(space, w_function, w_obj)
+ return CMethod(space, w_function, w_obj)
def cclassmethod_descr_get(space, w_function, w_obj, w_cls=None):
if not w_cls:
w_cls = space.type(w_obj)
- return Method(space, w_function, w_cls)
+ return CMethod(space, w_function, w_cls)
W_PyCFunctionObject.typedef = TypeDef(
@@ -382,7 +456,7 @@ W_PyCMethodObject.typedef = TypeDef(
W_PyCMethodObject.typedef.acceptable_as_base_class = False
W_PyCClassMethodObject.typedef = TypeDef(
- 'classmethod',
+ 'builtin_function_or_method',
__get__ = interp2app(cclassmethod_descr_get),
__call__ = interp2app(W_PyCClassMethodObject.descr_call),
__name__ = interp_attrproperty('name', cls=W_PyCClassMethodObject,
@@ -409,9 +483,21 @@ W_PyCWrapperObject.typedef = TypeDef(
W_PyCWrapperObject.typedef.acceptable_as_base_class = False
-@cpython_api([lltype.Ptr(PyMethodDef), PyObject, PyObject], PyObject)
-def PyCFunction_NewEx(space, ml, w_self, w_name):
- return W_PyCFunctionObject(space, ml, w_self, w_name)
+@cpython_api([lltype.Ptr(PyMethodDef), PyObject, PyObject, PyObject], PyObject)
+def PyCMethod_New(space, ml, w_self, w_name, w_type):
+ flags = rffi.cast(lltype.Signed, ml.c_ml_flags)
+ if flags & METH_METHOD:
+ if w_type is None:
+ raise oefmt(space.w_SystemError,
+ "attempting to create PyCMethod with a METH_METHOD "
+ "flag but no class");
+ return W_PyCMethodObject(space, ml, w_self, w_name, w_type)
+ else:
+ if w_type:
+ raise oefmt(space.w_SystemError,
+ "attempting to create PyCFunction with class "
+ "but no METH_METHOD flag");
+ return W_PyCFunctionObject(space, ml, w_self, w_name)
@cts.decl("PyCFunction PyCFunction_GetFunction(PyObject *)")
def PyCFunction_GetFunction(space, w_obj):
@@ -436,7 +522,7 @@ def PyClassMethod_New(space, w_func):
PyObject *
PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method)""")
def PyDescr_NewMethod(space, w_type, method):
- return W_PyCMethodObject(space, method, w_type)
+ return W_PyCMethodObject(space, method, None, None, w_type)
@cts.decl("""
PyObject *
@@ -479,7 +565,8 @@ def argtuple_from_pyobject_array(space, py_args, n):
args_w[i] = from_ref(space, py_args[i])
return space.newtuple(args_w)
-@cpython_api([PyObject, PyObjectP, Py_ssize_t, PyObject], PyObject)
+@cts.decl("PyObject *PyObject_Vectorcall(PyObject *, PyObject *const *, "
+ "size_t, PyObject *)")
def PyObject_Vectorcall(space, w_func, py_args, n, w_argnames):
if w_argnames is None:
@@ -497,11 +584,13 @@ def PyObject_Vectorcall(space, w_func, py_args, n, w_argnames):
w_result = space.call(w_func, w_args, w_kwargs)
return w_result
-@cpython_api([PyObject, PyObjectP, Py_ssize_t], PyObject)
+@cts.decl("PyObject *_PyObject_FastCall(PyObject *, PyObject *const *, "
+ "size_t)")
def _PyObject_FastCall(space, w_func, py_args, n):
return PyObject_Vectorcall(space, w_func, py_args, n, lltype.nullptr(PyObject.TO))
-@cpython_api([PyObject, PyObjectP, Py_ssize_t, PyObject], PyObject)
+@cts.decl("PyObject *PyObject_VectorcallDict(PyObject *, PyObject *const *, "
+ "size_t, PyObject *)")
def PyObject_VectorcallDict(space, w_func, py_args, n, w_kwargs):
w_args = argtuple_from_pyobject_array(space, py_args, n)
w_result = space.call(w_func, w_args, w_kwargs)
diff --git a/pypy/module/cpyext/modsupport.py b/pypy/module/cpyext/modsupport.py
index 4f8baee908..51c218057b 100644
--- a/pypy/module/cpyext/modsupport.py
+++ b/pypy/module/cpyext/modsupport.py
@@ -8,8 +8,8 @@ from pypy.module.cpyext.pyobject import (PyObject, as_pyobj, make_typedescr,
keepalive_until_here)
from pypy.interpreter.module import Module
from pypy.module.cpyext.methodobject import (
- W_PyCFunctionObject, PyCFunction_NewEx, PyDescr_NewMethod,
- PyMethodDef, PyDescr_NewClassMethod, PyStaticMethod_New)
+ W_PyCFunctionObject, W_PyCMethodObject,
+ PyMethodDef, W_PyCClassMethodObject, StaticMethod)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.module.cpyext.state import State
from pypy.interpreter.error import oefmt
@@ -202,12 +202,12 @@ def convert_method_defs(space, dict_w, methods, w_type, w_self=None, name=None):
if flags & METH_STATIC:
raise oefmt(space.w_ValueError,
"method cannot be both class and static")
- w_obj = PyDescr_NewClassMethod(space, w_type, method)
+ w_obj = W_PyCClassMethodObject(space, method, w_type)
elif flags & METH_STATIC:
- w_func = PyCFunction_NewEx(space, method, None, None)
- w_obj = PyStaticMethod_New(space, w_func)
+ w_func = W_PyCFunctionObject(space, method, None, None)
+ w_obj = StaticMethod(w_func)
else:
- w_obj = PyDescr_NewMethod(space, w_type, method)
+ w_obj = W_PyCMethodObject(space, method, None, None, w_type)
dict_w[methodname] = w_obj
diff --git a/pypy/module/cpyext/parse/cpyext_object.h b/pypy/module/cpyext/parse/cpyext_object.h
index 96e961a43c..91163d2ffb 100644
--- a/pypy/module/cpyext/parse/cpyext_object.h
+++ b/pypy/module/cpyext/parse/cpyext_object.h
@@ -313,4 +313,10 @@ typedef struct _heaptypeobject {
PySequenceMethods as_sequence;
PyBufferProcs as_buffer;
PyObject *ht_name, *ht_slots, *ht_qualname;
+ PyObject *ht_module;
} PyHeapTypeObject;
+
+typedef struct {
+ PyCFunctionObject func;
+ PyTypeObject *mm_class; /* Class that defines this method */
+} PyCMethodObject;
diff --git a/pypy/module/cpyext/pystate.py b/pypy/module/cpyext/pystate.py
index 77aae49c0b..91506050cf 100644
--- a/pypy/module/cpyext/pystate.py
+++ b/pypy/module/cpyext/pystate.py
@@ -1,16 +1,19 @@
from pypy.module.cpyext.api import (
cpython_api, CANNOT_FAIL, cpython_struct)
-from pypy.module.cpyext.pyobject import PyObject, decref, make_ref
-from pypy.interpreter.error import OperationError
+from pypy.module.cpyext.pyobject import PyObject, decref, make_ref, from_ref
+from pypy.module.cpyext.modsupport import PyModuleDef
+from pypy.interpreter.error import OperationError, oefmt
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib import rthread
from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import widen
PyInterpreterStateStruct = lltype.ForwardReference()
PyInterpreterState = lltype.Ptr(PyInterpreterStateStruct)
cpython_struct(
"PyInterpreterState",
- [('next', PyInterpreterState)],
+ [('next', PyInterpreterState),
+ ('modules_by_index', PyObject)],
PyInterpreterStateStruct)
PyThreadState = lltype.Ptr(cpython_struct(
"PyThreadState",
@@ -376,3 +379,49 @@ def _Py_IsFinalizing(space):
"""From CPython >= 3.7. On py3.6, it is present anyway and used to
implement _Py_Finalizing as a macro."""
return space.sys.finalizing
+
+def _PyInterpreterState_GET(space):
+ tstate = PyThreadState_Get(space)
+ return tstate.c_interp
+
+@cpython_api([PyObject, PyModuleDef], rffi.INT_real, error=-1)
+def PyState_AddModule(space, w_module, moddef):
+ if not moddef:
+ raise oefmt(space.w_SystemError, "module definition is NULL")
+ interp = _PyInterpreterState_GET(space)
+ index = widen(moddef.c_m_base.c_m_index)
+ if index < 0:
+ raise oefmt(space.w_SystemError, "module index < 0")
+ if not interp.c_modules_by_index:
+ w_by_index = space.newlist([])
+ interp.c_modules_by_index = make_ref(space, w_by_index)
+ else:
+ w_by_index = from_ref(space, interp.c_modules_by_index)
+ if moddef.c_m_slots:
+ raise oefmt(space.w_SystemError,
+ "PyState_AddModule called on module with slots");
+ if index < space.len_w(w_by_index):
+ w_module_seen = space.getitem(w_by_index, space.newint(index))
+ if space.eq_w(w_module_seen, w_module):
+ raise oefmt(space.w_SystemError, "module %R already added", w_module)
+ while space.len_w(w_by_index) <= index:
+ space.call_method(w_by_index, 'append', space.w_None)
+ space.setitem(w_by_index, space.newint(index), w_module)
+ return 0
+
+@cpython_api([PyModuleDef], rffi.INT_real, error=-1)
+def PyState_RemoveModule(space, moddef):
+ interp = _PyInterpreterState_GET(space)
+ if moddef.c_m_slots:
+ raise oefmt(space.w_SystemError,
+ "PyState_RemoveModule called on module with slots")
+ index = widen(moddef.c_m_base.c_m_index)
+ if index == 0:
+ raise oefmt(space.w_SystemError, "invalid module index")
+ if not interp.c_modules_by_index:
+ raise oefmt(space.w_SystemError, "Interpreters module-list not accessible.")
+ w_by_index = from_ref(space, interp.c_modules_by_index)
+ if index > space.len_w(w_by_index):
+ raise oefmt(space.w_SystemError, "Module index out of bounds.")
+ space.setitem(w_by_index, space.newint(index), space.w_None)
+ return 0
diff --git a/pypy/module/cpyext/src/call.c b/pypy/module/cpyext/src/call.c
index c1cad740eb..dc5d1b5db1 100644
--- a/pypy/module/cpyext/src/call.c
+++ b/pypy/module/cpyext/src/call.c
@@ -1,6 +1,8 @@
#include "Python.h"
#include <signal.h>
+#define _PyTuple_ITEMS PySequence_Fast_ITEMS
+
PyObject*
_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where)
{
diff --git a/pypy/module/cpyext/src/getargs.c b/pypy/module/cpyext/src/getargs.c
index 15242bfe88..71db60553b 100644
--- a/pypy/module/cpyext/src/getargs.c
+++ b/pypy/module/cpyext/src/getargs.c
@@ -2,8 +2,14 @@
/* New getargs implementation */
#include "Python.h"
+#ifdef PYPY_VERSION
+ #define _PyTuple_ITEMS PySequence_Fast_ITEMS
+#else
+ #include "pycore_tupleobject.h"
+#endif
#include <ctype.h>
+#include <float.h>
#ifdef __cplusplus
@@ -18,6 +24,32 @@ int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
int PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
const char *, char **, va_list);
+int _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, ...);
+int _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list);
+
+#ifdef HAVE_DECLSPEC_DLL
+/* Export functions */
+PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...);
+PyAPI_FUNC(int) _PyArg_ParseStack_SizeT(PyObject *const *args, Py_ssize_t nargs,
+ const char *format, ...);
+PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwnames,
+ struct _PyArg_Parser *parser, ...);
+PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...);
+PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
+ const char *, char **, ...);
+PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
+PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list);
+PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
+ const char *, char **, va_list);
+
+PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *, PyObject *,
+ struct _PyArg_Parser *, ...);
+PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list);
+#endif
#define FLAG_COMPAT 1
#define FLAG_SIZE_T 2
@@ -43,20 +75,28 @@ typedef struct {
#define STATIC_FREELIST_ENTRIES 8
/* Forward */
+static int vgetargs1_impl(PyObject *args, PyObject *const *stack, Py_ssize_t nargs,
+ const char *format, va_list *p_va, int flags);
static int vgetargs1(PyObject *, const char *, va_list *, int);
static void seterror(Py_ssize_t, const char *, int *, const char *, const char *);
-static char *convertitem(PyObject *, const char **, va_list *, int, int *,
- char *, size_t, freelist_t *);
-static char *converttuple(PyObject *, const char **, va_list *, int,
- int *, char *, size_t, int, freelist_t *);
-static char *convertsimple(PyObject *, const char **, va_list *, int, char *,
- size_t, freelist_t *);
-static Py_ssize_t convertbuffer(PyObject *, void **p, char **);
-static int getbuffer(PyObject *, Py_buffer *, char**);
+static const char *convertitem(PyObject *, const char **, va_list *, int, int *,
+ char *, size_t, freelist_t *);
+static const char *converttuple(PyObject *, const char **, va_list *, int,
+ int *, char *, size_t, int, freelist_t *);
+static const char *convertsimple(PyObject *, const char **, va_list *, int,
+ char *, size_t, freelist_t *);
+static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **);
+static int getbuffer(PyObject *, Py_buffer *, const char**);
static int vgetargskeywords(PyObject *, PyObject *,
const char *, char **, va_list *, int);
-static char *skipitem(const char **, va_list *, int);
+static int vgetargskeywordsfast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list *, int);
+static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *keywords, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ va_list *p_va, int flags);
+static const char *skipitem(const char **, va_list *, int);
int
PyArg_Parse(PyObject *args, const char *format, ...)
@@ -70,7 +110,7 @@ PyArg_Parse(PyObject *args, const char *format, ...)
return retval;
}
-int
+PyAPI_FUNC(int)
_PyArg_Parse_SizeT(PyObject *args, const char *format, ...)
{
int retval;
@@ -95,7 +135,7 @@ PyArg_ParseTuple(PyObject *args, const char *format, ...)
return retval;
}
-int
+PyAPI_FUNC(int)
_PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...)
{
int retval;
@@ -109,23 +149,54 @@ _PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...)
int
+_PyArg_ParseStack(PyObject *const *args, Py_ssize_t nargs, const char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1_impl(NULL, args, nargs, format, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseStack_SizeT(PyObject *const *args, Py_ssize_t nargs, const char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1_impl(NULL, args, nargs, format, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+int
PyArg_VaParse(PyObject *args, const char *format, va_list va)
{
va_list lva;
+ int retval;
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
- return vgetargs1(args, format, &lva, 0);
+ retval = vgetargs1(args, format, &lva, 0);
+ va_end(lva);
+ return retval;
}
-int
+PyAPI_FUNC(int)
_PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va)
{
va_list lva;
+ int retval;
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
- return vgetargs1(args, format, &lva, FLAG_SIZE_T);
+ retval = vgetargs1(args, format, &lva, FLAG_SIZE_T);
+ va_end(lva);
+ return retval;
}
@@ -185,7 +256,8 @@ cleanreturn(int retval, freelist_t *freelist)
static int
-vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
+vgetargs1_impl(PyObject *compat_args, PyObject *const *stack, Py_ssize_t nargs, const char *format,
+ va_list *p_va, int flags)
{
char msgbuf[256];
int levels[32];
@@ -196,17 +268,18 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
int level = 0;
int endfmt = 0;
const char *formatsave = format;
- Py_ssize_t i, len;
- char *msg;
+ Py_ssize_t i;
+ const char *msg;
int compat = flags & FLAG_COMPAT;
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist;
+ assert(nargs == 0 || stack != NULL);
+
freelist.entries = static_entries;
freelist.first_available = 0;
freelist.entries_malloced = 0;
- assert(compat || (args != (PyObject*)NULL));
flags = flags & ~FLAG_COMPAT;
while (endfmt == 0) {
@@ -243,7 +316,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
break;
default:
if (level == 0) {
- if (isalpha(Py_CHARMASK(c)))
+ if (isalpha(c))
if (c != 'e') /* skip encoded */
max++;
}
@@ -270,7 +343,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
if (compat) {
if (max == 0) {
- if (args == NULL)
+ if (compat_args == NULL)
return 1;
PyErr_Format(PyExc_TypeError,
"%.200s%s takes no arguments",
@@ -279,14 +352,14 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
return cleanreturn(0, &freelist);
}
else if (min == 1 && max == 1) {
- if (args == NULL) {
+ if (compat_args == NULL) {
PyErr_Format(PyExc_TypeError,
"%.200s%s takes at least one argument",
fname==NULL ? "function" : fname,
fname==NULL ? "" : "()");
return cleanreturn(0, &freelist);
}
- msg = convertitem(args, &format, p_va, flags, levels,
+ msg = convertitem(compat_args, &format, p_va, flags, levels,
msgbuf, sizeof(msgbuf), &freelist);
if (msg == NULL)
return cleanreturn(1, &freelist);
@@ -300,34 +373,26 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
}
}
- if (!PyTuple_Check(args)) {
- PyErr_SetString(PyExc_SystemError,
- "new style getargs format but argument is not a tuple");
- return cleanreturn(0, &freelist);
- }
-
- len = PyTuple_GET_SIZE(args);
-
- if (len < min || max < len) {
+ if (nargs < min || max < nargs) {
if (message == NULL)
PyErr_Format(PyExc_TypeError,
- "%.150s%s takes %s %d argument%s (%ld given)",
+ "%.150s%s takes %s %d argument%s (%zd given)",
fname==NULL ? "function" : fname,
fname==NULL ? "" : "()",
min==max ? "exactly"
- : len < min ? "at least" : "at most",
- len < min ? min : max,
- (len < min ? min : max) == 1 ? "" : "s",
- Py_SAFE_DOWNCAST(len, Py_ssize_t, long));
+ : nargs < min ? "at least" : "at most",
+ nargs < min ? min : max,
+ (nargs < min ? min : max) == 1 ? "" : "s",
+ nargs);
else
PyErr_SetString(PyExc_TypeError, message);
return cleanreturn(0, &freelist);
}
- for (i = 0; i < len; i++) {
+ for (i = 0; i < nargs; i++) {
if (*format == '|')
format++;
- msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
+ msg = convertitem(stack[i], &format, p_va,
flags, levels, msgbuf,
sizeof(msgbuf), &freelist);
if (msg) {
@@ -336,7 +401,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
}
}
- if (*format != '\0' && !isalpha(Py_CHARMASK(*format)) &&
+ if (*format != '\0' && !isalpha(*format) &&
*format != '(' &&
*format != '|' && *format != ':' && *format != ';') {
PyErr_Format(PyExc_SystemError,
@@ -347,6 +412,31 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
return cleanreturn(1, &freelist);
}
+static int
+vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
+{
+ PyObject **stack;
+ Py_ssize_t nargs;
+
+ if (!(flags & FLAG_COMPAT)) {
+ assert(args != NULL);
+
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_SystemError,
+ "new style getargs format but argument is not a tuple");
+ return 0;
+ }
+
+ stack = _PyTuple_ITEMS(args);
+ nargs = PyTuple_GET_SIZE(args);
+ }
+ else {
+ stack = NULL;
+ nargs = 0;
+ }
+
+ return vgetargs1_impl(args, stack, nargs, format, p_va, flags);
+}
static void
@@ -383,7 +473,12 @@ seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname,
PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg);
message = buf;
}
- PyErr_SetString(PyExc_TypeError, message);
+ if (msg[0] == '(') {
+ PyErr_SetString(PyExc_SystemError, message);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, message);
+ }
}
@@ -405,7 +500,7 @@ seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname,
and msgbuf is returned.
*/
-static char *
+static const char *
converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
int *levels, char *msgbuf, size_t bufsize, int toplevel,
freelist_t *freelist)
@@ -430,7 +525,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
else if (c == ':' || c == ';' || c == '\0')
break;
- else if (level == 0 && isalpha(Py_CHARMASK(c)))
+ else if (level == 0 && isalpha(c))
n++;
}
@@ -440,7 +535,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
toplevel ? "expected %d arguments, not %.50s" :
"must be %d-item sequence, not %.50s",
n,
- arg == Py_None ? "None" : arg->ob_type->tp_name);
+ arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
return msgbuf;
}
@@ -449,8 +544,10 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
levels[0] = 0;
if (toplevel) {
PyOS_snprintf(msgbuf, bufsize,
- "expected %d arguments, not %" PY_FORMAT_SIZE_T "d",
- n, len);
+ "expected %d argument%s, not %" PY_FORMAT_SIZE_T "d",
+ n,
+ n == 1 ? "" : "s",
+ len);
}
else {
PyOS_snprintf(msgbuf, bufsize,
@@ -463,7 +560,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
format = *p_format;
for (i = 0; i < n; i++) {
- char *msg;
+ const char *msg;
PyObject *item;
item = PySequence_GetItem(arg, i);
if (item == NULL) {
@@ -490,11 +587,11 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
/* Convert a single item. */
-static char *
+static const char *
convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,
int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist)
{
- char *msg;
+ const char *msg;
const char *format = *p_format;
if (*format == '(' /* ')' */) {
@@ -517,9 +614,21 @@ convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,
-/* Format an error message generated by convertsimple(). */
+/* Format an error message generated by convertsimple().
+ displayname must be UTF-8 encoded.
+*/
-static char *
+void
+_PyArg_BadArgument(const char *fname, const char *displayname,
+ const char *expected, PyObject *arg)
+{
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() %.200s must be %.50s, not %.50s",
+ fname, displayname, expected,
+ arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
+}
+
+static const char *
converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
{
assert(expected != NULL);
@@ -531,7 +640,7 @@ converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
else {
PyOS_snprintf(msgbuf, bufsize,
"must be %.50s, not %.50s", expected,
- arg == Py_None ? "None" : arg->ob_type->tp_name);
+ arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
}
return msgbuf;
}
@@ -539,7 +648,9 @@ converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
#define CONV_UNICODE "(unicode conversion error)"
/* Explicitly check for float arguments when integers are expected.
- Return 1 for error, 0 if ok. */
+ Return 1 for error, 0 if ok.
+ XXX Should be removed after the end of the deprecation period in
+ _PyLong_FromNbIndexOrNbInt. */
static int
float_argument_error(PyObject *arg)
{
@@ -561,14 +672,20 @@ float_argument_error(PyObject *arg)
When you add new format codes, please don't forget poor skipitem() below.
*/
-static char *
+static const char *
convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
char *msgbuf, size_t bufsize, freelist_t *freelist)
{
/* For # codes */
#define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\
if (flags & FLAG_SIZE_T) q2=va_arg(*p_va, Py_ssize_t*); \
- else q=va_arg(*p_va, int*);
+ else { \
+ if (PyErr_WarnEx(PyExc_DeprecationWarning, \
+ "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) { \
+ return NULL; \
+ } \
+ q=va_arg(*p_va, int*); \
+ }
#define STORE_SIZE(s) \
if (flags & FLAG_SIZE_T) \
*q2=s; \
@@ -585,7 +702,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
const char *format = *p_format;
char c = *format++;
- char *sarg;
+ const char *sarg;
switch (c) {
@@ -741,14 +858,13 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
break;
}
-#ifdef HAVE_LONG_LONG
- case 'L': {/* PY_LONG_LONG */
- PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * );
- PY_LONG_LONG ival;
+ case 'L': {/* long long */
+ long long *p = va_arg( *p_va, long long * );
+ long long ival;
if (float_argument_error(arg))
RETURN_ERR_OCCURRED;
ival = PyLong_AsLongLong(arg);
- if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred())
+ if (ival == (long long)-1 && PyErr_Occurred())
RETURN_ERR_OCCURRED;
else
*p = ival;
@@ -756,8 +872,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
case 'K': { /* long long sized bitfield */
- unsigned PY_LONG_LONG *p = va_arg(*p_va, unsigned PY_LONG_LONG *);
- unsigned PY_LONG_LONG ival;
+ unsigned long long *p = va_arg(*p_va, unsigned long long *);
+ unsigned long long ival;
if (PyLong_Check(arg))
ival = PyLong_AsUnsignedLongLongMask(arg);
else
@@ -765,12 +881,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
*p = ival;
break;
}
-#endif
case 'f': {/* float */
float *p = va_arg(*p_va, float *);
double dval = PyFloat_AsDouble(arg);
- if (PyErr_Occurred())
+ if (dval == -1.0 && PyErr_Occurred())
RETURN_ERR_OCCURRED;
else
*p = (float) dval;
@@ -780,7 +895,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
case 'd': {/* double */
double *p = va_arg(*p_va, double *);
double dval = PyFloat_AsDouble(arg);
- if (PyErr_Occurred())
+ if (dval == -1.0 && PyErr_Occurred())
RETURN_ERR_OCCURRED;
else
*p = dval;
@@ -812,7 +927,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
case 'C': {/* unicode char */
int *p = va_arg(*p_va, int *);
int kind;
- void *data;
+ const void *data;
if (!PyUnicode_Check(arg))
return converterr("a unicode character", arg, msgbuf, bufsize);
@@ -846,7 +961,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
case 'y': {/* any bytes-like object */
void **p = (void **)va_arg(*p_va, char **);
- char *buf;
+ const char *buf;
Py_ssize_t count;
if (*format == '*') {
if (getbuffer(arg, (Py_buffer*)p, &buf) < 0)
@@ -859,7 +974,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
break;
}
- count = convertbuffer(arg, p, &buf);
+ count = convertbuffer(arg, (const void **)p, &buf);
if (count < 0)
return converterr(buf, arg, msgbuf, bufsize);
if (*format == '#') {
@@ -890,10 +1005,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
if (sarg == NULL)
return converterr(CONV_UNICODE,
arg, msgbuf, bufsize);
- PyBuffer_FillInfo(p, arg, sarg, len, 1, 0);
+ PyBuffer_FillInfo(p, arg, (void *)sarg, len, 1, 0);
}
else { /* any bytes-like object */
- char *buf;
+ const char *buf;
if (getbuffer(arg, p, &buf) < 0)
return converterr(buf, arg, msgbuf, bufsize);
}
@@ -905,7 +1020,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
format++;
} else if (*format == '#') { /* a string or read-only bytes-like object */
/* "s#" or "z#" */
- void **p = (void **)va_arg(*p_va, char **);
+ const void **p = (const void **)va_arg(*p_va, const char **);
FETCH_SIZE;
if (c == 'z' && arg == Py_None) {
@@ -923,7 +1038,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
else { /* read-only bytes-like object */
/* XXX Really? */
- char *buf;
+ const char *buf;
Py_ssize_t count = convertbuffer(arg, p, &buf);
if (count < 0)
return converterr(buf, arg, msgbuf, bufsize);
@@ -932,7 +1047,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
format++;
} else {
/* "s" or "z" */
- char **p = va_arg(*p_va, char **);
+ const char **p = va_arg(*p_va, const char **);
Py_ssize_t len;
sarg = NULL;
@@ -989,7 +1104,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
*p = PyUnicode_AsUnicodeAndSize(arg, &len);
if (*p == NULL)
RETURN_ERR_OCCURRED;
- if (Py_UNICODE_strlen(*p) != (size_t)len) {
+ if (wcslen(*p) != (size_t)len) {
PyErr_SetString(PyExc_ValueError, "embedded null character");
RETURN_ERR_OCCURRED;
}
@@ -1036,39 +1151,34 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
(PyBytes_Check(arg) || PyByteArray_Check(arg))) {
s = arg;
Py_INCREF(s);
- if (PyObject_AsCharBuffer(s, &ptr, &size) < 0)
- return converterr("(AsCharBuffer failed)",
- arg, msgbuf, bufsize);
+ if (PyBytes_Check(arg)) {
+ size = PyBytes_GET_SIZE(s);
+ ptr = PyBytes_AS_STRING(s);
+ }
+ else {
+ size = PyByteArray_GET_SIZE(s);
+ ptr = PyByteArray_AS_STRING(s);
+ }
}
- else {
- PyObject *u;
-
- /* Convert object to Unicode */
- u = PyUnicode_FromObject(arg);
- if (u == NULL)
- return converterr(
- "string or unicode or text buffer",
- arg, msgbuf, bufsize);
-
+ else if (PyUnicode_Check(arg)) {
/* Encode object; use default error handling */
- s = PyUnicode_AsEncodedString(u,
+ s = PyUnicode_AsEncodedString(arg,
encoding,
NULL);
- Py_DECREF(u);
if (s == NULL)
return converterr("(encoding failed)",
arg, msgbuf, bufsize);
- if (!PyBytes_Check(s)) {
- Py_DECREF(s);
- return converterr(
- "(encoder failed to return bytes)",
- arg, msgbuf, bufsize);
- }
+ assert(PyBytes_Check(s));
size = PyBytes_GET_SIZE(s);
ptr = PyBytes_AS_STRING(s);
if (ptr == NULL)
ptr = "";
}
+ else {
+ return converterr(
+ recode_strings ? "str" : "str, bytes or bytearray",
+ arg, msgbuf, bufsize);
+ }
/* Write output; output is guaranteed to be 0-terminated */
if (*format == '#') {
@@ -1093,7 +1203,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
trailing 0-byte
*/
- FETCH_SIZE;
+ int *q = NULL; Py_ssize_t *q2 = NULL;
+ if (flags & FLAG_SIZE_T) {
+ q2 = va_arg(*p_va, Py_ssize_t*);
+ }
+ else {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "PY_SSIZE_T_CLEAN will be required for '#' formats", 1))
+ {
+ Py_DECREF(s);
+ return NULL;
+ }
+ q = va_arg(*p_va, int*);
+ }
format++;
if (q == NULL && q2 == NULL) {
@@ -1118,7 +1240,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
} else {
if (size + 1 > BUFFER_LEN) {
Py_DECREF(s);
- PyErr_Format(PyExc_TypeError,
+ PyErr_Format(PyExc_ValueError,
"encoded string too long "
"(%zd, maximum length %zd)",
(Py_ssize_t)size, (Py_ssize_t)(BUFFER_LEN-1));
@@ -1126,7 +1248,19 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
}
memcpy(*buffer, ptr, size+1);
- STORE_SIZE(size);
+
+ if (flags & FLAG_SIZE_T) {
+ *q2 = size;
+ }
+ else {
+ if (INT_MAX < size) {
+ Py_DECREF(s);
+ PyErr_SetString(PyExc_OverflowError,
+ "size does not fit in an int");
+ return converterr("", arg, msgbuf, bufsize);
+ }
+ *q = (int)size;
+ }
} else {
/* Using a 0-terminated buffer:
@@ -1201,7 +1335,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
type = va_arg(*p_va, PyTypeObject*);
p = va_arg(*p_va, PyObject **);
format++;
- if (PyType_IsSubtype(arg->ob_type, type))
+ if (PyType_IsSubtype(Py_TYPE(arg), type))
*p = arg;
else
return converterr(type->tp_name, arg, msgbuf, bufsize);
@@ -1272,7 +1406,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
static Py_ssize_t
-convertbuffer(PyObject *arg, void **p, char **errmsg)
+convertbuffer(PyObject *arg, const void **p, const char **errmsg)
{
PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer;
Py_ssize_t count;
@@ -1294,7 +1428,7 @@ convertbuffer(PyObject *arg, void **p, char **errmsg)
}
static int
-getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
+getbuffer(PyObject *arg, Py_buffer *view, const char **errmsg)
{
if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) {
*errmsg = "bytes-like object";
@@ -1336,7 +1470,7 @@ PyArg_ParseTupleAndKeywords(PyObject *args,
return retval;
}
-int
+PyAPI_FUNC(int)
_PyArg_ParseTupleAndKeywords_SizeT(PyObject *args,
PyObject *keywords,
const char *format,
@@ -1380,13 +1514,14 @@ PyArg_VaParseTupleAndKeywords(PyObject *args,
return 0;
}
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0);
+ va_end(lva);
return retval;
}
-int
+PyAPI_FUNC(int)
_PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
PyObject *keywords,
const char *format,
@@ -1404,10 +1539,92 @@ _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
return 0;
}
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
retval = vgetargskeywords(args, keywords, format,
kwlist, &lva, FLAG_SIZE_T);
+ va_end(lva);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast(args, keywords, parser, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast(args, keywords, parser, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+PyAPI_FUNC(int)
+_PyArg_VaParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ va_copy(lva, va);
+
+ retval = vgetargskeywordsfast(args, keywords, parser, &lva, 0);
+ va_end(lva);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ va_copy(lva, va);
+
+ retval = vgetargskeywordsfast(args, keywords, parser, &lva, FLAG_SIZE_T);
+ va_end(lva);
return retval;
}
@@ -1420,7 +1637,7 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs)
}
if (!_PyDict_HasOnlyStringKeys(kwargs)) {
PyErr_SetString(PyExc_TypeError,
- "keyword arguments must be strings");
+ "keywords must be strings");
return 0;
}
return 1;
@@ -1429,16 +1646,17 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs)
#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
static int
-vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
+vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
char **kwlist, va_list *p_va, int flags)
{
char msgbuf[512];
int levels[32];
- const char *fname, *msg, *custom_msg, *keyword;
+ const char *fname, *msg, *custom_msg;
int min = INT_MAX;
int max = INT_MAX;
- int i, len;
- Py_ssize_t nargs, nkeywords;
+ int i, pos, len;
+ int skip = 0;
+ Py_ssize_t nargs, nkwargs;
PyObject *current_arg;
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist;
@@ -1448,7 +1666,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
freelist.entries_malloced = 0;
assert(args != NULL && PyTuple_Check(args));
- assert(keywords == NULL || PyDict_Check(keywords));
+ assert(kwargs == NULL || PyDict_Check(kwargs));
assert(format != NULL);
assert(kwlist != NULL);
assert(p_va != NULL);
@@ -1465,9 +1683,17 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
custom_msg++;
}
+ /* scan kwlist and count the number of positional-only parameters */
+ for (pos = 0; kwlist[pos] && !*kwlist[pos]; pos++) {
+ }
/* scan kwlist and get greatest possible nbr of args */
- for (len=0; kwlist[len]; len++)
- continue;
+ for (len = pos; kwlist[len]; len++) {
+ if (!*kwlist[len]) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty keyword parameter name");
+ return cleanreturn(0, &freelist);
+ }
+ }
if (len > STATIC_FREELIST_ENTRIES) {
freelist.entries = PyMem_NEW(freelistentry_t, len);
@@ -1479,24 +1705,26 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
}
nargs = PyTuple_GET_SIZE(args);
- nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords);
- if (nargs + nkeywords > len) {
+ nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
+ if (nargs + nkwargs > len) {
+ /* Adding "keyword" (when nargs == 0) prevents producing wrong error
+ messages in some special cases (see bpo-31229). */
PyErr_Format(PyExc_TypeError,
- "%s%s takes at most %d argument%s (%zd given)",
+ "%.200s%s takes at most %d %sargument%s (%zd given)",
(fname == NULL) ? "function" : fname,
(fname == NULL) ? "" : "()",
len,
+ (nargs == 0) ? "keyword " : "",
(len == 1) ? "" : "s",
- nargs + nkeywords);
+ nargs + nkwargs);
return cleanreturn(0, &freelist);
}
/* convert tuple args and keyword args in same loop, using kwlist to drive process */
for (i = 0; i < len; i++) {
- keyword = kwlist[i];
if (*format == '|') {
if (min != INT_MAX) {
- PyErr_SetString(PyExc_RuntimeError,
+ PyErr_SetString(PyExc_SystemError,
"Invalid format string (| specified twice)");
return cleanreturn(0, &freelist);
}
@@ -1505,14 +1733,14 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
format++;
if (max != INT_MAX) {
- PyErr_SetString(PyExc_RuntimeError,
+ PyErr_SetString(PyExc_SystemError,
"Invalid format string ($ before |)");
return cleanreturn(0, &freelist);
}
}
if (*format == '$') {
if (max != INT_MAX) {
- PyErr_SetString(PyExc_RuntimeError,
+ PyErr_SetString(PyExc_SystemError,
"Invalid format string ($ specified twice)");
return cleanreturn(0, &freelist);
}
@@ -1520,119 +1748,800 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
max = i;
format++;
+ if (max < pos) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty parameter name after $");
+ return cleanreturn(0, &freelist);
+ }
+ if (skip) {
+ /* Now we know the minimal and the maximal numbers of
+ * positional arguments and can raise an exception with
+ * informative message (see below). */
+ break;
+ }
if (max < nargs) {
- PyErr_Format(PyExc_TypeError,
- "Function takes %s %d positional arguments"
- " (%d given)",
- (min != INT_MAX) ? "at most" : "exactly",
- max, nargs);
+ if (max == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes no positional arguments",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()");
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ (min != INT_MAX) ? "at most" : "exactly",
+ max,
+ max == 1 ? "" : "s",
+ nargs);
+ }
return cleanreturn(0, &freelist);
}
}
if (IS_END_OF_FORMAT(*format)) {
- PyErr_Format(PyExc_RuntimeError,
+ PyErr_Format(PyExc_SystemError,
"More keyword list entries (%d) than "
"format specifiers (%d)", len, i);
return cleanreturn(0, &freelist);
}
- current_arg = NULL;
- if (nkeywords) {
- current_arg = PyDict_GetItemString(keywords, keyword);
- }
- if (current_arg) {
- --nkeywords;
+ if (!skip) {
if (i < nargs) {
+ current_arg = PyTuple_GET_ITEM(args, i);
+ }
+ else if (nkwargs && i >= pos) {
+ current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
+ if (current_arg) {
+ --nkwargs;
+ }
+ else if (PyErr_Occurred()) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = NULL;
+ }
+
+ if (current_arg) {
+ msg = convertitem(current_arg, &format, p_va, flags,
+ levels, msgbuf, sizeof(msgbuf), &freelist);
+ if (msg) {
+ seterror(i+1, msg, levels, fname, custom_msg);
+ return cleanreturn(0, &freelist);
+ }
+ continue;
+ }
+
+ if (i < min) {
+ if (i < pos) {
+ assert (min == INT_MAX);
+ assert (max == INT_MAX);
+ skip = 1;
+ /* At that moment we still don't know the minimal and
+ * the maximal numbers of positional arguments. Raising
+ * an exception is deferred until we encounter | and $
+ * or the end of the format. */
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
+ "argument '%s' (pos %d)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ kwlist[i], i+1);
+ return cleanreturn(0, &freelist);
+ }
+ }
+ /* current code reports success when all required args
+ * fulfilled and no keyword args left, with no further
+ * validation. XXX Maybe skip this in debug build ?
+ */
+ if (!nkwargs && !skip) {
+ return cleanreturn(1, &freelist);
+ }
+ }
+
+ /* We are into optional args, skip through to any remaining
+ * keyword args */
+ msg = skipitem(&format, p_va, flags);
+ if (msg) {
+ PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,
+ format);
+ return cleanreturn(0, &freelist);
+ }
+ }
+
+ if (skip) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ (Py_MIN(pos, min) < i) ? "at least" : "exactly",
+ Py_MIN(pos, min),
+ Py_MIN(pos, min) == 1 ? "" : "s",
+ nargs);
+ return cleanreturn(0, &freelist);
+ }
+
+ if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
+ PyErr_Format(PyExc_SystemError,
+ "more argument specifiers than keyword list entries "
+ "(remaining format:'%s')", format);
+ return cleanreturn(0, &freelist);
+ }
+
+ if (nkwargs > 0) {
+ PyObject *key;
+ Py_ssize_t j;
+ /* make sure there are no arguments given by name and position */
+ for (i = pos; i < nargs; i++) {
+ current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
+ if (current_arg) {
/* arg present in tuple and in dict */
PyErr_Format(PyExc_TypeError,
- "Argument given by name ('%s') "
+ "argument for %.200s%s given by name ('%s') "
"and position (%d)",
- keyword, i+1);
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ kwlist[i], i+1);
+ return cleanreturn(0, &freelist);
+ }
+ else if (PyErr_Occurred()) {
return cleanreturn(0, &freelist);
}
}
- else if (nkeywords && PyErr_Occurred())
- return cleanreturn(0, &freelist);
- else if (i < nargs)
- current_arg = PyTuple_GET_ITEM(args, i);
+ /* make sure there are no extraneous keyword arguments */
+ j = 0;
+ while (PyDict_Next(kwargs, &j, &key, NULL)) {
+ int match = 0;
+ if (!PyUnicode_Check(key)) {
+ PyErr_SetString(PyExc_TypeError,
+ "keywords must be strings");
+ return cleanreturn(0, &freelist);
+ }
+ for (i = pos; i < len; i++) {
+ if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) {
+ PyErr_Format(PyExc_TypeError,
+ "'%U' is an invalid keyword "
+ "argument for %.200s%s",
+ key,
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+ return cleanreturn(0, &freelist);
+ }
+ }
+ }
+
+ return cleanreturn(1, &freelist);
+}
+
+
+/* List of static parsers. */
+static struct _PyArg_Parser *static_arg_parsers = NULL;
+
+static int
+parser_init(struct _PyArg_Parser *parser)
+{
+ const char * const *keywords;
+ const char *format, *msg;
+ int i, len, min, max, nkw;
+ PyObject *kwtuple;
+
+ assert(parser->keywords != NULL);
+ if (parser->kwtuple != NULL) {
+ return 1;
+ }
+
+ keywords = parser->keywords;
+ /* scan keywords and count the number of positional-only parameters */
+ for (i = 0; keywords[i] && !*keywords[i]; i++) {
+ }
+ parser->pos = i;
+ /* scan keywords and get greatest possible nbr of args */
+ for (; keywords[i]; i++) {
+ if (!*keywords[i]) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty keyword parameter name");
+ return 0;
+ }
+ }
+ len = i;
+
+ format = parser->format;
+ if (format) {
+ /* grab the function name or custom error msg first (mutually exclusive) */
+ parser->fname = strchr(parser->format, ':');
+ if (parser->fname) {
+ parser->fname++;
+ parser->custom_msg = NULL;
+ }
+ else {
+ parser->custom_msg = strchr(parser->format,';');
+ if (parser->custom_msg)
+ parser->custom_msg++;
+ }
+
+ min = max = INT_MAX;
+ for (i = 0; i < len; i++) {
+ if (*format == '|') {
+ if (min != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string (| specified twice)");
+ return 0;
+ }
+ if (max != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string ($ before |)");
+ return 0;
+ }
+ min = i;
+ format++;
+ }
+ if (*format == '$') {
+ if (max != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string ($ specified twice)");
+ return 0;
+ }
+ if (i < parser->pos) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty parameter name after $");
+ return 0;
+ }
+ max = i;
+ format++;
+ }
+ if (IS_END_OF_FORMAT(*format)) {
+ PyErr_Format(PyExc_SystemError,
+ "More keyword list entries (%d) than "
+ "format specifiers (%d)", len, i);
+ return 0;
+ }
+
+ msg = skipitem(&format, NULL, 0);
+ if (msg) {
+ PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,
+ format);
+ return 0;
+ }
+ }
+ parser->min = Py_MIN(min, len);
+ parser->max = Py_MIN(max, len);
+
+ if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
+ PyErr_Format(PyExc_SystemError,
+ "more argument specifiers than keyword list entries "
+ "(remaining format:'%s')", format);
+ return 0;
+ }
+ }
+
+ nkw = len - parser->pos;
+ kwtuple = PyTuple_New(nkw);
+ if (kwtuple == NULL) {
+ return 0;
+ }
+ keywords = parser->keywords + parser->pos;
+ for (i = 0; i < nkw; i++) {
+ PyObject *str = PyUnicode_FromString(keywords[i]);
+ if (str == NULL) {
+ Py_DECREF(kwtuple);
+ return 0;
+ }
+ PyUnicode_InternInPlace(&str);
+ PyTuple_SET_ITEM(kwtuple, i, str);
+ }
+ parser->kwtuple = kwtuple;
+
+ assert(parser->next == NULL);
+ parser->next = static_arg_parsers;
+ static_arg_parsers = parser;
+ return 1;
+}
+
+static void
+parser_clear(struct _PyArg_Parser *parser)
+{
+ Py_CLEAR(parser->kwtuple);
+}
+
+static PyObject*
+find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key)
+{
+ Py_ssize_t i, nkwargs;
+
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ for (i = 0; i < nkwargs; i++) {
+ PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
+
+ /* kwname == key will normally find a match in since keyword keys
+ should be interned strings; if not retry below in a new loop. */
+ if (kwname == key) {
+ return kwstack[i];
+ }
+ }
+
+ for (i = 0; i < nkwargs; i++) {
+ PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
+ assert(PyUnicode_Check(kwname));
+ if (_PyUnicode_EQ(kwname, key)) {
+ return kwstack[i];
+ }
+ }
+ return NULL;
+}
+
+static int
+vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ va_list *p_va, int flags)
+{
+ PyObject *kwtuple;
+ char msgbuf[512];
+ int levels[32];
+ const char *format;
+ const char *msg;
+ PyObject *keyword;
+ int i, pos, len;
+ Py_ssize_t nkwargs;
+ PyObject *current_arg;
+ freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
+ freelist_t freelist;
+ PyObject *const *kwstack = NULL;
+
+ freelist.entries = static_entries;
+ freelist.first_available = 0;
+ freelist.entries_malloced = 0;
+
+ assert(kwargs == NULL || PyDict_Check(kwargs));
+ assert(kwargs == NULL || kwnames == NULL);
+ assert(p_va != NULL);
+
+ if (parser == NULL) {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ if (kwnames != NULL && !PyTuple_Check(kwnames)) {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ if (!parser_init(parser)) {
+ return 0;
+ }
+
+ kwtuple = parser->kwtuple;
+ pos = parser->pos;
+ len = pos + (int)PyTuple_GET_SIZE(kwtuple);
+
+ if (len > STATIC_FREELIST_ENTRIES) {
+ freelist.entries = PyMem_NEW(freelistentry_t, len);
+ if (freelist.entries == NULL) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ freelist.entries_malloced = 1;
+ }
+
+ if (kwargs != NULL) {
+ nkwargs = PyDict_GET_SIZE(kwargs);
+ }
+ else if (kwnames != NULL) {
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ kwstack = args + nargs;
+ }
+ else {
+ nkwargs = 0;
+ }
+ if (nargs + nkwargs > len) {
+ /* Adding "keyword" (when nargs == 0) prevents producing wrong error
+ messages in some special cases (see bpo-31229). */
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes at most %d %sargument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ len,
+ (nargs == 0) ? "keyword " : "",
+ (len == 1) ? "" : "s",
+ nargs + nkwargs);
+ return cleanreturn(0, &freelist);
+ }
+ if (parser->max < nargs) {
+ if (parser->max == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes no positional arguments",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()");
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ (parser->min < parser->max) ? "at most" : "exactly",
+ parser->max,
+ parser->max == 1 ? "" : "s",
+ nargs);
+ }
+ return cleanreturn(0, &freelist);
+ }
+
+ format = parser->format;
+ /* convert tuple args and keyword args in same loop, using kwtuple to drive process */
+ for (i = 0; i < len; i++) {
+ if (*format == '|') {
+ format++;
+ }
+ if (*format == '$') {
+ format++;
+ }
+ assert(!IS_END_OF_FORMAT(*format));
+
+ if (i < nargs) {
+ current_arg = args[i];
+ }
+ else if (nkwargs && i >= pos) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ if (current_arg) {
+ --nkwargs;
+ }
+ }
+ else {
+ current_arg = NULL;
+ }
if (current_arg) {
msg = convertitem(current_arg, &format, p_va, flags,
levels, msgbuf, sizeof(msgbuf), &freelist);
if (msg) {
- seterror(i+1, msg, levels, fname, custom_msg);
+ seterror(i+1, msg, levels, parser->fname, parser->custom_msg);
return cleanreturn(0, &freelist);
}
continue;
}
- if (i < min) {
- PyErr_Format(PyExc_TypeError, "Required argument "
- "'%s' (pos %d) not found",
- keyword, i+1);
+ if (i < parser->min) {
+ /* Less arguments than required */
+ if (i < pos) {
+ Py_ssize_t min = Py_MIN(pos, parser->min);
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ min < parser->max ? "at least" : "exactly",
+ min,
+ min == 1 ? "" : "s",
+ nargs);
+ }
+ else {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
+ PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
+ "argument '%U' (pos %d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ }
return cleanreturn(0, &freelist);
}
/* current code reports success when all required args
* fulfilled and no keyword args left, with no further
* validation. XXX Maybe skip this in debug build ?
*/
- if (!nkeywords)
+ if (!nkwargs) {
return cleanreturn(1, &freelist);
+ }
- /* We are into optional args, skip thru to any remaining
+ /* We are into optional args, skip through to any remaining
* keyword args */
msg = skipitem(&format, p_va, flags);
- if (msg) {
- PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg,
- format);
- return cleanreturn(0, &freelist);
+ assert(msg == NULL);
+ }
+
+ assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$'));
+
+ if (nkwargs > 0) {
+ Py_ssize_t j;
+ /* make sure there are no arguments given by name and position */
+ for (i = pos; i < nargs; i++) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ if (current_arg) {
+ /* arg present in tuple and in dict */
+ PyErr_Format(PyExc_TypeError,
+ "argument for %.200s%s given by name ('%U') "
+ "and position (%d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ return cleanreturn(0, &freelist);
+ }
+ }
+ /* make sure there are no extraneous keyword arguments */
+ j = 0;
+ while (1) {
+ int match;
+ if (kwargs != NULL) {
+ if (!PyDict_Next(kwargs, &j, &keyword, NULL))
+ break;
+ }
+ else {
+ if (j >= PyTuple_GET_SIZE(kwnames))
+ break;
+ keyword = PyTuple_GET_ITEM(kwnames, j);
+ j++;
+ }
+
+ match = PySequence_Contains(kwtuple, keyword);
+ if (match <= 0) {
+ if (!match) {
+ PyErr_Format(PyExc_TypeError,
+ "'%S' is an invalid keyword "
+ "argument for %.200s%s",
+ keyword,
+ (parser->fname == NULL) ? "this function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()");
+ }
+ return cleanreturn(0, &freelist);
+ }
}
}
- if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
- PyErr_Format(PyExc_RuntimeError,
- "more argument specifiers than keyword list entries "
- "(remaining format:'%s')", format);
- return cleanreturn(0, &freelist);
+ return cleanreturn(1, &freelist);
+}
+
+static int
+vgetargskeywordsfast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list *p_va, int flags)
+{
+ PyObject **stack;
+ Py_ssize_t nargs;
+
+ if (args == NULL
+ || !PyTuple_Check(args)
+ || (keywords != NULL && !PyDict_Check(keywords)))
+ {
+ PyErr_BadInternalCall();
+ return 0;
}
- /* make sure there are no extraneous keyword arguments */
- if (nkeywords > 0) {
- PyObject *key, *value;
- Py_ssize_t pos = 0;
- while (PyDict_Next(keywords, &pos, &key, &value)) {
- int match = 0;
- char* ks;
- if (!PyUnicode_Check(key)) {
- PyErr_SetString(PyExc_TypeError,
- "keywords must be strings");
- return cleanreturn(0, &freelist);
+ stack = _PyTuple_ITEMS(args);
+ nargs = PyTuple_GET_SIZE(args);
+ return vgetargskeywordsfast_impl(stack, nargs, keywords, NULL,
+ parser, p_va, flags);
+}
+
+
+#undef _PyArg_UnpackKeywords
+
+PyObject * const *
+_PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ int minpos, int maxpos, int minkw,
+ PyObject **buf)
+{
+ PyObject *kwtuple;
+ PyObject *keyword;
+ int i, posonly, minposonly, maxargs;
+ int reqlimit = minkw ? maxpos + minkw : minpos;
+ Py_ssize_t nkwargs;
+ PyObject *current_arg;
+ PyObject * const *kwstack = NULL;
+
+ assert(kwargs == NULL || PyDict_Check(kwargs));
+ assert(kwargs == NULL || kwnames == NULL);
+
+ if (parser == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ if (kwnames != NULL && !PyTuple_Check(kwnames)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ if (args == NULL && nargs == 0) {
+ args = buf;
+ }
+
+ if (!parser_init(parser)) {
+ return NULL;
+ }
+
+ kwtuple = parser->kwtuple;
+ posonly = parser->pos;
+ minposonly = Py_MIN(posonly, minpos);
+ maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple);
+
+ if (kwargs != NULL) {
+ nkwargs = PyDict_GET_SIZE(kwargs);
+ }
+ else if (kwnames != NULL) {
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ kwstack = args + nargs;
+ }
+ else {
+ nkwargs = 0;
+ }
+ if (nkwargs == 0 && minkw == 0 && minpos <= nargs && nargs <= maxpos) {
+ /* Fast path. */
+ return args;
+ }
+ if (nargs + nkwargs > maxargs) {
+ /* Adding "keyword" (when nargs == 0) prevents producing wrong error
+ messages in some special cases (see bpo-31229). */
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes at most %d %sargument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ maxargs,
+ (nargs == 0) ? "keyword " : "",
+ (maxargs == 1) ? "" : "s",
+ nargs + nkwargs);
+ return NULL;
+ }
+ if (nargs > maxpos) {
+ if (maxpos == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes no positional arguments",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()");
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ (minpos < maxpos) ? "at most" : "exactly",
+ maxpos,
+ (maxpos == 1) ? "" : "s",
+ nargs);
+ }
+ return NULL;
+ }
+ if (nargs < minposonly) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ minposonly < maxpos ? "at least" : "exactly",
+ minposonly,
+ minposonly == 1 ? "" : "s",
+ nargs);
+ return NULL;
+ }
+
+ /* copy tuple args */
+ for (i = 0; i < nargs; i++) {
+ buf[i] = args[i];
+ }
+
+ /* copy keyword args using kwtuple to drive process */
+ for (i = Py_MAX((int)nargs, posonly); i < maxargs; i++) {
+ if (nkwargs) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return NULL;
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
}
+ }
+ else if (i >= reqlimit) {
+ break;
+ }
+ else {
+ current_arg = NULL;
+ }
- /* check that _PyUnicode_AsString() result is not NULL */
- ks = _PyUnicode_AsString(key);
- if (ks != NULL) {
- for (i = 0; i < len; i++) {
- if (!strcmp(ks, kwlist[i])) {
- match = 1;
- break;
- }
+ buf[i] = current_arg;
+
+ if (current_arg) {
+ --nkwargs;
+ }
+ else if (i < minpos || (maxpos <= i && i < reqlimit)) {
+ /* Less arguments than required */
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
+ "argument '%U' (pos %d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ return NULL;
+ }
+ }
+
+ if (nkwargs > 0) {
+ Py_ssize_t j;
+ /* make sure there are no arguments given by name and position */
+ for (i = posonly; i < nargs; i++) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return NULL;
}
}
- if (!match) {
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ if (current_arg) {
+ /* arg present in tuple and in dict */
PyErr_Format(PyExc_TypeError,
- "'%U' is an invalid keyword "
- "argument for this function",
- key);
- return cleanreturn(0, &freelist);
+ "argument for %.200s%s given by name ('%U') "
+ "and position (%d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ return NULL;
+ }
+ }
+ /* make sure there are no extraneous keyword arguments */
+ j = 0;
+ while (1) {
+ int match;
+ if (kwargs != NULL) {
+ if (!PyDict_Next(kwargs, &j, &keyword, NULL))
+ break;
+ }
+ else {
+ if (j >= PyTuple_GET_SIZE(kwnames))
+ break;
+ keyword = PyTuple_GET_ITEM(kwnames, j);
+ j++;
+ }
+
+ match = PySequence_Contains(kwtuple, keyword);
+ if (match <= 0) {
+ if (!match) {
+ PyErr_Format(PyExc_TypeError,
+ "'%S' is an invalid keyword "
+ "argument for %.200s%s",
+ keyword,
+ (parser->fname == NULL) ? "this function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()");
+ }
+ return NULL;
}
}
}
- return cleanreturn(1, &freelist);
+ return buf;
}
-static char *
+static const char *
skipitem(const char **p_format, va_list *p_va, int flags)
{
const char *format = *p_format;
@@ -1653,10 +2562,8 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'I': /* int sized bitfield */
case 'l': /* long int */
case 'k': /* long int sized bitfield */
-#ifdef HAVE_LONG_LONG
- case 'L': /* PY_LONG_LONG */
- case 'K': /* PY_LONG_LONG sized bitfield */
-#endif
+ case 'L': /* long long */
+ case 'K': /* long long sized bitfield */
case 'n': /* Py_ssize_t */
case 'f': /* float */
case 'd': /* double */
@@ -1668,7 +2575,9 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'Y': /* string object */
case 'U': /* unicode string object */
{
- (void) va_arg(*p_va, void *);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, void *);
+ }
break;
}
@@ -1676,13 +2585,15 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'e': /* string with encoding */
{
- (void) va_arg(*p_va, const char *);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, const char *);
+ }
if (!(*format == 's' || *format == 't'))
/* after 'e', only 's' and 't' is allowed */
goto err;
format++;
- /* explicit fallthrough to string cases */
}
+ /* fall through */
case 's': /* string */
case 'z': /* string or None */
@@ -1691,14 +2602,25 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'Z': /* unicode string or None */
case 'w': /* buffer, read-write */
{
- (void) va_arg(*p_va, char **);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, char **);
+ }
if (*format == '#') {
- if (flags & FLAG_SIZE_T)
- (void) va_arg(*p_va, Py_ssize_t *);
- else
- (void) va_arg(*p_va, int *);
+ if (p_va != NULL) {
+ if (flags & FLAG_SIZE_T)
+ (void) va_arg(*p_va, Py_ssize_t *);
+ else {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
+ return NULL;
+ }
+ (void) va_arg(*p_va, int *);
+ }
+ }
format++;
- } else if ((c == 's' || c == 'z' || c == 'y') && *format == '*') {
+ } else if ((c == 's' || c == 'z' || c == 'y' || c == 'w')
+ && *format == '*')
+ {
format++;
}
break;
@@ -1708,24 +2630,30 @@ skipitem(const char **p_format, va_list *p_va, int flags)
{
if (*format == '!') {
format++;
- (void) va_arg(*p_va, PyTypeObject*);
- (void) va_arg(*p_va, PyObject **);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, PyTypeObject*);
+ (void) va_arg(*p_va, PyObject **);
+ }
}
else if (*format == '&') {
typedef int (*converter)(PyObject *, void *);
- (void) va_arg(*p_va, converter);
- (void) va_arg(*p_va, void *);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, converter);
+ (void) va_arg(*p_va, void *);
+ }
format++;
}
else {
- (void) va_arg(*p_va, PyObject **);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, PyObject **);
+ }
}
break;
}
case '(': /* bypass tuple, not handled at all previously */
{
- char *msg;
+ const char *msg;
for (;;) {
if (*format==')')
break;
@@ -1754,66 +2682,117 @@ err:
}
+#undef _PyArg_CheckPositional
+
int
-PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
+_PyArg_CheckPositional(const char *name, Py_ssize_t nargs,
+ Py_ssize_t min, Py_ssize_t max)
{
- Py_ssize_t i, l;
- PyObject **o;
- va_list vargs;
-
-#ifdef HAVE_STDARG_PROTOTYPES
- va_start(vargs, max);
-#else
- va_start(vargs);
-#endif
-
assert(min >= 0);
assert(min <= max);
- if (!PyTuple_Check(args)) {
- va_end(vargs);
- PyErr_SetString(PyExc_SystemError,
- "PyArg_UnpackTuple() argument list is not a tuple");
- return 0;
- }
- l = PyTuple_GET_SIZE(args);
- if (l < min) {
+
+ if (nargs < min) {
if (name != NULL)
PyErr_Format(
PyExc_TypeError,
- "%s expected %s%zd arguments, got %zd",
- name, (min == max ? "" : "at least "), min, l);
+ "%.200s expected %s%zd argument%s, got %zd",
+ name, (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs);
else
PyErr_Format(
PyExc_TypeError,
- "unpacked tuple should have %s%zd elements,"
+ "unpacked tuple should have %s%zd element%s,"
" but has %zd",
- (min == max ? "" : "at least "), min, l);
- va_end(vargs);
+ (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs);
return 0;
}
- if (l > max) {
+
+ if (nargs == 0) {
+ return 1;
+ }
+
+ if (nargs > max) {
if (name != NULL)
PyErr_Format(
PyExc_TypeError,
- "%s expected %s%zd arguments, got %zd",
- name, (min == max ? "" : "at most "), max, l);
+ "%.200s expected %s%zd argument%s, got %zd",
+ name, (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs);
else
PyErr_Format(
PyExc_TypeError,
- "unpacked tuple should have %s%zd elements,"
+ "unpacked tuple should have %s%zd element%s,"
" but has %zd",
- (min == max ? "" : "at most "), max, l);
- va_end(vargs);
+ (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+unpack_stack(PyObject *const *args, Py_ssize_t nargs, const char *name,
+ Py_ssize_t min, Py_ssize_t max, va_list vargs)
+{
+ Py_ssize_t i;
+ PyObject **o;
+
+ if (!_PyArg_CheckPositional(name, nargs, min, max)) {
return 0;
}
- for (i = 0; i < l; i++) {
+
+ for (i = 0; i < nargs; i++) {
o = va_arg(vargs, PyObject **);
- *o = PyTuple_GET_ITEM(args, i);
+ *o = args[i];
}
- va_end(vargs);
return 1;
}
+int
+PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...)
+{
+ PyObject **stack;
+ Py_ssize_t nargs;
+ int retval;
+ va_list vargs;
+
+ if (!PyTuple_Check(args)) {
+ PyErr_SetString(PyExc_SystemError,
+ "PyArg_UnpackTuple() argument list is not a tuple");
+ return 0;
+ }
+ stack = _PyTuple_ITEMS(args);
+ nargs = PyTuple_GET_SIZE(args);
+
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, max);
+#else
+ va_start(vargs);
+#endif
+ retval = unpack_stack(stack, nargs, name, min, max, vargs);
+ va_end(vargs);
+ return retval;
+}
+
+int
+_PyArg_UnpackStack(PyObject *const *args, Py_ssize_t nargs, const char *name,
+ Py_ssize_t min, Py_ssize_t max, ...)
+{
+ int retval;
+ va_list vargs;
+
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, max);
+#else
+ va_start(vargs);
+#endif
+ retval = unpack_stack(args, nargs, name, min, max, vargs);
+ va_end(vargs);
+ return retval;
+}
+
+
+#undef _PyArg_NoKeywords
+#undef _PyArg_NoKwnames
+#undef _PyArg_NoPositional
/* For type constructors that don't take keyword args
*
@@ -1821,23 +2800,24 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m
* not empty, returns 1 otherwise
*/
int
-_PyArg_NoKeywords(const char *funcname, PyObject *kw)
+_PyArg_NoKeywords(const char *funcname, PyObject *kwargs)
{
- if (kw == NULL)
+ if (kwargs == NULL) {
return 1;
- if (!PyDict_CheckExact(kw)) {
+ }
+ if (!PyDict_CheckExact(kwargs)) {
PyErr_BadInternalCall();
return 0;
}
- if (PyDict_Size(kw) == 0)
+ if (PyDict_GET_SIZE(kwargs) == 0) {
return 1;
+ }
- PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments",
+ PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
funcname);
return 0;
}
-
int
_PyArg_NoPositional(const char *funcname, PyObject *args)
{
@@ -1850,11 +2830,41 @@ _PyArg_NoPositional(const char *funcname, PyObject *args)
if (PyTuple_GET_SIZE(args) == 0)
return 1;
- PyErr_Format(PyExc_TypeError, "%s does not take positional arguments",
+ PyErr_Format(PyExc_TypeError, "%.200s() takes no positional arguments",
funcname);
return 0;
}
+int
+_PyArg_NoKwnames(const char *funcname, PyObject *kwnames)
+{
+ if (kwnames == NULL) {
+ return 1;
+ }
+
+ assert(PyTuple_CheckExact(kwnames));
+
+ if (PyTuple_GET_SIZE(kwnames) == 0) {
+ return 1;
+ }
+
+ PyErr_Format(PyExc_TypeError, "%s() takes no keyword arguments", funcname);
+ return 0;
+}
+
+void
+_PyArg_Fini(void)
+{
+ struct _PyArg_Parser *tmp, *s = static_arg_parsers;
+ while (s) {
+ tmp = s->next;
+ s->next = NULL;
+ parser_clear(s);
+ s = tmp;
+ }
+ static_arg_parsers = NULL;
+}
+
#ifdef __cplusplus
};
#endif
diff --git a/pypy/module/cpyext/src/modsupport.c b/pypy/module/cpyext/src/modsupport.c
index 710a482419..95697d94c2 100644
--- a/pypy/module/cpyext/src/modsupport.c
+++ b/pypy/module/cpyext/src/modsupport.c
@@ -6,6 +6,12 @@
#define FLAG_SIZE_T 1
typedef double va_double;
+// Fast inlined version of PyType_HasFeature()
+static inline int
+_PyType_HasFeature(PyTypeObject *type, unsigned long feature) {
+ return ((type->tp_flags & feature) != 0);
+}
+
static PyObject *va_build_value(const char *, va_list, int);
/* Package context -- the full module name for package imports
@@ -618,3 +624,57 @@ PyModuleDef_Init(struct PyModuleDef* def)
}
return (PyObject*)def;
}
+
+PyObject *
+PyType_GetModule(PyTypeObject *type)
+{
+ assert(PyType_Check(type));
+ if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "PyType_GetModule: Type '%s' is not a heap type",
+ type->tp_name);
+ return NULL;
+ }
+
+ PyHeapTypeObject* et = (PyHeapTypeObject*)type;
+ if (!et->ht_module) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "PyType_GetModule: Type '%s' has no associated module",
+ type->tp_name);
+ return NULL;
+ }
+ return et->ht_module;
+
+}
+
+void *
+PyType_GetModuleState(PyTypeObject *type)
+{
+ PyObject *m = PyType_GetModule(type);
+ if (m == NULL) {
+ return NULL;
+ }
+ return PyModule_GetState(m);
+}
+
+PyObject*
+PyState_FindModule(struct PyModuleDef* module)
+{
+ Py_ssize_t index = module->m_base.m_index;
+ PyThreadState *tstate = PyThreadState_Get();
+ PyInterpreterState *state = tstate->interp;
+ PyObject *res;
+ if (module->m_slots) {
+ return NULL;
+ }
+ if (index == 0)
+ return NULL;
+ if (state->modules_by_index == NULL)
+ return NULL;
+ if (index >= PyList_GET_SIZE(state->modules_by_index))
+ return NULL;
+ res = PyList_GET_ITEM(state->modules_by_index, index);
+ return res==Py_None ? NULL : res;
+}
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
index db78f4a578..312eac3a48 100644
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -126,6 +126,7 @@ static PyMethodDef foo_methods[] = {
{"classmeth", (PyCFunction)foo_classmeth, METH_NOARGS|METH_CLASS, NULL},
{"fake_classmeth", (PyCFunction)foo_classmeth, METH_NOARGS, NULL},
{"unset_string_member", (PyCFunction)foo_unset, METH_NOARGS, NULL},
+ {"__class_getitem__", (PyCFunction)Py_GenericAlias, METH_O|METH_CLASS, "See PEP 585"},
{NULL, NULL} /* sentinel */
};
diff --git a/pypy/module/cpyext/test/multiphase2.c b/pypy/module/cpyext/test/multiphase2.c
index 3667c39778..d02709f0eb 100644
--- a/pypy/module/cpyext/test/multiphase2.c
+++ b/pypy/module/cpyext/test/multiphase2.c
@@ -118,7 +118,7 @@ testexport_foo(PyObject *self, PyObject *args)
}
/* Test that PyState registration fails */
-/*
+
PyDoc_STRVAR(call_state_registration_func_doc,
"register_state(0): call PyState_FindModule()\n\
register_state(1): call PyState_AddModule()\n\
@@ -156,7 +156,6 @@ call_state_registration_func(PyObject *mod, PyObject *args)
}
Py_RETURN_NONE;
}
-*/
static PyType_Slot Str_Type_slots[] = {
{Py_tp_base, NULL}, /* filled out in module exec function */
@@ -174,8 +173,8 @@ static PyType_Spec Str_Type_spec = {
static PyMethodDef testexport_methods[] = {
{"foo", testexport_foo, METH_VARARGS,
testexport_foo_doc},
-/* {"call_state_registration_func", call_state_registration_func,
- METH_VARARGS, call_state_registration_func_doc},*/
+ {"call_state_registration_func", call_state_registration_func,
+ METH_VARARGS, call_state_registration_func_doc},
{NULL, NULL} /* sentinel */
};
diff --git a/pypy/module/cpyext/test/test_module.py b/pypy/module/cpyext/test/test_module.py
index 3b178e0aa5..20732436b3 100644
--- a/pypy/module/cpyext/test/test_module.py
+++ b/pypy/module/cpyext/test/test_module.py
@@ -250,6 +250,14 @@ class AppTestMultiPhase2(AppTestCpythonExtensionBase):
module.__spec__.loader.exec_module(module)
assert ex_class is module.Example
+ def test_try_registration(self):
+ module = self.import_module(name=self.name, use_imp=True)
+ assert module.call_state_registration_func(0) is None
+ with raises(SystemError):
+ module.call_state_registration_func(1)
+ with raises(SystemError):
+ module.call_state_registration_func(2)
+
def w_load_from_name(self, name, origin=None, use_prefix=True):
from importlib import machinery, util
if not origin:
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
index 53bcb93fb0..f2c4fc4cf6 100644
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -132,8 +132,21 @@ class AppTestTypeObject(AppTestCpythonExtensionBase):
def test_classmethod(self):
module = self.import_module(name="foo")
- obj = module.fooType.classmeth()
+ classmeth = module.fooType.classmeth
+ obj = classmeth()
assert obj is module.fooType
+ class _C:
+ def _m(self): pass
+ MethodType = type(_C()._m)
+ print(type(classmeth).mro())
+ print(MethodType.mro())
+ assert not isinstance(classmeth, MethodType)
+
+ def test_class_getitem(self):
+ module = self.import_module(name='foo')
+ f = module.fooType.__class_getitem__
+ out = f(42)
+ assert str(out) == 'foo.foo[42]'
def test_methoddescr(self):
module = self.import_module(name='foo')
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
index 414bd02857..0ed823a1ce 100644
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -922,16 +922,16 @@ class TestUnicode(BaseApiTest):
def test_locale(self, space):
- # Input is bytes
- w_input = space.newbytes("test")
- with rffi.scoped_str2charp('strict') as errors:
- w_ret = PyUnicode_DecodeLocale(space, w_input, errors)
- assert space.utf8_w(w_ret) == 'test'
- with rffi.scoped_str2charp('surrogateescape') as errors:
- w_ret = PyUnicode_DecodeLocale(space, w_input, errors)
- assert space.utf8_w(w_ret) == 'test'
-
- # Input is unicode
+ # Input is char *
+ with rffi.scoped_str2charp('test') as test:
+ with rffi.scoped_str2charp('strict') as errors:
+ w_ret = PyUnicode_DecodeLocale(space, test, errors)
+ assert space.utf8_w(w_ret) == 'test'
+ with rffi.scoped_str2charp('surrogateescape') as errors:
+ w_ret = PyUnicode_DecodeLocale(space, test, errors)
+ assert space.utf8_w(w_ret) == 'test'
+
+ # Input is w_unicode
w_input = space.newtext("test", 4)
with rffi.scoped_str2charp('strict') as errors:
w_ret = PyUnicode_EncodeLocale(space, w_input, errors)
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
index ed801cd6d7..9f86ec8cdd 100644
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -26,7 +26,7 @@ from pypy.module.cpyext.api import (
from rpython.tool.cparser import CTypeSpace
from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
- PyCFunction_NewEx, PyCFunction, PyMethodDef,
+ PyCFunction, PyMethodDef,
W_PyCMethodObject, W_PyCFunctionObject, extract_doc, extract_txtsig,
W_PyCWrapperObject)
from pypy.module.cpyext.modsupport import convert_method_defs
@@ -233,7 +233,7 @@ def methoddescr_realize(space, obj):
method = rffi.cast(lltype.Ptr(PyMethodDef), obj)
w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
w_obj = space.allocate_instance(W_PyCMethodObject, w_type)
- w_obj.__init__(space, method, w_type)
+ w_obj.__init__(space, method, None, None, w_type)
track_reference(space, obj, w_obj)
return w_obj
@@ -437,7 +437,7 @@ def add_tp_new_wrapper(space, dict_w, pto):
if "__new__" in dict_w:
return
pyo = rffi.cast(PyObject, pto)
- dict_w["__new__"] = PyCFunction_NewEx(space, get_new_method_def(space),
+ dict_w["__new__"] = W_PyCFunctionObject(space, get_new_method_def(space),
from_ref(space, pyo), None)
def inherit_special(space, pto, w_obj, base_pto):
@@ -927,6 +927,12 @@ def get_ht_slot(ht, slotnum):
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)""",
result_is_ll=True)
def PyType_FromSpecWithBases(space, spec, bases):
+ return PyType_FromSpecWithBases(space, None, spec, bases)
+
+@cts.decl("""PyObject *
+ PyType_FromModuleAndSpec(PyObject *, PyType_Spec *spec, PyObject *bases)""",
+ result_is_ll=True)
+def PyType_FromSpecWithBases(space, module, spec, bases):
from pypy.module.cpyext.unicodeobject import PyUnicode_FromString
state = space.fromcache(State)
p_type = cts.cast('PyTypeObject*', make_ref(space, space.w_type))
@@ -945,6 +951,9 @@ def PyType_FromSpecWithBases(space, spec, bases):
res.c_ht_name = make_ref(space, space.newtext(name))
res.c_ht_qualname = res.c_ht_name
incref(space, res.c_ht_qualname)
+ if module:
+ incref(space, module)
+ res.c_ht_module = module
typ.c_tp_name = spec.c_name
slotdefs = rffi.cast(rffi.CArrayPtr(cts.gettype('PyType_Slot')), spec.c_slots)
if not bases:
@@ -1009,7 +1018,6 @@ def PyType_FromSpecWithBases(space, spec, bases):
w_type.setdictvalue(space, '__module__', space.newtext(modname))
return res
-
@cpython_api([PyTypeObjectPtr, rffi.INT], rffi.VOIDP)
def PyType_GetSlot(space, typ, slot):
""" Use the Py_tp* macros in typeslots.h to return a slot function
@@ -1047,3 +1055,8 @@ def PyType_Modified(space, w_obj):
return
if w_obj.is_cpytype():
w_obj.mutated(None)
+
+@cpython_api([PyObject, PyObject], PyObject, header='genericaliasobject.h')
+def Py_GenericAlias(space, w_cls, w_item):
+ from pypy.objspace.std.util import generic_alias_class_getitem
+ return generic_alias_class_getitem(space, w_cls, w_item)
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
index 85583c681a..44fd15d471 100644
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -767,8 +767,8 @@ def PyUnicode_EncodeLocale(space, w_obj, errors):
ulen = space.len_w(w_obj)
return space.newbytes(utf8_encode_locale(utf8, ulen, s))
-@cpython_api([PyObject, CONST_STRING], PyObject)
-def PyUnicode_DecodeLocale(space, w_obj, errors):
+@cpython_api([CONST_STRING, CONST_STRING], PyObject)
+def PyUnicode_DecodeLocale(space, obj, errors):
from pypy.module._codecs.locale import str_decode_locale
if errors:
s = rffi.charp2str(errors)
@@ -777,7 +777,20 @@ def PyUnicode_DecodeLocale(space, w_obj, errors):
if not s in ('strict', 'surrogateescape'):
raise oefmt(space.w_ValueError, "only 'strict' and 'surrogateescape' "
"error handlers are supported, not '%s'", s)
- utf8 = space.utf8_w(w_obj)
+ utf8 = rffi.charp2str(obj)
+ return space.newtext(*str_decode_locale(utf8, s))
+
+@cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject)
+def PyUnicode_DecodeLocaleAndSize(space, obj, length, errors):
+ from pypy.module._codecs.locale import str_decode_locale
+ if errors:
+ s = rffi.charp2str(errors)
+ else:
+ s = 'strict'
+ if not s in ('strict', 'surrogateescape'):
+ raise oefmt(space.w_ValueError, "only 'strict' and 'surrogateescape' "
+ "error handlers are supported, not '%s'", s)
+ utf8 = rffi.charpsize2str(obj, length)
return space.newtext(*str_decode_locale(utf8, s))
@cpython_api([PyObject, PyObjectP], rffi.INT_real, error=0)
@@ -1175,6 +1188,44 @@ def PyUnicode_Concat(space, w_left, w_right):
return space.add(w_left, w_right)
@cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=CANNOT_FAIL)
+def _PyUnicode_EqualToASCIIString(space, w_uni, string):
+ """Test whether a unicode is equal to ASCII string. Return 1 if true,
+ 0 otherwise. The right argument must be ASCII-encoded string.
+ Any error occurs inside will be cleared before return."""
+ utf8 = space.utf8_w(w_uni)
+ lgt = space.len_w(w_uni)
+ i = 0
+ # Compare Unicode string and source character set string
+ for ch in rutf8.Utf8StringIterator(utf8):
+ if string[i] == '\0':
+ break
+ s = ord(string[i])
+ if ch != s:
+ if ch != s:
+ return 0
+ i += 1
+ if i < lgt:
+ return 0 # uni is longer
+ if string[i] != '\0':
+ return 0 # str is longer
+ return 1
+
+@cpython_api([PyObject, PyObject], rffi.INT_real, error=CANNOT_FAIL)
+def _PyUnicode_EQ(space, w_aa, w_bb):
+ if not space.isinstance_w(w_aa, space.w_unicode) or not space.isinstance_w(w_bb, space.w_unicode):
+ raise oefmt(space.w_TypeError, "_PyUnicode_EQ(aa, bb) must be called with two str instances")
+ aa = space.utf8_w(w_aa)
+ la = space.len_w(w_aa)
+ bb = space.utf8_w(w_bb)
+ lb = space.len_w(w_bb)
+ if la != lb:
+ return 0
+ if la == 0:
+ return 1
+ if aa == bb:
+ return 1
+ return 0
+@cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=CANNOT_FAIL)
def PyUnicode_CompareWithASCIIString(space, w_uni, string):
"""Compare a unicode object, uni, with string and return -1, 0, 1 for less
than, equal, and greater than, respectively. It is best to pass only
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
index 3f8af079ef..90c0651cc9 100644
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -218,9 +218,13 @@ def _unwrap_path(space, w_value, allow_fd=True, nullable=False):
"expected %S.__fspath__() to return str or bytes, not %T",
w_value, w_result)
- raise oefmt(space.w_TypeError,
- "illegal type for path parameter (should be "
- "%s, not %T)", allowed_types, w_value)
+ raise oefmt(space.w_TypeError,
+ 'expected %T.__fspath__() to return str or bytes, not %T',
+ w_value,
+ w_result
+ )
+ raise oefmt(
+ space.w_TypeError, "path should be %s, not %T", allowed_types, w_value)
class _PathOrFd(Unwrapper):
def unwrap(self, space, w_value):
@@ -261,7 +265,7 @@ def unwrap_fd(space, w_value, allowed_types='integer'):
raise
if result == -1:
# -1 is used as sentinel value for not a fd
- raise oefmt(space.w_ValueError, "invalid file descriptor: -1")
+ raise oefmt(space.w_OSError, "invalid file descriptor: -1")
return result
def _unwrap_dirfd(space, w_value):
@@ -707,6 +711,7 @@ def dup2(space, fd, fd2, inheritable=1):
rposix.dup2(fd, fd2, inheritable)
except OSError as e:
raise wrap_oserror(space, e, eintr_retry=False)
+ return space.newint(fd2)
@unwrap_spec(mode=c_int,
dir_fd=DirFD(rposix.HAVE_FACCESSAT), effective_ids=bool,
@@ -1076,7 +1081,7 @@ entries '.' and '..' even if they are present in the directory."""
raise oefmt(space.w_TypeError,
"listdir: illegal type for path argument")
try:
- result = rposix.fdlistdir(os.dup(path.as_fd))
+ result = rposix.fdlistdir(rposix.dup(path.as_fd, inheritable=False))
except OSError as e:
raise wrap_oserror(space, e, eintr_retry=False)
return space.newlist([space.newfilename(f) for f in result])
diff --git a/pypy/module/posix/interp_scandir.py b/pypy/module/posix/interp_scandir.py
index 4f963a46b6..24eea1be10 100644
--- a/pypy/module/posix/interp_scandir.py
+++ b/pypy/module/posix/interp_scandir.py
@@ -1,4 +1,5 @@
import stat
+import sys
from errno import ENOENT, ENOTDIR
from rpython.rlib import rgc
from rpython.rlib import rposix, rposix_scandir, rposix_stat
@@ -111,17 +112,16 @@ class W_ScandirIterator(W_Root):
dirp = self.dirp
if dirp:
self.dirp = rposix_scandir.NULL_DIRP
+ if not _WIN32 and self.dirfd != -1:
+ rposix.c_rewinddir(dirp)
rposix_scandir.closedir(dirp)
+ self.dirfd = -1
def iter_w(self):
return self
def fail(self, err=None):
- dirp = self.dirp
- if dirp:
- self.dirfd = -1
- self.dirp = rposix_scandir.NULL_DIRP
- rposix_scandir.closedir(dirp)
+ self._close()
if err is None:
raise OperationError(self.space.w_StopIteration, self.space.w_None)
else:
diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py
index f275484889..bab81fa729 100644
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -232,13 +232,38 @@ class AppTestPosix:
with raises(TypeError) as excinfo:
self.posix.stat(2.)
assert "should be string, bytes, os.PathLike or integer, not float" in str(excinfo.value)
- with raises(ValueError):
+ with raises(OSError):
self.posix.stat(-1)
with raises(ValueError):
self.posix.stat(b"abc\x00def")
with raises(ValueError):
self.posix.stat(u"abc\x00def")
+ def test_path_t_convertor(self):
+ posix = self.posix
+
+ class FakePath:
+ """Simple implementing of the path protocol.
+ """
+ def __init__(self, path):
+ self.path = path
+
+ def __repr__(self):
+ return '<FakePath {}>'.format(self.path)
+
+ def __fspath__(self):
+ if (isinstance(self.path, BaseException) or
+ isinstance(self.path, type) and
+ issubclass(self.path, BaseException)):
+ raise self.path
+ else:
+ return self.path
+ fd = posix.open(self.path, posix.O_RDONLY, 0o777)
+ with raises(TypeError) as exc:
+ posix.stat(FakePath(fd))
+ assert 'to return str or bytes' in exc.value.args[0]
+
+
if hasattr(__import__(os.name), "statvfs"):
def test_statvfs(self):
st = self.posix.statvfs(".")
@@ -550,6 +575,8 @@ class AppTestPosix:
os.utime('xxx', 3)
with raises(TypeError):
os.utime('xxx', [5, 5])
+ with raises(TypeError):
+ os.utime('xxx', ns=[5, 5])
with raises(OSError) as exc:
os.utime('somefilewhichihopewouldneverappearhere', None)
assert exc.value.errno == errno.ENOENT
@@ -1653,6 +1680,21 @@ class AppTestPosix:
retP = [x.name for x in self.posix.scandir(self.Path('.'))]
assert retU == retP
+ def test_scandir_fd(self):
+ os = self.posix
+ fd = None
+ try:
+ fd = os.open(self.Path('.'), os.O_RDONLY)
+ except PermissionError:
+ skip("Cannot open '.'")
+ try:
+ with os.scandir(fd) as it:
+ entries = list(it)
+ names = os.listdir(fd)
+ assert len(entries) == len(names)
+ finally:
+ os.close(fd)
+
def test_execv_no_args(self):
posix = self.posix
with raises(ValueError):
@@ -1907,3 +1949,5 @@ class AppTestPep475Retry:
assert signalled != []
assert got.startswith(b'h')
+
+
diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py
index 83c5d84feb..371e5bfd13 100644
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -135,9 +135,10 @@ def expat_external(*a, **kw):
return rffi.llexternal(*a, **kw)
INTERNED_CCHARP = "INTERNED"
+CONST_CCHARPP = lltype.Ptr(lltype.Array(rffi.CONST_CCHARP, hints={'nolength': True}))
HANDLERS = dict(
- StartElementHandler = [INTERNED_CCHARP, rffi.CCHARPP],
+ StartElementHandler = [INTERNED_CCHARP, CONST_CCHARPP],
EndElementHandler = [INTERNED_CCHARP],
ProcessingInstructionHandler = [INTERNED_CCHARP, INTERNED_CCHARP],
CharacterDataHandler = [rffi.CCHARP, rffi.INT],
@@ -145,23 +146,23 @@ HANDLERS = dict(
NotationDeclHandler = [INTERNED_CCHARP] * 4,
StartNamespaceDeclHandler = [INTERNED_CCHARP, INTERNED_CCHARP],
EndNamespaceDeclHandler = [INTERNED_CCHARP],
- CommentHandler = [rffi.CCHARP],
+ CommentHandler = [INTERNED_CCHARP],
StartCdataSectionHandler = [],
EndCdataSectionHandler = [],
- DefaultHandler = [rffi.CCHARP, rffi.INT],
- DefaultHandlerExpand = [rffi.CCHARP, rffi.INT],
+ DefaultHandler = [INTERNED_CCHARP, rffi.INT],
+ DefaultHandlerExpand = [INTERNED_CCHARP, rffi.INT],
NotStandaloneHandler = [],
- ExternalEntityRefHandler = [rffi.CCHARP] + [INTERNED_CCHARP] * 3,
+ ExternalEntityRefHandler = [INTERNED_CCHARP] * 4,
StartDoctypeDeclHandler = [INTERNED_CCHARP, INTERNED_CCHARP,
INTERNED_CCHARP, rffi.INT],
EndDoctypeDeclHandler = [],
- EntityDeclHandler = [INTERNED_CCHARP, rffi.INT, rffi.CCHARP, rffi.INT,
+ EntityDeclHandler = [INTERNED_CCHARP, rffi.INT, INTERNED_CCHARP, rffi.INT,
INTERNED_CCHARP, INTERNED_CCHARP, INTERNED_CCHARP,
INTERNED_CCHARP],
- XmlDeclHandler = [rffi.CCHARP, rffi.CCHARP, rffi.INT],
+ XmlDeclHandler = [INTERNED_CCHARP, INTERNED_CCHARP, rffi.INT],
ElementDeclHandler = [INTERNED_CCHARP, lltype.Ptr(XML_Content)],
AttlistDeclHandler = [INTERNED_CCHARP, INTERNED_CCHARP,
- rffi.CCHARP, rffi.CCHARP, rffi.INT],
+ INTERNED_CCHARP, INTERNED_CCHARP, rffi.INT],
)
if XML_COMBINED_VERSION >= 19504:
HANDLERS['SkippedEntityHandler'] = [INTERNED_CCHARP, rffi.INT]
@@ -224,13 +225,14 @@ for index, (name, params) in enumerate(HANDLERS.items()):
'w_arg%d = parser.w_convert_attributes(space, arg%d)' % (i, i))
elif name in ["CharacterDataHandler", "DefaultHandlerExpand", "DefaultHandler"] and i == 0:
converters.append(
- 'w_arg%d = parser.w_convert_charp_n(space, arg%d, arg%d)' % (i, i, i+1))
+ 'w_arg%d = parser.w_convert_interned_n(space, arg%d, arg%d)' % (i, i, i+1))
del warg_names[i+1]
+ ARG = rffi.CONST_CCHARP
elif name in ["EntityDeclHandler"] and i == 2:
converters.append(
- 'w_arg%d = parser.w_convert_charp_n(space, arg%d, arg%d)' % (i, i, i+1))
+ 'w_arg%d = parser.w_convert_interned_n(space, arg%d, arg%d)' % (i, i, i+1))
del warg_names[i+1]
-
+ ARG = rffi.CONST_CCHARP
# the standard conversions
elif ARG == rffi.CCHARP:
converters.append(
@@ -238,7 +240,7 @@ for index, (name, params) in enumerate(HANDLERS.items()):
elif ARG == INTERNED_CCHARP:
converters.append(
'w_arg%d = parser.w_convert_interned(space, arg%d)' % (i, i))
- ARG = rffi.CCHARP
+ ARG = rffi.CONST_CCHARP
elif ARG == lltype.Ptr(XML_Content):
converters.append(
'w_arg%d = parser.w_convert_model(space, arg%d)' % (i, i))
@@ -324,7 +326,7 @@ def UnknownEncodingHandlerData_callback(ll_userdata, name, info):
space = userdata.space
parser = userdata.parser()
- name = rffi.charp2str(name)
+ name = rffi.constcharp2str(name)
try:
parser.UnknownEncodingHandler(space, name, info)
@@ -337,7 +339,7 @@ def UnknownEncodingHandlerData_callback(ll_userdata, name, info):
result = 1
return rffi.cast(rffi.INT, result)
callback_type = lltype.Ptr(lltype.FuncType(
- [rffi.VOIDP, rffi.CCHARP, XML_Encoding_Ptr], rffi.INT))
+ [rffi.VOIDP, rffi.CONST_CCHARP, XML_Encoding_Ptr], rffi.INT))
XML_SetUnknownEncodingHandler = expat_external(
'XML_SetUnknownEncodingHandler',
[XML_Parser, callback_type, rffi.VOIDP], lltype.Void)
@@ -378,7 +380,7 @@ XML_GetErrorCode = expat_external(
'XML_GetErrorCode', [XML_Parser], rffi.INT)
XML_ErrorString = expat_external(
'XML_ErrorString', [rffi.INT],
- rffi.CCHARP)
+ rffi.CONST_CCHARP)
XML_GetCurrentLineNumber = expat_external(
'XML_GetCurrentLineNumber', [XML_Parser], rffi.INT)
XML_GetErrorLineNumber = XML_GetCurrentLineNumber
@@ -396,10 +398,10 @@ XML_ExternalEntityParserCreate = expat_external(
XML_Parser)
XML_ExpatVersion = expat_external(
- 'XML_ExpatVersion', [], rffi.CCHARP)
+ 'XML_ExpatVersion', [], rffi.CONST_CCHARP)
def get_expat_version(space):
- return space.newtext(rffi.charp2str(XML_ExpatVersion()))
+ return space.newtext(rffi.constcharp2str(XML_ExpatVersion()))
def get_expat_version_info(space):
return space.newtuple([
@@ -497,7 +499,7 @@ getting the advantage of providing document type information to the parser.
def w_convert_interned(self, space, data):
if not data:
return space.w_None
- w_data = self.w_convert_charp(space, data)
+ w_data = self.w_convert(space, rffi.constcharp2str(data))
if not self.w_intern:
return w_data
@@ -516,6 +518,13 @@ getting the advantage of providing document type information to the parser.
else:
return space.w_None
+ def w_convert_interned_n(self, space, data, length):
+ ll_length = rffi.cast(lltype.Signed, length)
+ if data:
+ return self.w_convert(space, rffi.constcharpsize2str(data, ll_length))
+ else:
+ return space.w_None
+
def w_convert_attributes(self, space, attrs):
if self.specified_attributes:
maxindex = XML_GetSpecifiedAttributeCount(self.itself)
@@ -526,15 +535,15 @@ getting the advantage of providing document type information to the parser.
if self.ordered_attributes:
w_attrs = space.newlist([
- self.w_convert_charp(space, attrs[i])
+ self.w_convert_interned(space, attrs[i])
for i in range(maxindex)])
else:
w_attrs = space.newdict()
for i in range(0, maxindex, 2):
space.setitem(
w_attrs,
- self.w_convert_charp(space, attrs[i]),
- self.w_convert_charp(space, attrs[i + 1]))
+ self.w_convert_interned(space, attrs[i]),
+ self.w_convert_interned(space, attrs[i + 1]))
return w_attrs
@@ -711,7 +720,7 @@ information passed to the ExternalEntityRefHandler."""
# Error management
def set_error(self, space, code):
- err = rffi.charp2strn(XML_ErrorString(code), 200)
+ err = rffi.constcharp2str(XML_ErrorString(code))
lineno = XML_GetCurrentLineNumber(self.itself)
colno = XML_GetCurrentColumnNumber(self.itself)
msg = "%s: line %d, column %d" % (err, lineno, colno)
@@ -867,5 +876,5 @@ Return a new XML parser object."""
def ErrorString(space, code):
"""ErrorString(errno) -> string
Returns string error for given number."""
- return space.newtext(rffi.charp2str(XML_ErrorString(code)))
+ return space.newtext(rffi.constcharp2str(XML_ErrorString(code)))
diff --git a/pypy/module/pyexpat/test/test_build.py b/pypy/module/pyexpat/test/test_build.py
index 1a916835c5..67895f02e7 100644
--- a/pypy/module/pyexpat/test/test_build.py
+++ b/pypy/module/pyexpat/test/test_build.py
@@ -21,7 +21,7 @@ def test_build():
parser = interp_pyexpat.XML_ParserCreate("test")
interp_pyexpat.XML_ParserFree(parser)
res = interp_pyexpat.XML_ErrorString(3)
- os.write(1, rffi.charp2str(res))
+ os.write(1, rffi.constcharp2str(res))
return 0
t = TranslationContext()
diff --git a/pypy/module/select/interp_epoll.py b/pypy/module/select/interp_epoll.py
index 809098badc..91b780101b 100644
--- a/pypy/module/select/interp_epoll.py
+++ b/pypy/module/select/interp_epoll.py
@@ -17,7 +17,36 @@ from rpython.translator.tool.cbuild import ExternalCompilationInfo
eci = ExternalCompilationInfo(
- includes = ['sys/epoll.h']
+ includes = ['sys/epoll.h', 'stddef.h', 'stdlib.h', 'stdio.h'],
+ post_include_bits = [
+ "RPY_EXTERN\n"
+ "int pypy_epoll_ctl(int, int, int, uint32_t);"
+ "RPY_EXTERN\n"
+ "int pypy_epoll_wait(int, uint32_t*, int*, int, int);"
+ ],
+ separate_module_sources = ['''
+ int pypy_epoll_ctl(int epfd, int op, int fd, uint32_t events){
+ struct epoll_event evt = {events, (epoll_data_t)fd};
+ return epoll_ctl(epfd, op, fd, &evt);
+ };
+ int pypy_epoll_wait(int epfd, uint32_t *fds, int *evnts, int maxevents, int timeout){
+ struct epoll_event *events = malloc(sizeof(struct epoll_event) * maxevents);
+ if (events == NULL) {
+ return -1;
+ }
+ int ret = epoll_wait(epfd, events, maxevents, timeout);
+ if (ret < 0) {
+ free(events);
+ return ret;
+ }
+ for (int i=0; i<ret; i++) {
+ fds[i] = events[i].data.fd;
+ evnts[i] = events[i].events;
+ }
+ free(events);
+ return ret;
+ };
+ '''],
)
class CConfig:
@@ -50,7 +79,6 @@ for symbol in public_symbols:
public_symbols[symbol] = intmask(cconfig[symbol])
-epoll_event = cconfig["epoll_event"]
EPOLL_CTL_ADD = cconfig["EPOLL_CTL_ADD"]
EPOLL_CTL_MOD = cconfig["EPOLL_CTL_MOD"]
EPOLL_CTL_DEL = cconfig["EPOLL_CTL_DEL"]
@@ -64,22 +92,22 @@ epoll_create1 = rffi.llexternal(
"epoll_create1", [rffi.INT], rffi.INT, compilation_info=eci,
save_err=rffi.RFFI_SAVE_ERRNO
)
-epoll_ctl = rffi.llexternal(
- "epoll_ctl",
- [rffi.INT, rffi.INT, rffi.INT, lltype.Ptr(epoll_event)],
+pypy_epoll_ctl = rffi.llexternal(
+ "pypy_epoll_ctl",
+ [rffi.INT, rffi.INT, rffi.INT, rffi.UINT],
rffi.INT,
compilation_info=eci,
save_err=rffi.RFFI_SAVE_ERRNO
)
-epoll_wait = rffi.llexternal(
- "epoll_wait",
- [rffi.INT, rffi.CArrayPtr(epoll_event), rffi.INT, rffi.INT],
+pypy_epoll_wait = rffi.llexternal(
+ "pypy_epoll_wait",
+ [rffi.INT, rffi.CArrayPtr(rffi.UINT), rffi.CArrayPtr(rffi.INT),
+ rffi.INT, rffi.INT],
rffi.INT,
compilation_info=eci,
save_err=rffi.RFFI_SAVE_ERRNO
)
-
class W_Epoll(W_Root):
def __init__(self, space, epfd):
self.space = space
@@ -121,15 +149,11 @@ class W_Epoll(W_Root):
def epoll_ctl(self, space, ctl, w_fd, eventmask, ignore_ebadf=False):
fd = space.c_filedescriptor_w(w_fd)
- with lltype.scoped_alloc(epoll_event) as ev:
- ev.c_events = rffi.cast(rffi.UINT, eventmask)
- rffi.setintfield(ev.c_data, 'c_fd', fd)
-
- result = epoll_ctl(self.epfd, ctl, fd, ev)
- if ignore_ebadf and get_saved_errno() == errno.EBADF:
- result = 0
- if result < 0:
- raise exception_from_saved_errno(space, space.w_IOError)
+ result = pypy_epoll_ctl(self.epfd, ctl, fd, rffi.cast(rffi.UINT, eventmask))
+ if ignore_ebadf and get_saved_errno() == errno.EBADF:
+ result = 0
+ if result < 0:
+ raise exception_from_saved_errno(space, space.w_IOError)
def descr_get_closed(self, space):
return space.newbool(self.get_closed())
@@ -171,27 +195,27 @@ class W_Epoll(W_Root):
raise oefmt(space.w_ValueError,
"maxevents must be greater than 0, not %d", maxevents)
- with lltype.scoped_alloc(rffi.CArray(epoll_event), maxevents) as evs:
- while True:
- nfds = epoll_wait(self.epfd, evs, maxevents, itimeout)
- if nfds < 0:
- if get_saved_errno() == errno.EINTR:
- space.getexecutioncontext().checksignals()
- if itimeout >= 0:
- timeout = end_time - timeutils.monotonic(space)
- timeout = max(timeout, 0.0)
- itimeout = int(timeout * 1000.0 + 0.999)
- continue
- raise exception_from_saved_errno(space, space.w_IOError)
- break
-
- elist_w = [None] * nfds
- for i in xrange(nfds):
- event = evs[i]
- elist_w[i] = space.newtuple(
- [space.newint(event.c_data.c_fd), space.newint(event.c_events)]
- )
- return space.newlist(elist_w)
+ with lltype.scoped_alloc(rffi.CArray(rffi.UINT), maxevents) as fids:
+ with lltype.scoped_alloc(rffi.CArray(rffi.INT), maxevents) as events:
+ while True:
+ nfds = pypy_epoll_wait(self.epfd, fids, events, maxevents, itimeout)
+ if nfds < 0:
+ if get_saved_errno() == errno.EINTR:
+ space.getexecutioncontext().checksignals()
+ if itimeout >= 0:
+ timeout = end_time - timeutils.monotonic(space)
+ timeout = max(timeout, 0.0)
+ itimeout = int(timeout * 1000.0 + 0.999)
+ continue
+ raise exception_from_saved_errno(space, space.w_IOError)
+ break
+
+ elist_w = [None] * nfds
+ for i in xrange(nfds):
+ elist_w[i] = space.newtuple(
+ [space.newint(fids[i]), space.newint(events[i])]
+ )
+ return space.newlist(elist_w)
def descr_enter(self, space):
self.check_closed(space)
diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py
index 69ea2b453c..8617c445c4 100644
--- a/pypy/module/thread/os_thread.py
+++ b/pypy/module/thread/os_thread.py
@@ -135,8 +135,8 @@ class Bootstrapper(object):
if not e.match(space, space.w_SystemExit):
ident = rthread.get_ident()
# PyPy adds the thread ident
- where = 'thread %d started by ' % ident
- e.write_unraisable(space, where, w_callable)
+ where = 'in thread %d started by ' % ident
+ e.write_unraisable(space, where, w_callable, with_traceback=True)
e.clear(space)
# clean up space.threadlocals to remove the ExecutionContext
# entry corresponding to the current thread
diff --git a/pypy/objspace/std/intobject.py b/pypy/objspace/std/intobject.py
index 21008c89bb..668c916d60 100644
--- a/pypy/objspace/std/intobject.py
+++ b/pypy/objspace/std/intobject.py
@@ -760,11 +760,15 @@ class W_IntObject(W_AbstractIntObject):
descr_or, descr_ror = _make_generic_descr_binop('or', ovf=False)
descr_xor, descr_rxor = _make_generic_descr_binop('xor', ovf=False)
- def _make_descr_binop(func, ovf=True, ovf2small=None):
+ def _make_descr_binop(func, ovf=True, ovf2small=None, ovf_func=None):
opname = func.__name__[1:]
descr_name, descr_rname = 'descr_' + opname, 'descr_r' + opname
if ovf:
- ovf2long = _make_ovf2long(opname, ovf2small)
+ if ovf_func:
+ ovf2long = ovf_func
+ assert not ovf2small # must be part of ovf_func
+ else:
+ ovf2long = _make_ovf2long(opname, ovf2small)
@func_renamer(descr_name)
def descr_binop(self, space, w_other):
@@ -802,8 +806,20 @@ class W_IntObject(W_AbstractIntObject):
return descr_binop, descr_rbinop
+ def _ovf2long_lshift(space, x, w_x, y, w_y):
+ if _recover_with_smalllong(space):
+ return _lshift_ovf2small(space, x, y)
+
+ from pypy.objspace.std.longobject import W_LongObject, W_AbstractLongObject
+ if w_x is None or not isinstance(w_x, W_AbstractLongObject):
+ w_x = W_LongObject.fromint(space, x)
+
+ # crucially, *don't* convert w_y to W_LongObject, it will just be
+ # converted back (huge lshifts always overflow)
+ return w_x._int_lshift(space, y)
+
descr_lshift, descr_rlshift = _make_descr_binop(
- _lshift, ovf2small=_lshift_ovf2small)
+ _lshift, ovf_func=_ovf2long_lshift)
descr_rshift, descr_rrshift = _make_descr_binop(_rshift, ovf=False)
descr_floordiv, descr_rfloordiv = _make_descr_binop(_floordiv)
diff --git a/pypy/objspace/std/proxyobject.py b/pypy/objspace/std/proxyobject.py
index 918c5dea5a..638e63932d 100644
--- a/pypy/objspace/std/proxyobject.py
+++ b/pypy/objspace/std/proxyobject.py
@@ -2,7 +2,7 @@
"""
from pypy.interpreter import baseobjspace
from pypy.interpreter.error import OperationError, oefmt
-
+from pypy.module.exceptions import interp_exceptions
def transparent_class(name, BaseCls):
class W_Transparent(BaseCls):
@@ -64,3 +64,4 @@ def transparent_class(name, BaseCls):
return W_Transparent
W_Transparent = transparent_class('W_Transparent', baseobjspace.W_Root)
+W_TransparentBaseException = transparent_class('W_TransparentBaseException', interp_exceptions.W_BaseException)
diff --git a/pypy/objspace/std/test/test_bytesobject.py b/pypy/objspace/std/test/test_bytesobject.py
index 921412d065..9e3c9c55a9 100644
--- a/pypy/objspace/std/test/test_bytesobject.py
+++ b/pypy/objspace/std/test/test_bytesobject.py
@@ -676,7 +676,6 @@ class AppTestBytesObject:
def test_unicode_join_str_arg_ascii(self):
raises(TypeError, ''.join, [b'\xc3\xa1'])
- @pytest.mark.xfail(reason='setdefaultencoding does not work?')
def test_unicode_join_endcase(self):
# This class inserts a Unicode object into its argument's natural
# iteration, in the 3rd position.
diff --git a/pypy/objspace/std/transparent.py b/pypy/objspace/std/transparent.py
index 89c971e9e8..401503f5ba 100644
--- a/pypy/objspace/std/transparent.py
+++ b/pypy/objspace/std/transparent.py
@@ -4,8 +4,9 @@ from pypy.interpreter import gateway
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.typedef import Function, GeneratorIterator, PyTraceback, \
PyFrame, PyCode
-from pypy.objspace.std.proxyobject import W_Transparent
+from pypy.objspace.std.proxyobject import W_Transparent, W_TransparentBaseException
from pypy.objspace.std.typeobject import W_TypeObject
+from pypy.module.exceptions import interp_exceptions
from rpython.rlib.unroll import unrolling_iterable
@@ -62,6 +63,8 @@ completely controlled by the controller."""
return W_TransparentGenerator(space, w_type, w_controller)
if space.issubtype_w(w_type, space.gettypeobject(PyCode.typedef)):
return W_TransparentCode(space, w_type, w_controller)
+ if space.issubtype_w(w_type, space.gettypeobject(interp_exceptions.W_BaseException.typedef)):
+ return W_TransparentBaseException(space, w_type, w_controller)
if w_type.layout.typedef is space.w_object.layout.typedef:
return W_Transparent(space, w_type, w_controller)
else:
diff --git a/pypy/tool/pytest/apptest.py b/pypy/tool/pytest/apptest.py
index 566260da50..a598c59af4 100644
--- a/pypy/tool/pytest/apptest.py
+++ b/pypy/tool/pytest/apptest.py
@@ -140,7 +140,7 @@ if 1:
def __exit__(self, *tp):
__tracebackhide__ = True
if tp[0] is None:
- pytest.fail("DID NOT RAISE")
+ raise AssertionError("DID NOT RAISE")
self.value = tp[1]
return issubclass(tp[0], self.expected_exception)
diff --git a/pypy/tool/release/check_versions.py b/pypy/tool/release/check_versions.py
index 66d7332d94..29f39433ea 100644
--- a/pypy/tool/release/check_versions.py
+++ b/pypy/tool/release/check_versions.py
@@ -33,6 +33,9 @@ def assert_in(a, b):
pypy_versions = {
+ '7.3.8rc1': {'python_version': ['3.9.10', '3.8.12', '3.7.12', '2.7.18'],
+ 'date': '2022-01-26',
+ },
'7.3.7': {'python_version': ['3.8.12', '3.7.12'],
'date': '2021-10-25',
},
@@ -78,7 +81,7 @@ pypy_versions = {
'7.3.2': {'python_version': ['3.7.9', '3.6.9', '2.7.13'],
'date': '2020-09-25',
},
- 'nightly': {'python_version': ['2.7', '3.6', '3.7', '3.8']},
+ 'nightly': {'python_version': ['2.7', '3.6', '3.7', '3.8', '3.9']},
}
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
index 250b05e8d3..cd62bcc0f6 100755
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -336,9 +336,6 @@ def create_package(basedir, options, _fake=False):
'*.lib', '*.exp', '*.manifest', '__pycache__'))
for file in ['README.rst',]:
shutil.copy(str(basedir.join(file)), str(pypydir))
- for file in ['_testcapimodule.c', '_ctypes_test.c']:
- shutil.copyfile(str(basedir.join('lib_pypy', file)),
- str(target.join(file)))
# Use original LICENCE file
base_file = str(basedir.join('LICENSE'))
with open(base_file) as fid:
diff --git a/pypy/tool/release/repackage.sh b/pypy/tool/release/repackage.sh
index fdabf22ef4..7d6d9c3d7d 100644
--- a/pypy/tool/release/repackage.sh
+++ b/pypy/tool/release/repackage.sh
@@ -5,8 +5,8 @@ pmaj=3 # python main version: 2 or 3
pmin=8 # python minor version
maj=7
min=3
-rev=7
-#rc=rc3 # comment this line for actual release
+rev=8
+rc=rc1 # comment this line for actual release
function maybe_exit {
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
@@ -48,7 +48,7 @@ fi
function repackage_builds {
# Download latest builds from the buildmaster, rename the top
# level directory, and repackage ready to be uploaded
- for plat in linux linux64 osx64 aarch64 s390x # linux-armhf-raspbian linux-armel
+ for plat in linux linux64 osx64 # s390x aarch64 linux-armhf-raspbian linux-armel
do
echo downloading package for $plat
if wget -q --show-progress http://buildbot.pypy.org/nightly/$branchname/pypy-c-jit-latest-$plat.tar.bz2
diff --git a/pypy/tool/release/versions.json b/pypy/tool/release/versions.json
index e30d057ffa..b77e667561 100644
--- a/pypy/tool/release/versions.json
+++ b/pypy/tool/release/versions.json
@@ -1,5 +1,135 @@
[
-{
+ {
+ "pypy_version": "7.3.8rc1",
+ "python_version": "3.9.10",
+ "stable": false,
+ "latest_pypy": false,
+ "date": "2022-01-26",
+ "files": [
+ {
+ "filename": "pypy3.9-v7.3.8rc1-linux32.tar.bz2",
+ "arch": "i686",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy3.9-v7.3.8rc1-linux32.tar.bz2"
+ },
+ {
+ "filename": "pypy3.9-v7.3.8rc1-linux64.tar.bz2",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy3.9-v7.3.8rc1-linux64.tar.bz2"
+ },
+ {
+ "filename": "pypy3.9-v7.3.8rc1-osx64.tar.bz2",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://downloads.python.org/pypy/pypy3.9-v7.3.8rc1-osx64.tar.bz2"
+ },
+ {
+ "filename": "pypy3.9-v7.3.8rc1-win64.zip",
+ "arch": "x64",
+ "platform": "win64",
+ "download_url": "https://downloads.python.org/pypy/pypy3.9-v7.3.8rc1-win64.zip"
+ }
+ ]
+ },
+ {
+ "pypy_version": "7.3.8rc1",
+ "python_version": "3.8.12",
+ "stable": false,
+ "latest_pypy": false,
+ "date": "2022-01-26",
+ "files": [
+ {
+ "filename": "pypy3.8-v7.3.8rc1-linux32.tar.bz2",
+ "arch": "i686",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.8rc1-linux32.tar.bz2"
+ },
+ {
+ "filename": "pypy3.8-v7.3.8rc1-linux64.tar.bz2",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.8rc1-linux64.tar.bz2"
+ },
+ {
+ "filename": "pypy3.8-v7.3.8rc1-osx64.tar.bz2",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.8rc1-osx64.tar.bz2"
+ },
+ {
+ "filename": "pypy3.8-v7.3.8rc1-win64.zip",
+ "arch": "x64",
+ "platform": "win64",
+ "download_url": "https://downloads.python.org/pypy/pypy3.8-v7.3.8rc1-win64.zip"
+ }
+ ]
+ },{
+ "pypy_version": "7.3.8rc1",
+ "python_version": "3.7.12",
+ "stable": false,
+ "latest_pypy": false,
+ "date": "2022-01-26",
+ "files": [
+ {
+ "filename": "pypy3.7-v7.3.8rc1-linux32.tar.bz2",
+ "arch": "i686",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.8rc1-linux32.tar.bz2"
+ },
+ {
+ "filename": "pypy3.7-v7.3.8rc1-linux64.tar.bz2",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.8rc1-linux64.tar.bz2"
+ },
+ {
+ "filename": "pypy3.7-v7.3.8rc1-osx64.tar.bz2",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.8rc1-osx64.tar.bz2"
+ },
+ {
+ "filename": "pypy3.7-v7.3.8rc1-win64.zip",
+ "arch": "x64",
+ "platform": "win64",
+ "download_url": "https://downloads.python.org/pypy/pypy3.7-v7.3.8rc1-win64.zip"
+ }
+ ]
+ },{
+ "pypy_version": "7.3.8rc1",
+ "python_version": "2.7.18",
+ "stable": false,
+ "latest_pypy": false,
+ "date": "2022-01-26",
+ "files": [
+ {
+ "filename": "pypy2.7-v7.3.8rc1-linux32.tar.bz2",
+ "arch": "i686",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.8rc1-linux32.tar.bz2"
+ },
+ {
+ "filename": "pypy2.7-v7.3.8rc1-linux64.tar.bz2",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.8rc1-linux64.tar.bz2"
+ },
+ {
+ "filename": "pypy2.7-v7.3.8rc1-osx64.tar.bz2",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.8rc1-osx64.tar.bz2"
+ },
+ {
+ "filename": "pypy2.7-v7.3.8rc1-win64.zip",
+ "arch": "x64",
+ "platform": "win64",
+ "download_url": "https://downloads.python.org/pypy/pypy2.7-v7.3.8rc1-win64.zip"
+ }
+ ]
+ },
+ {
"pypy_version": "7.3.7",
"python_version": "3.8.12",
"stable": true,
@@ -1876,5 +2006,49 @@
"download_url": "http://buildbot.pypy.org/nightly/py3.8/pypy-c-jit-latest-s390x.tar.bz2"
}
]
+ },
+ {
+ "pypy_version": "nightly",
+ "python_version": "3.9",
+ "stable": false,
+ "latest_pypy": false,
+ "files": [
+ {
+ "filename": "pypy-c-jit-latest-aarch64.tar.bz2",
+ "arch": "aarch64",
+ "platform": "linux",
+ "download_url": "http://buildbot.pypy.org/nightly/py3.9/pypy-c-jit-latest-aarch64.tar.bz2"
+ },
+ {
+ "filename": "pypy-c-jit-latest-linux.tar.bz2",
+ "arch": "i686",
+ "platform": "linux",
+ "download_url": "http://buildbot.pypy.org/nightly/py3.9/pypy-c-jit-latest-linux.tar.bz2"
+ },
+ {
+ "filename": "pypy-c-jit-latest-linux64.tar.bz2",
+ "arch": "x64",
+ "platform": "linux",
+ "download_url": "http://buildbot.pypy.org/nightly/py3.9/pypy-c-jit-latest-linux64.tar.bz2"
+ },
+ {
+ "filename": "pypy-c-jit-latest-osx64.tar.bz2",
+ "arch": "x64",
+ "platform": "darwin",
+ "download_url": "http://buildbot.pypy.org/nightly/py3.9/pypy-c-jit-latest-osx64.tar.bz2"
+ },
+ {
+ "filename": "pypy-c-jit-latest-win64.zip",
+ "arch": "x64",
+ "platform": "win64",
+ "download_url": "http://buildbot.pypy.org/nightly/py3.9/pypy-c-jit-latest-win64.zip"
+ },
+ {
+ "filename": "pypy-c-jit-latest-s390x.tar.bz2",
+ "arch": "s390x",
+ "platform": "linux",
+ "download_url": "http://buildbot.pypy.org/nightly/py3.9/pypy-c-jit-latest-s390x.tar.bz2"
+ }
+ ]
}
]
diff --git a/rpython/rlib/_rsocket_rffi.py b/rpython/rlib/_rsocket_rffi.py
index bcd031a050..3fb4ca72b1 100644
--- a/rpython/rlib/_rsocket_rffi.py
+++ b/rpython/rlib/_rsocket_rffi.py
@@ -1,7 +1,7 @@
from rpython.rtyper.lltypesystem import rffi
from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.tool import rffi_platform as platform
-from rpython.rtyper.lltypesystem.rffi import CCHARP
+from rpython.rtyper.lltypesystem.rffi import CCHARP, CONST_CCHARP
from rpython.rlib import jit
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.translator.platform import platform as target_platform
@@ -1164,7 +1164,7 @@ def external_c(name, args, result, **kwargs):
if _POSIX:
dup = external('dup', [socketfd_type], socketfd_type, save_err=SAVE_ERR)
- gai_strerror = external('gai_strerror', [rffi.INT], CCHARP)
+ gai_strerror = external('gai_strerror', [rffi.INT], CONST_CCHARP)
#h_errno = c_int.in_dll(socketdll, 'h_errno')
#
@@ -1432,7 +1432,7 @@ else:
socket_strerror_str = os.strerror
def gai_strerror_str(errno):
- return rffi.charp2str(gai_strerror(errno))
+ return rffi.constcharp2str(gai_strerror(errno))
def socket_strerror_unicode(errno):
return socket_strerror_str(errno).decode('latin-1')
diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py
index fc4a35d363..7a0c913dc7 100644
--- a/rpython/rlib/ropenssl.py
+++ b/rpython/rlib/ropenssl.py
@@ -100,7 +100,7 @@ X509_NAME = rffi.COpaquePtr('X509_NAME')
X509_VERIFY_PARAM = rffi.COpaquePtr('X509_VERIFY_PARAM')
stack_st_X509_OBJECT = rffi.COpaquePtr('STACK_OF(X509_OBJECT)')
DIST_POINT = rffi.COpaquePtr('DIST_POINT')
-stack_st_DIST_POINT = rffi.COpaquePtr('STACK_OF(X509_OBJECT)')
+stack_st_DIST_POINT = rffi.COpaquePtr('STACK_OF(DIST_POINT)')
DH = rffi.COpaquePtr('DH')
EC_KEY = rffi.COpaquePtr('EC_KEY')
AUTHORITY_INFO_ACCESS = rffi.COpaquePtr('AUTHORITY_INFO_ACCESS')
diff --git a/rpython/rlib/rvmprof/src/shared/vmprof_getpc.h b/rpython/rlib/rvmprof/src/shared/vmprof_getpc.h
index 5a633715cb..da643ad04b 100644
--- a/rpython/rlib/rvmprof/src/shared/vmprof_getpc.h
+++ b/rpython/rlib/rvmprof/src/shared/vmprof_getpc.h
@@ -52,7 +52,7 @@
// the needed __BSD_VISIBLE.
#ifdef __APPLE__
#include <limits.h>
-#define _XOPEN_SOURCE 500
+#define _XOPEN_SOURCE 700
#endif
#include "vmprof_config.h"
diff --git a/rpython/translator/c/src/dtoa.c b/rpython/translator/c/src/dtoa.c
index 225ba42316..35204ae5c0 100644
--- a/rpython/translator/c/src/dtoa.c
+++ b/rpython/translator/c/src/dtoa.c
@@ -122,9 +122,15 @@
#define HAVE_UINT32_T
#define HAVE_INT32_T
#define HAVE_UINT64_T
+#ifndef PY_UINT32_T
#define PY_UINT32_T unsigned int
+#endif
+#ifndef PY_INT32_T
#define PY_INT32_T int
+#endif
+#ifndef PY_UINT64_T
#define PY_UINT64_T unsigned long long
+#endif
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
diff --git a/rpython/translator/c/src/support.c b/rpython/translator/c/src/support.c
index 3b05c5aa4f..b4b1837058 100644
--- a/rpython/translator/c/src/support.c
+++ b/rpython/translator/c/src/support.c
@@ -12,7 +12,9 @@
#define Sign_bit 0x80000000
#define NAN_WORD0 0x7ff80000
#define NAN_WORD1 0
+#ifndef PY_UINT32_T
#define PY_UINT32_T unsigned int
+#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define IEEE_8087
diff --git a/rpython/translator/c/test/test_extfunc.py b/rpython/translator/c/test/test_extfunc.py
index ca3d474022..61cb133314 100644
--- a/rpython/translator/c/test/test_extfunc.py
+++ b/rpython/translator/c/test/test_extfunc.py
@@ -166,7 +166,9 @@ def test_os_stat():
f = compile(call_stat, [])
res = eval(f())
assert res[0] == os.stat(filename).st_mode
- assert res[1] == os.stat(filename).st_ino
+ # windows zeros out st_ino in the app-level os.stat
+ if sys.platform != 'win32':
+ assert res[1] == os.stat(filename).st_ino
st_ctime = res[2]
if isinstance(st_ctime, float):
assert (st_ctime - os.stat(filename).st_ctime) < 0.1
diff --git a/rpython/translator/platform/windows.py b/rpython/translator/platform/windows.py
index b5a76eb2c1..32571d532d 100644
--- a/rpython/translator/platform/windows.py
+++ b/rpython/translator/platform/windows.py
@@ -211,7 +211,7 @@ class MsvcPlatform(Platform):
returncode, stdout, stderr = _run_subprocess(
'ml.exe' if not x64 else 'ml64.exe', [], env=self.c_environ)
r = re.search('Macro Assembler', stderr)
- except OSError:
+ except (EnvironmentError, OSError):
r = None
masm32 = "'Could not find ml.exe'"
masm64 = "'Could not find ml.exe'"
diff --git a/rpython/translator/tool/cbuild.py b/rpython/translator/tool/cbuild.py
index 0225f2f948..a9cdf21996 100644
--- a/rpython/translator/tool/cbuild.py
+++ b/rpython/translator/tool/cbuild.py
@@ -119,6 +119,10 @@ class ExternalCompilationInfo(object):
macro, value = macro.split('=')
else:
value = '1'
+ if macro == '_XOPEN_SOURCE':
+ # use default _XOPEN_SOURCE since we always define
+ # _GNU_SOURCE, which then defines a _XOPEN_SOURCE itself
+ continue
pre_include_bits.append('#define %s %s' % (macro, value))
elif arg.startswith('-L') or arg.startswith('-l'):
raise ValueError('linker flag found in compiler options: %r'