Author: Armin Rigo <ar...@tunes.org> Branch: py3.5 Changeset: r89636:6d7e97a686d7 Date: 2017-01-17 18:03 +0100 http://bitbucket.org/pypy/pypy/changeset/6d7e97a686d7/
Log: hg merge default diff too long, truncating to 2000 out of 3163 lines diff --git a/lib-python/2.7/sqlite3/test/regression.py b/lib-python/2.7/sqlite3/test/regression.py --- a/lib-python/2.7/sqlite3/test/regression.py +++ b/lib-python/2.7/sqlite3/test/regression.py @@ -351,10 +351,7 @@ self.assertRaises(ValueError, cur.execute, " \0select 2") self.assertRaises(ValueError, cur.execute, "select 2\0") - @test_support.impl_detail(pypy=False) def CheckCommitCursorReset(self): - # This test is for logic added in 2.7.13 which PyPy doesn't - # implement. See http://bugs.python.org/issue29006 """ Connection.commit() did reset cursors, which made sqlite3 to return rows multiple times when fetched from cursors diff --git a/lib-python/2.7/test/test_capi.py b/lib-python/2.7/test/test_capi.py --- a/lib-python/2.7/test/test_capi.py +++ b/lib-python/2.7/test/test_capi.py @@ -26,7 +26,6 @@ skips = [] if support.check_impl_detail(pypy=True): skips += [ - 'test_broken_memoryview', 'test_buildvalue_N', 'test_capsule', 'test_lazy_hash_inheritance', diff --git a/lib-python/2.7/test/test_multiprocessing.py b/lib-python/2.7/test/test_multiprocessing.py --- a/lib-python/2.7/test/test_multiprocessing.py +++ b/lib-python/2.7/test/test_multiprocessing.py @@ -1969,9 +1969,10 @@ if not gc.isenabled(): gc.enable() self.addCleanup(gc.disable) - #thresholds = gc.get_threshold() - #self.addCleanup(gc.set_threshold, *thresholds) - #gc.set_threshold(10) + if test_support.check_impl_detail(cpython=True): + thresholds = gc.get_threshold() + self.addCleanup(gc.set_threshold, *thresholds) + gc.set_threshold(10) # perform numerous block allocations, with cyclic references to make # sure objects are collected asynchronously by the gc diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -231,6 +231,7 @@ self.__statements_counter = 0 self.__rawstatements = set() self._statement_cache = _StatementCache(self, cached_statements) + self.__statements_already_committed = [] self.__func_cache = {} self.__aggregates = {} @@ -374,6 +375,14 @@ if cursor is not None: cursor._reset = True + def _reset_already_committed_statements(self): + lst = self.__statements_already_committed + self.__statements_already_committed = [] + for weakref in lst: + statement = weakref() + if statement is not None: + statement._reset() + @_check_thread_wrap @_check_closed_wrap def __call__(self, sql): @@ -429,15 +438,18 @@ if not self._in_transaction: return - # The following line is a KNOWN DIFFERENCE with CPython 2.7.13. - # More precisely, the corresponding line was removed in the - # version 2.7.13 of CPython, but this is causing troubles for - # PyPy (and potentially for CPython too): - # - # http://bugs.python.org/issue29006 - # - # So for now, we keep this line. - self.__do_all_statements(Statement._reset, False) + # PyPy fix for non-refcounting semantics: since 2.7.13 (and in + # <= 2.6.x), the statements are not automatically reset upon + # commit. However, if this is followed by some specific SQL + # operations like "drop table", these open statements come in + # the way and cause the "drop table" to fail. On CPython the + # problem is much less important because typically all the old + # statements are freed already by reference counting. So here, + # we copy all the still-alive statements to another list which + # is usually ignored, except if we get SQLITE_LOCKED + # afterwards---at which point we reset all statements in this + # list. + self.__statements_already_committed = self.__statements[:] statement_star = _ffi.new('sqlite3_stmt **') ret = _lib.sqlite3_prepare_v2(self._db, b"COMMIT", -1, @@ -866,8 +878,18 @@ self.__statement._set_params(params) # Actually execute the SQL statement + ret = _lib.sqlite3_step(self.__statement._statement) + # PyPy: if we get SQLITE_LOCKED, it's probably because + # one of the cursors created previously is still alive + # and not reset and the operation we're trying to do + # makes Sqlite unhappy about that. In that case, we + # automatically reset all old cursors and try again. + if ret == _lib.SQLITE_LOCKED: + self.__connection._reset_already_committed_statements() + ret = _lib.sqlite3_step(self.__statement._statement) + if ret == _lib.SQLITE_ROW: if multiple: raise ProgrammingError("executemany() can only execute DML statements.") diff --git a/lib_pypy/_testcapimodule.c b/lib_pypy/_testcapimodule.c --- a/lib_pypy/_testcapimodule.c +++ b/lib_pypy/_testcapimodule.c @@ -2856,7 +2856,7 @@ m = PyModule_Create(&_testcapimodule); if (m == NULL) return NULL; - + Py_TYPE(&_HashInheritanceTester_Type)=&PyType_Type; Py_TYPE(&test_structmembersType)=&PyType_Type; diff --git a/lib_pypy/audioop.py b/lib_pypy/audioop.py --- a/lib_pypy/audioop.py +++ b/lib_pypy/audioop.py @@ -374,7 +374,7 @@ sample_count = _sample_count(cp, size) - rv = ffi.new("unsigned char[]", len(cp) * 2) + rv = ffi.new("char[]", len(cp) * 2) lib.tostereo(rv, ffi.from_buffer(cp), len(cp), size, fac1, fac2) return ffi.buffer(rv)[:] @@ -385,7 +385,7 @@ if len(cp1) != len(cp2): raise error("Lengths should be the same") - rv = ffi.new("unsigned char[]", len(cp1)) + rv = ffi.new("char[]", len(cp1)) lib.add(rv, ffi.from_buffer(cp1), ffi.from_buffer(cp2), len(cp1), size) return ffi.buffer(rv)[:] @@ -488,7 +488,7 @@ ceiling = (q + 1) * outrate nbytes = ceiling * bytes_per_frame - rv = ffi.new("unsigned char[]", nbytes) + rv = ffi.new("char[]", nbytes) trim_index = lib.ratecv(rv, cp, frame_count, size, nchannels, inrate, outrate, state_d, prev_i, cur_i, diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -496,11 +496,6 @@ the rest is kept. If you return an unexpected string from ``__hex__()`` you get an exception (or a crash before CPython 2.7.13). -* The ``sqlite`` module was updated on 2.7.13 to no longer reset all - cursors when there is a commit. This causes troubles for PyPy (and - potentially for CPython too), and so for now we didn't port this change: - see http://bugs.python.org/issue29006. - .. _`is ignored in PyPy`: http://bugs.python.org/issue14621 .. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html .. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/ diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst --- a/pypy/doc/faq.rst +++ b/pypy/doc/faq.rst @@ -26,16 +26,16 @@ Almost! -The mostly likely stumbling block for any given project is support for +The most likely stumbling block for any given project is support for :ref:`extension modules <extension-modules>`. PyPy supports a continually growing number of extension modules, but so far mostly only those found in the standard library. The language features (including builtin types and functions) are very -complete and well tested, so if your project does not use many +refined and well tested, so if your project doesn't use many extension modules there is a good chance that it will work with PyPy. -We list the differences we know about in :doc:`cpython differences <cpython_differences>`. +We list the known differences in :doc:`cpython differences <cpython_differences>`. Module xyz does not work with PyPy: ImportError @@ -76,10 +76,10 @@ You cannot import *any* extension module in a `sandboxed PyPy`_, sorry. Even the built-in modules available are very limited. -Sandboxing in PyPy is a good proof of concept, really safe IMHO, but -it is only a proof of concept. It seriously requires someone working -on it. Before this occurs, it can only be used it for "pure Python" -examples: programs that import mostly nothing (or only pure Python +Sandboxing in PyPy is a good proof of concept, and is without a doubt +safe IMHO, however it is only a proof of concept. It currently requires +some work from a motivated developer. However, until then it can only be used for "pure Python" +example: programs that import mostly nothing (or only pure Python modules, recursively). .. _`sandboxed PyPy`: sandbox.html diff --git a/pypy/doc/getting-started-dev.rst b/pypy/doc/getting-started-dev.rst --- a/pypy/doc/getting-started-dev.rst +++ b/pypy/doc/getting-started-dev.rst @@ -336,6 +336,6 @@ that fixes some bugs and is translatable. * :source:`pypy/objspace/std` contains the :ref:`Standard object space <standard-object-space>`. The main file - is :source:`pypy/objspace/std/objspace.py`. For each type, the files ``xxxtype.py`` and - ``xxxobject.py`` contain respectively the definition of the type and its - (default) implementation. + is :source:`pypy/objspace/std/objspace.py`. For each type, the file + ``xxxobject.py`` contains the implementation for objects of type ``xxx``, + as a first approximation. (Some types have multiple implementations.) diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -110,3 +110,21 @@ Do not recreate the object in PyMemoryView_FromBuffer, rather pass it to the returned PyMemoryViewObject, to take ownership of it. Fixes a ref leak. + +.. branch: issue2464 + +Give (almost?) all GetSetProperties a valid __objclass__. + +.. branch: TreeStain/fixed-typo-line-29-mostly-to-most-1484469416419 +.. branch: TreeStain/main-lines-changed-in-l77-l83-made-para-1484471558033 + +.. branch: missing-tp_new + +Improve mixing app-level classes in c-extensions, especially if the app-level +class has a ``tp_new`` or ``tp_dealloc``. The issue is that c-extensions expect +all the method slots to be filled with a function pointer, where app-level will +search up the mro for an appropriate function at runtime. With this branch we +now fill many more slots in the c-extenion type objects. +Also fix for c-extension type that calls ``tp_hash`` during initialization +(str, unicode types), and fix instantiating c-extension types from built-in +classes by enforcing an order of instaniation. diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -143,7 +143,11 @@ pass def fget(self, space, w_self): assert self is prop - prop = typedef.GetSetProperty(fget, use_closure=True) + # NB. this GetSetProperty is not copied when creating the + # W_TypeObject because of 'cls'. Without it, a duplicate of the + # GetSetProperty is taken and it is given the w_objclass that is + # the W_TypeObject + prop = typedef.GetSetProperty(fget, use_closure=True, cls=W_SomeType) W_SomeType.typedef = typedef.TypeDef( 'some_type', x=prop) diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -277,12 +277,15 @@ self.use_closure = use_closure def copy_for_type(self, w_objclass): - new = instantiate(GetSetProperty) - new._init(self.fget, self.fset, self.fdel, self.doc, self.reqcls, - None, self.use_closure) - new.name = self.name - new.w_objclass = w_objclass - return new + if self.objclass_getter is None: + new = instantiate(GetSetProperty) + new._init(self.fget, self.fset, self.fdel, self.doc, self.reqcls, + None, self.use_closure) + new.name = self.name + new.w_objclass = w_objclass + return new + else: + return self @unwrap_spec(w_cls = WrappedDefault(None)) def descr_property_get(self, space, w_obj, w_cls=None): @@ -513,7 +516,7 @@ return lifeline.get_any_weakref(space) dict_descr = GetSetProperty(descr_get_dict, descr_set_dict, descr_del_dict, - doc="dictionary for instance variables") + doc="dictionary for instance variables (if defined)") dict_descr.name = '__dict__' @@ -548,7 +551,7 @@ return space.newtuple([w_docstring]) weakref_descr = GetSetProperty(descr_get_weakref, - doc="list of weak references to the object") + doc="list of weak references to the object (if defined)") weakref_descr.name = '__weakref__' def make_weakref_descr(cls): diff --git a/pypy/module/_pypyjson/interp_decoder.py b/pypy/module/_pypyjson/interp_decoder.py --- a/pypy/module/_pypyjson/interp_decoder.py +++ b/pypy/module/_pypyjson/interp_decoder.py @@ -109,7 +109,7 @@ else: raise DecoderError( "No JSON object could be decoded: unexpected '%s' at" % ch, - self.pos) + i) def decode_null(self, i): if (self.ll_chars[i] == 'u' and @@ -247,7 +247,7 @@ raise DecoderError("Unterminated array starting at", start) else: raise DecoderError("Unexpected '%s' when decoding array" % ch, - self.pos) + i-1) def decode_object(self, i): start = i @@ -287,7 +287,7 @@ raise DecoderError("Unterminated object starting at", start) else: raise DecoderError("Unexpected '%s' when decoding object" % ch, - self.pos) + i-1) def decode_string(self, i): @@ -312,18 +312,17 @@ self.last_type = TYPE_STRING self.pos = i return self.space.wrap(content_unicode) - elif ch == '\\': - content_so_far = self.getslice(start, i-1) + elif ch == '\\' or ch < '\x20': self.pos = i-1 - return self.decode_string_escaped(start, content_so_far) - elif ch < '\x20': - raise DecoderError("Invalid control character at", self.pos-1) + return self.decode_string_escaped(start) - def decode_string_escaped(self, start, content_so_far): - builder = StringBuilder(len(content_so_far)*2) # just an estimate - builder.append(content_so_far) + def decode_string_escaped(self, start): i = self.pos + builder = StringBuilder((i - start) * 2) # just an estimate + assert start >= 0 + assert i >= 0 + builder.append_slice(self.s, start, i) while True: ch = self.ll_chars[i] i += 1 @@ -336,27 +335,31 @@ return self.space.wrap(content_unicode) elif ch == '\\': i = self.decode_escape_sequence(i, builder) - elif ch == '\0': - raise DecoderError("Unterminated string starting at", start) + elif ch < '\x20': + if ch == '\0': + raise DecoderError("Unterminated string starting at", + start - 1) + else: + raise DecoderError("Invalid control character at", i-1) else: - builder.append_multiple_char(ch, 1) # we should implement append_char + builder.append(ch) def decode_escape_sequence(self, i, builder): ch = self.ll_chars[i] i += 1 - put = builder.append_multiple_char - if ch == '\\': put('\\', 1) - elif ch == '"': put('"' , 1) - elif ch == '/': put('/' , 1) - elif ch == 'b': put('\b', 1) - elif ch == 'f': put('\f', 1) - elif ch == 'n': put('\n', 1) - elif ch == 'r': put('\r', 1) - elif ch == 't': put('\t', 1) + put = builder.append + if ch == '\\': put('\\') + elif ch == '"': put('"' ) + elif ch == '/': put('/' ) + elif ch == 'b': put('\b') + elif ch == 'f': put('\f') + elif ch == 'n': put('\n') + elif ch == 'r': put('\r') + elif ch == 't': put('\t') elif ch == 'u': return self.decode_escape_sequence_unicode(i, builder) else: - raise DecoderError("Invalid \\escape: %s" % ch, self.pos-1) + raise DecoderError("Invalid \\escape: %s" % ch, i-1) return i def decode_escape_sequence_unicode(self, i, builder): diff --git a/pypy/module/_pypyjson/test/test__pypyjson.py b/pypy/module/_pypyjson/test/test__pypyjson.py --- a/pypy/module/_pypyjson/test/test__pypyjson.py +++ b/pypy/module/_pypyjson/test/test__pypyjson.py @@ -215,6 +215,23 @@ assert check("\\\"\b\f\n\r\t") == '\\\\\\"\\b\\f\\n\\r\\t' assert check("\x07") == "\\u0007" + def test_error_position(self): + import _pypyjson + test_cases = [ + ('[,', "No JSON object could be decoded: unexpected ',' at", 1), + ('{"spam":[}', "No JSON object could be decoded: unexpected '}' at", 9), + ('[42:', "Unexpected ':' when decoding array", 3), + ('[42 "spam"', "Unexpected '\"' when decoding array", 4), + ('[42,]', "No JSON object could be decoded: unexpected ']' at", 4), + ('{"spam":[42}', "Unexpected '}' when decoding array", 11), + ('["]', 'Unterminated string starting at', 1), + ('["spam":', "Unexpected ':' when decoding array", 7), + ('[{]', "No JSON object could be decoded: unexpected ']' at", 2), + ] + for inputtext, errmsg, errpos in test_cases: + exc = raises(ValueError, _pypyjson.loads, inputtext) + assert exc.value.args == (errmsg, inputtext, errpos) + def test_keys_reuse(self): import _pypyjson s = '[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]' diff --git a/pypy/module/_ssl/test/allsans.pem b/pypy/module/_ssl/test/allsans.pem deleted file mode 100644 --- a/pypy/module/_ssl/test/allsans.pem +++ /dev/null @@ -1,37 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOoy7/QOtTjQ0niE -6uDcTwtkC0R2Tvy1AjVnXohCntZfdzbTGDoYTgXSOLsP8A697jUiJ8VCePGH50xG -Z4DKnAF3a9O3a9nr2pLXb0iY3XOMv+YEBii7CfI+3oxFYgCl0sMgHzDD2ZTVYAsm -DWgLUVsE2gHEccRwrM2tPf2EgR+FAgMBAAECgYEA3qyfyYVSeTrTYxO93x6ZaVMu -A2IZp9zSxMQL9bKiI2GRj+cV2ebSCGbg2btFnD6qBor7FWsmYz+8g6FNN/9sY4az -61rMqMtQvLBe+7L8w70FeTze4qQ4Y1oQri0qD6tBWhDVlpnbI5Py9bkZKD67yVUk -elcEA/5x4PrYXkuqsAECQQD80NjT0mDvaY0JOOaQFSEpMv6QiUA8GGX8Xli7IoKb -tAolPG8rQBa+qSpcWfDMTrWw/aWHuMEEQoP/bVDH9W4FAkEA7SYQbBAKnojZ5A3G -kOHdV7aeivRQxQk/JN8Fb8oKB9Csvpv/BsuGxPKXHdhFa6CBTTsNRtHQw/szPo4l -xMIjgQJAPoMxqibR+0EBM6+TKzteSL6oPXsCnBl4Vk/J5vPgkbmR7KUl4+7j8N8J -b2554TrxKEN/w7CGYZRE6UrRd7ATNQJAWD7Yz41sli+wfPdPU2xo1BHljyl4wMk/ -EPZYbI/PCbdyAH/F935WyQTIjNeEhZc1Zkq6FwdOWw8ns3hrv3rKgQJAHXv1BqUa -czGPIFxX2TNoqtcl6/En4vrxVB1wzsfzkkDAg98kBl7qsF+S3qujSzKikjeaVbI2 -/CyWR2P3yLtOmA== ------END PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDcjCCAtugAwIBAgIJAN5dc9TOWjB7MA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV -BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u -IFNvZnR3YXJlIEZvdW5kYXRpb24xEDAOBgNVBAMMB2FsbHNhbnMwHhcNMTYwODA1 -MTAyMTExWhcNMjYwODAzMTAyMTExWjBdMQswCQYDVQQGEwJYWTEXMBUGA1UEBwwO -Q2FzdGxlIEFudGhyYXgxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0 -aW9uMRAwDgYDVQQDDAdhbGxzYW5zMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDqMu/0DrU40NJ4hOrg3E8LZAtEdk78tQI1Z16IQp7WX3c20xg6GE4F0ji7D/AO -ve41IifFQnjxh+dMRmeAypwBd2vTt2vZ69qS129ImN1zjL/mBAYouwnyPt6MRWIA -pdLDIB8ww9mU1WALJg1oC1FbBNoBxHHEcKzNrT39hIEfhQIDAQABo4IBODCCATQw -ggEwBgNVHREEggEnMIIBI4IHYWxsc2Fuc6AeBgMqAwSgFwwVc29tZSBvdGhlciBp -ZGVudGlmaWVyoDUGBisGAQUCAqArMCmgEBsOS0VSQkVST1MuUkVBTE2hFTAToAMC -AQGhDDAKGwh1c2VybmFtZYEQdXNlckBleGFtcGxlLm9yZ4IPd3d3LmV4YW1wbGUu -b3JnpGcwZTELMAkGA1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMw -IQYDVQQKDBpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjEYMBYGA1UEAwwPZGly -bmFtZSBleGFtcGxlhhdodHRwczovL3d3dy5weXRob24ub3JnL4cEfwAAAYcQAAAA -AAAAAAAAAAAAAAAAAYgEKgMEBTANBgkqhkiG9w0BAQsFAAOBgQAy16h+F+nOmeiT -VWR0fc8F/j6FcadbLseAUaogcC15OGxCl4UYpLV88HBkABOoGCpP155qwWTwOrdG -iYPGJSusf1OnJEbvzFejZf6u078bPd9/ZL4VWLjv+FPGkjd+N+/OaqMvgj8Lu99f -3Y/C4S7YbHxxwff6C6l2Xli+q6gnuQ== ------END CERTIFICATE----- diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -39,6 +39,7 @@ from rpython.rlib import rawrefcount from rpython.rlib import rthread from rpython.rlib.debug import fatalerror_notb +from pypy.objspace.std.typeobject import W_TypeObject, find_best_base DEBUG_WRAPPER = True @@ -903,6 +904,7 @@ retval = fatal_value boxed_args = () tb = None + state = space.fromcache(State) try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, @@ -921,7 +923,6 @@ boxed_args += (arg_conv, ) if pygilstate_ensure: boxed_args += (args[-1], ) - state = space.fromcache(State) try: result = callable(space, *boxed_args) if not we_are_translated() and DEBUG_WRAPPER: @@ -967,6 +968,7 @@ except Exception as e: unexpected_exception(pname, e, tb) _restore_gil_state(pygilstate_release, gilstate, gil_release, _gil_auto, tid) + state.check_and_raise_exception(always=True) return fatal_value assert lltype.typeOf(retval) == restype @@ -1127,6 +1129,34 @@ setup_init_functions(eci, prefix) return modulename.new(ext='') +def attach_recursively(space, static_pyobjs, static_objs_w, attached_objs, i): + # Start at i but make sure all the base classes are already attached + from pypy.module.cpyext.pyobject import get_typedescr, make_ref + if i in attached_objs: + return + py_obj = static_pyobjs[i] + w_obj = static_objs_w[i] + w_base = None + # w_obj can be NotImplemented, which is not a W_TypeObject + if isinstance(w_obj, W_TypeObject): + bases_w = w_obj.bases_w + if bases_w: + w_base = find_best_base(bases_w) + if w_base: + try: + j = static_objs_w.index(w_base) + except ValueError: + j = -1 + if j >=0 and j not in attached_objs: + attach_recursively(space, static_pyobjs, static_objs_w, + attached_objs, j) + w_type = space.type(w_obj) + typedescr = get_typedescr(w_type.layout.typedef) + py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, + make_ref(space, w_type)) + typedescr.attach(space, py_obj, w_obj) + attached_objs.append(i) + class StaticObjectBuilder(object): def __init__(self): @@ -1147,7 +1177,6 @@ def attach_all(self, space): # this is RPython, called once in pypy-c when it imports cpyext - from pypy.module.cpyext.pyobject import get_typedescr, make_ref from pypy.module.cpyext.typeobject import finish_type_1, finish_type_2 from pypy.module.cpyext.pyobject import track_reference # @@ -1157,14 +1186,9 @@ track_reference(space, static_pyobjs[i], static_objs_w[i]) # self.cpyext_type_init = [] + attached_objs = [] for i in range(len(static_objs_w)): - py_obj = static_pyobjs[i] - w_obj = static_objs_w[i] - w_type = space.type(w_obj) - typedescr = get_typedescr(w_type.layout.typedef) - py_obj.c_ob_type = rffi.cast(PyTypeObjectPtr, - make_ref(space, w_type)) - typedescr.attach(space, py_obj, w_obj) + attach_recursively(space, static_pyobjs, static_objs_w, attached_objs, i) cpyext_type_init = self.cpyext_type_init self.cpyext_type_init = None for pto, w_type in cpyext_type_init: diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py --- a/pypy/module/cpyext/bytesobject.py +++ b/pypy/module/cpyext/bytesobject.py @@ -80,14 +80,18 @@ """ py_str = rffi.cast(PyBytesObject, py_obj) s = space.str_w(w_obj) - if py_str.c_ob_size < len(s): + len_s = len(s) + if py_str.c_ob_size < len_s: raise oefmt(space.w_ValueError, "bytes_attach called on object with ob_size %d but trying to store %d", - py_str.c_ob_size, len(s)) + py_str.c_ob_size, len_s) with rffi.scoped_nonmovingbuffer(s) as s_ptr: - rffi.c_memcpy(py_str.c_ob_sval, s_ptr, len(s)) - py_str.c_ob_sval[len(s)] = '\0' - py_str.c_ob_shash = space.hash_w(w_obj) + rffi.c_memcpy(py_str.c_ob_sval, s_ptr, len_s) + py_str.c_ob_sval[len_s] = '\0' + # if py_obj has a tp_hash, this will try to call it, but the objects are + # not fully linked yet + #py_str.c_ob_shash = space.hash_w(w_obj) + py_str.c_ob_shash = space.hash_w(space.newbytes(s)) py_str.c_ob_sstate = rffi.cast(rffi.INT, 1) # SSTATE_INTERNED_MORTAL def bytes_realize(space, py_obj): @@ -100,7 +104,9 @@ w_type = from_ref(space, rffi.cast(PyObject, py_obj.c_ob_type)) w_obj = space.allocate_instance(W_BytesObject, w_type) w_obj.__init__(s) - py_str.c_ob_shash = space.hash_w(w_obj) + # if py_obj has a tp_hash, this will try to call it but the object is + # not realized yet + py_str.c_ob_shash = space.hash_w(space.newbytes(s)) py_str.c_ob_sstate = rffi.cast(rffi.INT, 1) # SSTATE_INTERNED_MORTAL track_reference(space, py_obj, w_obj) return w_obj diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py --- a/pypy/module/cpyext/listobject.py +++ b/pypy/module/cpyext/listobject.py @@ -90,11 +90,10 @@ return 0 @cpython_api([rffi.VOIDP], Py_ssize_t, error=CANNOT_FAIL) -def PyList_GET_SIZE(space, w_list): +def PyList_GET_SIZE(space, w_obj): """Macro form of PyList_Size() without error checking. """ - assert isinstance(w_list, W_ListObject) - return w_list.length() + return space.len_w(w_obj) @cpython_api([PyObject], Py_ssize_t, error=-1) diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py --- a/pypy/module/cpyext/slotdefs.py +++ b/pypy/module/cpyext/slotdefs.py @@ -18,6 +18,7 @@ from pypy.module.cpyext.pyerrors import PyErr_Occurred from pypy.module.cpyext.memoryobject import fill_Py_buffer from pypy.module.cpyext.state import State +from pypy.module.cpyext import userslot from pypy.interpreter.error import OperationError, oefmt from pypy.interpreter.argument import Arguments from rpython.rlib.buffer import Buffer @@ -506,6 +507,10 @@ @specialize.memo() def get_slot_tp_function(space, typedef, name): + """Return a description of the slot C function to use for the built-in + type for 'typedef'. The 'name' is the slot name. This is a memo + function that, after translation, returns one of a built-in finite set. + """ key = (typedef, name) try: return SLOTS[key] @@ -543,6 +548,19 @@ return space.call_function(slot_fn, w_self) handled = True + for tp_name, attr in [('tp_hash', '__hash__'), + ]: + if name == tp_name: + slot_fn = w_type.getdictvalue(space, attr) + if slot_fn is None: + return + @slot_function([PyObject], lltype.Signed, error=-1) + @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name)) + def slot_func(space, w_obj): + return space.int_w(space.call_function(slot_fn, w_obj)) + handled = True + + # binary functions for tp_name, attr in [('tp_as_number.c_nb_add', '__add__'), ('tp_as_number.c_nb_subtract', '__sub__'), @@ -748,7 +766,7 @@ else: assert False - function = globals().get(FUNCTION, None) + function = getattr(userslot, FUNCTION or '!missing', None) assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS if FLAGS: if wrapper is Ellipsis: @@ -811,7 +829,7 @@ static slotdef slotdefs[] = { SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, "x.__len__() <==> len(x)"), - SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, + SQSLOT("__add__", sq_concat, slot_sq_concat, wrap_binaryfunc, "x.__add__(y) <==> x+y"), SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, "x.__mul__(n) <==> x*n"), @@ -928,9 +946,7 @@ "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS), TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"), - TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), - TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), - TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""), + TPSLOT("__getattr__", tp_getattro, slot_tp_getattr, NULL, ""), TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, "x.__setattr__('name', value) <==> x.name = value"), TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), diff --git a/pypy/module/cpyext/test/foo3.c b/pypy/module/cpyext/test/foo3.c --- a/pypy/module/cpyext/test/foo3.c +++ b/pypy/module/cpyext/test/foo3.c @@ -8,6 +8,24 @@ return newType; } +PyObject * typ = NULL; +PyObject* datetimetype_tp_new(PyTypeObject* metatype, PyObject* args, PyObject* kwds) +{ + PyObject* newType; + if (typ == NULL) + { + PyErr_Format(PyExc_TypeError, "could not import datetime.datetime"); + return NULL; + } + newType = ((PyTypeObject*)typ)->tp_new(metatype, args, kwds); + return newType; +} + +void datetimetype_tp_dealloc(PyObject* self) +{ + return ((PyTypeObject*)typ)->tp_dealloc(self); +} + #define BASEFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE PyTypeObject footype = { @@ -58,6 +76,54 @@ /*tp_weaklist*/ 0 }; +PyTypeObject datetimetype = { + PyVarObject_HEAD_INIT(NULL, 0) + /*tp_name*/ "foo3.datetimetype", + /*tp_basicsize*/ sizeof(PyTypeObject), + /*tp_itemsize*/ 0, + /*tp_dealloc*/ datetimetype_tp_dealloc, + /*tp_print*/ 0, + /*tp_getattr*/ 0, + /*tp_setattr*/ 0, + /*tp_compare*/ 0, + /*tp_repr*/ 0, + /*tp_as_number*/ 0, + /*tp_as_sequence*/ 0, + /*tp_as_mapping*/ 0, + /*tp_hash*/ 0, + /*tp_call*/ 0, + /*tp_str*/ 0, + /*tp_getattro*/ 0, + /*tp_setattro*/ 0, + /*tp_as_buffer*/ 0, + /*tp_flags*/ BASEFLAGS, + /*tp_doc*/ 0, + /*tp_traverse*/ 0, + /*tp_clear*/ 0, + /*tp_richcompare*/ 0, + /*tp_weaklistoffset*/ 0, + /*tp_iter*/ 0, + /*tp_iternext*/ 0, + /*tp_methods*/ 0, + /*tp_members*/ 0, + /*tp_getset*/ 0, + /*tp_base*/ 0, // set to &PyType_Type in module init function (why can it not be done here?) + /*tp_dict*/ 0, + /*tp_descr_get*/ 0, + /*tp_descr_set*/ 0, + /*tp_dictoffset*/ 0, + /*tp_init*/ 0, + /*tp_alloc*/ 0, + /*tp_new*/ datetimetype_tp_new, + /*tp_free*/ 0, + /*tp_is_gc*/ 0, + /*tp_bases*/ 0, + /*tp_mro*/ 0, + /*tp_cache*/ 0, + /*tp_subclasses*/ 0, + /*tp_weaklist*/ 0 +}; + static PyMethodDef sbkMethods[] = {{NULL, NULL, 0, NULL}}; static struct PyModuleDef moduledef = { @@ -81,6 +147,16 @@ PyInit_foo3(void) { PyObject *mod, *d; + PyObject *module = NULL; + module = PyImport_ImportModule("datetime"); + typ = PyObject_GetAttrString(module, "datetime"); + Py_DECREF(module); + if (!PyType_Check(typ)) { + PyErr_Format(PyExc_TypeError, "datetime.datetime is not a type object"); + return NULL; + } + datetimetype.tp_base = (PyTypeObject*)typ; + PyType_Ready(&datetimetype); footype.tp_base = &PyType_Type; PyType_Ready(&footype); mod = PyModule_Create(&moduledef); @@ -91,6 +167,8 @@ return NULL; if (PyDict_SetItemString(d, "footype", (PyObject *)&footype) < 0) return NULL; + if (PyDict_SetItemString(d, "datetimetype", (PyObject *)&datetimetype) < 0) + return NULL; Py_INCREF(&footype); return mod; } diff --git a/pypy/module/cpyext/test/test_dictobject.py b/pypy/module/cpyext/test/test_dictobject.py --- a/pypy/module/cpyext/test/test_dictobject.py +++ b/pypy/module/cpyext/test/test_dictobject.py @@ -1,83 +1,82 @@ import py from rpython.rtyper.lltypesystem import rffi, lltype -from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.module.cpyext.test.test_api import BaseApiTest, raises_w from pypy.module.cpyext.api import Py_ssize_tP, PyObjectP, PyTypeObjectPtr from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.interpreter.error import OperationError from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase +from pypy.module.cpyext.dictproxyobject import * +from pypy.module.cpyext.dictobject import * +from pypy.module.cpyext.pyobject import decref class TestDictObject(BaseApiTest): - def test_dict(self, space, api): - d = api.PyDict_New() + def test_dict(self, space): + d = PyDict_New(space) assert space.eq_w(d, space.newdict()) - assert space.eq_w(api.PyDict_GetItem(space.wrap({"a": 72}), + assert space.eq_w(PyDict_GetItem(space, space.wrap({"a": 72}), space.wrap("a")), space.wrap(72)) - assert api.PyDict_SetItem(d, space.wrap("c"), space.wrap(42)) >= 0 + PyDict_SetItem(space, d, space.wrap("c"), space.wrap(42)) assert space.eq_w(space.getitem(d, space.wrap("c")), space.wrap(42)) space.setitem(d, space.wrap("name"), space.wrap(3)) - assert space.eq_w(api.PyDict_GetItem(d, space.wrap("name")), + assert space.eq_w(PyDict_GetItem(space, d, space.wrap("name")), space.wrap(3)) space.delitem(d, space.wrap("name")) - assert not api.PyDict_GetItem(d, space.wrap("name")) - assert not api.PyErr_Occurred() + assert not PyDict_GetItem(space, d, space.wrap("name")) buf = rffi.str2charp("name") - assert not api.PyDict_GetItemString(d, buf) + assert not PyDict_GetItemString(space, d, buf) rffi.free_charp(buf) - assert not api.PyErr_Occurred() - assert api.PyDict_Contains(d, space.wrap("c")) - assert not api.PyDict_Contains(d, space.wrap("z")) + assert PyDict_Contains(space, d, space.wrap("c")) + assert not PyDict_Contains(space, d, space.wrap("z")) - assert api.PyDict_DelItem(d, space.wrap("c")) == 0 - assert api.PyDict_DelItem(d, space.wrap("name")) < 0 - assert api.PyErr_Occurred() is space.w_KeyError - api.PyErr_Clear() - assert api.PyDict_Size(d) == 0 + PyDict_DelItem(space, d, space.wrap("c")) + with raises_w(space, KeyError): + PyDict_DelItem(space, d, space.wrap("name")) + assert PyDict_Size(space, d) == 0 space.setitem(d, space.wrap("some_key"), space.wrap(3)) buf = rffi.str2charp("some_key") - assert api.PyDict_DelItemString(d, buf) == 0 - assert api.PyDict_Size(d) == 0 - assert api.PyDict_DelItemString(d, buf) < 0 - assert api.PyErr_Occurred() is space.w_KeyError - api.PyErr_Clear() + PyDict_DelItemString(space, d, buf) + assert PyDict_Size(space, d) == 0 + with raises_w(space, KeyError): + PyDict_DelItemString(space, d, buf) rffi.free_charp(buf) d = space.wrap({'a': 'b'}) - api.PyDict_Clear(d) - assert api.PyDict_Size(d) == 0 + PyDict_Clear(space, d) + assert PyDict_Size(space, d) == 0 - def test_check(self, space, api): - d = api.PyDict_New() - assert api.PyDict_Check(d) - assert api.PyDict_CheckExact(d) + def test_check(self, space): + d = PyDict_New(space, ) + assert PyDict_Check(space, d) + assert PyDict_CheckExact(space, d) sub = space.appexec([], """(): class D(dict): pass return D""") d = space.call_function(sub) - assert api.PyDict_Check(d) - assert not api.PyDict_CheckExact(d) + assert PyDict_Check(space, d) + assert not PyDict_CheckExact(space, d) i = space.wrap(2) - assert not api.PyDict_Check(i) - assert not api.PyDict_CheckExact(i) + assert not PyDict_Check(space, i) + assert not PyDict_CheckExact(space, i) - def test_keys(self, space, api): + def test_keys(self, space): w_d = space.newdict() space.setitem(w_d, space.wrap("a"), space.wrap("b")) - assert space.eq_w(api.PyDict_Keys(w_d), space.wrap(["a"])) - assert space.eq_w(api.PyDict_Values(w_d), space.wrap(["b"])) - assert space.eq_w(api.PyDict_Items(w_d), space.wrap([("a", "b")])) + assert space.eq_w(PyDict_Keys(space, w_d), space.wrap(["a"])) + assert space.eq_w(PyDict_Values(space, w_d), space.wrap(["b"])) + assert space.eq_w(PyDict_Items(space, w_d), space.wrap([("a", "b")])) - def test_merge(self, space, api): + def test_merge(self, space): w_d = space.newdict() space.setitem(w_d, space.wrap("a"), space.wrap("b")) @@ -86,35 +85,34 @@ space.setitem(w_d2, space.wrap("c"), space.wrap("d")) space.setitem(w_d2, space.wrap("e"), space.wrap("f")) - api.PyDict_Merge(w_d, w_d2, 0) + PyDict_Merge(space, w_d, w_d2, 0) assert space.unwrap(w_d) == dict(a='b', c='d', e='f') - api.PyDict_Merge(w_d, w_d2, 1) + PyDict_Merge(space, w_d, w_d2, 1) assert space.unwrap(w_d) == dict(a='c', c='d', e='f') - def test_update(self, space, api): + def test_update(self, space): w_d = space.newdict() space.setitem(w_d, space.wrap("a"), space.wrap("b")) - w_d2 = api.PyDict_Copy(w_d) + w_d2 = PyDict_Copy(space, w_d) assert not space.is_w(w_d2, w_d) space.setitem(w_d, space.wrap("c"), space.wrap("d")) space.setitem(w_d2, space.wrap("e"), space.wrap("f")) - api.PyDict_Update(w_d, w_d2) + PyDict_Update(space, w_d, w_d2) assert space.unwrap(w_d) == dict(a='b', c='d', e='f') - def test_update_doesnt_accept_list_of_tuples(self, space, api): + def test_update_doesnt_accept_list_of_tuples(self, space): w_d = space.newdict() space.setitem(w_d, space.wrap("a"), space.wrap("b")) w_d2 = space.wrap([("c", "d"), ("e", "f")]) - api.PyDict_Update(w_d, w_d2) - assert api.PyErr_Occurred() is space.w_AttributeError - api.PyErr_Clear() + with raises_w(space, AttributeError): + PyDict_Update(space, w_d, w_d2) assert space.unwrap(w_d) == dict(a='b') # unchanged - def test_iter(self, space, api): + def test_iter(self, space): w_dict = space.sys.getdict(space) py_dict = make_ref(space, w_dict) @@ -125,7 +123,7 @@ try: w_copy = space.newdict() - while api.PyDict_Next(w_dict, ppos, pkey, pvalue): + while PyDict_Next(space, w_dict, ppos, pkey, pvalue): w_key = from_ref(space, pkey[0]) w_value = from_ref(space, pvalue[0]) space.setitem(w_copy, w_key, w_value) @@ -134,12 +132,12 @@ lltype.free(pkey, flavor='raw') lltype.free(pvalue, flavor='raw') - api.Py_DecRef(py_dict) # release borrowed references + decref(space, py_dict) # release borrowed references assert space.eq_w(space.len(w_copy), space.len(w_dict)) assert space.eq_w(w_copy, w_dict) - def test_iterkeys(self, space, api): + def test_iterkeys(self, space): w_dict = space.sys.getdict(space) py_dict = make_ref(space, w_dict) @@ -151,11 +149,11 @@ values_w = [] try: ppos[0] = 0 - while api.PyDict_Next(w_dict, ppos, pkey, None): + while PyDict_Next(space, w_dict, ppos, pkey, None): w_key = from_ref(space, pkey[0]) keys_w.append(w_key) ppos[0] = 0 - while api.PyDict_Next(w_dict, ppos, None, pvalue): + while PyDict_Next(space, w_dict, ppos, None, pvalue): w_value = from_ref(space, pvalue[0]) values_w.append(w_value) finally: @@ -163,7 +161,7 @@ lltype.free(pkey, flavor='raw') lltype.free(pvalue, flavor='raw') - api.Py_DecRef(py_dict) # release borrowed references + decref(space, py_dict) # release borrowed references assert space.eq_w(space.newlist(keys_w), space.call_function( @@ -174,18 +172,18 @@ space.w_list, space.call_method(w_dict, "values"))) - def test_dictproxy(self, space, api): + def test_dictproxy(self, space): w_dict = space.sys.get('modules') - w_proxy = api.PyDictProxy_New(w_dict) + w_proxy = PyDictProxy_New(space, w_dict) assert space.contains_w(w_proxy, space.wrap('sys')) raises(OperationError, space.setitem, w_proxy, space.wrap('sys'), space.w_None) raises(OperationError, space.delitem, w_proxy, space.wrap('sys')) raises(OperationError, space.call_method, w_proxy, 'clear') - assert api.PyDictProxy_Check(w_proxy) + assert PyDictProxy_Check(space, w_proxy) - def test_typedict1(self, space, api): + def test_typedict1(self, space): py_type = make_ref(space, space.w_int) py_dict = rffi.cast(PyTypeObjectPtr, py_type).c_tp_dict ppos = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw') @@ -195,7 +193,7 @@ pvalue = lltype.malloc(PyObjectP.TO, 1, flavor='raw') try: w_copy = space.newdict() - while api.PyDict_Next(py_dict, ppos, pkey, pvalue): + while PyDict_Next(space, py_dict, ppos, pkey, pvalue): w_key = from_ref(space, pkey[0]) w_value = from_ref(space, pvalue[0]) space.setitem(w_copy, w_key, w_value) @@ -203,7 +201,7 @@ lltype.free(ppos, flavor='raw') lltype.free(pkey, flavor='raw') lltype.free(pvalue, flavor='raw') - api.Py_DecRef(py_type) # release borrowed references + decref(space, py_type) # release borrowed references # do something with w_copy ? class AppTestDictObject(AppTestCpythonExtensionBase): diff --git a/pypy/module/cpyext/test/test_eval.py b/pypy/module/cpyext/test/test_eval.py --- a/pypy/module/cpyext/test/test_eval.py +++ b/pypy/module/cpyext/test/test_eval.py @@ -1,17 +1,26 @@ +import sys +import os +import pytest from rpython.rtyper.lltypesystem import rffi, lltype from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase -from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.module.cpyext.test.test_api import BaseApiTest, raises_w +from pypy.module.cpyext.object import PyObject_Size, PyObject_GetItem +from pypy.module.cpyext.pythonrun import Py_AtExit from pypy.module.cpyext.eval import ( - Py_single_input, Py_file_input, Py_eval_input, PyCompilerFlags) -from pypy.module.cpyext.api import (c_fopen, c_fclose, c_fileno, - Py_ssize_tP, is_valid_fd) + Py_single_input, Py_file_input, Py_eval_input, PyCompilerFlags, + PyEval_CallObjectWithKeywords, PyObject_CallObject, PyEval_EvalCode, + PyRun_SimpleString, PyRun_String, PyRun_StringFlags, PyRun_File, + PyEval_GetBuiltins, PyEval_GetLocals, PyEval_GetGlobals, + _PyEval_SliceIndex) +from pypy.module.cpyext.api import ( + c_fopen, c_fclose, c_fileno, Py_ssize_tP, is_valid_fd) from pypy.interpreter.gateway import interp2app +from pypy.interpreter.error import OperationError from pypy.interpreter.astcompiler import consts from rpython.tool.udir import udir -import sys, os class TestEval(BaseApiTest): - def test_eval(self, space, api): + def test_eval(self, space): w_l, w_f = space.fixedview(space.appexec([], """(): l = [] def f(arg1, arg2): @@ -22,7 +31,7 @@ """)) w_t = space.newtuple([space.wrap(1), space.wrap(2)]) - w_res = api.PyEval_CallObjectWithKeywords(w_f, w_t, None) + w_res = PyEval_CallObjectWithKeywords(space, w_f, w_t, None) assert space.int_w(w_res) == 2 assert space.len_w(w_l) == 2 w_f = space.appexec([], """(): @@ -35,10 +44,10 @@ w_t = space.newtuple([space.w_None, space.w_None]) w_d = space.newdict() space.setitem(w_d, space.wrap("xyz"), space.wrap(3)) - w_res = api.PyEval_CallObjectWithKeywords(w_f, w_t, w_d) + w_res = PyEval_CallObjectWithKeywords(space, w_f, w_t, w_d) assert space.int_w(w_res) == 21 - def test_call_object(self, space, api): + def test_call_object(self, space): w_l, w_f = space.fixedview(space.appexec([], """(): l = [] def f(arg1, arg2): @@ -49,7 +58,7 @@ """)) w_t = space.newtuple([space.wrap(1), space.wrap(2)]) - w_res = api.PyObject_CallObject(w_f, w_t) + w_res = PyObject_CallObject(space, w_f, w_t) assert space.int_w(w_res) == 2 assert space.len_w(w_l) == 2 @@ -61,11 +70,11 @@ """) w_t = space.newtuple([space.wrap(1), space.wrap(2)]) - w_res = api.PyObject_CallObject(w_f, w_t) + w_res = PyObject_CallObject(space, w_f, w_t) assert space.int_w(w_res) == 10 - def test_evalcode(self, space, api): + def test_evalcode(self, space): w_f = space.appexec([], """(): def f(*args): assert isinstance(args, tuple) @@ -77,84 +86,78 @@ w_globals = space.newdict() w_locals = space.newdict() space.setitem(w_locals, space.wrap("args"), w_t) - w_res = api.PyEval_EvalCode(w_f.code, w_globals, w_locals) + w_res = PyEval_EvalCode(space, w_f.code, w_globals, w_locals) assert space.int_w(w_res) == 10 - def test_run_simple_string(self, space, api): + def test_run_simple_string(self, space): def run(code): buf = rffi.str2charp(code) try: - return api.PyRun_SimpleString(buf) + return PyRun_SimpleString(space, buf) finally: rffi.free_charp(buf) - assert 0 == run("42 * 43") + assert run("42 * 43") == 0 # no error + with pytest.raises(OperationError): + run("4..3 * 43") - assert -1 == run("4..3 * 43") - - assert api.PyErr_Occurred() - api.PyErr_Clear() - - def test_run_string(self, space, api): + def test_run_string(self, space): def run(code, start, w_globals, w_locals): buf = rffi.str2charp(code) try: - return api.PyRun_String(buf, start, w_globals, w_locals) + return PyRun_String(space, buf, start, w_globals, w_locals) finally: rffi.free_charp(buf) w_globals = space.newdict() assert 42 * 43 == space.unwrap( run("42 * 43", Py_eval_input, w_globals, w_globals)) - assert api.PyObject_Size(w_globals) == 0 + assert PyObject_Size(space, w_globals) == 0 assert run("a = 42 * 43", Py_single_input, w_globals, w_globals) == space.w_None assert 42 * 43 == space.unwrap( - api.PyObject_GetItem(w_globals, space.wrap("a"))) + PyObject_GetItem(space, w_globals, space.wrap("a"))) - def test_run_string_flags(self, space, api): + def test_run_string_flags(self, space): flags = lltype.malloc(PyCompilerFlags, flavor='raw') flags.c_cf_flags = rffi.cast(rffi.INT, consts.PyCF_SOURCE_IS_UTF8) w_globals = space.newdict() buf = rffi.str2charp("a = 'caf\xc3\xa9'") try: - api.PyRun_StringFlags(buf, Py_single_input, - w_globals, w_globals, flags) + PyRun_StringFlags(space, buf, Py_single_input, w_globals, + w_globals, flags) finally: rffi.free_charp(buf) w_a = space.getitem(w_globals, space.wrap("a")) assert space.unwrap(w_a) == u'caf\xe9' lltype.free(flags, flavor='raw') - def test_run_file(self, space, api): + def test_run_file(self, space): filepath = udir / "cpyext_test_runfile.py" filepath.write("raise ZeroDivisionError") fp = c_fopen(str(filepath), "rb") filename = rffi.str2charp(str(filepath)) w_globals = w_locals = space.newdict() - api.PyRun_File(fp, filename, Py_file_input, w_globals, w_locals) + with raises_w(space, ZeroDivisionError): + PyRun_File(space, fp, filename, Py_file_input, w_globals, w_locals) c_fclose(fp) - assert api.PyErr_Occurred() is space.w_ZeroDivisionError - api.PyErr_Clear() # try again, but with a closed file fp = c_fopen(str(filepath), "rb") os.close(c_fileno(fp)) - api.PyRun_File(fp, filename, Py_file_input, w_globals, w_locals) + with raises_w(space, IOError): + PyRun_File(space, fp, filename, Py_file_input, w_globals, w_locals) if is_valid_fd(c_fileno(fp)): c_fclose(fp) - assert api.PyErr_Occurred() is space.w_IOError - api.PyErr_Clear() - rffi.free_charp(filename) - def test_getbuiltins(self, space, api): - assert api.PyEval_GetBuiltins() is space.builtin.w_dict + def test_getbuiltins(self, space): + assert PyEval_GetBuiltins(space) is space.builtin.w_dict def cpybuiltins(space): - return api.PyEval_GetBuiltins() + return PyEval_GetBuiltins(space) w_cpybuiltins = space.wrap(interp2app(cpybuiltins)) w_result = space.appexec([w_cpybuiltins], """(cpybuiltins): @@ -168,13 +171,13 @@ """) assert space.len_w(w_result) == 1 - def test_getglobals(self, space, api): - assert api.PyEval_GetLocals() is None - assert api.PyEval_GetGlobals() is None + def test_getglobals(self, space): + assert PyEval_GetLocals(space) is None + assert PyEval_GetGlobals(space) is None def cpyvars(space): - return space.newtuple([api.PyEval_GetGlobals(), - api.PyEval_GetLocals()]) + return space.newtuple([PyEval_GetGlobals(space), + PyEval_GetLocals(space)]) w_cpyvars = space.wrap(interp2app(cpyvars)) w_result = space.appexec([w_cpyvars], """(cpyvars): @@ -186,26 +189,26 @@ assert sorted(locals) == ['cpyvars', 'x'] assert sorted(globals) == ['__builtins__', 'anonymous', 'y'] - def test_sliceindex(self, space, api): + def test_sliceindex(self, space): pi = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw') - assert api._PyEval_SliceIndex(space.w_None, pi) == 0 - api.PyErr_Clear() + with pytest.raises(OperationError): + _PyEval_SliceIndex(space, space.w_None, pi) - assert api._PyEval_SliceIndex(space.wrap(123), pi) == 1 + assert _PyEval_SliceIndex(space, space.wrap(123), pi) == 1 assert pi[0] == 123 - assert api._PyEval_SliceIndex(space.wrap(1 << 66), pi) == 1 + assert _PyEval_SliceIndex(space, space.wrap(1 << 66), pi) == 1 assert pi[0] == sys.maxint lltype.free(pi, flavor='raw') - def test_atexit(self, space, api): + def test_atexit(self, space): lst = [] def func(): lst.append(42) - api.Py_AtExit(func) + Py_AtExit(space, func) cpyext = space.getbuiltinmodule('cpyext') - cpyext.shutdown(space) # simulate shutdown + cpyext.shutdown(space) # simulate shutdown assert lst == [42] class AppTestCall(AppTestCpythonExtensionBase): @@ -269,6 +272,7 @@ return res; """), ]) + def f(*args): return args assert module.call_func(f) == (None,) @@ -323,7 +327,7 @@ ]) assert module.get_flags() == (0, 0) - ns = {'module':module} + ns = {'module': module} if not hasattr(sys, 'pypy_version_info'): # no barry_as_FLUFL on pypy exec("""from __future__ import barry_as_FLUFL \nif 1: def nested_flags(): diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py --- a/pypy/module/cpyext/test/test_floatobject.py +++ b/pypy/module/cpyext/test/test_floatobject.py @@ -1,36 +1,40 @@ +import pytest +from pypy.interpreter.error import OperationError from pypy.module.cpyext.test.test_api import BaseApiTest from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase from rpython.rtyper.lltypesystem import rffi +from pypy.module.cpyext.floatobject import ( + PyFloat_FromDouble, PyFloat_AsDouble, PyFloat_AS_DOUBLE, PyNumber_Float, + _PyFloat_Unpack4, _PyFloat_Unpack8) class TestFloatObject(BaseApiTest): - def test_floatobject(self, space, api): - assert space.unwrap(api.PyFloat_FromDouble(3.14)) == 3.14 - assert api.PyFloat_AsDouble(space.wrap(23.45)) == 23.45 - assert api.PyFloat_AS_DOUBLE(space.wrap(23.45)) == 23.45 + def test_floatobject(self, space): + assert space.unwrap(PyFloat_FromDouble(space, 3.14)) == 3.14 + assert PyFloat_AsDouble(space, space.wrap(23.45)) == 23.45 + assert PyFloat_AS_DOUBLE(space, space.wrap(23.45)) == 23.45 + with pytest.raises(OperationError): + PyFloat_AsDouble(space, space.w_None) - assert api.PyFloat_AsDouble(space.w_None) == -1 - api.PyErr_Clear() - - def test_coerce(self, space, api): - assert space.type(api.PyNumber_Float(space.wrap(3))) is space.w_float - assert space.type(api.PyNumber_Float(space.wrap("3"))) is space.w_float + def test_coerce(self, space): + assert space.type(PyNumber_Float(space, space.wrap(3))) is space.w_float + assert space.type(PyNumber_Float(space, space.wrap("3"))) is space.w_float w_obj = space.appexec([], """(): class Coerce(object): def __float__(self): return 42.5 return Coerce()""") - assert space.eq_w(api.PyNumber_Float(w_obj), space.wrap(42.5)) + assert space.eq_w(PyNumber_Float(space, w_obj), space.wrap(42.5)) - def test_unpack(self, space, api): + def test_unpack(self, space): with rffi.scoped_str2charp("\x9a\x99\x99?") as ptr: - assert abs(api._PyFloat_Unpack4(ptr, 1) - 1.2) < 1e-7 + assert abs(_PyFloat_Unpack4(space, ptr, 1) - 1.2) < 1e-7 with rffi.scoped_str2charp("?\x99\x99\x9a") as ptr: - assert abs(api._PyFloat_Unpack4(ptr, 0) - 1.2) < 1e-7 + assert abs(_PyFloat_Unpack4(space, ptr, 0) - 1.2) < 1e-7 with rffi.scoped_str2charp("\x1f\x85\xebQ\xb8\x1e\t@") as ptr: - assert abs(api._PyFloat_Unpack8(ptr, 1) - 3.14) < 1e-15 + assert abs(_PyFloat_Unpack8(space, ptr, 1) - 3.14) < 1e-15 with rffi.scoped_str2charp("@\t\x1e\xb8Q\xeb\x85\x1f") as ptr: - assert abs(api._PyFloat_Unpack8(ptr, 0) - 3.14) < 1e-15 + assert abs(_PyFloat_Unpack8(space, ptr, 0) - 3.14) < 1e-15 class AppTestFloatObject(AppTestCpythonExtensionBase): def test_fromstring(self): @@ -79,8 +83,6 @@ assert math.isinf(neginf) def test_macro_accepts_wrong_pointer_type(self): - import math - module = self.import_extension('foo', [ ("test_macros", "METH_NOARGS", """ diff --git a/pypy/module/cpyext/test/test_funcobject.py b/pypy/module/cpyext/test/test_funcobject.py --- a/pypy/module/cpyext/test/test_funcobject.py +++ b/pypy/module/cpyext/test/test_funcobject.py @@ -1,16 +1,18 @@ -from rpython.rtyper.lltypesystem import rffi, lltype -from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase +from rpython.rtyper.lltypesystem import rffi from pypy.module.cpyext.test.test_api import BaseApiTest -from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref +from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref, decref +from pypy.module.cpyext.methodobject import PyClassMethod_New from pypy.module.cpyext.funcobject import ( - PyFunctionObject, PyCodeObject, CODE_FLAGS) -from pypy.interpreter.function import Function, Method + PyFunctionObject, PyCodeObject, CODE_FLAGS, PyMethod_Function, + PyMethod_Self, PyMethod_New, PyFunction_GetCode, + PyCode_NewEmpty, PyCode_GetNumFree) +from pypy.interpreter.function import Function from pypy.interpreter.pycode import PyCode globals().update(CODE_FLAGS) class TestFunctionObject(BaseApiTest): - def test_function(self, space, api): + def test_function(self, space): w_function = space.appexec([], """(): def f(): pass return f @@ -19,10 +21,10 @@ assert (from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.gettypeobject(Function.typedef)) assert "f" == space.unwrap( - from_ref(space, rffi.cast(PyFunctionObject, ref).c_func_name)) - api.Py_DecRef(ref) + from_ref(space, rffi.cast(PyFunctionObject, ref).c_func_name)) + decref(space, ref) - def test_method(self, space, api): + def test_method(self, space): w_method = space.appexec([], """(): class C(list): def method(self): pass @@ -32,29 +34,29 @@ w_function = space.getattr(w_method, space.wrap("__func__")) w_self = space.getattr(w_method, space.wrap("__self__")) - assert space.is_w(api.PyMethod_Function(w_method), w_function) - assert space.is_w(api.PyMethod_Self(w_method), w_self) + assert space.is_w(PyMethod_Function(space, w_method), w_function) + assert space.is_w(PyMethod_Self(space, w_method), w_self) - w_method2 = api.PyMethod_New(w_function, w_self) + w_method2 = PyMethod_New(space, w_function, w_self) assert space.eq_w(w_method, w_method2) - def test_getcode(self, space, api): + def test_getcode(self, space): w_function = space.appexec([], """(): def func(x, y, z): return x return func """) - w_code = api.PyFunction_GetCode(w_function) + w_code = PyFunction_GetCode(space, w_function) assert w_code.co_name == "func" ref = make_ref(space, w_code) assert (from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.gettypeobject(PyCode.typedef)) assert "func" == space.unwrap( - from_ref(space, rffi.cast(PyCodeObject, ref).c_co_name)) + from_ref(space, rffi.cast(PyCodeObject, ref).c_co_name)) assert 3 == rffi.cast(PyCodeObject, ref).c_co_argcount - api.Py_DecRef(ref) + decref(space, ref) - def test_co_flags(self, space, api): + def test_co_flags(self, space): def get_flags(signature, body="pass"): w_code = space.appexec([], """(): def func(%s): %s @@ -62,36 +64,36 @@ """ % (signature, body)) ref = make_ref(space, w_code) co_flags = rffi.cast(PyCodeObject, ref).c_co_flags - api.Py_DecRef(ref) + decref(space, ref) return co_flags assert get_flags("x") == CO_NESTED | CO_OPTIMIZED | CO_NEWLOCALS assert get_flags("x, *args") & CO_VARARGS assert get_flags("x, **kw") & CO_VARKEYWORDS assert get_flags("x", "yield x") & CO_GENERATOR - def test_newcode(self, space, api): + def test_newcode(self, space): filename = rffi.str2charp('filename') funcname = rffi.str2charp('funcname') - w_code = api.PyCode_NewEmpty(filename, funcname, 3) + w_code = PyCode_NewEmpty(space, filename, funcname, 3) assert w_code.co_filename == 'filename' assert w_code.co_firstlineno == 3 ref = make_ref(space, w_code) assert "filename" == space.unwrap( from_ref(space, rffi.cast(PyCodeObject, ref).c_co_filename)) - api.Py_DecRef(ref) + decref(space, ref) rffi.free_charp(filename) rffi.free_charp(funcname) - def test_getnumfree(self, space, api): + def test_getnumfree(self, space): w_function = space.appexec([], """(): a = 5 def method(x): return a, x return method """) - assert api.PyCode_GetNumFree(w_function.code) == 1 + assert PyCode_GetNumFree(space, w_function.code) == 1 - def test_classmethod(self, space, api): + def test_classmethod(self, space): w_function = space.appexec([], """(): def method(x): return x return method @@ -103,6 +105,7 @@ space.setattr(w_class, space.wrap("method"), w_function) assert space.is_w(space.call_method(w_instance, "method"), w_instance) # now a classmethod - w_classmethod = api.PyClassMethod_New(w_function) + w_classmethod = PyClassMethod_New(space, w_function) space.setattr(w_class, space.wrap("classmethod"), w_classmethod) - assert space.is_w(space.call_method(w_instance, "classmethod"), w_class) + assert space.is_w( + space.call_method(w_instance, "classmethod"), w_class) diff --git a/pypy/module/cpyext/test/test_import.py b/pypy/module/cpyext/test/test_import.py --- a/pypy/module/cpyext/test/test_import.py +++ b/pypy/module/cpyext/test/test_import.py @@ -1,48 +1,51 @@ from pypy.module.cpyext.test.test_api import BaseApiTest from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase +from pypy.module.cpyext.import_ import * +from pypy.module.cpyext.import_ import ( + _PyImport_AcquireLock, _PyImport_ReleaseLock) from rpython.rtyper.lltypesystem import rffi class TestImport(BaseApiTest): - def test_import(self, space, api): - stat = api.PyImport_Import(space.wrap("stat")) + def test_import(self, space): + stat = PyImport_Import(space, space.wrap("stat")) assert stat assert space.getattr(stat, space.wrap("S_IMODE")) - def test_addmodule(self, space, api): + def test_addmodule(self, space): with rffi.scoped_str2charp("sys") as modname: - w_sys = api.PyImport_AddModule(modname) + w_sys = PyImport_AddModule(space, modname) assert w_sys is space.sys with rffi.scoped_str2charp("foobar") as modname: - w_foobar = api.PyImport_AddModule(modname) + w_foobar = PyImport_AddModule(space, modname) assert space.str_w(space.getattr(w_foobar, space.wrap('__name__'))) == 'foobar' def test_getmoduledict(self, space, api): testmod = "contextlib" - w_pre_dict = api.PyImport_GetModuleDict() + w_pre_dict = PyImport_GetModuleDict(space, ) assert not space.contains_w(w_pre_dict, space.wrap(testmod)) with rffi.scoped_str2charp(testmod) as modname: - w_module = api.PyImport_ImportModule(modname) + w_module = PyImport_ImportModule(space, modname) print w_module assert w_module - w_dict = api.PyImport_GetModuleDict() + w_dict = PyImport_GetModuleDict(space, ) assert space.contains_w(w_dict, space.wrap(testmod)) - def test_reload(self, space, api): - stat = api.PyImport_Import(space.wrap("stat")) + def test_reload(self, space): + stat = PyImport_Import(space, space.wrap("stat")) space.delattr(stat, space.wrap("S_IMODE")) - stat = api.PyImport_ReloadModule(stat) + stat = PyImport_ReloadModule(space, stat) assert space.getattr(stat, space.wrap("S_IMODE")) - def test_lock(self, space, api): + def test_lock(self, space): # "does not crash" - api._PyImport_AcquireLock() - api._PyImport_AcquireLock() - api._PyImport_ReleaseLock() - api._PyImport_ReleaseLock() + _PyImport_AcquireLock(space, ) + _PyImport_AcquireLock(space, ) + _PyImport_ReleaseLock(space, ) + _PyImport_ReleaseLock(space, ) class AppTestImportLogic(AppTestCpythonExtensionBase): diff --git a/pypy/module/cpyext/test/test_memoryobject.py b/pypy/module/cpyext/test/test_memoryobject.py --- a/pypy/module/cpyext/test/test_memoryobject.py +++ b/pypy/module/cpyext/test/test_memoryobject.py @@ -30,12 +30,14 @@ assert view.c_len == 5 o = rffi.charp2str(view.c_buf) assert o == 'hello' - w_mv = from_ref(space, api.PyMemoryView_FromBuffer(view)) + ref = api.PyMemoryView_FromBuffer(view) + w_mv = from_ref(space, ref) for f in ('format', 'itemsize', 'ndim', 'readonly', 'shape', 'strides', 'suboffsets'): w_f = space.wrap(f) assert space.eq_w(space.getattr(w_mv, w_f), space.getattr(w_memoryview, w_f)) + api.Py_DecRef(ref) class AppTestPyBuffer_FillInfo(AppTestCpythonExtensionBase): def test_fillWithObject(self): diff --git a/pypy/module/cpyext/test/test_pyerrors.py b/pypy/module/cpyext/test/test_pyerrors.py --- a/pypy/module/cpyext/test/test_pyerrors.py +++ b/pypy/module/cpyext/test/test_pyerrors.py @@ -90,7 +90,7 @@ api.PyErr_WriteUnraisable(w_where) space.call_method(space.sys.get('stderr'), "flush") out, err = capfd.readouterr() - assert "Exception ValueError: 'message' in 'location' ignored" == err.strip() + assert "Exception ignored in: 'location'\nValueError: message" == err.strip() @pytest.mark.skipif(True, reason='not implemented yet') def test_interrupt_occurred(self, space, api): diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py --- a/pypy/module/cpyext/test/test_typeobject.py +++ b/pypy/module/cpyext/test/test_typeobject.py @@ -2,6 +2,7 @@ from rpython.rtyper.lltypesystem import rffi from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.module.cpyext.api import generic_cpy_call from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.typeobject import PyTypeObjectPtr @@ -634,26 +635,6 @@ assert module.tp_init(list, x, ("hi",)) is None assert x == ["h", "i"] - def test_tp_str(self): - module = self.import_extension('foo', [ - ("tp_str", "METH_VARARGS", - ''' - PyTypeObject *type = (PyTypeObject *)PyTuple_GET_ITEM(args, 0); - PyObject *obj = PyTuple_GET_ITEM(args, 1); - if (!type->tp_str) - { - PyErr_SetNone(PyExc_ValueError); - return NULL; - } - return type->tp_str(obj); - ''' - ) - ]) - class D(int): - def __str__(self): - return "more text" - assert module.tp_str(int, D(42)) == "42" - def test_mp_ass_subscript(self): module = self.import_extension('foo', [ ("new_obj", "METH_NOARGS", @@ -942,9 +923,12 @@ assert (d + a) == 5 assert pow(d,b) == 16 - def test_tp_new_in_subclass_of_type(self): + def test_tp_new_in_subclass(self): + import datetime module = self.import_module(name='foo3') module.footype("X", (object,), {}) + a = module.datetimetype(1, 1, 1) + assert isinstance(a, module.datetimetype) def test_app_subclass_of_c_type(self): import sys @@ -1130,7 +1114,6 @@ # class X(object, metaclass=FooType): pass X = FooType('X', (object,), {}) - print(repr(X)) X() def test_multiple_inheritance3(self): diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -1,5 +1,6 @@ # encoding: utf-8 -from pypy.module.cpyext.test.test_api import BaseApiTest +import pytest +from pypy.module.cpyext.test.test_api import BaseApiTest, raises_w from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase from pypy.module.cpyext.unicodeobject import ( Py_UNICODE, PyUnicodeObject, new_empty_unicode) @@ -7,6 +8,7 @@ from pypy.module.cpyext.pyobject import Py_DecRef, from_ref from rpython.rtyper.lltypesystem import rffi, lltype import sys, py +from pypy.module.cpyext.unicodeobject import * class AppTestUnicodeObject(AppTestCpythonExtensionBase): def test_unicodeobject(self): @@ -209,44 +211,45 @@ assert module.test_macro_invocations() == u'' class TestUnicode(BaseApiTest): - def test_unicodeobject(self, space, api): - assert api.PyUnicode_GET_SIZE(space.wrap(u'späm')) == 4 - assert api.PyUnicode_GetSize(space.wrap(u'späm')) == 4 + def test_unicodeobject(self, space): + assert PyUnicode_GET_SIZE(space, space.wrap(u'späm')) == 4 + assert PyUnicode_GetSize(space, space.wrap(u'späm')) == 4 unichar = rffi.sizeof(Py_UNICODE) - assert api.PyUnicode_GET_DATA_SIZE(space.wrap(u'späm')) == 4 * unichar + assert PyUnicode_GET_DATA_SIZE(space, space.wrap(u'späm')) == 4 * unichar - encoding = rffi.charp2str(api.PyUnicode_GetDefaultEncoding()) + encoding = rffi.charp2str(PyUnicode_GetDefaultEncoding(space, )) w_default_encoding = space.call_function( space.sys.get('getdefaultencoding') ) assert encoding == space.unwrap(w_default_encoding) - def test_AS(self, space, api): + def test_AS(self, space): word = space.wrap(u'spam') - array = rffi.cast(rffi.CWCHARP, api.PyUnicode_AS_DATA(word)) - array2 = api.PyUnicode_AS_UNICODE(word) - array3 = api.PyUnicode_AsUnicode(word) + array = rffi.cast(rffi.CWCHARP, PyUnicode_AS_DATA(space, word)) + array2 = PyUnicode_AS_UNICODE(space, word) + array3 = PyUnicode_AsUnicode(space, word) for (i, char) in enumerate(space.unwrap(word)): assert array[i] == char assert array2[i] == char assert array3[i] == char - self.raises(space, api, TypeError, api.PyUnicode_AsUnicode, - space.newbytes('spam')) + with raises_w(space, TypeError): + PyUnicode_AsUnicode(space, space.newbytes('spam')) utf_8 = rffi.str2charp('utf-8') - encoded = api.PyUnicode_AsEncodedString(space.wrap(u'späm'), + encoded = PyUnicode_AsEncodedString(space, space.wrap(u'späm'), utf_8, None) assert space.unwrap(encoded) == 'sp\xc3\xa4m' - encoded_obj = api.PyUnicode_AsEncodedObject(space.wrap(u'späm'), + encoded_obj = PyUnicode_AsEncodedObject(space, space.wrap(u'späm'), utf_8, None) assert space.eq_w(encoded, encoded_obj) - self.raises(space, api, TypeError, api.PyUnicode_AsEncodedString, - space.newtuple([1, 2, 3]), None, None) - self.raises(space, api, TypeError, api.PyUnicode_AsEncodedString, - space.newbytes(''), None, None) + with raises_w(space, TypeError): + PyUnicode_AsEncodedString( + space, space.newtuple([1, 2, 3]), None, None) + with raises_w(space, TypeError): + PyUnicode_AsEncodedString(space, space.newbytes(''), None, None) ascii = rffi.str2charp('ascii') replace = rffi.str2charp('replace') - encoded = api.PyUnicode_AsEncodedString(space.wrap(u'späm'), + encoded = PyUnicode_AsEncodedString(space, space.wrap(u'späm'), ascii, replace) assert space.unwrap(encoded) == 'sp?m' rffi.free_charp(utf_8) @@ -254,45 +257,45 @@ rffi.free_charp(ascii) buf = rffi.unicode2wcharp(u"12345") - api.PyUnicode_AsWideChar(space.wrap(u'longword'), buf, 5) + PyUnicode_AsWideChar(space, space.wrap(u'longword'), buf, 5) assert rffi.wcharp2unicode(buf) == 'longw' - api.PyUnicode_AsWideChar(space.wrap(u'a'), buf, 5) + PyUnicode_AsWideChar(space, space.wrap(u'a'), buf, 5) assert rffi.wcharp2unicode(buf) == 'a' rffi.free_wcharp(buf) - def test_fromstring(self, space, api): + def test_fromstring(self, space): s = rffi.str2charp(u'sp\x09m'.encode("utf-8")) - w_res = api.PyUnicode_FromString(s) + w_res = PyUnicode_FromString(space, s) assert space.unwrap(w_res) == u'sp\x09m' - res = api.PyUnicode_FromStringAndSize(s, 4) + res = PyUnicode_FromStringAndSize(space, s, 4) w_res = from_ref(space, res) - api.Py_DecRef(res) + Py_DecRef(space, res) assert space.unwrap(w_res) == u'sp\x09m' rffi.free_charp(s) - def test_internfromstring(self, space, api): + def test_internfromstring(self, space): with rffi.scoped_str2charp('foo') as s: - w_res = api.PyUnicode_InternFromString(s) + w_res = PyUnicode_InternFromString(space, s) assert space.unwrap(w_res) == u'foo' - w_res2 = api.PyUnicode_InternFromString(s) + w_res2 = PyUnicode_InternFromString(space, s) assert w_res is w_res2 - def test_unicode_resize(self, space, api): + def test_unicode_resize(self, space): py_uni = new_empty_unicode(space, 10) ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw') py_uni.c_buffer[0] = u'a' py_uni.c_buffer[1] = u'b' py_uni.c_buffer[2] = u'c' ar[0] = rffi.cast(PyObject, py_uni) - api.PyUnicode_Resize(ar, 3) + PyUnicode_Resize(space, ar, 3) py_uni = rffi.cast(PyUnicodeObject, ar[0]) assert py_uni.c_length == 3 assert py_uni.c_buffer[1] == u'b' assert py_uni.c_buffer[3] == u'\x00' # the same for growing ar[0] = rffi.cast(PyObject, py_uni) - api.PyUnicode_Resize(ar, 10) + PyUnicode_Resize(space, ar, 10) py_uni = rffi.cast(PyUnicodeObject, ar[0]) assert py_uni.c_length == 10 assert py_uni.c_buffer[1] == 'b' @@ -300,47 +303,46 @@ Py_DecRef(space, ar[0]) lltype.free(ar, flavor='raw') - def test_AsUTF8String(self, space, api): + def test_AsUTF8String(self, space): w_u = space.wrap(u'sp\x09m') - w_res = api.PyUnicode_AsUTF8String(w_u) + w_res = PyUnicode_AsUTF8String(space, w_u) assert space.type(w_res) is space.w_str assert space.unwrap(w_res) == 'sp\tm' - def test_decode_utf8(self, space, api): + def test_decode_utf8(self, space): u = rffi.str2charp(u'sp\x134m'.encode("utf-8")) - w_u = api.PyUnicode_DecodeUTF8(u, 5, None) + w_u = PyUnicode_DecodeUTF8(space, u, 5, None) assert space.type(w_u) is space.w_unicode assert space.unwrap(w_u) == u'sp\x134m' - w_u = api.PyUnicode_DecodeUTF8(u, 2, None) + w_u = PyUnicode_DecodeUTF8(space, u, 2, None) assert space.type(w_u) is space.w_unicode assert space.unwrap(w_u) == 'sp' rffi.free_charp(u) - def test_encode_utf8(self, space, api): + def test_encode_utf8(self, space): u = rffi.unicode2wcharp(u'sp\x09m') - w_s = api.PyUnicode_EncodeUTF8(u, 4, None) + w_s = PyUnicode_EncodeUTF8(space, u, 4, None) assert space.unwrap(w_s) == u'sp\x09m'.encode('utf-8') rffi.free_wcharp(u) - def test_encode_decimal(self, space, api): + def test_encode_decimal(self, space): with rffi.scoped_unicode2wcharp(u' (12, 35 ABC)') as u: with rffi.scoped_alloc_buffer(20) as buf: - res = api.PyUnicode_EncodeDecimal(u, 13, buf.raw, None) + res = PyUnicode_EncodeDecimal(space, u, 13, buf.raw, None) s = rffi.charp2str(buf.raw) assert res == 0 assert s == ' (12, 35 ABC)' with rffi.scoped_unicode2wcharp(u' (12, \u1234\u1235)') as u: with rffi.scoped_alloc_buffer(20) as buf: - res = api.PyUnicode_EncodeDecimal(u, 9, buf.raw, None) - assert res == -1 - api.PyErr_Clear() + with pytest.raises(OperationError): + PyUnicode_EncodeDecimal(space, u, 9, buf.raw, None) with rffi.scoped_unicode2wcharp(u' (12, \u1234\u1235)') as u: with rffi.scoped_alloc_buffer(20) as buf: with rffi.scoped_str2charp("replace") as errors: - res = api.PyUnicode_EncodeDecimal(u, 9, buf.raw, + res = PyUnicode_EncodeDecimal(space, u, 9, buf.raw, errors) s = rffi.charp2str(buf.raw) assert res == 0 @@ -349,117 +351,117 @@ with rffi.scoped_unicode2wcharp(u'12\u1234') as u: with rffi.scoped_alloc_buffer(20) as buf: with rffi.scoped_str2charp("xmlcharrefreplace") as errors: - res = api.PyUnicode_EncodeDecimal(u, 3, buf.raw, + res = PyUnicode_EncodeDecimal(space, u, 3, buf.raw, errors) s = rffi.charp2str(buf.raw) assert res == 0 assert s == "12ሴ" - def test_encode_fsdefault(self, space, api): + def test_encode_fsdefault(self, space): w_u = space.wrap(u'späm') - w_s = api.PyUnicode_EncodeFSDefault(w_u) + w_s = PyUnicode_EncodeFSDefault(space, w_u) if w_s is None: - api.PyErr_Clear() + PyErr_Clear(space) py.test.skip("Requires a unicode-aware fsencoding") with rffi.scoped_str2charp(space.str_w(w_s)) as encoded: - w_decoded = api.PyUnicode_DecodeFSDefaultAndSize(encoded, space.len_w(w_s)) + w_decoded = PyUnicode_DecodeFSDefaultAndSize(space, encoded, space.len_w(w_s)) assert space.eq_w(w_decoded, w_u) - w_decoded = api.PyUnicode_DecodeFSDefault(encoded) + w_decoded = PyUnicode_DecodeFSDefault(space, encoded) assert space.eq_w(w_decoded, w_u) - def test_fsconverter(self, space, api): + def test_fsconverter(self, space): # Input is bytes w_input = space.newbytes("test") with lltype.scoped_alloc(PyObjectP.TO, 1) as result: # Decoder - ret = api.PyUnicode_FSDecoder(w_input, result) + ret = PyUnicode_FSDecoder(space, w_input, result) assert ret == Py_CLEANUP_SUPPORTED assert space.isinstance_w(from_ref(space, result[0]), space.w_unicode) - assert api.PyUnicode_FSDecoder(None, result) == 1 + assert PyUnicode_FSDecoder(space, None, result) == 1 # Converter - ret = api.PyUnicode_FSConverter(w_input, result) + ret = PyUnicode_FSConverter(space, w_input, result) assert ret == Py_CLEANUP_SUPPORTED assert space.eq_w(from_ref(space, result[0]), w_input) - assert api.PyUnicode_FSDecoder(None, result) == 1 + assert PyUnicode_FSDecoder(space, None, result) == 1 # Input is unicode w_input = space.wrap("test") with lltype.scoped_alloc(PyObjectP.TO, 1) as result: # Decoder - ret = api.PyUnicode_FSDecoder(w_input, result) + ret = PyUnicode_FSDecoder(space, w_input, result) assert ret == Py_CLEANUP_SUPPORTED assert space.eq_w(from_ref(space, result[0]), w_input) - assert api.PyUnicode_FSDecoder(None, result) == 1 + assert PyUnicode_FSDecoder(space, None, result) == 1 # Converter - ret = api.PyUnicode_FSConverter(w_input, result) + ret = PyUnicode_FSConverter(space, w_input, result) assert ret == Py_CLEANUP_SUPPORTED assert space.isinstance_w(from_ref(space, result[0]), space.w_bytes) - assert api.PyUnicode_FSDecoder(None, result) == 1 + assert PyUnicode_FSDecoder(space, None, result) == 1 - def test_IS(self, space, api): + def test_IS(self, space): for char in [0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x85, 0xa0, 0x1680, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200a, #0x200b is in Other_Default_Ignorable_Code_Point in 4.1.0 0x2028, 0x2029, 0x202f, 0x205f, 0x3000]: - assert api.Py_UNICODE_ISSPACE(unichr(char)) - assert not api.Py_UNICODE_ISSPACE(u'a') + assert Py_UNICODE_ISSPACE(space, unichr(char)) + assert not Py_UNICODE_ISSPACE(space, u'a') - assert api.Py_UNICODE_ISALPHA(u'a') - assert not api.Py_UNICODE_ISALPHA(u'0') - assert api.Py_UNICODE_ISALNUM(u'a') - assert api.Py_UNICODE_ISALNUM(u'0') - assert not api.Py_UNICODE_ISALNUM(u'+') + assert Py_UNICODE_ISALPHA(space, u'a') + assert not Py_UNICODE_ISALPHA(space, u'0') + assert Py_UNICODE_ISALNUM(space, u'a') + assert Py_UNICODE_ISALNUM(space, u'0') + assert not Py_UNICODE_ISALNUM(space, u'+') - assert api.Py_UNICODE_ISDECIMAL(u'\u0660') - assert not api.Py_UNICODE_ISDECIMAL(u'a') - assert api.Py_UNICODE_ISDIGIT(u'9') - assert not api.Py_UNICODE_ISDIGIT(u'@') - assert api.Py_UNICODE_ISNUMERIC(u'9') - assert not api.Py_UNICODE_ISNUMERIC(u'@') + assert Py_UNICODE_ISDECIMAL(space, u'\u0660') + assert not Py_UNICODE_ISDECIMAL(space, u'a') + assert Py_UNICODE_ISDIGIT(space, u'9') + assert not Py_UNICODE_ISDIGIT(space, u'@') + assert Py_UNICODE_ISNUMERIC(space, u'9') + assert not Py_UNICODE_ISNUMERIC(space, u'@') for char in [0x0a, 0x0d, 0x1c, 0x1d, 0x1e, 0x85, 0x2028, 0x2029]: - assert api.Py_UNICODE_ISLINEBREAK(unichr(char)) + assert Py_UNICODE_ISLINEBREAK(space, unichr(char)) - assert api.Py_UNICODE_ISLOWER(u'\xdf') # sharp s - assert api.Py_UNICODE_ISUPPER(u'\xde') # capital thorn - assert api.Py_UNICODE_ISLOWER(u'a') - assert not api.Py_UNICODE_ISUPPER(u'a') - assert not api.Py_UNICODE_ISTITLE(u'\xce') - assert api.Py_UNICODE_ISTITLE( + assert Py_UNICODE_ISLOWER(space, u'\xdf') # sharp s _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit