Author: Alex Gaynor <alex.gay...@gmail.com> Branch: Changeset: r58272:73639025b26e Date: 2012-10-20 11:13 -0700 http://bitbucket.org/pypy/pypy/changeset/73639025b26e/
Log: merged upstream diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py --- a/pypy/module/_cffi_backend/ctypefunc.py +++ b/pypy/module/_cffi_backend/ctypefunc.py @@ -4,8 +4,9 @@ import sys from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.error import wrap_oserror from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rlib import jit, clibffi, jit_libffi +from pypy.rlib import jit, clibffi, jit_libffi, rposix from pypy.rlib.jit_libffi import CIF_DESCRIPTION, CIF_DESCRIPTION_P from pypy.rlib.jit_libffi import FFI_TYPE, FFI_TYPE_P, FFI_TYPE_PP from pypy.rlib.jit_libffi import SIZE_OF_FFI_ARG @@ -147,9 +148,13 @@ argtype = self.fargs[i] if isinstance(argtype, W_CTypePointer): data = rffi.ptradd(buffer, cif_descr.exchange_args[i]) - if get_mustfree_flag(data): + flag = get_mustfree_flag(data) + if flag == 1: raw_string = rffi.cast(rffi.CCHARPP, data)[0] lltype.free(raw_string, flavor='raw') + elif flag == 2: + file = rffi.cast(rffi.CCHARPP, data)[0] + rffi_fclose(file) lltype.free(buffer, flavor='raw') return w_res @@ -164,6 +169,27 @@ assert isinstance(abi, int) return space.wrap(abi) +rffi_fdopen = rffi.llexternal("fdopen", [rffi.INT, rffi.CCHARP], rffi.CCHARP) +rffi_fclose = rffi.llexternal("fclose", [rffi.CCHARP], rffi.INT) + +def prepare_file_call_argument(fileobj): + import os + space = fileobj.space + fileobj.direct_flush() + fd = fileobj.direct_fileno() + if fd < 0: + raise OperationError(space.w_ValueError, + space.wrap("file has no OS file descriptor")) + try: + fd2 = os.dup(fd) + f = rffi_fdopen(fd2, fileobj.mode) + if not f: + os.close(fd2) + raise OSError(rposix.get_errno(), "fdopen failed") + except OSError, e: + raise wrap_oserror(space, e) + return f + # ____________________________________________________________ diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -157,7 +157,7 @@ space = self.space ob = space.interpclass_w(w_ob) if not isinstance(ob, cdataobj.W_CData): - raise self._convert_error("compatible pointer", w_ob) + raise self._convert_error("cdata pointer", w_ob) other = ob.ctype if not isinstance(other, W_CTypePtrBase): from pypy.module._cffi_backend import ctypearray @@ -177,7 +177,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = [] + _attrs_ = ['is_file'] + _immutable_fields_ = ['is_file'] def __init__(self, space, ctitem): from pypy.module._cffi_backend import ctypearray @@ -186,6 +187,7 @@ extra = "(*)" # obscure case: see test_array_add else: extra = " *" + self.is_file = (ctitem.name == "struct _IO_FILE") W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): @@ -234,7 +236,7 @@ p = rffi.ptradd(cdata, i * self.ctitem.size) return cdataobj.W_CData(space, p, self) - def _prepare_pointer_call_argument(self, w_init): + def _prepare_pointer_call_argument(self, w_init, cdata): space = self.space if (space.isinstance_w(w_init, space.w_list) or space.isinstance_w(w_init, space.w_tuple)): @@ -242,10 +244,19 @@ elif space.isinstance_w(w_init, space.w_basestring): # from a string, we add the null terminator length = space.int_w(space.len(w_init)) + 1 + elif self.is_file: + from pypy.module._file.interp_file import W_File + from pypy.module._cffi_backend import ctypefunc + ob = space.interpclass_w(w_init) + if isinstance(ob, W_File): + result = ctypefunc.prepare_file_call_argument(ob) + rffi.cast(rffi.CCHARPP, cdata)[0] = result + return 2 + return 0 else: - return lltype.nullptr(rffi.CCHARP.TO) + return 0 if self.ctitem.size <= 0: - return lltype.nullptr(rffi.CCHARP.TO) + return 0 try: datasize = ovfcheck(length * self.ctitem.size) except OverflowError: @@ -258,25 +269,19 @@ except Exception: lltype.free(result, flavor='raw') raise - return result + rffi.cast(rffi.CCHARPP, cdata)[0] = result + return 1 def convert_argument_from_object(self, cdata, w_ob): from pypy.module._cffi_backend.ctypefunc import set_mustfree_flag space = self.space ob = space.interpclass_w(w_ob) - if isinstance(ob, cdataobj.W_CData): - buffer = lltype.nullptr(rffi.CCHARP.TO) - else: - buffer = self._prepare_pointer_call_argument(w_ob) - # - if buffer: - rffi.cast(rffi.CCHARPP, cdata)[0] = buffer - set_mustfree_flag(cdata, True) - return True - else: - set_mustfree_flag(cdata, False) + result = (not isinstance(ob, cdataobj.W_CData) and + self._prepare_pointer_call_argument(w_ob, cdata)) + if result == 0: self.convert_from_object(cdata, w_ob) - return False + set_mustfree_flag(cdata, result) + return result def getcfield(self, attr): return self.ctitem.getcfield(attr) diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -2211,3 +2211,56 @@ buffer(p)[:] = bytearray(b"foo\x00") assert len(p) == 4 assert list(p) == [b"f", b"o", b"o", b"\x00"] + +def test_FILE(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + BFILE = new_struct_type("_IO_FILE") + BFILEP = new_pointer_type(BFILE) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BInt = new_primitive_type("int") + BFunc = new_function_type((BCharP, BFILEP), BInt, False) + BFunc2 = new_function_type((BFILEP, BCharP), BInt, True) + ll = find_and_load_library('c') + fputs = ll.load_function(BFunc, "fputs") + fscanf = ll.load_function(BFunc2, "fscanf") + # + import posix + fdr, fdw = posix.pipe() + fr1 = posix.fdopen(fdr, 'r', 256) + fw1 = posix.fdopen(fdw, 'w', 256) + # + fw1.write(b"X") + res = fputs(b"hello world\n", fw1) + assert res >= 0 + fw1.close() + # + p = newp(new_array_type(BCharP, 100), None) + res = fscanf(fr1, b"%s\n", p) + assert res == 1 + assert string(p) == b"Xhello" + fr1.close() + +def test_FILE_only_for_FILE_arg(): + if sys.platform == "win32": + py.test.skip("testing FILE not implemented") + # + B_NOT_FILE = new_struct_type("NOT_FILE") + B_NOT_FILEP = new_pointer_type(B_NOT_FILE) + BChar = new_primitive_type("char") + BCharP = new_pointer_type(BChar) + BInt = new_primitive_type("int") + BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False) + ll = find_and_load_library('c') + fputs = ll.load_function(BFunc, "fputs") + # + import posix + fdr, fdw = posix.pipe() + fr1 = posix.fdopen(fdr, 'r') + fw1 = posix.fdopen(fdw, 'w') + # + e = py.test.raises(TypeError, fputs, b"hello world\n", fw1) + assert str(e.value) == ("initializer for ctype 'struct NOT_FILE *' must " + "be a cdata pointer, not file") diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -98,12 +98,13 @@ try: return W_LongObject.fromfloat(space, w_floatobj.floatval) except OverflowError: - if isnan(w_floatobj.floatval): - raise OperationError( - space.w_ValueError, - space.wrap("cannot convert float NaN to integer")) - raise OperationError(space.w_OverflowError, - space.wrap("cannot convert float infinity to long")) + raise OperationError( + space.w_OverflowError, + space.wrap("cannot convert float infinity to integer")) + except ValueError: + raise OperationError(space.w_ValueError, + space.wrap("cannot convert float NaN to integer")) + def trunc__Float(space, w_floatobj): whole = math.modf(w_floatobj.floatval)[1] try: @@ -308,7 +309,7 @@ # Convert to long and use its hash. try: w_lval = W_LongObject.fromfloat(space, v) - except OverflowError: + except (OverflowError, ValueError): # can't convert to long int -- arbitrary if v < 0: return -271828 diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py --- a/pypy/rlib/rbigint.py +++ b/pypy/rlib/rbigint.py @@ -1,7 +1,7 @@ from pypy.rlib.rarithmetic import LONG_BIT, intmask, longlongmask, r_uint, r_ulonglong, r_longlonglong from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen, is_valid_int from pypy.rlib.rarithmetic import most_neg_value_of_same_type -from pypy.rlib.rfloat import isfinite +from pypy.rlib.rfloat import isinf, isnan from pypy.rlib.debug import make_sure_not_resized, check_regular_int from pypy.rlib.objectmodel import we_are_translated, specialize from pypy.rlib import jit @@ -207,10 +207,11 @@ def fromfloat(dval): """ Create a new bigint object from a float """ # This function is not marked as pure because it can raise - if isfinite(dval): - return rbigint._fromfloat_finite(dval) - else: - raise OverflowError + if isinf(dval): + raise OverflowError("cannot convert float infinity to integer") + if isnan(dval): + raise ValueError("cannot convert float NaN to integer") + return rbigint._fromfloat_finite(dval) @staticmethod @jit.elidable diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py --- a/pypy/rlib/test/test_rbigint.py +++ b/pypy/rlib/test/test_rbigint.py @@ -4,6 +4,7 @@ from random import random, randint, sample from pypy.rlib.rbigint import rbigint, SHIFT, MASK, KARATSUBA_CUTOFF from pypy.rlib.rbigint import _store_digit, _mask_digit +from pypy.rlib.rfloat import NAN from pypy.rlib import rbigint as lobj from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong, intmask from pypy.rpython.test.test_llinterp import interpret @@ -266,6 +267,7 @@ x = 12345.6789e200 x *= x assert raises(OverflowError, rbigint.fromfloat, x) + assert raises(ValueError, rbigint.fromfloat, NAN) # f1 = rbigint.fromfloat(9007199254740991.0) assert f1.tolong() == 9007199254740991 diff --git a/pypy/translator/goal/query.py b/pypy/translator/goal/query.py --- a/pypy/translator/goal/query.py +++ b/pypy/translator/goal/query.py @@ -49,7 +49,7 @@ s_ev = annotator.binding(ev, None) if s_et: if s_et.knowntype == type: - if s_et.__class__ == annmodel.SomeObject: + if s_et.__class__ == annmodel.SomeType: if hasattr(s_et, 'is_type_of') and s_et.is_type_of == [ev]: continue else: _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit