Author: Richard Plangger <planri...@gmail.com> Branch: fix-longevity Changeset: r82521:3dce5a6242ac Date: 2016-02-25 17:58 +0100 http://bitbucket.org/pypy/pypy/changeset/3dce5a6242ac/
Log: (remi, plan_rich) merged default diff too long, truncating to 2000 out of 2557 lines diff --git a/LICENSE b/LICENSE --- a/LICENSE +++ b/LICENSE @@ -41,29 +41,29 @@ Amaury Forgeot d'Arc Antonio Cuni Samuele Pedroni + Matti Picus Alex Gaynor Brian Kearns - Matti Picus Philip Jenvey Michael Hudson + Ronan Lamy David Schneider + Manuel Jacob Holger Krekel Christian Tismer Hakan Ardo - Manuel Jacob - Ronan Lamy Benjamin Peterson + Richard Plangger Anders Chrigstrom Eric van Riet Paap Wim Lavrijsen - Richard Plangger Richard Emslie Alexander Schremmer Dan Villiom Podlaski Christiansen + Remi Meier Lukas Diekmann Sven Hager Anders Lehmann - Remi Meier Aurelien Campeas Niklaus Haldimann Camillo Bruni @@ -72,8 +72,8 @@ Romain Guillebert Leonardo Santagada Seo Sanghyeon + Ronny Pfannschmidt Justin Peel - Ronny Pfannschmidt David Edelsohn Anders Hammarquist Jakub Gustak @@ -95,6 +95,7 @@ Tyler Wade Michael Foord Stephan Diehl + Vincent Legoll Stefan Schwarzer Valentino Volonghi Tomek Meka @@ -105,9 +106,9 @@ Jean-Paul Calderone Timo Paulssen Squeaky + Marius Gedminas Alexandre Fayolle Simon Burton - Marius Gedminas Martin Matusiak Konstantin Lopuhin Wenzhu Man @@ -116,16 +117,20 @@ Ivan Sichmann Freitas Greg Price Dario Bertini + Stefano Rivera Mark Pearse Simon Cross Andreas Stührk - Stefano Rivera + Edd Barrett Jean-Philippe St. Pierre Guido van Rossum Pavel Vinogradov + Jeremy Thurgood Paweł Piotr Przeradowski + Spenser Bauman Paul deGrandis Ilya Osadchiy + marky1991 Tobias Oberstein Adrian Kuhn Boris Feigin @@ -134,14 +139,12 @@ Georg Brandl Bert Freudenberg Stian Andreassen - Edd Barrett + Tobias Pape Wanja Saatkamp Gerald Klix Mike Blume - Tobias Pape Oscar Nierstrasz Stefan H. Muller - Jeremy Thurgood Rami Chowdhury Eugene Oden Henry Mason @@ -153,6 +156,8 @@ Lukas Renggli Guenter Jantzen Ned Batchelder + Tim Felgentreff + Anton Gulenko Amit Regmi Ben Young Nicolas Chauvat @@ -162,12 +167,12 @@ Nicholas Riley Jason Chu Igor Trindade Oliveira - Tim Felgentreff + Yichao Yu Rocco Moretti Gintautas Miliauskas Michael Twomey Lucian Branescu Mihaila - Yichao Yu + Devin Jeanpierre Gabriel Lavoie Olivier Dormond Jared Grubb @@ -191,33 +196,33 @@ Stanislaw Halik Mikael Schönenberg Berkin Ilbeyi - Elmo M?ntynen + Elmo Mäntynen + Faye Zhao Jonathan David Riehl Anders Qvist Corbin Simpson Chirag Jadwani Beatrice During Alex Perry - Vincent Legoll + Vaibhav Sood Alan McIntyre - Spenser Bauman + William Leslie Alexander Sedov Attila Gobi + Jasper.Schulz Christopher Pope - Devin Jeanpierre - Vaibhav Sood Christian Tismer Marc Abramowitz Dan Stromberg Arjun Naik Valentina Mukhamedzhanova Stefano Parmesan + Mark Young Alexis Daboville Jens-Uwe Mager Carl Meyer Karl Ramm Pieter Zieschang - Anton Gulenko Gabriel Lukas Vacek Andrew Dalke @@ -225,6 +230,7 @@ Jakub Stasiak Nathan Taylor Vladimir Kryachko + Omer Katz Jacek Generowicz Alejandro J. Cura Jacob Oscarson @@ -239,6 +245,7 @@ Lars Wassermann Philipp Rustemeuer Henrik Vendelbo + Richard Lancaster Dan Buch Miguel de Val Borro Artur Lisiecki @@ -250,18 +257,18 @@ Tomo Cocoa Kim Jin Su Toni Mattis + Amber Brown Lucas Stadler Julian Berman Markus Holtermann roberto@goyle Yury V. Zaytsev Anna Katrina Dominguez - William Leslie Bobby Impollonia - Faye Zhao t...@eistee.fritz.box Andrew Thompson Yusei Tahara + Aaron Tubbs Ben Darnell Roberto De Ioris Juan Francisco Cantero Hurtado @@ -273,6 +280,7 @@ Christopher Armstrong Michael Hudson-Doyle Anders Sigfridsson + Nikolay Zinov Yasir Suhail Jason Michalski rafalgalczyn...@gmail.com @@ -282,6 +290,7 @@ Gustavo Niemeyer Stephan Busemann Rafał Gałczyński + Matt Bogosian Christian Muirhead Berker Peksag James Lan @@ -316,9 +325,9 @@ Stefan Marr jiaaro Mads Kiilerich - Richard Lancaster opassembler.py Antony Lee + Jason Madden Yaroslav Fedevych Jim Hunziker Markus Unterwaditzer @@ -327,6 +336,7 @@ squeaky Zearin soareschen + Jonas Pfannschmidt Kurt Griffiths Mike Bayer Matthew Miller diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -170,12 +170,8 @@ cmdline="--translationmodules", suggests=[("objspace.allworkingmodules", False)]), - BoolOption("usepycfiles", "Write and read pyc files when importing", - default=True), - BoolOption("lonepycfiles", "Import pyc files with no matching py file", - default=False, - requires=[("objspace.usepycfiles", True)]), + default=False), StrOption("soabi", "Tag to differentiate extension modules built for different Python interpreters", diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -1,5 +1,20 @@ -Making a PyPy Release -===================== +The PyPy Release Process +======================== + +Release Policy +++++++++++++++ + +We try to create a stable release a few times a year. These are released on +a branch named like release-2.x or release-4.x, and each release is tagged, +for instance release-4.0.1. + +After release, inevitably there are bug fixes. It is the responsibility of +the commiter who fixes a bug to make sure this fix is on the release branch, +so that we can then create a tagged bug-fix release, which will hopefully +happen more often than stable releases. + +How to Create a PyPy Release +++++++++++++++++++++++++++++ Overview -------- diff --git a/pypy/doc/tool/makecontributor.py b/pypy/doc/tool/makecontributor.py --- a/pypy/doc/tool/makecontributor.py +++ b/pypy/doc/tool/makecontributor.py @@ -72,6 +72,7 @@ 'Anton Gulenko':['anton gulenko', 'anton_gulenko'], 'Richard Lancaster':['richardlancaster'], 'William Leslie':['William ML Leslie'], + 'Spenser Bauman':['Spenser Andrew Bauman'], } alias_map = {} diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -277,7 +277,6 @@ if config.translation.sandbox: config.objspace.lonepycfiles = False - config.objspace.usepycfiles = False config.translating = True diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py --- a/pypy/module/cpyext/__init__.py +++ b/pypy/module/cpyext/__init__.py @@ -34,7 +34,7 @@ import pypy.module.cpyext.pyerrors import pypy.module.cpyext.typeobject import pypy.module.cpyext.object -import pypy.module.cpyext.stringobject +import pypy.module.cpyext.bytesobject import pypy.module.cpyext.tupleobject import pypy.module.cpyext.setobject import pypy.module.cpyext.dictobject diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/bytesobject.py @@ -0,0 +1,319 @@ +from pypy.interpreter.error import OperationError +from rpython.rtyper.lltypesystem import rffi, lltype +from pypy.module.cpyext.api import ( + cpython_api, cpython_struct, bootstrap_function, build_type_checkers, + PyObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL) +from pypy.module.cpyext.pyerrors import PyErr_BadArgument +from pypy.module.cpyext.pyobject import ( + PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference, + make_typedescr, get_typedescr) + +## +## Implementation of PyStringObject +## ================================ +## +## The problem +## ----------- +## +## PyString_AsString() must return a (non-movable) pointer to the underlying +## buffer, whereas pypy strings are movable. C code may temporarily store +## this address and use it, as long as it owns a reference to the PyObject. +## There is no "release" function to specify that the pointer is not needed +## any more. +## +## Also, the pointer may be used to fill the initial value of string. This is +## valid only when the string was just allocated, and is not used elsewhere. +## +## Solution +## -------- +## +## PyStringObject contains two additional members: the size and a pointer to a +## char buffer; it may be NULL. +## +## - A string allocated by pypy will be converted into a PyStringObject with a +## NULL buffer. The first time PyString_AsString() is called, memory is +## allocated (with flavor='raw') and content is copied. +## +## - A string allocated with PyString_FromStringAndSize(NULL, size) will +## allocate a PyStringObject structure, and a buffer with the specified +## size, but the reference won't be stored in the global map; there is no +## corresponding object in pypy. When from_ref() or Py_INCREF() is called, +## the pypy string is created, and added to the global map of tracked +## objects. The buffer is then supposed to be immutable. +## +## - _PyString_Resize() works only on not-yet-pypy'd strings, and returns a +## similar object. +## +## - PyString_Size() doesn't need to force the object. +## +## - There could be an (expensive!) check in from_ref() that the buffer still +## corresponds to the pypy gc-managed string. +## + +PyStringObjectStruct = lltype.ForwardReference() +PyStringObject = lltype.Ptr(PyStringObjectStruct) +PyStringObjectFields = PyObjectFields + \ + (("buffer", rffi.CCHARP), ("size", Py_ssize_t)) +cpython_struct("PyStringObject", PyStringObjectFields, PyStringObjectStruct) + +@bootstrap_function +def init_stringobject(space): + "Type description of PyStringObject" + make_typedescr(space.w_str.layout.typedef, + basestruct=PyStringObject.TO, + attach=string_attach, + dealloc=string_dealloc, + realize=string_realize) + +PyString_Check, PyString_CheckExact = build_type_checkers("String", "w_str") + +def new_empty_str(space, length): + """ + Allocate a PyStringObject and its buffer, but without a corresponding + interpreter object. The buffer may be mutated, until string_realize() is + called. Refcount of the result is 1. + """ + typedescr = get_typedescr(space.w_str.layout.typedef) + py_obj = typedescr.allocate(space, space.w_str) + py_str = rffi.cast(PyStringObject, py_obj) + + buflen = length + 1 + py_str.c_size = length + py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, buflen, + flavor='raw', zero=True) + return py_str + +def string_attach(space, py_obj, w_obj): + """ + Fills a newly allocated PyStringObject with the given string object. The + buffer must not be modified. + """ + py_str = rffi.cast(PyStringObject, py_obj) + py_str.c_size = len(space.str_w(w_obj)) + py_str.c_buffer = lltype.nullptr(rffi.CCHARP.TO) + +def string_realize(space, py_obj): + """ + Creates the string in the interpreter. The PyStringObject buffer must not + be modified after this call. + """ + py_str = rffi.cast(PyStringObject, py_obj) + s = rffi.charpsize2str(py_str.c_buffer, py_str.c_size) + w_obj = space.wrap(s) + track_reference(space, py_obj, w_obj) + return w_obj + +@cpython_api([PyObject], lltype.Void, header=None) +def string_dealloc(space, py_obj): + """Frees allocated PyStringObject resources. + """ + py_str = rffi.cast(PyStringObject, py_obj) + if py_str.c_buffer: + lltype.free(py_str.c_buffer, flavor="raw") + from pypy.module.cpyext.object import PyObject_dealloc + PyObject_dealloc(space, py_obj) + +#_______________________________________________________________________ + +@cpython_api([CONST_STRING, Py_ssize_t], PyObject) +def PyString_FromStringAndSize(space, char_p, length): + if char_p: + s = rffi.charpsize2str(char_p, length) + return make_ref(space, space.wrap(s)) + else: + return rffi.cast(PyObject, new_empty_str(space, length)) + +@cpython_api([CONST_STRING], PyObject) +def PyString_FromString(space, char_p): + s = rffi.charp2str(char_p) + return space.wrap(s) + +@cpython_api([PyObject], rffi.CCHARP, error=0) +def PyString_AsString(space, ref): + if from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.w_str: + pass # typecheck returned "ok" without forcing 'ref' at all + elif not PyString_Check(space, ref): # otherwise, use the alternate way + raise OperationError(space.w_TypeError, space.wrap( + "PyString_AsString only support strings")) + ref_str = rffi.cast(PyStringObject, ref) + if not ref_str.c_buffer: + # copy string buffer + w_str = from_ref(space, ref) + s = space.str_w(w_str) + ref_str.c_buffer = rffi.str2charp(s) + return ref_str.c_buffer + +@cpython_api([PyObject, rffi.CCHARPP, rffi.CArrayPtr(Py_ssize_t)], rffi.INT_real, error=-1) +def PyString_AsStringAndSize(space, ref, buffer, length): + if not PyString_Check(space, ref): + raise OperationError(space.w_TypeError, space.wrap( + "PyString_AsStringAndSize only support strings")) + ref_str = rffi.cast(PyStringObject, ref) + if not ref_str.c_buffer: + # copy string buffer + w_str = from_ref(space, ref) + s = space.str_w(w_str) + ref_str.c_buffer = rffi.str2charp(s) + buffer[0] = ref_str.c_buffer + if length: + length[0] = ref_str.c_size + else: + i = 0 + while ref_str.c_buffer[i] != '\0': + i += 1 + if i != ref_str.c_size: + raise OperationError(space.w_TypeError, space.wrap( + "expected string without null bytes")) + return 0 + +@cpython_api([PyObject], Py_ssize_t, error=-1) +def PyString_Size(space, ref): + if from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.w_str: + ref = rffi.cast(PyStringObject, ref) + return ref.c_size + else: + w_obj = from_ref(space, ref) + return space.len_w(w_obj) + +@cpython_api([PyObjectP, Py_ssize_t], rffi.INT_real, error=-1) +def _PyString_Resize(space, ref, newsize): + """A way to resize a string object even though it is "immutable". Only use this to + build up a brand new string object; don't use this if the string may already be + known in other parts of the code. It is an error to call this function if the + refcount on the input string object is not one. Pass the address of an existing + string object as an lvalue (it may be written into), and the new size desired. + On success, *string holds the resized string object and 0 is returned; + the address in *string may differ from its input value. If the reallocation + fails, the original string object at *string is deallocated, *string is + set to NULL, a memory exception is set, and -1 is returned. + """ + # XXX always create a new string so far + py_str = rffi.cast(PyStringObject, ref[0]) + if not py_str.c_buffer: + raise OperationError(space.w_SystemError, space.wrap( + "_PyString_Resize called on already created string")) + try: + py_newstr = new_empty_str(space, newsize) + except MemoryError: + Py_DecRef(space, ref[0]) + ref[0] = lltype.nullptr(PyObject.TO) + raise + to_cp = newsize + oldsize = py_str.c_size + if oldsize < newsize: + to_cp = oldsize + for i in range(to_cp): + py_newstr.c_buffer[i] = py_str.c_buffer[i] + Py_DecRef(space, ref[0]) + ref[0] = rffi.cast(PyObject, py_newstr) + return 0 + +@cpython_api([PyObject, PyObject], rffi.INT, error=CANNOT_FAIL) +def _PyString_Eq(space, w_str1, w_str2): + return space.eq_w(w_str1, w_str2) + +@cpython_api([PyObjectP, PyObject], lltype.Void) +def PyString_Concat(space, ref, w_newpart): + """Create a new string object in *string containing the contents of newpart + appended to string; the caller will own the new reference. The reference to + the old value of string will be stolen. If the new string cannot be created, + the old reference to string will still be discarded and the value of + *string will be set to NULL; the appropriate exception will be set.""" + + if not ref[0]: + return + + if w_newpart is None or not PyString_Check(space, ref[0]) or \ + not PyString_Check(space, w_newpart): + Py_DecRef(space, ref[0]) + ref[0] = lltype.nullptr(PyObject.TO) + return + w_str = from_ref(space, ref[0]) + w_newstr = space.add(w_str, w_newpart) + Py_DecRef(space, ref[0]) + ref[0] = make_ref(space, w_newstr) + +@cpython_api([PyObjectP, PyObject], lltype.Void) +def PyString_ConcatAndDel(space, ref, newpart): + """Create a new string object in *string containing the contents of newpart + appended to string. This version decrements the reference count of newpart.""" + PyString_Concat(space, ref, newpart) + Py_DecRef(space, newpart) + +@cpython_api([PyObject, PyObject], PyObject) +def PyString_Format(space, w_format, w_args): + """Return a new string object from format and args. Analogous to format % + args. The args argument must be a tuple.""" + return space.mod(w_format, w_args) + +@cpython_api([CONST_STRING], PyObject) +def PyString_InternFromString(space, string): + """A combination of PyString_FromString() and + PyString_InternInPlace(), returning either a new string object that has + been interned, or a new ("owned") reference to an earlier interned string + object with the same value.""" + s = rffi.charp2str(string) + return space.new_interned_str(s) + +@cpython_api([PyObjectP], lltype.Void) +def PyString_InternInPlace(space, string): + """Intern the argument *string in place. The argument must be the + address of a pointer variable pointing to a Python string object. + If there is an existing interned string that is the same as + *string, it sets *string to it (decrementing the reference count + of the old string object and incrementing the reference count of + the interned string object), otherwise it leaves *string alone and + interns it (incrementing its reference count). (Clarification: + even though there is a lot of talk about reference counts, think + of this function as reference-count-neutral; you own the object + after the call if and only if you owned it before the call.) + + This function is not available in 3.x and does not have a PyBytes + alias.""" + w_str = from_ref(space, string[0]) + w_str = space.new_interned_w_str(w_str) + Py_DecRef(space, string[0]) + string[0] = make_ref(space, w_str) + +@cpython_api([PyObject, CONST_STRING, CONST_STRING], PyObject) +def PyString_AsEncodedObject(space, w_str, encoding, errors): + """Encode a string object using the codec registered for encoding and return + the result as Python object. encoding and errors have the same meaning as + the parameters of the same name in the string encode() method. The codec to + be used is looked up using the Python codec registry. Return NULL if an + exception was raised by the codec. + + This function is not available in 3.x and does not have a PyBytes alias.""" + if not PyString_Check(space, w_str): + PyErr_BadArgument(space) + + w_encoding = w_errors = None + if encoding: + w_encoding = space.wrap(rffi.charp2str(encoding)) + if errors: + w_errors = space.wrap(rffi.charp2str(errors)) + return space.call_method(w_str, 'encode', w_encoding, w_errors) + +@cpython_api([PyObject, CONST_STRING, CONST_STRING], PyObject) +def PyString_AsDecodedObject(space, w_str, encoding, errors): + """Decode a string object by passing it to the codec registered + for encoding and return the result as Python object. encoding and + errors have the same meaning as the parameters of the same name in + the string encode() method. The codec to be used is looked up + using the Python codec registry. Return NULL if an exception was + raised by the codec. + + This function is not available in 3.x and does not have a PyBytes alias.""" + if not PyString_Check(space, w_str): + PyErr_BadArgument(space) + + w_encoding = w_errors = None + if encoding: + w_encoding = space.wrap(rffi.charp2str(encoding)) + if errors: + w_errors = space.wrap(rffi.charp2str(errors)) + return space.call_method(w_str, "decode", w_encoding, w_errors) + +@cpython_api([PyObject, PyObject], PyObject) +def _PyString_Join(space, w_sep, w_seq): + return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py --- a/pypy/module/cpyext/pyobject.py +++ b/pypy/module/cpyext/pyobject.py @@ -191,7 +191,7 @@ def from_ref(space, ref): """ Finds the interpreter object corresponding to the given reference. If the - object is not yet realized (see stringobject.py), creates it. + object is not yet realized (see bytesobject.py), creates it. """ assert is_pyobj(ref) if not ref: diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py deleted file mode 100644 --- a/pypy/module/cpyext/stringobject.py +++ /dev/null @@ -1,319 +0,0 @@ -from pypy.interpreter.error import OperationError -from rpython.rtyper.lltypesystem import rffi, lltype -from pypy.module.cpyext.api import ( - cpython_api, cpython_struct, bootstrap_function, build_type_checkers, - PyObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL) -from pypy.module.cpyext.pyerrors import PyErr_BadArgument -from pypy.module.cpyext.pyobject import ( - PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference, - make_typedescr, get_typedescr) - -## -## Implementation of PyStringObject -## ================================ -## -## The problem -## ----------- -## -## PyString_AsString() must return a (non-movable) pointer to the underlying -## buffer, whereas pypy strings are movable. C code may temporarily store -## this address and use it, as long as it owns a reference to the PyObject. -## There is no "release" function to specify that the pointer is not needed -## any more. -## -## Also, the pointer may be used to fill the initial value of string. This is -## valid only when the string was just allocated, and is not used elsewhere. -## -## Solution -## -------- -## -## PyStringObject contains two additional members: the size and a pointer to a -## char buffer; it may be NULL. -## -## - A string allocated by pypy will be converted into a PyStringObject with a -## NULL buffer. The first time PyString_AsString() is called, memory is -## allocated (with flavor='raw') and content is copied. -## -## - A string allocated with PyString_FromStringAndSize(NULL, size) will -## allocate a PyStringObject structure, and a buffer with the specified -## size, but the reference won't be stored in the global map; there is no -## corresponding object in pypy. When from_ref() or Py_INCREF() is called, -## the pypy string is created, and added to the global map of tracked -## objects. The buffer is then supposed to be immutable. -## -## - _PyString_Resize() works only on not-yet-pypy'd strings, and returns a -## similar object. -## -## - PyString_Size() doesn't need to force the object. -## -## - There could be an (expensive!) check in from_ref() that the buffer still -## corresponds to the pypy gc-managed string. -## - -PyStringObjectStruct = lltype.ForwardReference() -PyStringObject = lltype.Ptr(PyStringObjectStruct) -PyStringObjectFields = PyObjectFields + \ - (("buffer", rffi.CCHARP), ("size", Py_ssize_t)) -cpython_struct("PyStringObject", PyStringObjectFields, PyStringObjectStruct) - -@bootstrap_function -def init_stringobject(space): - "Type description of PyStringObject" - make_typedescr(space.w_str.layout.typedef, - basestruct=PyStringObject.TO, - attach=string_attach, - dealloc=string_dealloc, - realize=string_realize) - -PyString_Check, PyString_CheckExact = build_type_checkers("String", "w_str") - -def new_empty_str(space, length): - """ - Allocate a PyStringObject and its buffer, but without a corresponding - interpreter object. The buffer may be mutated, until string_realize() is - called. Refcount of the result is 1. - """ - typedescr = get_typedescr(space.w_str.layout.typedef) - py_obj = typedescr.allocate(space, space.w_str) - py_str = rffi.cast(PyStringObject, py_obj) - - buflen = length + 1 - py_str.c_size = length - py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, buflen, - flavor='raw', zero=True) - return py_str - -def string_attach(space, py_obj, w_obj): - """ - Fills a newly allocated PyStringObject with the given string object. The - buffer must not be modified. - """ - py_str = rffi.cast(PyStringObject, py_obj) - py_str.c_size = len(space.str_w(w_obj)) - py_str.c_buffer = lltype.nullptr(rffi.CCHARP.TO) - -def string_realize(space, py_obj): - """ - Creates the string in the interpreter. The PyStringObject buffer must not - be modified after this call. - """ - py_str = rffi.cast(PyStringObject, py_obj) - s = rffi.charpsize2str(py_str.c_buffer, py_str.c_size) - w_obj = space.wrap(s) - track_reference(space, py_obj, w_obj) - return w_obj - -@cpython_api([PyObject], lltype.Void, header=None) -def string_dealloc(space, py_obj): - """Frees allocated PyStringObject resources. - """ - py_str = rffi.cast(PyStringObject, py_obj) - if py_str.c_buffer: - lltype.free(py_str.c_buffer, flavor="raw") - from pypy.module.cpyext.object import PyObject_dealloc - PyObject_dealloc(space, py_obj) - -#_______________________________________________________________________ - -@cpython_api([CONST_STRING, Py_ssize_t], PyObject) -def PyString_FromStringAndSize(space, char_p, length): - if char_p: - s = rffi.charpsize2str(char_p, length) - return make_ref(space, space.wrap(s)) - else: - return rffi.cast(PyObject, new_empty_str(space, length)) - -@cpython_api([CONST_STRING], PyObject) -def PyString_FromString(space, char_p): - s = rffi.charp2str(char_p) - return space.wrap(s) - -@cpython_api([PyObject], rffi.CCHARP, error=0) -def PyString_AsString(space, ref): - if from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.w_str: - pass # typecheck returned "ok" without forcing 'ref' at all - elif not PyString_Check(space, ref): # otherwise, use the alternate way - raise OperationError(space.w_TypeError, space.wrap( - "PyString_AsString only support strings")) - ref_str = rffi.cast(PyStringObject, ref) - if not ref_str.c_buffer: - # copy string buffer - w_str = from_ref(space, ref) - s = space.str_w(w_str) - ref_str.c_buffer = rffi.str2charp(s) - return ref_str.c_buffer - -@cpython_api([PyObject, rffi.CCHARPP, rffi.CArrayPtr(Py_ssize_t)], rffi.INT_real, error=-1) -def PyString_AsStringAndSize(space, ref, buffer, length): - if not PyString_Check(space, ref): - raise OperationError(space.w_TypeError, space.wrap( - "PyString_AsStringAndSize only support strings")) - ref_str = rffi.cast(PyStringObject, ref) - if not ref_str.c_buffer: - # copy string buffer - w_str = from_ref(space, ref) - s = space.str_w(w_str) - ref_str.c_buffer = rffi.str2charp(s) - buffer[0] = ref_str.c_buffer - if length: - length[0] = ref_str.c_size - else: - i = 0 - while ref_str.c_buffer[i] != '\0': - i += 1 - if i != ref_str.c_size: - raise OperationError(space.w_TypeError, space.wrap( - "expected string without null bytes")) - return 0 - -@cpython_api([PyObject], Py_ssize_t, error=-1) -def PyString_Size(space, ref): - if from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.w_str: - ref = rffi.cast(PyStringObject, ref) - return ref.c_size - else: - w_obj = from_ref(space, ref) - return space.len_w(w_obj) - -@cpython_api([PyObjectP, Py_ssize_t], rffi.INT_real, error=-1) -def _PyString_Resize(space, ref, newsize): - """A way to resize a string object even though it is "immutable". Only use this to - build up a brand new string object; don't use this if the string may already be - known in other parts of the code. It is an error to call this function if the - refcount on the input string object is not one. Pass the address of an existing - string object as an lvalue (it may be written into), and the new size desired. - On success, *string holds the resized string object and 0 is returned; - the address in *string may differ from its input value. If the reallocation - fails, the original string object at *string is deallocated, *string is - set to NULL, a memory exception is set, and -1 is returned. - """ - # XXX always create a new string so far - py_str = rffi.cast(PyStringObject, ref[0]) - if not py_str.c_buffer: - raise OperationError(space.w_SystemError, space.wrap( - "_PyString_Resize called on already created string")) - try: - py_newstr = new_empty_str(space, newsize) - except MemoryError: - Py_DecRef(space, ref[0]) - ref[0] = lltype.nullptr(PyObject.TO) - raise - to_cp = newsize - oldsize = py_str.c_size - if oldsize < newsize: - to_cp = oldsize - for i in range(to_cp): - py_newstr.c_buffer[i] = py_str.c_buffer[i] - Py_DecRef(space, ref[0]) - ref[0] = rffi.cast(PyObject, py_newstr) - return 0 - -@cpython_api([PyObject, PyObject], rffi.INT, error=CANNOT_FAIL) -def _PyString_Eq(space, w_str1, w_str2): - return space.eq_w(w_str1, w_str2) - -@cpython_api([PyObjectP, PyObject], lltype.Void) -def PyString_Concat(space, ref, w_newpart): - """Create a new string object in *string containing the contents of newpart - appended to string; the caller will own the new reference. The reference to - the old value of string will be stolen. If the new string cannot be created, - the old reference to string will still be discarded and the value of - *string will be set to NULL; the appropriate exception will be set.""" - - if not ref[0]: - return - - if w_newpart is None or not PyString_Check(space, ref[0]) or \ - not PyString_Check(space, w_newpart): - Py_DecRef(space, ref[0]) - ref[0] = lltype.nullptr(PyObject.TO) - return - w_str = from_ref(space, ref[0]) - w_newstr = space.add(w_str, w_newpart) - Py_DecRef(space, ref[0]) - ref[0] = make_ref(space, w_newstr) - -@cpython_api([PyObjectP, PyObject], lltype.Void) -def PyString_ConcatAndDel(space, ref, newpart): - """Create a new string object in *string containing the contents of newpart - appended to string. This version decrements the reference count of newpart.""" - PyString_Concat(space, ref, newpart) - Py_DecRef(space, newpart) - -@cpython_api([PyObject, PyObject], PyObject) -def PyString_Format(space, w_format, w_args): - """Return a new string object from format and args. Analogous to format % - args. The args argument must be a tuple.""" - return space.mod(w_format, w_args) - -@cpython_api([CONST_STRING], PyObject) -def PyString_InternFromString(space, string): - """A combination of PyString_FromString() and - PyString_InternInPlace(), returning either a new string object that has - been interned, or a new ("owned") reference to an earlier interned string - object with the same value.""" - s = rffi.charp2str(string) - return space.new_interned_str(s) - -@cpython_api([PyObjectP], lltype.Void) -def PyString_InternInPlace(space, string): - """Intern the argument *string in place. The argument must be the - address of a pointer variable pointing to a Python string object. - If there is an existing interned string that is the same as - *string, it sets *string to it (decrementing the reference count - of the old string object and incrementing the reference count of - the interned string object), otherwise it leaves *string alone and - interns it (incrementing its reference count). (Clarification: - even though there is a lot of talk about reference counts, think - of this function as reference-count-neutral; you own the object - after the call if and only if you owned it before the call.) - - This function is not available in 3.x and does not have a PyBytes - alias.""" - w_str = from_ref(space, string[0]) - w_str = space.new_interned_w_str(w_str) - Py_DecRef(space, string[0]) - string[0] = make_ref(space, w_str) - -@cpython_api([PyObject, CONST_STRING, CONST_STRING], PyObject) -def PyString_AsEncodedObject(space, w_str, encoding, errors): - """Encode a string object using the codec registered for encoding and return - the result as Python object. encoding and errors have the same meaning as - the parameters of the same name in the string encode() method. The codec to - be used is looked up using the Python codec registry. Return NULL if an - exception was raised by the codec. - - This function is not available in 3.x and does not have a PyBytes alias.""" - if not PyString_Check(space, w_str): - PyErr_BadArgument(space) - - w_encoding = w_errors = None - if encoding: - w_encoding = space.wrap(rffi.charp2str(encoding)) - if errors: - w_errors = space.wrap(rffi.charp2str(errors)) - return space.call_method(w_str, 'encode', w_encoding, w_errors) - -@cpython_api([PyObject, CONST_STRING, CONST_STRING], PyObject) -def PyString_AsDecodedObject(space, w_str, encoding, errors): - """Decode a string object by passing it to the codec registered - for encoding and return the result as Python object. encoding and - errors have the same meaning as the parameters of the same name in - the string encode() method. The codec to be used is looked up - using the Python codec registry. Return NULL if an exception was - raised by the codec. - - This function is not available in 3.x and does not have a PyBytes alias.""" - if not PyString_Check(space, w_str): - PyErr_BadArgument(space) - - w_encoding = w_errors = None - if encoding: - w_encoding = space.wrap(rffi.charp2str(encoding)) - if errors: - w_errors = space.wrap(rffi.charp2str(errors)) - return space.call_method(w_str, "decode", w_encoding, w_errors) - -@cpython_api([PyObject, PyObject], PyObject) -def _PyString_Join(space, w_sep, w_seq): - return space.call_method(w_sep, 'join', w_seq) diff --git a/pypy/module/cpyext/structmember.py b/pypy/module/cpyext/structmember.py --- a/pypy/module/cpyext/structmember.py +++ b/pypy/module/cpyext/structmember.py @@ -6,7 +6,7 @@ from pypy.module.cpyext.intobject import PyInt_AsLong, PyInt_AsUnsignedLong from pypy.module.cpyext.pyerrors import PyErr_Occurred from pypy.module.cpyext.pyobject import PyObject, Py_DecRef, from_ref, make_ref -from pypy.module.cpyext.stringobject import ( +from pypy.module.cpyext.bytesobject import ( PyString_FromString, PyString_FromStringAndSize) from pypy.module.cpyext.floatobject import PyFloat_AsDouble from pypy.module.cpyext.longobject import ( diff --git a/pypy/module/cpyext/test/test_bytesobject.py b/pypy/module/cpyext/test/test_bytesobject.py new file mode 100644 --- /dev/null +++ b/pypy/module/cpyext/test/test_bytesobject.py @@ -0,0 +1,329 @@ +from rpython.rtyper.lltypesystem import rffi, lltype +from pypy.module.cpyext.test.test_api import BaseApiTest +from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase +from pypy.module.cpyext.bytesobject import new_empty_str, PyStringObject +from pypy.module.cpyext.api import PyObjectP, PyObject, Py_ssize_tP +from pypy.module.cpyext.pyobject import Py_DecRef, from_ref, make_ref + +import py +import sys + +class AppTestStringObject(AppTestCpythonExtensionBase): + def test_stringobject(self): + module = self.import_extension('foo', [ + ("get_hello1", "METH_NOARGS", + """ + return PyString_FromStringAndSize( + "Hello world<should not be included>", 11); + """), + ("get_hello2", "METH_NOARGS", + """ + return PyString_FromString("Hello world"); + """), + ("test_Size", "METH_NOARGS", + """ + PyObject* s = PyString_FromString("Hello world"); + int result = 0; + + if(PyString_Size(s) == 11) { + result = 1; + } + if(s->ob_type->tp_basicsize != sizeof(void*)*5) + result = 0; + Py_DECREF(s); + return PyBool_FromLong(result); + """), + ("test_Size_exception", "METH_NOARGS", + """ + PyObject* f = PyFloat_FromDouble(1.0); + Py_ssize_t size = PyString_Size(f); + + Py_DECREF(f); + return NULL; + """), + ("test_is_string", "METH_VARARGS", + """ + return PyBool_FromLong(PyString_Check(PyTuple_GetItem(args, 0))); + """)]) + assert module.get_hello1() == 'Hello world' + assert module.get_hello2() == 'Hello world' + assert module.test_Size() + raises(TypeError, module.test_Size_exception) + + assert module.test_is_string("") + assert not module.test_is_string(()) + + def test_string_buffer_init(self): + module = self.import_extension('foo', [ + ("getstring", "METH_NOARGS", + """ + PyObject *s, *t; + char* c; + Py_ssize_t len; + + s = PyString_FromStringAndSize(NULL, 4); + if (s == NULL) + return NULL; + t = PyString_FromStringAndSize(NULL, 3); + if (t == NULL) + return NULL; + Py_DECREF(t); + c = PyString_AsString(s); + c[0] = 'a'; + c[1] = 'b'; + c[3] = 'c'; + return s; + """), + ]) + s = module.getstring() + assert len(s) == 4 + assert s == 'ab\x00c' + + + + def test_AsString(self): + module = self.import_extension('foo', [ + ("getstring", "METH_NOARGS", + """ + PyObject* s1 = PyString_FromStringAndSize("test", 4); + char* c = PyString_AsString(s1); + PyObject* s2 = PyString_FromStringAndSize(c, 4); + Py_DECREF(s1); + return s2; + """), + ]) + s = module.getstring() + assert s == 'test' + + def test_py_string_as_string(self): + module = self.import_extension('foo', [ + ("string_as_string", "METH_VARARGS", + ''' + return PyString_FromStringAndSize(PyString_AsString( + PyTuple_GetItem(args, 0)), 4); + ''' + )]) + assert module.string_as_string("huheduwe") == "huhe" + + def test_py_string_as_string_None(self): + module = self.import_extension('foo', [ + ("string_None", "METH_VARARGS", + ''' + return PyString_AsString(Py_None); + ''' + )]) + raises(TypeError, module.string_None) + + def test_AsStringAndSize(self): + module = self.import_extension('foo', [ + ("getstring", "METH_NOARGS", + """ + PyObject* s1 = PyString_FromStringAndSize("te\\0st", 5); + char *buf; + Py_ssize_t len; + if (PyString_AsStringAndSize(s1, &buf, &len) < 0) + return NULL; + if (len != 5) { + PyErr_SetString(PyExc_AssertionError, "Bad Length"); + return NULL; + } + if (PyString_AsStringAndSize(s1, &buf, NULL) >= 0) { + PyErr_SetString(PyExc_AssertionError, "Should Have failed"); + return NULL; + } + PyErr_Clear(); + Py_DECREF(s1); + Py_INCREF(Py_None); + return Py_None; + """), + ]) + module.getstring() + + def test_format_v(self): + module = self.import_extension('foo', [ + ("test_string_format_v", "METH_VARARGS", + ''' + return helper("bla %d ble %s\\n", + PyInt_AsLong(PyTuple_GetItem(args, 0)), + PyString_AsString(PyTuple_GetItem(args, 1))); + ''' + ) + ], prologue=''' + PyObject* helper(char* fmt, ...) + { + va_list va; + PyObject* res; + va_start(va, fmt); + res = PyString_FromFormatV(fmt, va); + va_end(va); + return res; + } + ''') + res = module.test_string_format_v(1, "xyz") + assert res == "bla 1 ble xyz\n" + + def test_format(self): + module = self.import_extension('foo', [ + ("test_string_format", "METH_VARARGS", + ''' + return PyString_FromFormat("bla %d ble %s\\n", + PyInt_AsLong(PyTuple_GetItem(args, 0)), + PyString_AsString(PyTuple_GetItem(args, 1))); + ''' + ) + ]) + res = module.test_string_format(1, "xyz") + assert res == "bla 1 ble xyz\n" + + def test_intern_inplace(self): + module = self.import_extension('foo', [ + ("test_intern_inplace", "METH_O", + ''' + PyObject *s = args; + Py_INCREF(s); + PyString_InternInPlace(&s); + return s; + ''' + ) + ]) + # This does not test much, but at least the refcounts are checked. + assert module.test_intern_inplace('s') == 's' + +class TestString(BaseApiTest): + def test_string_resize(self, space, api): + py_str = new_empty_str(space, 10) + ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw') + py_str.c_buffer[0] = 'a' + py_str.c_buffer[1] = 'b' + py_str.c_buffer[2] = 'c' + ar[0] = rffi.cast(PyObject, py_str) + api._PyString_Resize(ar, 3) + py_str = rffi.cast(PyStringObject, ar[0]) + assert py_str.c_size == 3 + assert py_str.c_buffer[1] == 'b' + assert py_str.c_buffer[3] == '\x00' + # the same for growing + ar[0] = rffi.cast(PyObject, py_str) + api._PyString_Resize(ar, 10) + py_str = rffi.cast(PyStringObject, ar[0]) + assert py_str.c_size == 10 + assert py_str.c_buffer[1] == 'b' + assert py_str.c_buffer[10] == '\x00' + Py_DecRef(space, ar[0]) + lltype.free(ar, flavor='raw') + + def test_string_buffer(self, space, api): + py_str = new_empty_str(space, 10) + c_buf = py_str.c_ob_type.c_tp_as_buffer + assert c_buf + py_obj = rffi.cast(PyObject, py_str) + assert c_buf.c_bf_getsegcount(py_obj, lltype.nullptr(Py_ssize_tP.TO)) == 1 + ref = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw') + assert c_buf.c_bf_getsegcount(py_obj, ref) == 1 + assert ref[0] == 10 + lltype.free(ref, flavor='raw') + ref = lltype.malloc(rffi.VOIDPP.TO, 1, flavor='raw') + assert c_buf.c_bf_getreadbuffer(py_obj, 0, ref) == 10 + lltype.free(ref, flavor='raw') + Py_DecRef(space, py_obj) + + def test_Concat(self, space, api): + ref = make_ref(space, space.wrap('abc')) + ptr = lltype.malloc(PyObjectP.TO, 1, flavor='raw') + ptr[0] = ref + prev_refcnt = ref.c_ob_refcnt + api.PyString_Concat(ptr, space.wrap('def')) + assert ref.c_ob_refcnt == prev_refcnt - 1 + assert space.str_w(from_ref(space, ptr[0])) == 'abcdef' + api.PyString_Concat(ptr, space.w_None) + assert not ptr[0] + ptr[0] = lltype.nullptr(PyObject.TO) + api.PyString_Concat(ptr, space.wrap('def')) # should not crash + lltype.free(ptr, flavor='raw') + + def test_ConcatAndDel(self, space, api): + ref1 = make_ref(space, space.wrap('abc')) + ref2 = make_ref(space, space.wrap('def')) + ptr = lltype.malloc(PyObjectP.TO, 1, flavor='raw') + ptr[0] = ref1 + prev_refcnf = ref2.c_ob_refcnt + api.PyString_ConcatAndDel(ptr, ref2) + assert space.str_w(from_ref(space, ptr[0])) == 'abcdef' + assert ref2.c_ob_refcnt == prev_refcnf - 1 + Py_DecRef(space, ptr[0]) + ptr[0] = lltype.nullptr(PyObject.TO) + ref2 = make_ref(space, space.wrap('foo')) + prev_refcnf = ref2.c_ob_refcnt + api.PyString_ConcatAndDel(ptr, ref2) # should not crash + assert ref2.c_ob_refcnt == prev_refcnf - 1 + lltype.free(ptr, flavor='raw') + + def test_format(self, space, api): + assert "1 2" == space.unwrap( + api.PyString_Format(space.wrap('%s %d'), space.wrap((1, 2)))) + + def test_asbuffer(self, space, api): + bufp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') + lenp = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw') + + w_text = space.wrap("text") + assert api.PyObject_AsCharBuffer(w_text, bufp, lenp) == 0 + assert lenp[0] == 4 + assert rffi.charp2str(bufp[0]) == 'text' + + lltype.free(bufp, flavor='raw') + lltype.free(lenp, flavor='raw') + + def test_intern(self, space, api): + buf = rffi.str2charp("test") + w_s1 = api.PyString_InternFromString(buf) + w_s2 = api.PyString_InternFromString(buf) + rffi.free_charp(buf) + assert w_s1 is w_s2 + + def test_AsEncodedObject(self, space, api): + ptr = space.wrap('abc') + + errors = rffi.str2charp("strict") + + encoding = rffi.str2charp("hex") + res = api.PyString_AsEncodedObject( + ptr, encoding, errors) + assert space.unwrap(res) == "616263" + + res = api.PyString_AsEncodedObject( + ptr, encoding, lltype.nullptr(rffi.CCHARP.TO)) + assert space.unwrap(res) == "616263" + rffi.free_charp(encoding) + + encoding = rffi.str2charp("unknown_encoding") + self.raises(space, api, LookupError, api.PyString_AsEncodedObject, + ptr, encoding, errors) + rffi.free_charp(encoding) + + rffi.free_charp(errors) + + res = api.PyString_AsEncodedObject( + ptr, lltype.nullptr(rffi.CCHARP.TO), lltype.nullptr(rffi.CCHARP.TO)) + assert space.unwrap(res) == "abc" + + self.raises(space, api, TypeError, api.PyString_AsEncodedObject, + space.wrap(2), lltype.nullptr(rffi.CCHARP.TO), lltype.nullptr(rffi.CCHARP.TO) + ) + + def test_AsDecodedObject(self, space, api): + w_str = space.wrap('caf\xe9') + encoding = rffi.str2charp("latin-1") + w_res = api.PyString_AsDecodedObject(w_str, encoding, None) + rffi.free_charp(encoding) + assert space.unwrap(w_res) == u"caf\xe9" + + def test_eq(self, space, api): + assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) + assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) + + def test_join(self, space, api): + w_sep = space.wrap('<sep>') + w_seq = space.wrap(['a', 'b']) + w_joined = api._PyString_Join(w_sep, w_seq) + assert space.unwrap(w_joined) == 'a<sep>b' diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py deleted file mode 100644 --- a/pypy/module/cpyext/test/test_stringobject.py +++ /dev/null @@ -1,329 +0,0 @@ -from rpython.rtyper.lltypesystem import rffi, lltype -from pypy.module.cpyext.test.test_api import BaseApiTest -from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase -from pypy.module.cpyext.stringobject import new_empty_str, PyStringObject -from pypy.module.cpyext.api import PyObjectP, PyObject, Py_ssize_tP -from pypy.module.cpyext.pyobject import Py_DecRef, from_ref, make_ref - -import py -import sys - -class AppTestStringObject(AppTestCpythonExtensionBase): - def test_stringobject(self): - module = self.import_extension('foo', [ - ("get_hello1", "METH_NOARGS", - """ - return PyString_FromStringAndSize( - "Hello world<should not be included>", 11); - """), - ("get_hello2", "METH_NOARGS", - """ - return PyString_FromString("Hello world"); - """), - ("test_Size", "METH_NOARGS", - """ - PyObject* s = PyString_FromString("Hello world"); - int result = 0; - - if(PyString_Size(s) == 11) { - result = 1; - } - if(s->ob_type->tp_basicsize != sizeof(void*)*5) - result = 0; - Py_DECREF(s); - return PyBool_FromLong(result); - """), - ("test_Size_exception", "METH_NOARGS", - """ - PyObject* f = PyFloat_FromDouble(1.0); - Py_ssize_t size = PyString_Size(f); - - Py_DECREF(f); - return NULL; - """), - ("test_is_string", "METH_VARARGS", - """ - return PyBool_FromLong(PyString_Check(PyTuple_GetItem(args, 0))); - """)]) - assert module.get_hello1() == 'Hello world' - assert module.get_hello2() == 'Hello world' - assert module.test_Size() - raises(TypeError, module.test_Size_exception) - - assert module.test_is_string("") - assert not module.test_is_string(()) - - def test_string_buffer_init(self): - module = self.import_extension('foo', [ - ("getstring", "METH_NOARGS", - """ - PyObject *s, *t; - char* c; - Py_ssize_t len; - - s = PyString_FromStringAndSize(NULL, 4); - if (s == NULL) - return NULL; - t = PyString_FromStringAndSize(NULL, 3); - if (t == NULL) - return NULL; - Py_DECREF(t); - c = PyString_AsString(s); - c[0] = 'a'; - c[1] = 'b'; - c[3] = 'c'; - return s; - """), - ]) - s = module.getstring() - assert len(s) == 4 - assert s == 'ab\x00c' - - - - def test_AsString(self): - module = self.import_extension('foo', [ - ("getstring", "METH_NOARGS", - """ - PyObject* s1 = PyString_FromStringAndSize("test", 4); - char* c = PyString_AsString(s1); - PyObject* s2 = PyString_FromStringAndSize(c, 4); - Py_DECREF(s1); - return s2; - """), - ]) - s = module.getstring() - assert s == 'test' - - def test_py_string_as_string(self): - module = self.import_extension('foo', [ - ("string_as_string", "METH_VARARGS", - ''' - return PyString_FromStringAndSize(PyString_AsString( - PyTuple_GetItem(args, 0)), 4); - ''' - )]) - assert module.string_as_string("huheduwe") == "huhe" - - def test_py_string_as_string_None(self): - module = self.import_extension('foo', [ - ("string_None", "METH_VARARGS", - ''' - return PyString_AsString(Py_None); - ''' - )]) - raises(TypeError, module.string_None) - - def test_AsStringAndSize(self): - module = self.import_extension('foo', [ - ("getstring", "METH_NOARGS", - """ - PyObject* s1 = PyString_FromStringAndSize("te\\0st", 5); - char *buf; - Py_ssize_t len; - if (PyString_AsStringAndSize(s1, &buf, &len) < 0) - return NULL; - if (len != 5) { - PyErr_SetString(PyExc_AssertionError, "Bad Length"); - return NULL; - } - if (PyString_AsStringAndSize(s1, &buf, NULL) >= 0) { - PyErr_SetString(PyExc_AssertionError, "Should Have failed"); - return NULL; - } - PyErr_Clear(); - Py_DECREF(s1); - Py_INCREF(Py_None); - return Py_None; - """), - ]) - module.getstring() - - def test_format_v(self): - module = self.import_extension('foo', [ - ("test_string_format_v", "METH_VARARGS", - ''' - return helper("bla %d ble %s\\n", - PyInt_AsLong(PyTuple_GetItem(args, 0)), - PyString_AsString(PyTuple_GetItem(args, 1))); - ''' - ) - ], prologue=''' - PyObject* helper(char* fmt, ...) - { - va_list va; - PyObject* res; - va_start(va, fmt); - res = PyString_FromFormatV(fmt, va); - va_end(va); - return res; - } - ''') - res = module.test_string_format_v(1, "xyz") - assert res == "bla 1 ble xyz\n" - - def test_format(self): - module = self.import_extension('foo', [ - ("test_string_format", "METH_VARARGS", - ''' - return PyString_FromFormat("bla %d ble %s\\n", - PyInt_AsLong(PyTuple_GetItem(args, 0)), - PyString_AsString(PyTuple_GetItem(args, 1))); - ''' - ) - ]) - res = module.test_string_format(1, "xyz") - assert res == "bla 1 ble xyz\n" - - def test_intern_inplace(self): - module = self.import_extension('foo', [ - ("test_intern_inplace", "METH_O", - ''' - PyObject *s = args; - Py_INCREF(s); - PyString_InternInPlace(&s); - return s; - ''' - ) - ]) - # This does not test much, but at least the refcounts are checked. - assert module.test_intern_inplace('s') == 's' - -class TestString(BaseApiTest): - def test_string_resize(self, space, api): - py_str = new_empty_str(space, 10) - ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw') - py_str.c_buffer[0] = 'a' - py_str.c_buffer[1] = 'b' - py_str.c_buffer[2] = 'c' - ar[0] = rffi.cast(PyObject, py_str) - api._PyString_Resize(ar, 3) - py_str = rffi.cast(PyStringObject, ar[0]) - assert py_str.c_size == 3 - assert py_str.c_buffer[1] == 'b' - assert py_str.c_buffer[3] == '\x00' - # the same for growing - ar[0] = rffi.cast(PyObject, py_str) - api._PyString_Resize(ar, 10) - py_str = rffi.cast(PyStringObject, ar[0]) - assert py_str.c_size == 10 - assert py_str.c_buffer[1] == 'b' - assert py_str.c_buffer[10] == '\x00' - Py_DecRef(space, ar[0]) - lltype.free(ar, flavor='raw') - - def test_string_buffer(self, space, api): - py_str = new_empty_str(space, 10) - c_buf = py_str.c_ob_type.c_tp_as_buffer - assert c_buf - py_obj = rffi.cast(PyObject, py_str) - assert c_buf.c_bf_getsegcount(py_obj, lltype.nullptr(Py_ssize_tP.TO)) == 1 - ref = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw') - assert c_buf.c_bf_getsegcount(py_obj, ref) == 1 - assert ref[0] == 10 - lltype.free(ref, flavor='raw') - ref = lltype.malloc(rffi.VOIDPP.TO, 1, flavor='raw') - assert c_buf.c_bf_getreadbuffer(py_obj, 0, ref) == 10 - lltype.free(ref, flavor='raw') - Py_DecRef(space, py_obj) - - def test_Concat(self, space, api): - ref = make_ref(space, space.wrap('abc')) - ptr = lltype.malloc(PyObjectP.TO, 1, flavor='raw') - ptr[0] = ref - prev_refcnt = ref.c_ob_refcnt - api.PyString_Concat(ptr, space.wrap('def')) - assert ref.c_ob_refcnt == prev_refcnt - 1 - assert space.str_w(from_ref(space, ptr[0])) == 'abcdef' - api.PyString_Concat(ptr, space.w_None) - assert not ptr[0] - ptr[0] = lltype.nullptr(PyObject.TO) - api.PyString_Concat(ptr, space.wrap('def')) # should not crash - lltype.free(ptr, flavor='raw') - - def test_ConcatAndDel(self, space, api): - ref1 = make_ref(space, space.wrap('abc')) - ref2 = make_ref(space, space.wrap('def')) - ptr = lltype.malloc(PyObjectP.TO, 1, flavor='raw') - ptr[0] = ref1 - prev_refcnf = ref2.c_ob_refcnt - api.PyString_ConcatAndDel(ptr, ref2) - assert space.str_w(from_ref(space, ptr[0])) == 'abcdef' - assert ref2.c_ob_refcnt == prev_refcnf - 1 - Py_DecRef(space, ptr[0]) - ptr[0] = lltype.nullptr(PyObject.TO) - ref2 = make_ref(space, space.wrap('foo')) - prev_refcnf = ref2.c_ob_refcnt - api.PyString_ConcatAndDel(ptr, ref2) # should not crash - assert ref2.c_ob_refcnt == prev_refcnf - 1 - lltype.free(ptr, flavor='raw') - - def test_format(self, space, api): - assert "1 2" == space.unwrap( - api.PyString_Format(space.wrap('%s %d'), space.wrap((1, 2)))) - - def test_asbuffer(self, space, api): - bufp = lltype.malloc(rffi.CCHARPP.TO, 1, flavor='raw') - lenp = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw') - - w_text = space.wrap("text") - assert api.PyObject_AsCharBuffer(w_text, bufp, lenp) == 0 - assert lenp[0] == 4 - assert rffi.charp2str(bufp[0]) == 'text' - - lltype.free(bufp, flavor='raw') - lltype.free(lenp, flavor='raw') - - def test_intern(self, space, api): - buf = rffi.str2charp("test") - w_s1 = api.PyString_InternFromString(buf) - w_s2 = api.PyString_InternFromString(buf) - rffi.free_charp(buf) - assert w_s1 is w_s2 - - def test_AsEncodedObject(self, space, api): - ptr = space.wrap('abc') - - errors = rffi.str2charp("strict") - - encoding = rffi.str2charp("hex") - res = api.PyString_AsEncodedObject( - ptr, encoding, errors) - assert space.unwrap(res) == "616263" - - res = api.PyString_AsEncodedObject( - ptr, encoding, lltype.nullptr(rffi.CCHARP.TO)) - assert space.unwrap(res) == "616263" - rffi.free_charp(encoding) - - encoding = rffi.str2charp("unknown_encoding") - self.raises(space, api, LookupError, api.PyString_AsEncodedObject, - ptr, encoding, errors) - rffi.free_charp(encoding) - - rffi.free_charp(errors) - - res = api.PyString_AsEncodedObject( - ptr, lltype.nullptr(rffi.CCHARP.TO), lltype.nullptr(rffi.CCHARP.TO)) - assert space.unwrap(res) == "abc" - - self.raises(space, api, TypeError, api.PyString_AsEncodedObject, - space.wrap(2), lltype.nullptr(rffi.CCHARP.TO), lltype.nullptr(rffi.CCHARP.TO) - ) - - def test_AsDecodedObject(self, space, api): - w_str = space.wrap('caf\xe9') - encoding = rffi.str2charp("latin-1") - w_res = api.PyString_AsDecodedObject(w_str, encoding, None) - rffi.free_charp(encoding) - assert space.unwrap(w_res) == u"caf\xe9" - - def test_eq(self, space, api): - assert 1 == api._PyString_Eq(space.wrap("hello"), space.wrap("hello")) - assert 0 == api._PyString_Eq(space.wrap("hello"), space.wrap("world")) - - def test_join(self, space, api): - w_sep = space.wrap('<sep>') - w_seq = space.wrap(['a', 'b']) - w_joined = api._PyString_Join(w_sep, w_seq) - assert space.unwrap(w_joined) == 'a<sep>b' diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py --- a/pypy/module/cpyext/typeobject.py +++ b/pypy/module/cpyext/typeobject.py @@ -340,7 +340,7 @@ @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed, header=None, error=-1) def str_getreadbuffer(space, w_str, segment, ref): - from pypy.module.cpyext.stringobject import PyString_AsString + from pypy.module.cpyext.bytesobject import PyString_AsString if segment != 0: raise OperationError(space.w_SystemError, space.wrap ("accessing non-existent string segment")) @@ -353,7 +353,7 @@ @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed, header=None, error=-1) def str_getcharbuffer(space, w_str, segment, ref): - from pypy.module.cpyext.stringobject import PyString_AsString + from pypy.module.cpyext.bytesobject import PyString_AsString if segment != 0: raise OperationError(space.w_SystemError, space.wrap ("accessing non-existent string segment")) @@ -463,7 +463,7 @@ w_typename = space.getattr(w_type, space.wrap('__name__')) heaptype = rffi.cast(PyHeapTypeObject, pto) heaptype.c_ht_name = make_ref(space, w_typename) - from pypy.module.cpyext.stringobject import PyString_AsString + from pypy.module.cpyext.bytesobject import PyString_AsString pto.c_tp_name = PyString_AsString(space, heaptype.c_ht_name) else: pto.c_tp_name = rffi.str2charp(w_type.name) diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -9,7 +9,7 @@ from pypy.module.cpyext.pyobject import ( PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference, make_typedescr, get_typedescr) -from pypy.module.cpyext.stringobject import PyString_Check +from pypy.module.cpyext.bytesobject import PyString_Check from pypy.module.sys.interp_encoding import setdefaultencoding from pypy.module._codecs.interp_codecs import CodecState from pypy.objspace.std import unicodeobject @@ -17,7 +17,7 @@ from rpython.tool.sourcetools import func_renamer import sys -## See comment in stringobject.py. +## See comment in bytesobject.py. PyUnicodeObjectStruct = lltype.ForwardReference() PyUnicodeObject = lltype.Ptr(PyUnicodeObjectStruct) diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -85,7 +85,7 @@ # The "imp" module does not respect this, and is allowed to find # lone .pyc files. # check the .pyc file - if space.config.objspace.usepycfiles and space.config.objspace.lonepycfiles: + if space.config.objspace.lonepycfiles: pycfile = filepart + ".pyc" if file_exists(pycfile): # existing .pyc file @@ -888,17 +888,11 @@ """ w = space.wrap - if space.config.objspace.usepycfiles: - src_stat = os.fstat(fd) - cpathname = pathname + 'c' - mtime = int(src_stat[stat.ST_MTIME]) - mode = src_stat[stat.ST_MODE] - stream = check_compiled_module(space, cpathname, mtime) - else: - cpathname = None - mtime = 0 - mode = 0 - stream = None + src_stat = os.fstat(fd) + cpathname = pathname + 'c' + mtime = int(src_stat[stat.ST_MTIME]) + mode = src_stat[stat.ST_MODE] + stream = check_compiled_module(space, cpathname, mtime) if stream: # existing and up-to-date .pyc file @@ -913,7 +907,7 @@ else: code_w = parse_source_module(space, pathname, source) - if space.config.objspace.usepycfiles and write_pyc: + if write_pyc: if not space.is_true(space.sys.get('dont_write_bytecode')): write_compiled_module(space, code_w, cpathname, mode, mtime) diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -98,6 +98,10 @@ 'a=5\nb=6\rc="""hello\r\nworld"""\r', mode='wb') p.join('mod.py').write( 'a=15\nb=16\rc="""foo\r\nbar"""\r', mode='wb') + setuppkg("test_bytecode", + a = '', + b = '', + c = '') # create compiled/x.py and a corresponding pyc file p = setuppkg("compiled", x = "x = 84") @@ -119,7 +123,7 @@ stream.try_to_find_file_descriptor()) finally: stream.close() - if space.config.objspace.usepycfiles: + if not space.config.translation.sandbox: # also create a lone .pyc file p.join('lone.pyc').write(p.join('x.pyc').read(mode='rb'), mode='wb') @@ -146,6 +150,8 @@ """) def _teardown(space, w_saved_modules): + p = udir.join('impsubdir') + p.remove() space.appexec([w_saved_modules], """ ((saved_path, saved_modules)): import sys @@ -1342,15 +1348,56 @@ assert isinstance(importer, zipimport.zipimporter) -class AppTestNoPycFile(object): +class AppTestWriteBytecode(object): spaceconfig = { - "objspace.usepycfiles": False, - "objspace.lonepycfiles": False + "translation.sandbox": False } + def setup_class(cls): - usepycfiles = cls.spaceconfig['objspace.usepycfiles'] + cls.saved_modules = _setup(cls.space) + sandbox = cls.spaceconfig['translation.sandbox'] + cls.w_sandbox = cls.space.wrap(sandbox) + + def teardown_class(cls): + _teardown(cls.space, cls.saved_modules) + cls.space.appexec([], """ + (): + import sys + sys.dont_write_bytecode = False + """) + + def test_default(self): + import os.path + from test_bytecode import a + assert a.__file__.endswith('a.py') + assert os.path.exists(a.__file__ + 'c') == (not self.sandbox) + + def test_write_bytecode(self): + import os.path + import sys + sys.dont_write_bytecode = False + from test_bytecode import b + assert b.__file__.endswith('b.py') + assert os.path.exists(b.__file__ + 'c') + + def test_dont_write_bytecode(self): + import os.path + import sys + sys.dont_write_bytecode = True + from test_bytecode import c + assert c.__file__.endswith('c.py') + assert not os.path.exists(c.__file__ + 'c') + + +class AppTestWriteBytecodeSandbox(AppTestWriteBytecode): + spaceconfig = { + "translation.sandbox": True + } + + +class _AppTestLonePycFileBase(object): + def setup_class(cls): lonepycfiles = cls.spaceconfig['objspace.lonepycfiles'] - cls.w_usepycfiles = cls.space.wrap(usepycfiles) cls.w_lonepycfiles = cls.space.wrap(lonepycfiles) cls.saved_modules = _setup(cls.space) @@ -1359,10 +1406,7 @@ def test_import_possibly_from_pyc(self): from compiled import x - if self.usepycfiles: - assert x.__file__.endswith('x.pyc') - else: - assert x.__file__.endswith('x.py') + assert x.__file__.endswith('x.pyc') try: from compiled import lone except ImportError: @@ -1371,15 +1415,13 @@ assert self.lonepycfiles, "should not have found 'lone.pyc'" assert lone.__file__.endswith('lone.pyc') -class AppTestNoLonePycFile(AppTestNoPycFile): +class AppTestNoLonePycFile(_AppTestLonePycFileBase): spaceconfig = { - "objspace.usepycfiles": True, "objspace.lonepycfiles": False } -class AppTestLonePycFile(AppTestNoPycFile): +class AppTestLonePycFile(_AppTestLonePycFileBase): spaceconfig = { - "objspace.usepycfiles": True, "objspace.lonepycfiles": True } diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py --- a/pypy/module/sys/__init__.py +++ b/pypy/module/sys/__init__.py @@ -77,7 +77,7 @@ 'meta_path' : 'space.wrap([])', 'path_hooks' : 'space.wrap([])', 'path_importer_cache' : 'space.wrap({})', - 'dont_write_bytecode' : 'space.w_False', + 'dont_write_bytecode' : 'space.wrap(space.config.translation.sandbox)', 'getdefaultencoding' : 'interp_encoding.getdefaultencoding', 'setdefaultencoding' : 'interp_encoding.setdefaultencoding', diff --git a/pypy/module/sys/app.py b/pypy/module/sys/app.py --- a/pypy/module/sys/app.py +++ b/pypy/module/sys/app.py @@ -70,11 +70,11 @@ return None copyright_str = """ -Copyright 2003-2014 PyPy development team. +Copyright 2003-2016 PyPy development team. All Rights Reserved. For further information, see <http://pypy.org> -Portions Copyright (c) 2001-2014 Python Software Foundation. +Portions Copyright (c) 2001-2016 Python Software Foundation. All Rights Reserved. Portions Copyright (c) 2000 BeOpen.com. diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -30,6 +30,11 @@ contains_jmp = jit.JitDriver(greens = ['tp'], reds = 'auto', name = 'tuple.contains') +hash_driver = jit.JitDriver( + name='tuple.hash', + greens=['w_type'], + reds='auto') + class W_AbstractTupleObject(W_Root): __slots__ = () @@ -262,8 +267,14 @@ def length(self): return len(self.wrappeditems) - @jit.look_inside_iff(lambda self, _1: _unroll_condition(self)) def descr_hash(self, space): + if _unroll_condition(self): + return self._descr_hash_unroll(space) + else: + return self._descr_hash_jitdriver(space) + + @jit.unroll_safe + def _descr_hash_unroll(self, space): mult = 1000003 x = 0x345678 z = len(self.wrappeditems) @@ -275,6 +286,20 @@ x += 97531 return space.wrap(intmask(x)) + def _descr_hash_jitdriver(self, space): + mult = 1000003 + x = 0x345678 + z = len(self.wrappeditems) + w_type = space.type(self.wrappeditems[0]) + for w_item in self.wrappeditems: + hash_driver.jit_merge_point(w_type=w_type) + y = space.hash_w(w_item) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) + def descr_eq(self, space, w_other): if not isinstance(w_other, W_AbstractTupleObject): return space.w_NotImplemented diff --git a/pypy/tool/test/test_tab.py b/pypy/tool/test/test_tab.py --- a/pypy/tool/test/test_tab.py +++ b/pypy/tool/test/test_tab.py @@ -6,7 +6,7 @@ from pypy.conftest import pypydir ROOT = os.path.abspath(os.path.join(pypydir, '..')) -EXCLUDE = {} +EXCLUDE = {'/virt_test/lib/python2.7/site-packages/setuptools'} def test_no_tabs(): diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -2042,6 +2042,11 @@ self.vable_flags[op.args[0]] = op.args[2].value return [] + def rewrite_op_jit_enter_portal_frame(self, op): + return [op] + def rewrite_op_jit_leave_portal_frame(self, op): + return [op] + # --------- # ll_math.sqrt_nonneg() diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -944,6 +944,14 @@ pass @arguments("i") + def bhimpl_jit_enter_portal_frame(x): + pass + + @arguments() + def bhimpl_jit_leave_portal_frame(): + pass + + @arguments("i") _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit