from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
from pypy.module._cffi_backend import ctypeobj, cdataobj


# ____________________________________________________________

@unwrap_spec(w_ctype=ctypeobj.W_CType, w_init=WrappedDefault(None))
def newp(space, w_ctype, w_init):
    return w_ctype.newp(w_init)

# ____________________________________________________________

@unwrap_spec(w_ctype=ctypeobj.W_CType)
def cast(space, w_ctype, w_ob):
    return w_ctype.cast(w_ob)

# ____________________________________________________________

@unwrap_spec(w_ctype=ctypeobj.W_CType)
def callback(space, w_ctype, w_callable, w_error=None):
    from pypy.module._cffi_backend.ccallback import W_CDataCallback
    return W_CDataCallback(space, w_ctype, w_callable, w_error)

# ____________________________________________________________

@unwrap_spec(w_cdata=cdataobj.W_CData)
def typeof(space, w_cdata):
    return w_cdata.ctype

# ____________________________________________________________
Beispiel #2
0
class W_IntObject(W_AbstractIntObject):

    __slots__ = 'intval'
    _immutable_fields_ = ['intval']

    def __init__(self, intval):
        assert is_valid_int(intval)
        self.intval = int(intval)

    def __repr__(self):
        """representation for debugging purposes"""
        return "%s(%d)" % (self.__class__.__name__, self.intval)

    def is_w(self, space, w_other):
        from pypy.objspace.std.boolobject import W_BoolObject
        if (not isinstance(w_other, W_AbstractIntObject)
                or isinstance(w_other, W_BoolObject)):
            return False
        if self.user_overridden_class or w_other.user_overridden_class:
            return self is w_other
        x = self.intval
        try:
            y = space.int_w(w_other)
        except OperationError as e:
            if e.match(space, space.w_OverflowError):
                return False
            raise
        return x == y

    def int_w(self, space, allow_conversion=True):
        return self.intval

    def _int_w(self, space):
        return self.intval

    unwrap = _int_w

    def uint_w(self, space):
        intval = self.intval
        if intval < 0:
            raise oefmt(space.w_ValueError,
                        "cannot convert negative integer to unsigned")
        return r_uint(intval)

    def bigint_w(self, space, allow_conversion=True):
        return self.asbigint()

    def _bigint_w(self, space):
        return self.asbigint()

    def float_w(self, space, allow_conversion=True):
        return float(self.intval)

    # note that we do NOT implement _float_w, because __float__ cannot return
    # an int

    def int(self, space):
        if type(self) is W_IntObject:
            return self
        if not space.is_overloaded(self, space.w_int, '__int__'):
            return space.newint(self.intval)
        return W_Root.int(self, space)

    def asbigint(self):
        return rbigint.fromint(self.intval)

    @staticmethod
    @unwrap_spec(w_x=WrappedDefault(0))
    def descr_new(space, w_inttype, w_x, __posonly__, w_base=None):
        "Create and return a new object.  See help(type) for accurate signature."
        return _new_int(space, w_inttype, w_x, w_base)

    def descr_hash(self, space):
        return space.newint(_hash_int(self.intval))

    def as_w_long(self, space):
        return space.newlong(self.intval)

    def descr_bool(self, space):
        return space.newbool(self.intval != 0)

    def descr_invert(self, space):
        return wrapint(space, ~self.intval)

    def descr_neg(self, space):
        a = self.intval
        try:
            b = ovfcheck(-a)
        except OverflowError:
            if _recover_with_smalllong(space):
                from pypy.objspace.std.smalllongobject import W_SmallLongObject
                x = r_longlong(a)
                return W_SmallLongObject(-x)
            return self.as_w_long(space).descr_neg(space)
        return wrapint(space, b)

    def descr_abs(self, space):
        pos = self.intval >= 0
        return self.int(space) if pos else self.descr_neg(space)

    def descr_float(self, space):
        a = self.intval
        x = float(a)
        return space.newfloat(x)

    def descr_getnewargs(self, space):
        return space.newtuple([wrapint(space, self.intval)])

    def descr_bit_length(self, space):
        val = self.intval
        bits = 0
        if val < 0:
            # warning, "-val" overflows here
            val = -((val + 1) >> 1)
            bits = 1
        while val:
            bits += 1
            val >>= 1
        return space.newint(bits)

    def descr_repr(self, space):
        res = str(self.intval)
        return space.newutf8(res, len(res))  # res is always ASCII

    descr_str = func_with_new_name(descr_repr, 'descr_str')

    def descr_format(self, space, w_format_spec):
        return newformat.run_formatter(space, w_format_spec,
                                       "format_int_or_long", self,
                                       newformat.INT_KIND)

    @unwrap_spec(w_modulus=WrappedDefault(None))
    def descr_pow(self, space, w_exponent, w_modulus=None):
        if isinstance(w_exponent, W_IntObject):
            y = w_exponent.intval
        elif isinstance(w_exponent, W_AbstractIntObject):
            self = self.as_w_long(space)
            return self.descr_pow(space, w_exponent, w_modulus)
        else:
            return space.w_NotImplemented

        x = self.intval
        y = w_exponent.intval

        if space.is_none(w_modulus):
            z = 0
        elif isinstance(w_modulus, W_IntObject):
            z = w_modulus.intval
            if z == 0:
                raise oefmt(space.w_ValueError,
                            "pow() 3rd argument cannot be 0")
        else:
            # can't return NotImplemented (space.pow doesn't do full
            # ternary, i.e. w_modulus.__zpow__(self, w_exponent)), so
            # handle it ourselves
            return _pow_ovf2long(space, x, self, y, w_exponent, w_modulus)

        try:
            result = _pow(space, x, y, z)
        except OverflowError:
            return _pow_ovf2long(space, x, self, y, w_exponent, w_modulus)
        except ValueError:
            # float result, so let avoid a roundtrip in rbigint.
            self = self.descr_float(space)
            w_exponent = w_exponent.descr_float(space)
            return space.pow(self, w_exponent, space.w_None)

        return space.newint(result)

    @unwrap_spec(w_modulus=WrappedDefault(None))
    def descr_rpow(self, space, w_base, w_modulus=None):
        if isinstance(w_base, W_IntObject):
            return w_base.descr_pow(space, self, w_modulus)
        elif isinstance(w_base, W_AbstractIntObject):
            self = self.as_w_long(space)
            return self.descr_rpow(space, self, w_modulus)
        return space.w_NotImplemented

    def _make_descr_cmp(opname):
        op = getattr(operator, opname)
        descr_name = 'descr_' + opname

        @func_renamer(descr_name)
        def descr_cmp(self, space, w_other):
            if isinstance(w_other, W_IntObject):
                i = self.intval
                j = w_other.intval
                return space.newbool(op(i, j))
            elif isinstance(w_other, W_AbstractIntObject):
                self = self.as_w_long(space)
                return getattr(self, descr_name)(space, w_other)
            return space.w_NotImplemented

        return descr_cmp

    descr_lt = _make_descr_cmp('lt')
    descr_le = _make_descr_cmp('le')
    descr_eq = _make_descr_cmp('eq')
    descr_ne = _make_descr_cmp('ne')
    descr_gt = _make_descr_cmp('gt')
    descr_ge = _make_descr_cmp('ge')

    def _make_generic_descr_binop(opname, ovf=True):
        op = getattr(operator,
                     opname + '_' if opname in ('and', 'or') else opname)
        descr_name, descr_rname = 'descr_' + opname, 'descr_r' + opname
        if ovf:
            ovf2long = _make_ovf2long(opname)

        @func_renamer(descr_name)
        def descr_binop(self, space, w_other):
            if isinstance(w_other, W_IntObject):
                x = self.intval
                y = w_other.intval
                if ovf:
                    try:
                        z = ovfcheck(op(x, y))
                    except OverflowError:
                        return ovf2long(space, x, self, y, w_other)
                else:
                    z = op(x, y)
                return wrapint(space, z)
            elif isinstance(w_other, W_AbstractIntObject):
                self = self.as_w_long(space)
                return getattr(self, descr_name)(space, w_other)
            return space.w_NotImplemented

        if opname in COMMUTATIVE_OPS:

            @func_renamer(descr_rname)
            def descr_rbinop(self, space, w_other):
                return descr_binop(self, space, w_other)

            return descr_binop, descr_rbinop

        @func_renamer(descr_rname)
        def descr_rbinop(self, space, w_other):
            if isinstance(w_other, W_IntObject):
                x = self.intval
                y = w_other.intval
                if ovf:
                    try:
                        z = ovfcheck(op(y, x))
                    except OverflowError:
                        return ovf2long(space, y, w_other, x,
                                        self)  # XXX write a test
                else:
                    z = op(y, x)
                return wrapint(space, z)
            elif isinstance(w_other, W_AbstractIntObject):
                self = self.as_w_long(space)
                return getattr(self, descr_rname)(space, w_other)
            return space.w_NotImplemented

        return descr_binop, descr_rbinop

    descr_add, descr_radd = _make_generic_descr_binop('add')
    descr_sub, descr_rsub = _make_generic_descr_binop('sub')
    descr_mul, descr_rmul = _make_generic_descr_binop('mul')

    descr_and, descr_rand = _make_generic_descr_binop('and', ovf=False)
    descr_or, descr_ror = _make_generic_descr_binop('or', ovf=False)
    descr_xor, descr_rxor = _make_generic_descr_binop('xor', ovf=False)

    def _make_descr_binop(func, ovf=True, ovf2small=None):
        opname = func.__name__[1:]
        descr_name, descr_rname = 'descr_' + opname, 'descr_r' + opname
        if ovf:
            ovf2long = _make_ovf2long(opname, ovf2small)

        @func_renamer(descr_name)
        def descr_binop(self, space, w_other):
            if isinstance(w_other, W_IntObject):
                x = self.intval
                y = w_other.intval
                if ovf:
                    try:
                        return func(space, x, y)
                    except OverflowError:
                        return ovf2long(space, x, self, y, w_other)
                else:
                    return func(space, x, y)
            elif isinstance(w_other, W_AbstractIntObject):
                self = self.as_w_long(space)
                return getattr(self, descr_name)(space, w_other)
            return space.w_NotImplemented

        @func_renamer(descr_rname)
        def descr_rbinop(self, space, w_other):
            if isinstance(w_other, W_IntObject):
                x = self.intval
                y = w_other.intval
                if ovf:
                    try:
                        return func(space, y, x)
                    except OverflowError:
                        return ovf2long(space, y, w_other, x, self)
                else:
                    return func(space, y, x)
            elif isinstance(w_other, W_AbstractIntObject):
                self = self.as_w_long(space)
                return getattr(self, descr_rname)(space, w_other)
            return space.w_NotImplemented

        return descr_binop, descr_rbinop

    descr_lshift, descr_rlshift = _make_descr_binop(
        _lshift, ovf2small=_lshift_ovf2small)
    descr_rshift, descr_rrshift = _make_descr_binop(_rshift, ovf=False)

    descr_floordiv, descr_rfloordiv = _make_descr_binop(_floordiv)
    descr_truediv, descr_rtruediv = _make_descr_binop(_truediv)
    descr_mod, descr_rmod = _make_descr_binop(_mod)
    descr_divmod, descr_rdivmod = _make_descr_binop(
        _divmod, ovf2small=_divmod_ovf2small)
class W_FFIObject(W_Root):
    w_gc_wref_remove = None

    @jit.dont_look_inside
    def __init__(self, space, src_ctx):
        self.space = space
        self.types_dict = {}
        self.ctxobj = parse_c_type.allocate_ctxobj(src_ctx)
        self.is_static = bool(src_ctx)
        self.is_nonempty = bool(src_ctx)
        self._finalizer = FreeCtxObj(self.ctxobj)
        if src_ctx:
            self.cached_types = [None] * parse_c_type.get_num_types(src_ctx)
        else:
            self.cached_types = None
        self.w_FFIError = get_ffi_error(space)
        #
        # list of (W_FFIObject, W_LibObject) included in this ffi,
        # where the lib object may be None
        self.included_ffis_libs = []

    def fetch_int_constant(self, name):
        index = parse_c_type.search_in_globals(self.ctxobj.ctx, name)
        if index >= 0:
            g = self.ctxobj.ctx.c_globals[index]
            op = realize_c_type.getop(g.c_type_op)
            if (op == cffi_opcode.OP_CONSTANT_INT
                    or op == cffi_opcode.OP_ENUM):
                return realize_c_type.realize_global_int(self, g, index)
            raise oefmt(
                self.w_FFIError,
                "function, global variable or non-integer constant "
                "'%s' must be fetched from its original 'lib' "
                "object", name)

        for ffi1, _ in self.included_ffis_libs:
            w_result = ffi1.fetch_int_constant(name)
            if w_result is not None:
                return w_result
        return None

    @jit.elidable_promote()
    def get_string_to_type(self, string, consider_fn_as_fnptr):
        x = self.types_dict[string]  # KeyError if not found
        if isinstance(x, W_CType):
            return x
        else:
            assert isinstance(x, realize_c_type.W_RawFuncType)
            if consider_fn_as_fnptr:
                return x.unwrap_as_fnptr_in_elidable()
            else:
                raise KeyError  # don't handle this error case here

    @jit.dont_look_inside
    def parse_string_to_type(self, string, consider_fn_as_fnptr):
        # This cannot be made @elidable because it calls general space
        # functions (indirectly, e.g. via the new_xxx_type() functions).
        # The get_string_to_type() function above is elidable, and we
        # hope that in almost all cases, get_string_to_type() has already
        # found an answer.
        try:
            x = self.types_dict[string]
        except KeyError:
            info = self.ctxobj.info
            index = parse_c_type.parse_c_type(info, string)
            if index < 0:
                num_spaces = rffi.getintfield(info, 'c_error_location')
                raise oefmt(self.w_FFIError, "%s\n%s\n%s^",
                            rffi.charp2str(info.c_error_message), string,
                            " " * num_spaces)
            x = realize_c_type.realize_c_type_or_func(
                self, self.ctxobj.info.c_output, index)
            assert x is not None
            if isinstance(x, realize_c_type.W_RawFuncType):
                x.unwrap_as_fnptr(self)  # force it here
            self.types_dict[string] = x
        #
        if isinstance(x, W_CType):
            return x
        else:
            assert isinstance(x, realize_c_type.W_RawFuncType)
            if consider_fn_as_fnptr:
                return x.unwrap_as_fnptr_in_elidable()
            else:
                raise x.unexpected_fn_type(self)

    def ffi_type(self, w_x, accept):
        space = self.space
        if (accept & ACCEPT_STRING) and (space.isinstance_w(
                w_x, space.w_basestring)):
            string = space.str_w(w_x)
            consider_fn_as_fnptr = (accept & CONSIDER_FN_AS_FNPTR) != 0
            if jit.isconstant(string):
                try:
                    return self.get_string_to_type(string,
                                                   consider_fn_as_fnptr)
                except KeyError:
                    pass
            return self.parse_string_to_type(string, consider_fn_as_fnptr)
        if (accept & ACCEPT_CTYPE) and isinstance(w_x, W_CType):
            return w_x
        if (accept & ACCEPT_CDATA) and isinstance(w_x, W_CData):
            return w_x.ctype
        #
        m1 = "string" if accept & ACCEPT_STRING else ""
        m2 = "ctype object" if accept & ACCEPT_CTYPE else ""
        m3 = "cdata object" if accept & ACCEPT_CDATA else ""
        s12 = " or " if m1 and (m2 or m3) else ""
        s23 = " or " if m2 and m3 else ""
        raise oefmt(space.w_TypeError, "expected a %s%s%s%s%s, got '%T'", m1,
                    s12, m2, s23, m3, w_x)

    @unwrap_spec(module_name=str, _version=int, _types=str)
    def descr_init(self,
                   module_name='?',
                   _version=-1,
                   _types='',
                   w__globals=None,
                   w__struct_unions=None,
                   w__enums=None,
                   w__typenames=None,
                   w__includes=None):
        from pypy.module._cffi_backend import cdlopen
        #
        space = self.space
        if self.is_nonempty:
            raise oefmt(space.w_ValueError,
                        "cannot call FFI.__init__() more than once")
        self.is_nonempty = True
        #
        cdlopen.ffiobj_init(self, module_name, _version, _types, w__globals,
                            w__struct_unions, w__enums, w__typenames,
                            w__includes)

    doc_errno = "the value of 'errno' from/to the C calls"

    def get_errno(self, space):
        return cerrno.get_errno(space)

    def set_errno(self, space, errno):
        cerrno.set_errno(space, space.c_int_w(errno))

    def _more_addressof(self, args_w, w_ctype):
        # contains a loop, the JIT doesn't look inside this helper
        offset = 0
        for i in range(len(args_w)):
            w_ctype, ofs1 = w_ctype.direct_typeoffsetof(args_w[i], i > 0)
            offset += ofs1
        return w_ctype, offset

    def descr_addressof(self, w_arg, args_w):
        """\
Limited equivalent to the '&' operator in C:

1. ffi.addressof(<cdata 'struct-or-union'>) returns a cdata that is a
pointer to this struct or union.

2. ffi.addressof(<cdata>, field-or-index...) returns the address of a
field or array item inside the given structure or array, recursively
in case of nested structures or arrays.

3. ffi.addressof(<library>, "name") returns the address of the named
function or global variable."""
        #
        from pypy.module._cffi_backend.lib_obj import W_LibObject
        space = self.space
        if isinstance(w_arg, W_LibObject) and len(args_w) == 1:
            # case 3 in the docstring
            return w_arg.address_of_func_or_global_var(space.str_w(args_w[0]))
        #
        w_ctype = self.ffi_type(w_arg, ACCEPT_CDATA)
        if len(args_w) == 0:
            # case 1 in the docstring
            if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion)
                    and not isinstance(w_ctype, ctypearray.W_CTypeArray)):
                raise oefmt(space.w_TypeError,
                            "expected a cdata struct/union/array object")
            offset = 0
        else:
            # case 2 in the docstring
            if (not isinstance(w_ctype, ctypestruct.W_CTypeStructOrUnion)
                    and not isinstance(w_ctype, ctypearray.W_CTypeArray)
                    and not isinstance(w_ctype, ctypeptr.W_CTypePointer)):
                raise oefmt(
                    space.w_TypeError,
                    "expected a cdata struct/union/array/pointer object")
            if len(args_w) == 1:
                w_ctype, offset = w_ctype.direct_typeoffsetof(args_w[0], False)
            else:
                w_ctype, offset = self._more_addressof(args_w, w_ctype)
        #
        assert isinstance(w_arg, W_CData)
        cdata = w_arg.unsafe_escaping_ptr()
        cdata = rffi.ptradd(cdata, offset)
        w_ctypeptr = newtype.new_pointer_type(space, w_ctype)
        return W_CData(space, cdata, w_ctypeptr)

    def descr_alignof(self, w_arg):
        """\
Return the natural alignment size in bytes of the argument.
It can be a string naming a C type, or a 'cdata' instance."""
        #
        w_ctype = self.ffi_type(w_arg, ACCEPT_ALL)
        align = w_ctype.alignof()
        return self.space.wrap(align)

    @unwrap_spec(w_cdata=W_CData, size=int)
    def descr_buffer(self, w_cdata, size=-1):
        """\
Return a read-write buffer object that references the raw C data
ointed to by the given 'cdata'.  The 'cdata' must be a pointer or an
array.  Can be passed to functions expecting a buffer, or directly
manipulated with:

    buf[:]          get a copy of it in a regular string, or
    buf[idx]        as a single character
    buf[:] = ...
    buf[idx] = ...  change the content"""
        #
        return cbuffer.buffer(self.space, w_cdata, size)

    @unwrap_spec(w_python_callable=WrappedDefault(None),
                 w_error=WrappedDefault(None))
    def descr_callback(self, w_cdecl, w_python_callable, w_error):
        """\
Return a callback object or a decorator making such a callback object.
'cdecl' must name a C function pointer type.  The callback invokes the
specified 'python_callable' (which may be provided either directly or
via a decorator).  Important: the callback object must be manually
kept alive for as long as the callback may be invoked from the C code."""
        #
        w_ctype = self.ffi_type(
            w_cdecl, ACCEPT_STRING | ACCEPT_CTYPE | CONSIDER_FN_AS_FNPTR)
        space = self.space
        if not space.is_none(w_python_callable):
            return ccallback.W_CDataCallback(space, w_ctype, w_python_callable,
                                             w_error)
        else:
            # decorator mode: returns a single-argument function
            return space.appexec([w_ctype, w_error], """(ctype, error):
                import _cffi_backend
                return lambda python_callable: (
                    _cffi_backend.callback(ctype, python_callable, error))""")

    def descr_cast(self, w_arg, w_ob):
        """\
Similar to a C cast: returns an instance of the named C
type initialized with the given 'source'.  The source is
casted between integers or pointers of any type."""
        #
        w_ctype = self.ffi_type(w_arg, ACCEPT_STRING | ACCEPT_CTYPE)
        return w_ctype.cast(w_ob)

    def descr_from_buffer(self, w_python_buffer):
        """\
Return a <cdata 'char[]'> that points to the data of the given Python
object, which must support the buffer interface.  Note that this is
not meant to be used on the built-in types str, unicode, or bytearray
(you can build 'char[]' arrays explicitly) but only on objects
containing large quantities of raw data in some other format, like
'array.array' or numpy arrays."""
        #
        w_ctchara = newtype._new_chara_type(self.space)
        return func.from_buffer(self.space, w_ctchara, w_python_buffer)

    @unwrap_spec(w_arg=W_CData)
    def descr_from_handle(self, w_arg):
        """\
Cast a 'void *' back to a Python object.  Must be used *only* on the
pointers returned by new_handle(), and *only* as long as the exact
cdata object returned by new_handle() is still alive (somewhere else
in the program).  Failure to follow these rules will crash."""
        #
        return handle.from_handle(self.space, w_arg)

    @unwrap_spec(w_cdata=W_CData)
    def descr_gc(self, w_cdata, w_destructor):
        """\
Return a new cdata object that points to the same data.
Later, when this new cdata object is garbage-collected,
'destructor(old_cdata_object)' will be called."""
        #
        return cgc.gc_weakrefs_build(self, w_cdata, w_destructor)

    def descr___gc_wref_remove(self, w_ref):
        return cgc.gc_wref_remove(self, w_ref)

    @unwrap_spec(replace_with=str)
    def descr_getctype(self, w_cdecl, replace_with=''):
        """\
Return a string giving the C type 'cdecl', which may be itself a
string or a <ctype> object.  If 'replace_with' is given, it gives
extra text to append (or insert for more complicated C types), like a
variable name, or '*' to get actually the C type 'pointer-to-cdecl'."""
        #
        w_ctype = self.ffi_type(w_cdecl, ACCEPT_STRING | ACCEPT_CTYPE)
        replace_with = replace_with.strip(' ')
        if len(replace_with) == 0:
            result = w_ctype.name
        else:
            add_paren = (replace_with[0] == '*'
                         and isinstance(w_ctype, ctypearray.W_CTypeArray))
            add_space = (not add_paren and replace_with[0] != '['
                         and replace_with[0] != '(')
            #
            result = w_ctype.name[:w_ctype.name_position]
            if add_paren:
                result += '('
            if add_space:
                result += ' '
            result += replace_with
            if add_paren:
                result += ')'
            result += w_ctype.name[w_ctype.name_position:]
        # Python 3: bytes -> unicode string
        return self.space.wrap(result)

    @unwrap_spec(code=int)
    def descr_getwinerror(self, code=-1):
        """\
Return either the GetLastError() or the error number given by the
optional 'code' argument, as a tuple '(code, message)'."""
        #
        return cerrno.getwinerror(self.space, code)

    @unwrap_spec(w_init=WrappedDefault(None))
    def descr_new(self, w_arg, w_init):
        """\
Allocate an instance according to the specified C type and return a
pointer to it.  The specified C type must be either a pointer or an
array: ``new('X *')`` allocates an X and returns a pointer to it,
whereas ``new('X[n]')`` allocates an array of n X'es and returns an
array referencing it (which works mostly like a pointer, like in C).
You can also use ``new('X[]', n)`` to allocate an array of a
non-constant length n.

The memory is initialized following the rules of declaring a global
variable in C: by default it is zero-initialized, but an explicit
initializer can be given which can be used to fill all or part of the
memory.

When the returned <cdata> object goes out of scope, the memory is
freed.  In other words the returned <cdata> object has ownership of
the value of type 'cdecl' that it points to.  This means that the raw
data can be used as long as this object is kept alive, but must not be
used for a longer time.  Be careful about that when copying the
pointer to the memory somewhere else, e.g. into another structure."""
        #
        w_ctype = self.ffi_type(w_arg, ACCEPT_STRING | ACCEPT_CTYPE)
        return w_ctype.newp(w_init)

    def descr_new_handle(self, w_arg):
        """\
Return a non-NULL cdata of type 'void *' that contains an opaque
reference to the argument, which can be any Python object.  To cast it
back to the original object, use from_handle().  You must keep alive
the cdata object returned by new_handle()!"""
        #
        space = self.space
        return handle._newp_handle(space, newtype._new_voidp_type(space),
                                   w_arg)

    def _more_offsetof(self, w_ctype, w_arg0, args_w):
        # contains a loop, the JIT doesn't look inside this helper
        w_ctype, offset = w_ctype.direct_typeoffsetof(w_arg0, False)
        for i in range(len(args_w)):
            w_ctype, ofs1 = w_ctype.direct_typeoffsetof(args_w[i], True)
            offset += ofs1
        return offset

    def descr_offsetof(self, w_arg, w_field_or_array, args_w):
        """\
Return the offset of the named field inside the given structure or
array, which must be given as a C type name.  You can give several
field names in case of nested structures.  You can also give numeric
values which correspond to array items, in case of an array type."""
        #
        w_ctype = self.ffi_type(w_arg, ACCEPT_STRING | ACCEPT_CTYPE)
        if len(args_w) == 0:
            _, offset = w_ctype.direct_typeoffsetof(w_field_or_array, False)
        else:
            offset = self._more_offsetof(w_ctype, w_field_or_array, args_w)
        return self.space.wrap(offset)

    @unwrap_spec(w_cdata=W_CData, maxlen=int)
    def descr_string(self, w_cdata, maxlen=-1):
        """\
Return a Python string (or unicode string) from the 'cdata'.  If
'cdata' is a pointer or array of characters or bytes, returns the
null-terminated string.  The returned string extends until the first
null character, or at most 'maxlen' characters.  If 'cdata' is an
array then 'maxlen' defaults to its length.

If 'cdata' is a pointer or array of wchar_t, returns a unicode string
following the same rules.

If 'cdata' is a single character or byte or a wchar_t, returns it as a
string or unicode string.

If 'cdata' is an enum, returns the value of the enumerator as a
string, or 'NUMBER' if the value is out of range."""
        #
        return w_cdata.ctype.string(w_cdata, maxlen)

    def descr_sizeof(self, w_arg):
        """\
Return the size in bytes of the argument.
It can be a string naming a C type, or a 'cdata' instance."""
        #
        if isinstance(w_arg, W_CData):
            size = w_arg._sizeof()
        else:
            w_ctype = self.ffi_type(w_arg, ACCEPT_ALL)
            size = w_ctype.size
            if size < 0:
                raise oefmt(self.w_FFIError,
                            "don't know the size of ctype '%s'", w_ctype.name)
        return self.space.wrap(size)

    def descr_typeof(self, w_arg):
        """\
Parse the C type given as a string and return the
corresponding <ctype> object.
It can also be used on 'cdata' instance to get its C type."""
        #
        if isinstance(w_arg, wrapper.W_FunctionWrapper):
            return w_arg.typeof(self)
        return self.ffi_type(w_arg, ACCEPT_STRING | ACCEPT_CDATA)

    @unwrap_spec(filename="str_or_None", flags=int)
    def descr_dlopen(self, filename, flags=0):
        """\
Load and return a dynamic library identified by 'name'.  The standard
C library can be loaded by passing None.

Note that functions and types declared with 'ffi.cdef()' are not
linked to a particular library, just like C headers.  In the library
we only look for the actual (untyped) symbols at the time of their
first access."""
        #
        from pypy.module._cffi_backend import cdlopen
        return cdlopen.W_DlOpenLibObject(self, filename, flags)

    def descr_dlclose(self, w_lib):
        """\
Close a library obtained with ffi.dlopen().  After this call, access to
"functions or variables from the library will fail (possibly with a
segmentation fault)."""
        #
        from pypy.module._cffi_backend.lib_obj import W_LibObject
        lib = self.space.interp_w(W_LibObject, w_lib)
        lib.cdlopen_close()

    @unwrap_spec(name=str)
    def descr_integer_const(self, name):
        """\
Get the value of an integer constant.

'ffi.integer_const(\"xxx\")' is equivalent to 'lib.xxx' if xxx names an
integer constant.  The point of this function is limited to use cases
where you have an 'ffi' object but not any associated 'lib' object."""
        #
        w_result = self.fetch_int_constant(name)
        if w_result is None:
            raise oefmt(self.space.w_AttributeError,
                        "integer constant '%s' not found", name)
        return w_result
Beispiel #4
0
def divmod(space, w_x, w_y):
    """Return the tuple ((x-x%y)/y, x%y).  Invariant: div*y + mod == x."""
    return space.divmod(w_x, w_y)

# semi-private: works only for new-style classes.
def _issubtype(space, w_cls1, w_cls2):
    return space.issubtype(w_cls1, w_cls2)

# ____________________________________________________________

# Here 0.30103 is an upper bound for log10(2)
NDIGITS_MAX = int((rfloat.DBL_MANT_DIG - rfloat.DBL_MIN_EXP) * 0.30103)
NDIGITS_MIN = -int((rfloat.DBL_MAX_EXP + 1) * 0.30103)

@unwrap_spec(number=float, w_ndigits = WrappedDefault(0))
def round(space, number, w_ndigits):
    """round(number[, ndigits]) -> floating point number

Round a number to a given precision in decimal digits (default 0 digits).
This always returns a floating point number.  Precision may be negative."""
    # Algorithm copied directly from CPython

    # interpret 2nd argument as a Py_ssize_t; clip on overflow
    ndigits = space.getindex_w(w_ndigits, None)

    # nans, infinities and zeros round to themselves
    if not isfinite(number):
        z = number
    elif ndigits == 0:    # common case
        z = round_away(number)
Beispiel #5
0
class W_AbstractBytesObject(W_Root):
    __slots__ = ()
    exact_class_applevel_name = 'bytes'

    def is_w(self, space, w_other):
        if not isinstance(w_other, W_AbstractBytesObject):
            return False
        if self is w_other:
            return True
        if self.user_overridden_class or w_other.user_overridden_class:
            return False
        s1 = space.bytes_w(self)
        s2 = space.bytes_w(w_other)
        if len(s2) > 1:
            return s1 is s2
        if len(s2) == 0:
            return len(s1) == 0
        else:  # strings of len <= 1 are unique-ified
            return len(s1) == 1 and s1[0] == s2[0]

    def immutable_unique_id(self, space):
        if self.user_overridden_class:
            return None
        s = space.bytes_w(self)
        if len(s) > 1:
            uid = compute_unique_id(s)
        else:  # strings of len <= 1 are unique-ified
            if len(s) == 1:
                base = ord(s[0])  # base values 0-255
            else:
                base = 256  # empty string: base value 256
            uid = (base << IDTAG_SHIFT) | IDTAG_SPECIAL
        return space.newint(uid)

    def descr_add(self, space, w_other):
        """x.__add__(y) <==> x+y"""

    def descr_contains(self, space, w_sub):
        """x.__contains__(y) <==> y in x"""

    def descr_eq(self, space, w_other):
        """x.__eq__(y) <==> x==y"""

    def descr_ge(self, space, w_other):
        """x.__ge__(y) <==> x>=y"""

    def descr_getitem(self, space, w_index):
        """x.__getitem__(y) <==> x[y]"""

    def descr_getnewargs(self, space):
        ""

    def descr_gt(self, space, w_other):
        """x.__gt__(y) <==> x>y"""

    def descr_hash(self, space):
        """x.__hash__() <==> hash(x)"""

    def descr_isascii(self, space):
        """B.isascii() -> bool

        Return true if the string is empty or all characters in the string are ASCII, false otherwise.
        ASCII characters have code points in the range U+0000-U+007F."""

    def descr_iter(self, space):
        """x.__iter__() <==> iter(x)"""

    def descr_le(self, space, w_other):
        """x.__le__(y) <==> x<=y"""

    def descr_len(self, space):
        """x.__len__() <==> len(x)"""

    def descr_lt(self, space, w_other):
        """x.__lt__(y) <==> x<y"""

    def descr_mul(self, space, w_times):
        """x.__mul__(n) <==> x*n"""

    def descr_ne(self, space, w_other):
        """x.__ne__(y) <==> x!=y"""

    def descr_repr(self, space):
        """x.__repr__() <==> repr(x)"""

    def descr_rmod(self, space, w_values):
        """x.__rmod__(y) <==> y%x"""

    def descr_rmul(self, space, w_times):
        """x.__rmul__(n) <==> n*x"""

    def descr_str(self, space):
        """x.__str__() <==> str(x)"""

    def descr_capitalize(self, space):
        """B.capitalize() -> copy of B

        Return a capitalized version of B, i.e. make the first character
        have upper case and the rest lower case.
        """

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_center(self, space, width, w_fillchar):
        """B.center(width[, fillchar]) -> copy of B

        Return B centered in a string of length width. Padding is
        done using the specified fill character (default is a space).
        """

    def descr_count(self, space, w_sub, w_start=None, w_end=None):
        """B.count(sub[, start[, end]]) -> int

        Return the number of non-overlapping occurrences of substring sub in
        string B[start:end].  Optional arguments start and end are interpreted
        as in slice notation.
        """

    def descr_decode(self, space, w_encoding=None, w_errors=None):
        """B.decode(encoding=None, errors='strict') -> object

        Decode B using the codec registered for encoding. encoding defaults
        to the default encoding. errors may be given to set a different error
        handling scheme. Default is 'strict' meaning that encoding errors raise
        a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'
        as well as any other name registered with codecs.register_error that is
        able to handle UnicodeDecodeErrors.
        """

    def descr_endswith(self, space, w_suffix, w_start=None, w_end=None):
        """B.endswith(suffix[, start[, end]]) -> bool

        Return True if B ends with the specified suffix, False otherwise.
        With optional start, test B beginning at that position.
        With optional end, stop comparing B at that position.
        suffix can also be a tuple of bytes to try.
        """

    @unwrap_spec(tabsize=int)
    def descr_expandtabs(self, space, tabsize=8):
        """B.expandtabs([tabsize]) -> copy of B

        Return a copy of B where all tab characters are expanded using spaces.
        If tabsize is not given, a tab size of 8 characters is assumed.
        """

    def descr_find(self, space, w_sub, w_start=None, w_end=None):
        """B.find(sub[, start[, end]]) -> int

        Return the lowest index in B where substring sub is found,
        such that sub is contained within B[start:end].  Optional
        arguments start and end are interpreted as in slice notation.

        Return -1 on failure.
        """

    def descr_index(self, space, w_sub, w_start=None, w_end=None):
        """B.index(sub[, start[, end]]) -> int

        Like B.find() but raise ValueError when the substring is not found.
        """

    def descr_isalnum(self, space):
        """B.isalnum() -> bool

        Return True if all characters in B are alphanumeric
        and there is at least one character in B, False otherwise.
        """

    def descr_isalpha(self, space):
        """B.isalpha() -> bool

        Return True if all characters in B are alphabetic
        and there is at least one character in B, False otherwise.
        """

    def descr_isdigit(self, space):
        """B.isdigit() -> bool

        Return True if all characters in B are digits
        and there is at least one character in B, False otherwise.
        """

    def descr_islower(self, space):
        """B.islower() -> bool

        Return True if all cased characters in B are lowercase and there is
        at least one cased character in B, False otherwise.
        """

    def descr_isspace(self, space):
        """B.isspace() -> bool

        Return True if all characters in B are whitespace
        and there is at least one character in B, False otherwise.
        """

    def descr_istitle(self, space):
        """B.istitle() -> bool

        Return True if B is a titlecased string and there is at least one
        character in B, i.e. uppercase characters may only follow uncased
        characters and lowercase characters only cased ones. Return False
        otherwise.
        """

    def descr_isupper(self, space):
        """B.isupper() -> bool

        Return True if all cased characters in B are uppercase and there is
        at least one cased character in B, False otherwise.
        """

    def descr_join(self, space, w_list):
        """B.join(iterable) -> bytes

        Return a bytes object which is the concatenation of the bytes in the
        iterable.  The separator between elements is B.
        """

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_ljust(self, space, width, w_fillchar):
        """B.ljust(width[, fillchar]) -> copy of B

        Return B left-justified in a string of length width. Padding is
        done using the specified fill character (default is a space).
        """

    def descr_lower(self, space):
        """B.lower() -> copy of B

        Return a copy of the string B converted to lowercase.
        """

    def descr_lstrip(self, space, w_chars=None):
        """B.lstrip([chars]) -> copy of B

        Return a copy of the string B with leading whitespace removed.
        If chars is given and not None, remove characters in chars instead.
        """

    def descr_partition(self, space, w_sub):
        """B.partition(sep) -> (head, sep, tail)

        Search for the separator sep in B, and return the part before it,
        the separator itself, and the part after it.  If the separator is not
        found, return B and two empty bytes objects.
        """

    @unwrap_spec(count=int)
    def descr_replace(self, space, w_old, w_new, count=-1):
        """B.replace(old, new[, count]) -> copy of B

        Return a copy of string B with all occurrences of substring
        old replaced by new.  If the optional argument count is
        given, only the first count occurrences are replaced.
        """

    def descr_rfind(self, space, w_sub, w_start=None, w_end=None):
        """B.rfind(sub[, start[, end]]) -> int

        Return the highest index in B where substring sub is found,
        such that sub is contained within B[start:end].  Optional
        arguments start and end are interpreted as in slice notation.

        Return -1 on failure.
        """

    def descr_rindex(self, space, w_sub, w_start=None, w_end=None):
        """B.rindex(sub[, start[, end]]) -> int

        Like B.rfind() but raise ValueError when the substring is not found.
        """

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_rjust(self, space, width, w_fillchar):
        """B.rjust(width[, fillchar]) -> copy of B

        Return B right-justified in a string of length width. Padding is
        done using the specified fill character (default is a space).
        """

    def descr_rpartition(self, space, w_sub):
        """B.rpartition(sep) -> (head, sep, tail)

        Search for the separator sep in B, starting at the end of B, and return
        the part before it, the separator itself, and the part after it.  If
        the separator is not found, return two empty bytes objects and B.
        """

    @unwrap_spec(maxsplit=int)
    def descr_rsplit(self, space, w_sep=None, maxsplit=-1):
        """B.rsplit(sep=None, maxsplit=-1) -> list of bytes objects

        Return a list of the words in the string B, using sep as the
        delimiter string, starting at the end of the string and working
        to the front.  If maxsplit is given, at most maxsplit splits are
        done. If sep is not specified or is None, any whitespace string
        is a separator.
        """

    def descr_rstrip(self, space, w_chars=None):
        """B.rstrip([chars]) -> copy of B

        Return a copy of the string B with trailing whitespace removed.
        If chars is given and not None, remove characters in chars instead.
        """

    @unwrap_spec(maxsplit=int)
    def descr_split(self, space, w_sep=None, maxsplit=-1):
        """B.split(sep=None, maxsplit=-1) -> list of bytes objects

        Return a list of the words in the string B, using sep as the
        delimiter string.  If maxsplit is given, at most maxsplit
        splits are done. If sep is not specified or is None, any
        whitespace string is a separator and empty strings are removed
        from the result.
        """

    @unwrap_spec(keepends=bool)
    def descr_splitlines(self, space, keepends=False):
        """B.splitlines(keepends=False) -> list of bytes objects

        Return a list of the lines in B, breaking at line boundaries.
        Line breaks are not included in the resulting list unless keepends
        is given and true.
        """

    def descr_startswith(self, space, w_prefix, w_start=None, w_end=None):
        """B.startswith(prefix[, start[, end]]) -> bool

        Return True if B starts with the specified prefix, False otherwise.
        With optional start, test B beginning at that position.
        With optional end, stop comparing B at that position.
        prefix can also be a tuple of bytes to try.
        """

    def descr_strip(self, space, w_chars=None):
        """B.strip([chars]) -> copy of B

        Return a copy of the string B with leading and trailing
        whitespace removed.
        If chars is given and not None, remove characters in chars instead.
        """

    def descr_swapcase(self, space):
        """B.swapcase() -> copy of B

        Return a copy of the string B with uppercase characters
        converted to lowercase and vice versa.
        """

    def descr_title(self, space):
        """B.title() -> copy of B

        Return a titlecased version of B, i.e. words start with uppercase
        characters, all remaining cased characters have lowercase.
        """

    @unwrap_spec(w_delete=WrappedDefault(''))
    def descr_translate(self, space, w_table, w_delete):
        """B.translate(table[, deletechars]) -> copy of B

        Return a copy of the string B, where all characters occurring
        in the optional argument deletechars are removed, and the
        remaining characters have been mapped through the given
        translation table, which must be a string of length 256 or None.
        If the table argument is None, no translation is applied and
        the operation simply removes the characters in deletechars.
        """

    def descr_upper(self, space):
        """B.upper() -> copy of B

        Return a copy of the string B converted to uppercase.
        """

    @unwrap_spec(width=int)
    def descr_zfill(self, space, width):
        """B.zfill(width) -> copy of B

        Pad a numeric string B with zeros on the left, to fill a field
        of the specified width. The string B is never truncated.
        """

    def descr_mod(self, space, w_values):
        """B % values -> bytes
Beispiel #6
0
class W_BytearrayObject(W_Root):
    import_from_mixin(StringMethods)
    _KIND1 = "bytearray"
    _KIND2 = "bytearray"

    def __init__(self, data):
        check_list_of_chars(data)
        self._data = resizable_list_supporting_raw_ptr(data)
        self._offset = 0
        # NOTE: the bytearray data is in 'self._data[self._offset:]'
        check_nonneg(self._offset)
        _tweak_for_tests(self)

    def getdata(self):
        if self._offset > 0:
            self._data = self._data[self._offset:]
            self._offset = 0
        return self._data

    def __repr__(self):
        """representation for debugging purposes"""
        return "%s(%s)" % (self.__class__.__name__,
                           ''.join(self._data[self._offset:]))

    def buffer_w(self, space, flags):
        return SimpleView(BytearrayBuffer(self))

    def readbuf_w(self, space):
        return BytearrayBuffer(self, readonly=True)

    def writebuf_w(self, space):
        return BytearrayBuffer(self)

    def charbuf_w(self, space):
        return ''.join(self.getdata())

    def bytearray_list_of_chars_w(self, space):
        return self.getdata()

    def nonmovable_carray(self, space):
        return BytearrayBuffer(self).get_raw_address()

    def _new(self, value):
        if value is self._data:
            value = value[:]
        return W_BytearrayObject(value)

    def _new_from_buffer(self, buffer):
        return W_BytearrayObject([buffer[i] for i in range(len(buffer))])

    def _new_from_list(self, value):
        return W_BytearrayObject(value)

    def _empty(self):
        return W_BytearrayObject([])

    def _len(self):
        return len(self._data) - self._offset

    def _fixindex(self, space, index, errmsg="bytearray index out of range"):
        # for getitem/setitem/delitem of a single char
        if index >= 0:
            index += self._offset
            if index >= len(self._data):
                raise OperationError(space.w_IndexError, space.newtext(errmsg))
        else:
            index += len(self._data)    # count from the end
            if index < self._offset:
                raise OperationError(space.w_IndexError, space.newtext(errmsg))
        check_nonneg(index)
        return index

    def _getitem_result(self, space, index):
        character = self._data[self._fixindex(space, index)]
        return space.newint(ord(character))

    def _val(self, space):
        return self.getdata()

    @staticmethod
    def _use_rstr_ops(space, w_other):
        return False

    @staticmethod
    def _op_val(space, w_other, strict=None):
        # bytearray does not enforce the strict restriction (on strip at least)
        if isinstance(w_other, W_BytesObject):
            return w_other.str_w(space)
        return space.buffer_w(w_other, space.BUF_SIMPLE).as_str()

    def _chr(self, char):
        assert len(char) == 1
        return str(char)[0]

    def _multi_chr(self, char):
        return [char]

    @staticmethod
    def _builder(size=100):
        return ByteListBuilder(size)

    def _newlist_unwrapped(self, space, res):
        return space.newlist([W_BytearrayObject(i) for i in res])

    def _isupper(self, ch):
        return ch.isupper()

    def _islower(self, ch):
        return ch.islower()

    def _istitle(self, ch):
        return ch.isupper()

    def _isspace(self, ch):
        return ch.isspace()

    def _isalpha(self, ch):
        return ch.isalpha()

    def _isalnum(self, ch):
        return ch.isalnum()

    def _isdigit(self, ch):
        return ch.isdigit()

    _iscased = _isalpha

    def _islinebreak(self, ch):
        return (ch == '\n') or (ch == '\r')

    def _upper(self, ch):
        if ch.islower():
            o = ord(ch) - 32
            return chr(o)
        else:
            return ch

    def _lower(self, ch):
        if ch.isupper():
            o = ord(ch) + 32
            return chr(o)
        else:
            return ch

    _title = _upper

    def _join_return_one(self, space, w_obj):
        return False

    def _join_check_item(self, space, w_obj):
        if (space.isinstance_w(w_obj, space.w_bytes) or
            space.isinstance_w(w_obj, space.w_bytearray)):
            return 0
        return 1

    def ord(self, space):
        length = self._len()
        if length != 1:
            raise oefmt(space.w_TypeError,
                        "ord() expected a character, but string of length %d "
                        "found", length)
        return space.newint(ord(self._data[self._offset]))

    @staticmethod
    def descr_new(space, w_bytearraytype, __args__):
        return new_bytearray(space, w_bytearraytype, [])

    def descr_reduce(self, space):
        from pypy.interpreter.unicodehelper import str_decode_latin_1

        assert isinstance(self, W_BytearrayObject)
        w_dict = self.getdict(space)
        if w_dict is None:
            w_dict = space.w_None
        s, _, lgt = str_decode_latin_1(''.join(self.getdata()), 'strict',
            True, None)
        return space.newtuple([
            space.type(self), space.newtuple2(
                space.newutf8(s, lgt), space.newtext('latin-1')),
            w_dict])

    @staticmethod
    def descr_fromhex(space, w_bytearraytype, w_hexstring):
        hexstring = space.text_w(w_hexstring)
        data = _hexstring_to_array(space, hexstring)
        # in CPython bytearray.fromhex is a staticmethod, so
        # we ignore w_type and always return a bytearray
        return new_bytearray(space, space.w_bytearray, data)

    @unwrap_spec(encoding='text_or_none', errors='text_or_none')
    def descr_init(self, space, w_source=None, encoding=None, errors=None):
        if w_source is None:
            w_source = space.newbytes('')
        if encoding is not None:
            from pypy.objspace.std.unicodeobject import encode_object
            # if w_source is an integer this correctly raises a
            # TypeError the CPython error message is: "encoding or
            # errors without a string argument" ours is: "expected
            # unicode, got int object"
            w_source = encode_object(space, w_source, encoding, errors)

        # Is it an integer?
        # Note that we're calling space.getindex_w() instead of space.int_w().
        try:
            count = space.getindex_w(w_source, space.w_OverflowError)
        except OperationError as e:
            if not e.match(space, space.w_TypeError):
                raise
        else:
            if count < 0:
                raise oefmt(space.w_ValueError, "bytearray negative count")
            self._data = resizable_list_supporting_raw_ptr(['\0'] * count)
            self._offset = 0
            return

        data = makebytearraydata_w(space, w_source)
        self._data = resizable_list_supporting_raw_ptr(data)
        self._offset = 0
        _tweak_for_tests(self)

    def descr_repr(self, space):
        s, start, end, _ = self._convert_idx_params(space, None, None)

        # Good default if there are no replacements.
        buf = StringBuilder(len("bytearray(b'')") + (end - start))

        buf.append("bytearray(b")
        quote = "'"
        for i in range(start, end):
            c = s[i]
            if c == '"':
                quote = "'"
                break
            elif c == "'":
                quote = '"'
        buf.append(quote)

        for i in range(start, end):
            c = s[i]

            if c == '\\' or c == "'":
                buf.append('\\')
                buf.append(c)
            elif c == '\t':
                buf.append('\\t')
            elif c == '\r':
                buf.append('\\r')
            elif c == '\n':
                buf.append('\\n')
            elif not '\x20' <= c < '\x7f':
                n = ord(c)
                buf.append('\\x')
                buf.append("0123456789abcdef"[n >> 4])
                buf.append("0123456789abcdef"[n & 0xF])
            else:
                buf.append(c)

        buf.append(quote)
        buf.append(")")

        return space.newtext(buf.build())

    def descr_str(self, space):
        return space.newtext(''.join(self.getdata()))

    def descr_eq(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            return space.newbool(self.getdata() == w_other.getdata())

        try:
            buffer = _get_buffer(space, w_other)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise

        value = self._val(space)
        buffer_len = buffer.getlength()

        if len(value) != buffer_len:
            return space.newbool(False)

        min_length = min(len(value), buffer_len)
        return space.newbool(_memcmp(value, buffer, min_length) == 0)

    def descr_ne(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            return space.newbool(self.getdata() != w_other.getdata())

        try:
            buffer = _get_buffer(space, w_other)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise

        value = self._val(space)
        buffer_len = buffer.getlength()

        if len(value) != buffer_len:
            return space.newbool(True)

        min_length = min(len(value), buffer_len)
        return space.newbool(_memcmp(value, buffer, min_length) != 0)

    def _comparison_helper(self, space, w_other):
        value = self._val(space)

        if isinstance(w_other, W_BytearrayObject):
            other = w_other.getdata()
            other_len = len(other)
            cmp = _memcmp(value, other, min(len(value), len(other)))
        elif isinstance(w_other, W_BytesObject):
            other = w_other.str_w(space)
            other_len = len(other)
            cmp = _memcmp(value, other, min(len(value), len(other)))
        else:
            try:
                buffer = _get_buffer(space, w_other)
            except OperationError as e:
                if e.match(space, space.w_TypeError):
                    return False, 0, 0
                raise
            other_len = len(buffer)
            cmp = _memcmp(value, buffer, min(len(value), len(buffer)))

        return True, cmp, other_len

    def descr_lt(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp < 0 or (cmp == 0 and self._len() < other_len))

    def descr_le(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp < 0 or (cmp == 0 and self._len() <= other_len))

    def descr_gt(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp > 0 or (cmp == 0 and self._len() > other_len))

    def descr_ge(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp > 0 or (cmp == 0 and self._len() >= other_len))

    def descr_iter(self, space):
        return space.newseqiter(self)

    def descr_inplace_add(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            self._data += w_other.getdata()
            return self

        self._data += self._op_val(space, w_other)
        return self

    def descr_inplace_mul(self, space, w_times):
        try:
            times = space.getindex_w(w_times, space.w_OverflowError)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise
        data = self.getdata()
        data *= times
        return self

    def descr_setitem(self, space, w_index, w_other):
        if isinstance(w_index, W_SliceObject):
            sequence2 = makebytearraydata_w(space, w_other)
            oldsize = self._len()
            start, stop, step, slicelength = w_index.indices4(space, oldsize)
            if start == 0 and step == 1 and len(sequence2) <= slicelength:
                self._delete_from_start(slicelength - len(sequence2))
                slicelength = len(sequence2)
                if slicelength == 0:
                    return
            data = self._data
            start += self._offset
            _setitem_slice_helper(space, data, start, step,
                                  slicelength, sequence2, empty_elem='\x00')
        else:
            idx = space.getindex_w(w_index, space.w_IndexError,
                                   "bytearray index")
            newvalue = space.byte_w(w_other)
            self._data[self._fixindex(space, idx)] = newvalue

    def descr_delitem(self, space, w_idx):
        if isinstance(w_idx, W_SliceObject):
            start, stop, step, slicelength = w_idx.indices4(space, self._len())
            if start == 0 and step == 1:
                self._delete_from_start(slicelength)
            else:
                _delitem_slice_helper(space, self._data,
                                      start + self._offset, step, slicelength)
        else:
            idx = space.getindex_w(w_idx, space.w_IndexError,
                                   "bytearray index")
            idx = self._fixindex(space, idx)
            if idx == self._offset:    # fast path for del x[0] or del[-len]
                self._delete_from_start(1)
            else:
                del self._data[idx]

    def _delete_from_start(self, n):
        assert n >= 0
        self._offset += n
        jit.conditional_call(self._offset > len(self._data) / 2,
                             _shrink_after_delete_from_start, self)

    def descr_append(self, space, w_item):
        self._data.append(space.byte_w(w_item))

    def descr_extend(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            self._data += w_other.getdata()
        elif isinstance(w_other, W_BytesObject):    # performance only
            self._data += w_other.str_w(space)
        else:
            self._data += makebytearraydata_w(space, w_other)

    def descr_insert(self, space, w_idx, w_other):
        where = space.int_w(w_idx)
        data = self.getdata()
        index = get_positive_index(where, len(data))
        val = space.byte_w(w_other)
        data.insert(index, val)

    @unwrap_spec(w_idx=WrappedDefault(-1))
    def descr_pop(self, space, w_idx):
        index = space.int_w(w_idx)
        if self._len() == 0:
            raise oefmt(space.w_IndexError, "pop from empty bytearray")
        index = self._fixindex(space, index, "pop index out of range")
        result = self._data.pop(index)
        return space.newint(ord(result))

    def descr_remove(self, space, w_char):
        char = space.int_w(space.index(w_char))
        _data = self._data
        for index in range(self._offset, len(_data)):
            if ord(_data[index]) == char:
                del _data[index]
                return
        raise oefmt(space.w_ValueError, "value not found in bytearray")

    _StringMethods_descr_contains = descr_contains
    def descr_contains(self, space, w_sub):
        if space.isinstance_w(w_sub, space.w_int):
            char = space.int_w(w_sub)
            return _descr_contains_bytearray(self.getdata(), space, char)

        return self._StringMethods_descr_contains(space, w_sub)

    def descr_add(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            return self._new(self.getdata() + w_other.getdata())

        try:
            byte_string = self._op_val(space, w_other)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise
        return self._new(self.getdata() + list(byte_string))

    def descr_reverse(self, space):
        self.getdata().reverse()

    def descr_alloc(self, space):
        return space.newint(len(self._data) + 1)   # includes the _offset part

    def _convert_idx_params(self, space, w_start, w_end):
        # optimization: this version doesn't force getdata()
        start, end = unwrap_start_stop(space, self._len(), w_start, w_end)
        ofs = self._offset
        return (self._data, start + ofs, end + ofs, ofs)

    def descr_getitem(self, space, w_index):
        # optimization: this version doesn't force getdata()
        if isinstance(w_index, W_SliceObject):
            start, stop, step, sl = w_index.indices4(space, self._len())
            if sl == 0:
                return self._empty()
            elif step == 1:
                assert start >= 0 and stop >= 0
                ofs = self._offset
                return self._new(self._data[start + ofs : stop + ofs])
            else:
                start += self._offset
                ret = _descr_getslice_slowpath(self._data, start, step, sl)
                return self._new_from_list(ret)

        index = space.getindex_w(w_index, space.w_IndexError, self._KIND1)
        return self._getitem_result(space, index)
Beispiel #7
0
        if isinstance(ctx, rsre_core.StrMatchContext):
            assert use_builder == 'S'
            start = ctx._real_pos(start)
            end = ctx._real_pos(end)
            return strbuilder.append_slice(ctx._string, start, end)
        if isinstance(ctx, rsre_utf8.Utf8MatchContext):
            assert use_builder == 'U'
            return strbuilder.append_slice(ctx._utf8, start, end)
        assert 0, "unreachable"
    else:
        sublist_w.append(slice_w(space, ctx, start, end, space.w_None))


@unwrap_spec(flags=int,
             groups=int,
             w_groupindex=WrappedDefault(None),
             w_indexgroup=WrappedDefault(None))
def SRE_Pattern__new__(space,
                       w_subtype,
                       w_pattern,
                       flags,
                       w_code,
                       groups=0,
                       w_groupindex=None,
                       w_indexgroup=None):
    n = space.len_w(w_code)
    code = [
        intmask(space.uint_w(space.getitem(w_code, space.newint(i))))
        for i in range(n)
    ]
    #
Beispiel #8
0
            return ch

    def _lower(self, ch):
        if ch.isupper():
            o = ord(ch) + 32
            return chr(o)
        else:
            return ch

    _title = _upper

    def _newlist_unwrapped(self, space, lst):
        return space.newlist_bytes(lst)

    @staticmethod
    @unwrap_spec(w_object=WrappedDefault(""))
    def descr_new(space, w_stringtype, w_object):
        # NB. the default value of w_object is really a *wrapped* empty string:
        #     there is gateway magic at work
        w_obj = space.str(w_object)
        if space.is_w(w_stringtype, space.w_str):
            return w_obj  # XXX might be reworked when space.str() typechecks
        value = space.str_w(w_obj)
        w_obj = space.allocate_instance(W_BytesObject, w_stringtype)
        W_BytesObject.__init__(w_obj, value)
        return w_obj

    def descr_repr(self, space):
        s = self._value
        quote = "'"
        if quote in s and '"' not in s:
Beispiel #9
0
class W_AbstractBytesObject(W_Root):
    __slots__ = ()

    def is_w(self, space, w_other):
        if not isinstance(w_other, W_AbstractBytesObject):
            return False
        if self is w_other:
            return True
        if self.user_overridden_class or w_other.user_overridden_class:
            return False
        return space.str_w(self) is space.str_w(w_other)

    def immutable_unique_id(self, space):
        if self.user_overridden_class:
            return None
        return space.wrap(compute_unique_id(space.str_w(self)))

    def unicode_w(self, space):
        # Use the default encoding.
        encoding = getdefaultencoding(space)
        return space.unicode_w(decode_object(space, self, encoding, None))

    def descr_add(self, space, w_other):
        """x.__add__(y) <==> x+y"""

    def descr_contains(self, space, w_sub):
        """x.__contains__(y) <==> y in x"""

    def descr_eq(self, space, w_other):
        """x.__eq__(y) <==> x==y"""

    def descr__format__(self, space, w_format_spec):
        """S.__format__(format_spec) -> string

        Return a formatted version of S as described by format_spec.
        """

    def descr_ge(self, space, w_other):
        """x.__ge__(y) <==> x>=y"""

    def descr_getitem(self, space, w_index):
        """x.__getitem__(y) <==> x[y]"""

    def descr_getnewargs(self, space):
        ""

    def descr_getslice(self, space, w_start, w_stop):
        """x.__getslice__(i, j) <==> x[i:j]

        Use of negative indices is not supported.
        """

    def descr_gt(self, space, w_other):
        """x.__gt__(y) <==> x>y"""

    def descr_hash(self, space):
        """x.__hash__() <==> hash(x)"""

    def descr_le(self, space, w_other):
        """x.__le__(y) <==> x<=y"""

    def descr_len(self, space):
        """x.__len__() <==> len(x)"""

    def descr_lt(self, space, w_other):
        """x.__lt__(y) <==> x<y"""

    def descr_mod(self, space, w_values):
        """x.__mod__(y) <==> x%y"""

    def descr_mul(self, space, w_times):
        """x.__mul__(n) <==> x*n"""

    def descr_ne(self, space, w_other):
        """x.__ne__(y) <==> x!=y"""

    def descr_repr(self, space):
        """x.__repr__() <==> repr(x)"""

    def descr_rmod(self, space, w_values):
        """x.__rmod__(y) <==> y%x"""

    def descr_rmul(self, space, w_times):
        """x.__rmul__(n) <==> n*x"""

    def descr_str(self, space):
        """x.__str__() <==> str(x)"""

    def descr_capitalize(self, space):
        """S.capitalize() -> string

        Return a capitalized version of S, i.e. make the first character
        have upper case and the rest lower case.
        """

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_center(self, space, width, w_fillchar):
        """S.center(width[, fillchar]) -> string

        Return S centered in a string of length width. Padding is
        done using the specified fill character (default is a space).
        """

    def descr_count(self, space, w_sub, w_start=None, w_end=None):
        """S.count(sub[, start[, end]]) -> int

        Return the number of non-overlapping occurrences of substring sub in
        string S[start:end].  Optional arguments start and end are interpreted
        as in slice notation.
        """

    def descr_decode(self, space, w_encoding=None, w_errors=None):
        """S.decode(encoding=None, errors='strict') -> object

        Decode S using the codec registered for encoding. encoding defaults
        to the default encoding. errors may be given to set a different error
        handling scheme. Default is 'strict' meaning that encoding errors raise
        a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'
        as well as any other name registered with codecs.register_error that is
        able to handle UnicodeDecodeErrors.
        """

    def descr_encode(self, space, w_encoding=None, w_errors=None):
        """S.encode(encoding=None, errors='strict') -> object

        Encode S using the codec registered for encoding. encoding defaults
        to the default encoding. errors may be given to set a different error
        handling scheme. Default is 'strict' meaning that encoding errors raise
        a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and
        'xmlcharrefreplace' as well as any other name registered with
        codecs.register_error that is able to handle UnicodeEncodeErrors.
        """

    def descr_endswith(self, space, w_suffix, w_start=None, w_end=None):
        """S.endswith(suffix[, start[, end]]) -> bool

        Return True if S ends with the specified suffix, False otherwise.
        With optional start, test S beginning at that position.
        With optional end, stop comparing S at that position.
        suffix can also be a tuple of strings to try.
        """

    @unwrap_spec(tabsize=int)
    def descr_expandtabs(self, space, tabsize=8):
        """S.expandtabs([tabsize]) -> string

        Return a copy of S where all tab characters are expanded using spaces.
        If tabsize is not given, a tab size of 8 characters is assumed.
        """

    def descr_find(self, space, w_sub, w_start=None, w_end=None):
        """S.find(sub[, start[, end]]) -> int

        Return the lowest index in S where substring sub is found,
        such that sub is contained within S[start:end].  Optional
        arguments start and end are interpreted as in slice notation.

        Return -1 on failure.
        """

    def descr_format(self, space, __args__):
        """S.format(*args, **kwargs) -> string

        Return a formatted version of S, using substitutions from args and
        kwargs.  The substitutions are identified by braces ('{' and '}').
        """

    def descr_index(self, space, w_sub, w_start=None, w_end=None):
        """S.index(sub[, start[, end]]) -> int

        Like S.find() but raise ValueError when the substring is not found.
        """

    def descr_isalnum(self, space):
        """S.isalnum() -> bool

        Return True if all characters in S are alphanumeric
        and there is at least one character in S, False otherwise.
        """

    def descr_isalpha(self, space):
        """S.isalpha() -> bool

        Return True if all characters in S are alphabetic
        and there is at least one character in S, False otherwise.
        """

    def descr_isdigit(self, space):
        """S.isdigit() -> bool

        Return True if all characters in S are digits
        and there is at least one character in S, False otherwise.
        """

    def descr_islower(self, space):
        """S.islower() -> bool

        Return True if all cased characters in S are lowercase and there is
        at least one cased character in S, False otherwise.
        """

    def descr_isspace(self, space):
        """S.isspace() -> bool

        Return True if all characters in S are whitespace
        and there is at least one character in S, False otherwise.
        """

    def descr_istitle(self, space):
        """S.istitle() -> bool

        Return True if S is a titlecased string and there is at least one
        character in S, i.e. uppercase characters may only follow uncased
        characters and lowercase characters only cased ones. Return False
        otherwise.
        """

    def descr_isupper(self, space):
        """S.isupper() -> bool

        Return True if all cased characters in S are uppercase and there is
        at least one cased character in S, False otherwise.
        """

    def descr_join(self, space, w_list):
        """S.join(iterable) -> string

        Return a string which is the concatenation of the strings in the
        iterable.  The separator between elements is S.
        """

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_ljust(self, space, width, w_fillchar):
        """S.ljust(width[, fillchar]) -> string

        Return S left-justified in a string of length width. Padding is
        done using the specified fill character (default is a space).
        """

    def descr_lower(self, space):
        """S.lower() -> string

        Return a copy of the string S converted to lowercase.
        """

    def descr_lstrip(self, space, w_chars=None):
        """S.lstrip([chars]) -> string or unicode

        Return a copy of the string S with leading whitespace removed.
        If chars is given and not None, remove characters in chars instead.
        If chars is unicode, S will be converted to unicode before stripping
        """

    def descr_partition(self, space, w_sub):
        """S.partition(sep) -> (head, sep, tail)

        Search for the separator sep in S, and return the part before it,
        the separator itself, and the part after it.  If the separator is not
        found, return S and two empty strings.
        """

    @unwrap_spec(count=int)
    def descr_replace(self, space, w_old, w_new, count=-1):
        """S.replace(old, new[, count]) -> string

        Return a copy of string S with all occurrences of substring
        old replaced by new.  If the optional argument count is
        given, only the first count occurrences are replaced.
        """

    def descr_rfind(self, space, w_sub, w_start=None, w_end=None):
        """S.rfind(sub[, start[, end]]) -> int

        Return the highest index in S where substring sub is found,
        such that sub is contained within S[start:end].  Optional
        arguments start and end are interpreted as in slice notation.

        Return -1 on failure.
        """

    def descr_rindex(self, space, w_sub, w_start=None, w_end=None):
        """S.rindex(sub[, start[, end]]) -> int

        Like S.rfind() but raise ValueError when the substring is not found.
        """

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_rjust(self, space, width, w_fillchar):
        """S.rjust(width[, fillchar]) -> string

        Return S right-justified in a string of length width. Padding is
        done using the specified fill character (default is a space).
        """

    def descr_rpartition(self, space, w_sub):
        """S.rpartition(sep) -> (head, sep, tail)

        Search for the separator sep in S, starting at the end of S, and return
        the part before it, the separator itself, and the part after it.  If
        the separator is not found, return two empty strings and S.
        """

    @unwrap_spec(maxsplit=int)
    def descr_rsplit(self, space, w_sep=None, maxsplit=-1):
        """S.rsplit(sep=None, maxsplit=-1) -> list of strings

        Return a list of the words in the string S, using sep as the
        delimiter string, starting at the end of the string and working
        to the front.  If maxsplit is given, at most maxsplit splits are
        done. If sep is not specified or is None, any whitespace string
        is a separator.
        """

    def descr_rstrip(self, space, w_chars=None):
        """S.rstrip([chars]) -> string or unicode

        Return a copy of the string S with trailing whitespace removed.
        If chars is given and not None, remove characters in chars instead.
        If chars is unicode, S will be converted to unicode before stripping
        """

    @unwrap_spec(maxsplit=int)
    def descr_split(self, space, w_sep=None, maxsplit=-1):
        """S.split(sep=None, maxsplit=-1) -> list of strings

        Return a list of the words in the string S, using sep as the
        delimiter string.  If maxsplit is given, at most maxsplit
        splits are done. If sep is not specified or is None, any
        whitespace string is a separator and empty strings are removed
        from the result.
        """

    @unwrap_spec(keepends=bool)
    def descr_splitlines(self, space, keepends=False):
        """S.splitlines(keepends=False) -> list of strings

        Return a list of the lines in S, breaking at line boundaries.
        Line breaks are not included in the resulting list unless keepends
        is given and true.
        """

    def descr_startswith(self, space, w_prefix, w_start=None, w_end=None):
        """S.startswith(prefix[, start[, end]]) -> bool

        Return True if S starts with the specified prefix, False otherwise.
        With optional start, test S beginning at that position.
        With optional end, stop comparing S at that position.
        prefix can also be a tuple of strings to try.
        """

    def descr_strip(self, space, w_chars=None):
        """S.strip([chars]) -> string or unicode

        Return a copy of the string S with leading and trailing
        whitespace removed.
        If chars is given and not None, remove characters in chars instead.
        If chars is unicode, S will be converted to unicode before stripping
        """

    def descr_swapcase(self, space):
        """S.swapcase() -> string

        Return a copy of the string S with uppercase characters
        converted to lowercase and vice versa.
        """

    def descr_title(self, space):
        """S.title() -> string

        Return a titlecased version of S, i.e. words start with uppercase
        characters, all remaining cased characters have lowercase.
        """

    @unwrap_spec(w_deletechars=WrappedDefault(''))
    def descr_translate(self, space, w_table, w_deletechars):
        """S.translate(table[, deletechars]) -> string

        Return a copy of the string S, where all characters occurring
        in the optional argument deletechars are removed, and the
        remaining characters have been mapped through the given
        translation table, which must be a string of length 256 or None.
        If the table argument is None, no translation is applied and
        the operation simply removes the characters in deletechars.
        """

    def descr_upper(self, space):
        """S.upper() -> string

        Return a copy of the string S converted to uppercase.
        """

    @unwrap_spec(width=int)
    def descr_zfill(self, space, width):
        """S.zfill(width) -> string
    # Call get_source() to get the source code.
    w_source = space.call_function(w_get_source, w_module_name)
    if space.is_w(w_source, space.w_None):
        return None

    # Split the source into lines.
    w_source_list = space.call_method(w_source, "splitlines")

    # Get the source line.
    w_source_line = space.getitem(w_source_list, space.newint(lineno - 1))
    return w_source_line


@unwrap_spec(lineno=int,
             w_module=WrappedDefault(None),
             w_registry=WrappedDefault(None),
             w_module_globals=WrappedDefault(None))
def warn_explicit(space,
                  w_message,
                  w_category,
                  w_filename,
                  lineno,
                  w_module=None,
                  w_registry=None,
                  w_module_globals=None):
    "Low-level inferface to warnings functionality."

    w_source_line = get_source_line(space, w_module_globals, lineno)

    do_warn_explicit(space, w_category, w_message,
class W_StringIO(W_TextIOBase):
    def __init__(self, space):
        W_TextIOBase.__init__(self, space)
        self.buf = UnicodeIO()

    @unwrap_spec(w_newline=WrappedDefault(u"\n"))
    def descr_init(self, space, w_initvalue=None, w_newline=None):
        # In case __init__ is called multiple times
        self.buf = UnicodeIO()
        self.w_decoder = None
        self.readnl = None
        self.writenl = None

        if space.is_w(w_newline, space.w_None):
            newline = None
        else:
            newline = space.unicode_w(w_newline)

        if (newline is not None and newline != u"" and newline != u"\n"
                and newline != u"\r" and newline != u"\r\n"):
            # Not using oefmt() because I don't know how to use it
            # with unicode
            raise OperationError(
                space.w_ValueError,
                space.mod(space.newtext("illegal newline value: %s"),
                          w_newline))
        if newline is not None:
            self.readnl = newline
        self.readuniversal = newline is None or newline == u""
        self.readtranslate = newline is None
        if newline and newline[0] == u"\r":
            self.writenl = newline
        if self.readuniversal:
            self.w_decoder = space.call_function(
                space.gettypefor(W_IncrementalNewlineDecoder), space.w_None,
                space.newint(int(self.readtranslate)))

        if not space.is_none(w_initvalue):
            self.write_w(space, w_initvalue)
            self.buf.pos = 0

    def descr_getstate(self, space):
        w_initialval = self.getvalue_w(space)
        w_dict = space.call_method(self.w_dict, "copy")
        if self.readnl is None:
            w_readnl = space.w_None
        else:
            w_readnl = space.str(space.newunicode(self.readnl))  # YYY
        return space.newtuple(
            [w_initialval, w_readnl,
             space.newint(self.buf.pos), w_dict])

    def descr_setstate(self, space, w_state):
        self._check_closed(space)

        # We allow the state tuple to be longer than 4, because we may need
        # someday to extend the object's state without breaking
        # backwards-compatibility
        if (not space.isinstance_w(w_state, space.w_tuple)
                or space.len_w(w_state) < 4):
            raise oefmt(
                space.w_TypeError,
                "%T.__setstate__ argument should be a 4-tuple, got %T", self,
                w_state)
        w_initval, w_readnl, w_pos, w_dict = space.unpackiterable(w_state, 4)
        if not space.isinstance_w(w_initval, space.w_unicode):
            raise oefmt(space.w_TypeError,
                        "unicode argument expected, got '%T'", w_initval)
        # Initialize state
        self.descr_init(space, None, w_readnl)

        # Restore the buffer state. We're not doing it via __init__
        # because the string value in the state tuple has already been
        # translated once by __init__. So we do not take any chance and replace
        # object's buffer completely
        initval = space.unicode_w(w_initval)
        pos = space.getindex_w(w_pos, space.w_TypeError)
        if pos < 0:
            raise oefmt(space.w_ValueError,
                        "position value cannot be negative")
        self.buf = UnicodeIO(list(initval), pos)
        if not space.is_w(w_dict, space.w_None):
            if not space.isinstance_w(w_dict, space.w_dict):
                raise oefmt(space.w_TypeError,
                            "fourth item of state should be a dict, got a %T",
                            w_dict)
            # Alternatively, we could replace the internal dictionary
            # completely. However, it seems more practical to just update it.
            space.call_method(self.w_dict, "update", w_dict)

    def _check_closed(self, space, message=None):
        if self.buf is None:
            if message is None:
                message = "I/O operation on closed file"
            raise OperationError(space.w_ValueError, space.newtext(message))

    def write_w(self, space, w_obj):
        if not space.isinstance_w(w_obj, space.w_unicode):
            raise oefmt(space.w_TypeError,
                        "unicode argument expected, got '%T'", w_obj)
        self._check_closed(space)
        orig_size = space.len_w(w_obj)

        if self.w_decoder is not None:
            w_decoded = space.call_method(self.w_decoder, "decode", w_obj,
                                          space.w_True)
        else:
            w_decoded = w_obj
        if self.writenl:
            w_decoded = space.call_method(w_decoded, "replace",
                                          space.newtext("\n"),
                                          space.newunicode(self.writenl))
        string = space.unicode_w(w_decoded)
        if string:
            self.buf.write(string)

        return space.newint(orig_size)

    def read_w(self, space, w_size=None):
        self._check_closed(space)
        size = convert_size(space, w_size)
        return space.newunicode(self.buf.read(size))

    def readline_w(self, space, w_limit=None):
        self._check_closed(space)
        limit = convert_size(space, w_limit)
        if self.readuniversal:
            result = self.buf.readline_universal(limit)
        else:
            if self.readtranslate:
                # Newlines are already translated, only search for \n
                newline = u'\n'
            else:
                newline = self.readnl
            result = self.buf.readline(newline, limit)
        return space.newunicode(result)

    @unwrap_spec(pos=int, mode=int)
    def seek_w(self, space, pos, mode=0):
        self._check_closed(space)

        if not 0 <= mode <= 2:
            raise oefmt(space.w_ValueError,
                        "Invalid whence (%d, should be 0, 1 or 2)", mode)
        elif mode == 0 and pos < 0:
            raise oefmt(space.w_ValueError, "negative seek position: %d", pos)
        elif mode != 0 and pos != 0:
            raise oefmt(space.w_IOError, "Can't do nonzero cur-relative seeks")

        # XXX: this makes almost no sense, but its how CPython does it.
        if mode == 1:
            pos = self.buf.pos
        elif mode == 2:
            pos = len(self.buf.data)
        assert pos >= 0
        self.buf.seek(pos)
        return space.newint(pos)

    def truncate_w(self, space, w_size=None):
        self._check_closed(space)
        if space.is_none(w_size):
            size = self.buf.pos
        else:
            size = space.int_w(w_size)
        if size < 0:
            raise oefmt(space.w_ValueError, "Negative size value %d", size)
        self.buf.truncate(size)
        return space.newint(size)

    def getvalue_w(self, space):
        self._check_closed(space)
        return space.newunicode(self.buf.getvalue())

    def readable_w(self, space):
        self._check_closed(space)
        return space.w_True

    def writable_w(self, space):
        self._check_closed(space)
        return space.w_True

    def seekable_w(self, space):
        self._check_closed(space)
        return space.w_True

    def close_w(self, space):
        self.buf = None

    def needs_finalizer(self):
        # 'self.buf = None' is not necessary when the object goes away
        return type(self) is not W_StringIO

    def closed_get_w(self, space):
        return space.newbool(self.buf is None)

    def line_buffering_get_w(self, space):
        return space.w_False

    def newlines_get_w(self, space):
        if self.w_decoder is None:
            return space.w_None
        return space.getattr(self.w_decoder, space.newtext("newlines"))
Beispiel #12
0
class W_BoolObject(W_IntObject):
    def __init__(self, boolval):
        self.intval = int(not not boolval)

    def __nonzero__(self):
        raise Exception("no puede hacer esto; tiene que usar space.is_true()")

    def __repr__(self):
        """representation for debugging purposes"""
        return "%s(%s)" % (self.__class__.__name__, bool(self.intval))

    def is_w(self, space, w_other):
        return self is w_other

    def immutable_unique_id(self, space):
        return None

    def unwrap(self, space):
        return bool(self.intval)

    def uint_w(self, space):
        return r_uint(self.intval)

    def int(self, space):
        return space.newint(self.intval)

    @staticmethod
    @unwrap_spec(w_obj=WrappedDefault(False))
    def descr_new(space, w_booltype, w_obj):
        """T.__new__(S, ...) -> a new object with type S, a subtype of T"""
        space.w_bool.check_user_subclass(w_booltype)
        return space.newbool(space.is_true(w_obj))

    def descr_repr(self, space):
        return space.newtext('Cierto' if self.intval else 'Falso')

    descr_str = func_with_new_name(descr_repr, 'descr_str')

    def descr_nonzero(self, space):
        return self

    def _make_bitwise_binop(opname):
        descr_name = 'descr_' + opname
        int_op = getattr(W_IntObject, descr_name)
        op = getattr(operator,
                     opname + '_' if opname in ('and', 'or') else opname)

        @func_renamer(descr_name)
        def descr_binop(self, space, w_other):
            if not isinstance(w_other, W_BoolObject):
                return int_op(self, space, w_other)
            a = bool(self.intval)
            b = bool(w_other.intval)
            return space.newbool(op(a, b))

        @func_renamer('descr_r' + opname)
        def descr_rbinop(self, space, w_other):
            return descr_binop(self, space, w_other)

        return descr_binop, descr_rbinop

    descr_and, descr_rand = _make_bitwise_binop('and')
    descr_or, descr_ror = _make_bitwise_binop('or')
    descr_xor, descr_rxor = _make_bitwise_binop('xor')
Beispiel #13
0
class W_Kqueue(W_Root):
    def __init__(self, space, kqfd):
        self.kqfd = kqfd

    def descr__new__(space, w_subtype):
        kqfd = syscall_kqueue()
        if kqfd < 0:
            raise exception_from_saved_errno(space, space.w_IOError)
        return space.wrap(W_Kqueue(space, kqfd))

    @unwrap_spec(fd=int)
    def descr_fromfd(space, w_cls, fd):
        return space.wrap(W_Kqueue(space, fd))

    def __del__(self):
        self.close()

    def get_closed(self):
        return self.kqfd < 0

    def close(self):
        if not self.get_closed():
            kqfd = self.kqfd
            self.kqfd = -1
            socketclose_no_errno(kqfd)

    def check_closed(self, space):
        if self.get_closed():
            raise OperationError(
                space.w_ValueError,
                space.wrap("I/O operation on closed kqueue fd"))

    def descr_get_closed(self, space):
        return space.wrap(self.get_closed())

    def descr_fileno(self, space):
        self.check_closed(space)
        return space.wrap(self.kqfd)

    def descr_close(self, space):
        self.close()

    @unwrap_spec(max_events=int, w_timeout=WrappedDefault(None))
    def descr_control(self, space, w_changelist, max_events, w_timeout):

        self.check_closed(space)

        if max_events < 0:
            raise oefmt(space.w_ValueError,
                        "Length of eventlist must be 0 or positive, got %d",
                        max_events)

        if space.is_w(w_changelist, space.w_None):
            changelist_len = 0
        else:
            changelist_len = space.len_w(w_changelist)

        with lltype.scoped_alloc(rffi.CArray(kevent),
                                 changelist_len) as changelist:
            with lltype.scoped_alloc(rffi.CArray(kevent),
                                     max_events) as eventlist:
                with lltype.scoped_alloc(timespec) as timeout:

                    if not space.is_w(w_timeout, space.w_None):
                        _timeout = space.float_w(w_timeout)
                        if _timeout < 0:
                            raise oefmt(
                                space.w_ValueError,
                                "Timeout must be None or >= 0, got %s",
                                str(_timeout))
                        sec = int(_timeout)
                        nsec = int(1e9 * (_timeout - sec))
                        rffi.setintfield(timeout, 'c_tv_sec', sec)
                        rffi.setintfield(timeout, 'c_tv_nsec', nsec)
                        ptimeout = timeout
                    else:
                        ptimeout = lltype.nullptr(timespec)

                    if not space.is_w(w_changelist, space.w_None):
                        i = 0
                        for w_ev in space.listview(w_changelist):
                            ev = space.interp_w(W_Kevent, w_ev)
                            changelist[i].c_ident = ev.ident
                            changelist[i].c_filter = ev.filter
                            changelist[i].c_flags = ev.flags
                            changelist[i].c_fflags = ev.fflags
                            changelist[i].c_data = ev.data
                            changelist[i].c_udata = ev.udata
                            i += 1
                        pchangelist = changelist
                    else:
                        pchangelist = lltype.nullptr(rffi.CArray(kevent))

                    nfds = syscall_kevent(self.kqfd, pchangelist,
                                          changelist_len, eventlist,
                                          max_events, ptimeout)
                    if nfds < 0:
                        raise exception_from_saved_errno(
                            space, space.w_OSError)
                    else:
                        elist_w = [None] * nfds
                        for i in xrange(nfds):

                            evt = eventlist[i]

                            w_event = W_Kevent(space)
                            w_event.ident = evt.c_ident
                            w_event.filter = evt.c_filter
                            w_event.flags = evt.c_flags
                            w_event.fflags = evt.c_fflags
                            w_event.data = evt.c_data
                            w_event.udata = evt.c_udata

                            elist_w[i] = w_event

                    return space.newlist(elist_w)
Beispiel #14
0
    def reduce_w(self):
        space = self.space
        if self.single_argument():
            args_w = [self.w_c]
        else:
            args_w = [self.w_c, self.w_step]
        return space.newtuple([space.gettypefor(W_Count),
                               space.newtuple(args_w)])

def check_number(space, w_obj):
    if (space.lookup(w_obj, '__int__') is None and
        space.lookup(w_obj, '__float__') is None):
        raise oefmt(space.w_TypeError, "expected a number")

@unwrap_spec(w_start=WrappedDefault(0), w_step=WrappedDefault(1))
def W_Count___new__(space, w_subtype, w_start, w_step):
    check_number(space, w_start)
    check_number(space, w_step)
    r = space.allocate_instance(W_Count, w_subtype)
    r.__init__(space, w_start, w_step)
    return r

W_Count.typedef = TypeDef(
        'itertools.count',
        __new__ = interp2app(W_Count___new__),
        __iter__ = interp2app(W_Count.iter_w),
        next = interp2app(W_Count.next_w),
        __reduce__ = interp2app(W_Count.reduce_w),
        __repr__ = interp2app(W_Count.repr_w),
        __doc__ = """Make an iterator that returns evenly spaced values starting
Beispiel #15
0
class BufferedMixin:
    _mixin_ = True

    def __init__(self, space):
        W_IOBase.__init__(self, space)
        self.state = STATE_ZERO

        self.buffer = None

        self.abs_pos = 0  # Absolute position inside the raw stream (-1 if
        # unknown).
        self.pos = 0  # Current logical position in the buffer
        self.raw_pos = 0  # Position of the raw stream in the buffer.

        self.read_end = -1  # Just after the last buffered byte in the buffer,
        # or -1 if the buffer isn't ready for reading

        self.write_pos = 0  # Just after the last byte actually written
        self.write_end = -1  # Just after the last byte waiting to be written,
        # or -1 if the buffer isn't ready for writing.

        self.lock = None

        self.readable = False
        self.writable = False

    def _reader_reset_buf(self):
        self.read_end = -1

    def _writer_reset_buf(self):
        self.write_pos = 0
        self.write_end = -1

    def _init(self, space):
        if self.buffer_size <= 0:
            raise oefmt(space.w_ValueError,
                        "buffer size must be strictly positive")

        if space.config.translation.split_gc_address_space:
            # When using split GC address space, it is not possible to get the
            # raw address of a GC buffer. Therefore we use a buffer backed by
            # raw memory.
            self.buffer = RawByteBuffer(self.buffer_size)
        else:
            # TODO: test whether using the raw buffer is faster
            self.buffer = ByteBuffer(self.buffer_size)

        self.lock = TryLock(space)

        try:
            self._raw_tell(space)
        except OperationError:
            pass

    def _check_init(self, space):
        if self.state == STATE_ZERO:
            raise oefmt(space.w_ValueError,
                        "I/O operation on uninitialized object")
        elif self.state == STATE_DETACHED:
            raise oefmt(space.w_ValueError, "raw stream has been detached")

    def _check_closed(self, space, message=None):
        self._check_init(space)
        W_IOBase._check_closed(self, space, message)

    def _raw_tell(self, space):
        w_pos = space.call_method(self.w_raw, "tell")
        pos = space.r_longlong_w(w_pos)
        if pos < 0:
            raise oefmt(space.w_IOError,
                        "raw stream returned invalid position")

        self.abs_pos = pos
        return pos

    def closed_get_w(self, space):
        self._check_init(space)
        return space.getattr(self.w_raw, space.newtext("closed"))

    def name_get_w(self, space):
        self._check_init(space)
        return space.getattr(self.w_raw, space.newtext("name"))

    def mode_get_w(self, space):
        self._check_init(space)
        return space.getattr(self.w_raw, space.newtext("mode"))

    def readable_w(self, space):
        self._check_init(space)
        return space.call_method(self.w_raw, "readable")

    def writable_w(self, space):
        self._check_init(space)
        return space.call_method(self.w_raw, "writable")

    def seekable_w(self, space):
        self._check_init(space)
        return space.call_method(self.w_raw, "seekable")

    def isatty_w(self, space):
        self._check_init(space)
        return space.call_method(self.w_raw, "isatty")

    def repr_w(self, space):
        typename = space.type(self).name
        try:
            w_name = space.getattr(self, space.newtext("name"))
        except OperationError as e:
            if not e.match(space, space.w_Exception):
                raise
            return space.newtext("<%s>" % (typename, ))
        else:
            name_repr = space.text_w(space.repr(w_name))
            return space.newtext("<%s name=%s>" % (typename, name_repr))

    # ______________________________________________

    @signature(types.any(), returns=types.int())
    def _readahead(self):
        if self.readable and self.read_end != -1:
            available = self.read_end - self.pos
            assert available >= 0
            return available
        return 0

    def _raw_offset(self):
        if self.raw_pos >= 0 and ((self.readable and self.read_end != -1) or
                                  (self.writable and self.write_end != -1)):
            return self.raw_pos - self.pos
        return 0

    def tell_w(self, space):
        self._check_init(space)
        pos = self._raw_tell(space) - self._raw_offset()
        return space.newint(pos)

    @unwrap_spec(pos=r_longlong, whence=int)
    def seek_w(self, space, pos, whence=0):
        self._check_init(space)
        if whence not in (0, 1, 2):
            raise oefmt(space.w_ValueError,
                        "whence must be between 0 and 2, not %d", whence)
        self._check_closed(space, "seek of closed file")
        if whence != 2 and self.readable:
            # Check if seeking leaves us inside the current buffer, so as to
            # return quickly if possible. Also, we needn't take the lock in
            # this fast path.
            if self.abs_pos == -1:
                self._raw_tell(space)
            current = self.abs_pos
            available = self._readahead()
            if available > 0:
                if whence == 0:
                    offset = pos - (current - self._raw_offset())
                else:
                    offset = pos
                if -self.pos <= offset <= available:
                    newpos = self.pos + int(offset)
                    assert newpos >= 0
                    self.pos = newpos
                    return space.newint(current - available + offset)

        # Fallback: invoke raw seek() method and clear buffer
        with self.lock:
            if self.writable:
                self._writer_flush_unlocked(space)
                self._writer_reset_buf()

            if whence == 1:
                pos -= self._raw_offset()
            n = self._raw_seek(space, pos, whence)
            self.raw_pos = -1
            if self.readable:
                self._reader_reset_buf()
            return space.newint(n)

    def _raw_seek(self, space, pos, whence):
        w_pos = space.call_method(self.w_raw, "seek", space.newint(pos),
                                  space.newint(whence))
        pos = space.r_longlong_w(w_pos)
        if pos < 0:
            raise oefmt(space.w_IOError,
                        "Raw stream returned invalid position")
        self.abs_pos = pos
        return pos

    def _closed(self, space):
        return space.is_true(space.getattr(self.w_raw,
                                           space.newtext("closed")))

    def close_w(self, space):
        self._check_init(space)
        with self.lock:
            if self._closed(space):
                return
        try:
            space.call_method(self, "flush")
        finally:
            with self.lock:
                space.call_method(self.w_raw, "close")

    def simple_flush_w(self, space):
        self._check_init(space)
        return space.call_method(self.w_raw, "flush")

    def _writer_flush_unlocked(self, space):
        if self.write_end == -1 or self.write_pos == self.write_end:
            return
        # First, rewind
        rewind = self._raw_offset() + (self.pos - self.write_pos)
        if rewind != 0:
            self._raw_seek(space, -rewind, 1)
            self.raw_pos -= rewind

        written = 0
        while self.write_pos < self.write_end:
            try:
                n = self._raw_write(space, self.write_pos, self.write_end)
            except BlockingIOError:
                raise make_write_blocking_error(space, 0)
            self.write_pos += n
            self.raw_pos = self.write_pos
            written += n
            # Partial writes can return successfully when interrupted by a
            # signal (see write(2)).  We must run signal handlers before
            # blocking another time, possibly indefinitely.
            space.getexecutioncontext().checksignals()

        self._writer_reset_buf()

    def _write(self, space, data):
        w_data = space.newbytes(data)
        while True:
            try:
                w_written = space.call_method(self.w_raw, "write", w_data)
            except OperationError as e:
                if trap_eintr(space, e):
                    continue  # try again
                raise
            else:
                break

        if space.is_w(w_written, space.w_None):
            # Non-blocking stream would have blocked.
            raise BlockingIOError()

        written = space.getindex_w(w_written, space.w_IOError)
        if not 0 <= written <= len(data):
            raise oefmt(space.w_IOError, "raw write() returned invalid length")
        if self.abs_pos != -1:
            self.abs_pos += written
        return written

    def _raw_write(self, space, start, end):
        return self._write(space, self.buffer[start:end])

    def detach_w(self, space):
        self._check_init(space)
        space.call_method(self, "flush")
        w_raw = self.w_raw
        self.w_raw = None
        self.state = STATE_DETACHED
        return w_raw

    def fileno_w(self, space):
        self._check_init(space)
        return space.call_method(self.w_raw, "fileno")

    @unwrap_spec(w_size=WrappedDefault(None))
    def truncate_w(self, space, w_size):
        self._check_init(space)
        with self.lock:
            if self.writable:
                self._flush_and_rewind_unlocked(space)
            # invalidate cached position
            self.abs_pos = -1

            return space.call_method(self.w_raw, "truncate", w_size)

    # ________________________________________________________________
    # Read methods

    def read_w(self, space, w_size=None):
        self._check_init(space)
        self._check_closed(space, "read of closed file")
        size = convert_size(space, w_size)

        if size == -1:
            # read until the end of stream
            with self.lock:
                return self._read_all(space)
        elif size >= 0:
            res = self._read_fast(size)
            if res is None:
                with self.lock:
                    res = self._read_generic(space, size)
        else:
            raise oefmt(space.w_ValueError,
                        "read length must be positive or -1")
        return space.newbytes(res)

    @unwrap_spec(size=int)
    def peek_w(self, space, size=0):
        self._check_init(space)
        self._check_closed(space, "peek of closed file")
        with self.lock:
            if self.writable:
                self._flush_and_rewind_unlocked(space)
            # Constraints:
            # 1. we don't want to advance the file position.
            # 2. we don't want to lose block alignment, so we can't shift the
            #    buffer to make some place.
            # Therefore, we either return `have` bytes (if > 0), or a full
            # buffer.
            have = self._readahead()
            if have > 0:
                data = self.buffer[self.pos:self.pos + have]
                return space.newbytes(data)

            # Fill the buffer from the raw stream, and copy it to the result
            self._reader_reset_buf()
            try:
                size = self._fill_buffer(space)
            except BlockingIOError:
                size = 0
            self.pos = 0
            data = self.buffer[0:size]
            return space.newbytes(data)

    @unwrap_spec(size=int)
    def read1_w(self, space, size):
        self._check_init(space)
        self._check_closed(space, "read of closed file")

        if size < 0:
            raise oefmt(space.w_ValueError, "read length must be positive")
        if size == 0:
            return space.newbytes("")

        with self.lock:
            # Return up to n bytes.  If at least one byte is buffered, we only
            # return buffered bytes.  Otherwise, we do one raw read.

            # XXX: this mimicks the io.py implementation but is probably
            # wrong. If we need to read from the raw stream, then we could
            # actually read all `n` bytes asked by the caller (and possibly
            # more, so as to fill our buffer for the next reads).

            have = self._readahead()
            if have == 0:
                if self.writable:
                    self._flush_and_rewind_unlocked(space)

                # Fill the buffer from the raw stream
                self._reader_reset_buf()
                self.pos = 0
                try:
                    have = self._fill_buffer(space)
                except BlockingIOError:
                    have = 0
            if size > have:
                size = have
            endpos = self.pos + size
            data = self.buffer[self.pos:endpos]
            self.pos = endpos
            return space.newbytes(data)

    def _read_all(self, space):
        "Read all the file, don't update the cache"
        # Must run with the lock held!
        builder = StringBuilder()
        # First copy what we have in the current buffer
        current_size = self._readahead()
        data = None
        if current_size:
            data = self.buffer[self.pos:self.pos + current_size]
            builder.append(data)
            self.pos += current_size
        # We're going past the buffer's bounds, flush it
        if self.writable:
            self._flush_and_rewind_unlocked(space)
        self._reader_reset_buf()

        while True:
            # Read until EOF or until read() would block
            w_data = space.call_method(self.w_raw, "read")
            if space.is_w(w_data, space.w_None):
                if current_size == 0:
                    return w_data
                break
            data = space.bytes_w(w_data)
            size = len(data)
            if size == 0:
                break
            builder.append(data)
            current_size += size
            if self.abs_pos != -1:
                self.abs_pos += size
        return space.newbytes(builder.build())

    def _raw_read(self, space, buffer, start, length):
        assert buffer is not None
        length = intmask(length)
        start = intmask(start)
        w_view = SimpleView(SubBuffer(buffer, start, length)).wrap(space)
        while True:
            try:
                w_size = space.call_method(self.w_raw, "readinto", w_view)
            except OperationError as e:
                if trap_eintr(space, e):
                    continue  # try again
                raise
            else:
                break

        if space.is_w(w_size, space.w_None):
            raise BlockingIOError()
        size = space.int_w(w_size)
        if size < 0 or size > length:
            raise oefmt(
                space.w_IOError,
                "raw readinto() returned invalid length %d (should "
                "have been between 0 and %d)", size, length)
        if self.abs_pos != -1:
            self.abs_pos += size
        return size

    def _fill_buffer(self, space):
        start = self.read_end
        if start == -1:
            start = 0
        length = self.buffer_size - start
        size = self._raw_read(space, self.buffer, start, length)
        if size > 0:
            self.read_end = self.raw_pos = start + size
        return size

    def _read_generic(self, space, n):
        """Generic read function: read from the stream until enough bytes are
           read, or until an EOF occurs or until read() would block."""
        # Must run with the lock held!
        current_size = self._readahead()
        if n <= current_size:
            return self._read_fast(n)

        result_buffer = ByteBuffer(n)
        remaining = n
        written = 0
        if current_size:
            self.output_slice(space, result_buffer, written,
                              self.buffer[self.pos:self.pos + current_size])
            remaining -= current_size
            written += current_size
            self.pos += current_size

        # Flush the write buffer if necessary
        if self.writable:
            self._flush_and_rewind_unlocked(space)
        self._reader_reset_buf()

        # Read whole blocks, and don't buffer them
        while remaining > 0:
            r = self.buffer_size * (remaining // self.buffer_size)
            if r == 0:
                break
            try:
                size = self._raw_read(space, result_buffer, written, r)
            except BlockingIOError:
                if written == 0:
                    return None
                size = 0
            if size == 0:
                return result_buffer[0:written]
            remaining -= size
            written += size

        self.pos = 0
        self.raw_pos = 0
        self.read_end = 0

        while remaining > 0 and self.read_end < self.buffer_size:
            try:
                size = self._fill_buffer(space)
            except BlockingIOError:
                # EOF or read() would block
                if written == 0:
                    return None
                size = 0
            if size == 0:
                break

            if remaining > 0:
                if size > remaining:
                    size = remaining
                self.output_slice(space, result_buffer, written,
                                  self.buffer[self.pos:self.pos + size])
                self.pos += size
                written += size
                remaining -= size

        return result_buffer[0:written]

    def _read_fast(self, n):
        """Read n bytes from the buffer if it can, otherwise return None.
           This function is simple enough that it can run unlocked."""
        current_size = self._readahead()
        if n <= current_size:
            endpos = self.pos + n
            res = self.buffer[self.pos:endpos]
            self.pos = endpos
            return res
        return None

    def readline_w(self, space, w_limit=None):
        self._check_init(space)
        self._check_closed(space, "readline of closed file")

        limit = convert_size(space, w_limit)

        # First, try to find a line in the buffer. This can run
        # unlocked because the calls to the C API are simple enough
        # that they can't trigger any thread switch.
        have = self._readahead()
        if limit >= 0 and have > limit:
            have = limit
        for pos in range(self.pos, self.pos + have):
            if self.buffer[pos] == '\n':
                break
        else:
            pos = -1
        if pos >= 0:
            w_res = space.newbytes(self.buffer[self.pos:pos + 1])
            self.pos = pos + 1
            return w_res
        if have == limit:
            w_res = space.newbytes(self.buffer[self.pos:self.pos + have])
            self.pos += have
            return w_res

        written = 0
        with self.lock:
            # Now we try to get some more from the raw stream
            chunks = []
            if have > 0:
                chunks.append(self.buffer[self.pos:self.pos + have])
                written += have
                self.pos += have
                if limit >= 0:
                    limit -= have
            if self.writable:
                self._flush_and_rewind_unlocked(space)

            while True:
                self._reader_reset_buf()
                have = self._fill_buffer(space)
                if have == 0:
                    break
                if limit >= 0 and have > limit:
                    have = limit
                pos = 0
                found = False
                while pos < have:
                    c = self.buffer.getitem(pos)
                    pos += 1
                    if c == '\n':
                        self.pos = pos
                        found = True
                        break
                chunks.append(self.buffer[0:pos])
                if found:
                    break
                if have == limit:
                    self.pos = have
                    break
                written += have
                if limit >= 0:
                    limit -= have
            return space.newbytes(''.join(chunks))

    # ____________________________________________________
    # Write methods

    def _adjust_position(self, new_pos):
        assert new_pos >= 0
        self.pos = new_pos
        if self.readable and self.read_end != -1 and self.read_end < new_pos:
            self.read_end = self.pos

    def write_w(self, space, w_data):
        self._check_init(space)
        self._check_closed(space, "write to closed file")
        data = space.getarg_w('s*', w_data).as_str()
        size = len(data)

        with self.lock:
            if (not (self.readable and self.read_end != -1)
                    and not (self.writable and self.write_end != -1)):
                self.pos = 0
                self.raw_pos = 0
            available = self.buffer_size - self.pos
            # Fast path: the data to write can be fully buffered
            if size <= available:
                for i in range(size):
                    self.buffer[self.pos + i] = data[i]
                if self.write_end == -1 or self.write_pos > self.pos:
                    self.write_pos = self.pos
                self._adjust_position(self.pos + size)
                if self.pos > self.write_end:
                    self.write_end = self.pos
                return space.newint(size)

            # First write the current buffer
            try:
                self._writer_flush_unlocked(space)
            except OperationError as e:
                if not e.match(space,
                               space.gettypeobject(W_BlockingIOError.typedef)):
                    raise
                w_exc = e.get_w_value(space)
                assert isinstance(w_exc, W_BlockingIOError)
                if self.readable:
                    self._reader_reset_buf()
                # Make some place by shifting the buffer
                for i in range(self.write_pos, self.write_end):
                    self.buffer.setitem(i - self.write_pos,
                                        self.buffer.getitem(i))
                self.write_end -= self.write_pos
                self.raw_pos -= self.write_pos
                newpos = self.pos - self.write_pos
                assert newpos >= 0
                self.pos = newpos
                self.write_pos = 0
                available = self.buffer_size - self.write_end
                assert available >= 0
                if size <= available:
                    # Everything can be buffered
                    for i in range(size):
                        self.buffer[self.write_end + i] = data[i]
                    self.write_end += size
                    self.pos += size
                    return space.newint(size)
                # Buffer as much as possible
                for i in range(available):
                    self.buffer[self.write_end + i] = data[i]
                self.write_end += available
                self.pos += available
                # Modifying the existing exception will will change
                # e.characters_written but not e.args[2].  Therefore
                # we just replace with a new error.
                raise make_write_blocking_error(space, available)

            # Adjust the raw stream position if it is away from the logical
            # stream position. This happens if the read buffer has been filled
            # but not modified (and therefore _bufferedwriter_flush_unlocked()
            # didn't rewind the raw stream by itself).
            offset = self._raw_offset()
            if offset:
                self._raw_seek(space, -offset, 1)
                self.raw_pos -= offset

            # Then write buf itself. At this point the buffer has been emptied
            remaining = size
            written = 0
            while remaining > self.buffer_size:
                try:
                    n = self._write(space, data[written:])
                except BlockingIOError:
                    # Write failed because raw file is non-blocking
                    if remaining > self.buffer_size:
                        # Can't buffer everything, still buffer as much as
                        # possible
                        for i in range(self.buffer_size):
                            self.buffer[i] = data[written + i]
                        self.raw_pos = 0
                        self._adjust_position(self.buffer_size)
                        self.write_end = self.buffer_size
                        written += self.buffer_size
                        raise make_write_blocking_error(space, written)
                    break
                written += n
                remaining -= n
                # Partial writes can return successfully when interrupted by a
                # signal (see write(2)).  We must run signal handlers before
                # blocking another time, possibly indefinitely.
                space.getexecutioncontext().checksignals()

            if self.readable:
                self._reader_reset_buf()
            if remaining > 0:
                for i in range(remaining):
                    self.buffer[i] = data[written + i]
                written += remaining
            self.write_pos = 0
            self.write_end = remaining
            self._adjust_position(remaining)
            self.raw_pos = 0
        return space.newint(written)

    def flush_w(self, space):
        self._check_init(space)
        self._check_closed(space, "flush of closed file")
        with self.lock:
            self._flush_and_rewind_unlocked(space)

    def _flush_and_rewind_unlocked(self, space):
        self._writer_flush_unlocked(space)
        if self.readable:
            # Rewind the raw stream so that its position corresponds to
            # the current logical position.
            try:
                self._raw_seek(space, -self._raw_offset(), 1)
            finally:
                self._reader_reset_buf()
class W_XMLParserType(W_Root):
    id = -1

    def __init__(self, space, parser, w_intern):
        self.itself = parser
        self.register_finalizer(space)

        self.w_intern = w_intern

        self.ordered_attributes = False
        self.specified_attributes = False
        self.ns_prefixes = False

        self.handlers = [None] * NB_HANDLERS

        self.buffer = None
        self.buffer_size = 8192
        self.buffer_used = 0
        self.w_character_data_handler = None

        self._exc_info = None

        # Set user data for callback function
        self.id = global_storage.get_nonmoving_id(CallbackData(space, self))
        XML_SetUserData(self.itself, rffi.cast(rffi.VOIDP, self.id))

    def _finalize_(self):
        if XML_ParserFree:  # careful with CPython interpreter shutdown
            if self.itself:
                XML_ParserFree(self.itself)
                self.itself = lltype.nullptr(XML_Parser.TO)
        if global_storage and self.id >= 0:
            try:
                global_storage.free_nonmoving_id(self.id)
            except KeyError:
                pass  # maybe global_storage.clear() was already called
            self.id = -1

    @unwrap_spec(flag=int)
    def SetParamEntityParsing(self, space, flag):
        """SetParamEntityParsing(flag) -> success
Controls parsing of parameter entities (including the external DTD
subset). Possible flag values are XML_PARAM_ENTITY_PARSING_NEVER,
XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE and
XML_PARAM_ENTITY_PARSING_ALWAYS. Returns true if setting the flag
was successful."""
        XML_SetParamEntityParsing(self.itself, flag)

    @unwrap_spec(w_flag=WrappedDefault(True))
    def UseForeignDTD(self, space, w_flag):
        """UseForeignDTD([flag])
Allows the application to provide an artificial external subset if one is
not specified as part of the document instance.  This readily allows the
use of a 'default' document type controlled by the application, while still
getting the advantage of providing document type information to the parser.
'flag' defaults to True if not provided."""
        flag = space.is_true(w_flag)
        XML_UseForeignDTD(self.itself, flag)

    # Handlers management

    def w_convert(self, space, s):
        from pypy.interpreter.unicodehelper import decode_utf8
        return space.newtext(s)

    def w_convert_charp(self, space, data):
        if data:
            return self.w_convert(space, rffi.charp2str(data))
        else:
            return space.w_None

    def w_convert_interned(self, space, data):
        if not data:
            return space.w_None
        w_data = self.w_convert_charp(space, data)
        if not self.w_intern:
            return w_data

        try:
            return space.getitem(self.w_intern, w_data)
        except OperationError as e:
            if not e.match(space, space.w_KeyError):
                raise
        space.setitem(self.w_intern, w_data, w_data)
        return w_data

    def w_convert_charp_n(self, space, data, length):
        ll_length = rffi.cast(lltype.Signed, length)
        if data:
            return self.w_convert(space, rffi.charp2strn(data, ll_length))
        else:
            return space.w_None

    def w_convert_attributes(self, space, attrs):
        if self.specified_attributes:
            maxindex = XML_GetSpecifiedAttributeCount(self.itself)
        else:
            maxindex = 0
            while attrs[maxindex]:
                maxindex += 2  # copied

        if self.ordered_attributes:
            w_attrs = space.newlist([
                self.w_convert_charp(space, attrs[i]) for i in range(maxindex)
            ])
        else:
            w_attrs = space.newdict()
            for i in range(0, maxindex, 2):
                space.setitem(w_attrs, self.w_convert_charp(space, attrs[i]),
                              self.w_convert_charp(space, attrs[i + 1]))

        return w_attrs

    def w_convert_model(self, space, model):
        children = [
            self.w_convert_model(space, model.c_children[i])
            for i in range(model.c_numchildren)
        ]
        return space.newtuple([
            space.newint(model.c_type),
            space.newint(model.c_quant),
            self.w_convert_charp(space, model.c_name),
            space.newtuple(children)
        ])

    def buffer_string(self, space, w_string, length):
        ll_length = rffi.cast(lltype.Signed, length)
        if self.buffer is not None:
            if self.buffer_used + ll_length > self.buffer_size:
                self.flush_character_buffer(space)
                # handler might have changed; drop the rest on the floor
                # if there isn't a handler anymore
                if self.w_character_data_handler is None:
                    return True
            if ll_length <= self.buffer_size:
                self.buffer.append(w_string)
                self.buffer_used += ll_length
                return True
            else:
                self.buffer = []
                self.buffer_used = 0
        return False

    def gethandler(self, space, name, index):
        if name == 'CharacterDataHandler':
            return self.w_character_data_handler or space.w_None
        return self.handlers[index]

    @specialize.arg(2)
    def sethandler(self, space, name, w_handler, index, setter, handler):
        if name == 'CharacterDataHandler':
            self.flush_character_buffer(space)
            if space.is_w(w_handler, space.w_None):
                self.w_character_data_handler = None
            else:
                self.w_character_data_handler = w_handler
        #
        self.handlers[index] = w_handler
        setter(self.itself, handler)

    all_chars = ''.join(chr(i) for i in range(256))

    def UnknownEncodingHandler(self, space, name, info):
        # Yes, supports only 8bit encodings
        translationmap = space.unicode_w(
            space.call_method(space.newbytes(self.all_chars), "decode",
                              space.newtext(name), space.newtext("replace")))

        if len(translationmap) != 256:
            raise oefmt(space.w_ValueError,
                        "multi-byte encodings are not supported")

        for i in range(256):
            c = translationmap[i]
            if c == u'\ufffd':
                info.c_map[i] = rffi.cast(rffi.INT, -1)
            else:
                info.c_map[i] = rffi.cast(rffi.INT, c)
        info.c_data = lltype.nullptr(rffi.VOIDP.TO)
        info.c_convert = lltype.nullptr(rffi.VOIDP.TO)
        info.c_release = lltype.nullptr(rffi.VOIDP.TO)
        return True

    @staticmethod
    def _make_property(name):
        index, setter, handler = SETTERS[name]

        #
        def descr_get_property(self, space):
            return self.gethandler(space, name, index)

        #
        def descr_set_property(self, space, w_value):
            return self.sethandler(space, name, w_value, index, setter,
                                   handler)

        #
        return GetSetProperty(descr_get_property,
                              descr_set_property,
                              cls=W_XMLParserType)

    def get_namespace_prefixes(self, space):
        return space.newbool(self.ns_prefixes)

    def set_namespace_prefixes(self, space, w_value):
        self.ns_prefixes = space.bool_w(w_value)
        XML_SetReturnNSTriplet(self.itself, self.ns_prefixes)

    # Parse methods

    @unwrap_spec(isfinal=int)
    def Parse(self, space, w_data, isfinal=False):
        """Parse(data[, isfinal])
Parse XML data.  `isfinal' should be true at end of input."""
        if space.isinstance_w(w_data, space.w_unicode):
            data = encode_utf8(space, w_data.unicode_w(space))
            # Explicitly set UTF-8 encoding. Return code ignored.
            XML_SetEncoding(self.itself, "utf-8")
        else:
            data = space.charbuf_w(w_data)
        isfinal = bool(isfinal)
        res = XML_Parse(self.itself, data, len(data), isfinal)
        if self._exc_info:
            e = self._exc_info
            self._exc_info = None
            raise e
        elif res == 0:
            exc = self.set_error(space, XML_GetErrorCode(self.itself))
            raise exc
        self.flush_character_buffer(space)
        return space.newint(res)

    def ParseFile(self, space, w_file):
        """ParseFile(file)
Parse XML data from file-like object."""
        eof = False
        while not eof:
            w_data = space.call_method(w_file, 'read', space.newint(2048))
            eof = space.len_w(w_data) == 0
            w_res = self.Parse(space, w_data, isfinal=eof)
        return w_res

    @unwrap_spec(base='text')
    def SetBase(self, space, base):
        XML_SetBase(self.itself, base)

    def ExternalEntityParserCreate(self, space, w_context, w_encoding=None):
        """ExternalEntityParserCreate(context[, encoding])
Create a parser for parsing an external entity based on the
information passed to the ExternalEntityRefHandler."""
        if space.is_w(w_context, space.w_None):
            context = None
        else:
            context = space.text_w(w_context)

        if space.is_none(w_encoding):
            encoding = None
        else:
            encoding = space.text_w(w_encoding)

        xmlparser = XML_ExternalEntityParserCreate(self.itself, context,
                                                   encoding)
        if not xmlparser:
            raise MemoryError

        parser = W_XMLParserType(space, xmlparser, self.w_intern)

        # copy handlers from self
        for i in range(NB_HANDLERS):
            parser.handlers[i] = self.handlers[i]

        return parser

    def flush_character_buffer(self, space):
        if not self.buffer:
            return
        w_data = space.call_function(
            space.getattr(space.newtext(''), space.newtext('join')),
            space.newlist(self.buffer))
        self.buffer = []
        self.buffer_used = 0

        if self.w_character_data_handler:
            space.call_function(self.w_character_data_handler, w_data)

    # Error management

    def set_error(self, space, code):
        err = rffi.charp2strn(XML_ErrorString(code), 200)
        lineno = XML_GetCurrentLineNumber(self.itself)
        colno = XML_GetCurrentColumnNumber(self.itself)
        msg = "%s: line %d, column %d" % (err, lineno, colno)
        w_errorcls = space.fromcache(Cache).w_error
        w_error = space.call_function(w_errorcls, space.newtext(msg))
        space.setattr(w_error, space.newtext("code"), space.newint(code))
        space.setattr(w_error, space.newtext("offset"), space.newint(colno))
        space.setattr(w_error, space.newtext("lineno"), space.newint(lineno))

        self.w_error = w_error
        return OperationError(w_errorcls, w_error)

    def descr_ErrorCode(self, space):
        return space.newint(XML_GetErrorCode(self.itself))

    def descr_ErrorLineNumber(self, space):
        return space.newint(XML_GetErrorLineNumber(self.itself))

    def descr_ErrorColumnNumber(self, space):
        return space.newint(XML_GetErrorColumnNumber(self.itself))

    def descr_ErrorByteIndex(self, space):
        return space.newint(XML_GetErrorByteIndex(self.itself))

    def get_buffer_size(self, space):
        return space.newint(self.buffer_size)

    def set_buffer_size(self, space, w_value):
        value = space.getindex_w(w_value, space.w_OverflowError)
        if value <= 0:
            raise oefmt(space.w_ValueError,
                        "buffer_size must be greater than zero")
        self.flush_character_buffer(space)
        self.buffer_size = value

    def get_buffer_text(self, space):
        return space.newbool(self.buffer is not None)

    def set_buffer_text(self, space, w_value):
        if space.is_true(w_value):
            self.buffer = []
            self.buffer_used = 0
        else:
            self.flush_character_buffer(space)
            self.buffer = None

    def get_intern(self, space):
        if self.w_intern:
            return self.w_intern
        else:
            return space.w_None
Beispiel #17
0
class StringMethods(object):
    def _sliced(self, space, s, start, stop, orig_obj):
        assert start >= 0
        assert stop >= 0
        #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj),
        #                                                space.w_bytes):
        #    return orig_obj
        return self._new(s[start:stop])

    def _convert_idx_params(self, space, w_start, w_end):
        value = self._val(space)
        lenself = len(value)
        start, end = unwrap_start_stop(space, lenself, w_start, w_end)
        # the None means "no offset"; see bytearrayobject.py
        return (value, start, end, None)

    def _multi_chr(self, c):
        return c

    def descr_len(self, space):
        return space.newint(self._len())

    #def descr_iter(self, space):
    #    pass

    def descr_contains(self, space, w_sub):
        value, start, end, _ = self._convert_idx_params(space, None, None)
        if self._use_rstr_ops(space, w_sub):
            other = self._op_val(space, w_sub)
            return space.newbool(value.find(other, start, end) >= 0)

        from pypy.objspace.std.bytesobject import W_BytesObject
        if isinstance(w_sub, W_BytesObject):
            other = self._op_val(space, w_sub)
            res = find(value, other, start, end)
        else:
            buffer = _get_buffer(space, w_sub)
            res = find(value, buffer, start, end)

        return space.newbool(res >= 0)

    def descr_add(self, space, w_other):
        if self._use_rstr_ops(space, w_other):
            try:
                other = self._op_val(space, w_other)
            except OperationError as e:
                if e.match(space, space.w_TypeError):
                    return space.w_NotImplemented
                raise
            return self._new(self._val(space) + other)

        # Bytearray overrides this method, CPython doesn't support contacting
        # buffers and strs, and unicodes are always handled above
        return space.w_NotImplemented

    def descr_mul(self, space, w_times):
        try:
            times = space.getindex_w(w_times, space.w_OverflowError)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise
        if times <= 0:
            return self._empty()
        if self._len() == 1:
            return self._new(self._multi_chr(self._val(space)[0]) * times)
        return self._new(self._val(space) * times)

    descr_rmul = descr_mul

    def descr_getitem(self, space, w_index):
        if isinstance(w_index, W_SliceObject):
            selfvalue = self._val(space)
            length = len(selfvalue)
            start, stop, step, sl = w_index.indices4(space, length)
            if sl == 0:
                return self._empty()
            elif step == 1:
                assert start >= 0 and stop >= 0
                return self._sliced(space, selfvalue, start, stop, self)
            else:
                ret = _descr_getslice_slowpath(selfvalue, start, step, sl)
                return self._new_from_list(ret)

        index = space.getindex_w(w_index, space.w_IndexError, "string index")
        return self._getitem_result(space, index)

    def _getitem_result(self, space, index):
        selfvalue = self._val(space)
        try:
            character = selfvalue[index]
        except IndexError:
            raise oefmt(space.w_IndexError, "string index out of range")
        return self._new(character)

    def descr_getslice(self, space, w_start, w_stop):
        selfvalue = self._val(space)
        start, stop = normalize_simple_slice(space, len(selfvalue), w_start,
                                             w_stop)
        if start == stop:
            return self._empty()
        else:
            return self._sliced(space, selfvalue, start, stop, self)

    def descr_capitalize(self, space):
        value = self._val(space)
        if len(value) == 0:
            return self._empty()

        builder = self._builder(len(value))
        builder.append(self._upper(value[0]))
        for i in range(1, len(value)):
            builder.append(self._lower(value[i]))
        return self._new(builder.build())

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_center(self, space, width, w_fillchar):
        value = self._val(space)
        fillchar = self._op_val(space, w_fillchar)
        if len(fillchar) != 1:
            raise oefmt(space.w_TypeError,
                        "center() argument 2 must be a single character")

        d = width - len(value)
        if d > 0:
            offset = d // 2 + (d & width & 1)
            fillchar = self._multi_chr(fillchar[0])
            centered = offset * fillchar + value + (d - offset) * fillchar
        else:
            centered = value

        return self._new(centered)

    def descr_count(self, space, w_sub, w_start=None, w_end=None):
        value, start, end, _ = self._convert_idx_params(space, w_start, w_end)

        if self._use_rstr_ops(space, w_sub):
            return space.newint(
                value.count(self._op_val(space, w_sub), start, end))

        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        from pypy.objspace.std.bytesobject import W_BytesObject
        if isinstance(w_sub, W_BytearrayObject):
            res = count(value, w_sub.getdata(), start, end)
        elif isinstance(w_sub, W_BytesObject):
            res = count(value, w_sub._value, start, end)
        else:
            buffer = _get_buffer(space, w_sub)
            res = count(value, buffer, start, end)

        assert res >= 0
        return space.newint(res)

    def descr_decode(self, space, w_encoding=None, w_errors=None):
        from pypy.objspace.std.unicodeobject import (_get_encoding_and_errors,
                                                     decode_object,
                                                     unicode_from_string)
        encoding, errors = _get_encoding_and_errors(space, w_encoding,
                                                    w_errors)

        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        if (encoding is None and errors is None
                and not isinstance(self, W_BytearrayObject)):
            return unicode_from_string(space, self)
        return decode_object(space, self, encoding, errors)

    def descr_encode(self, space, w_encoding=None, w_errors=None):
        from pypy.objspace.std.unicodeobject import (_get_encoding_and_errors,
                                                     encode_object)
        encoding, errors = _get_encoding_and_errors(space, w_encoding,
                                                    w_errors)
        return encode_object(space, self, encoding, errors)

    @unwrap_spec(tabsize=int)
    def descr_expandtabs(self, space, tabsize=8):
        value = self._val(space)
        if not value:
            return self._empty()

        if self._use_rstr_ops(space, self):
            splitted = value.split(self._chr('\t'))
        else:
            splitted = split(value, self._chr('\t'))

        try:
            if tabsize > 0:
                ovfcheck(len(splitted) * tabsize)
        except OverflowError:
            raise oefmt(space.w_OverflowError, "new string is too long")
        expanded = oldtoken = splitted.pop(0)

        for token in splitted:
            expanded += self._multi_chr(self._chr(' ')) * self._tabindent(
                oldtoken, tabsize) + token
            oldtoken = token

        return self._new(expanded)

    def _tabindent(self, token, tabsize):
        """calculates distance behind the token to the next tabstop"""

        if tabsize <= 0:
            return 0
        distance = tabsize
        if token:
            distance = 0
            offset = len(token)

            while 1:
                if token[offset - 1] == "\n" or token[offset - 1] == "\r":
                    break
                distance += 1
                offset -= 1
                if offset == 0:
                    break

            # the same like distance = len(token) - (offset + 1)
            distance = (tabsize - distance) % tabsize
            if distance == 0:
                distance = tabsize

        return distance

    def descr_find(self, space, w_sub, w_start=None, w_end=None):
        value, start, end, ofs = self._convert_idx_params(
            space, w_start, w_end)

        if self._use_rstr_ops(space, w_sub):
            res = value.find(self._op_val(space, w_sub), start, end)
            return space.newint(res)

        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        from pypy.objspace.std.bytesobject import W_BytesObject
        if isinstance(w_sub, W_BytearrayObject):
            res = find(value, w_sub.getdata(), start, end)
        elif isinstance(w_sub, W_BytesObject):
            res = find(value, w_sub._value, start, end)
        else:
            buffer = _get_buffer(space, w_sub)
            res = find(value, buffer, start, end)
        if ofs is not None and res >= 0:
            res -= ofs
        return space.newint(res)

    def descr_rfind(self, space, w_sub, w_start=None, w_end=None):
        value, start, end, ofs = self._convert_idx_params(
            space, w_start, w_end)

        if self._use_rstr_ops(space, w_sub):
            res = value.rfind(self._op_val(space, w_sub), start, end)
            return space.newint(res)

        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        from pypy.objspace.std.bytesobject import W_BytesObject
        if isinstance(w_sub, W_BytearrayObject):
            res = rfind(value, w_sub.getdata(), start, end)
        elif isinstance(w_sub, W_BytesObject):
            res = rfind(value, w_sub._value, start, end)
        else:
            buffer = _get_buffer(space, w_sub)
            res = rfind(value, buffer, start, end)
        if ofs is not None and res >= 0:
            res -= ofs
        return space.newint(res)

    def descr_index(self, space, w_sub, w_start=None, w_end=None):
        value, start, end, ofs = self._convert_idx_params(
            space, w_start, w_end)

        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        from pypy.objspace.std.bytesobject import W_BytesObject
        if self._use_rstr_ops(space, w_sub):
            res = value.find(self._op_val(space, w_sub), start, end)
        elif isinstance(w_sub, W_BytearrayObject):
            res = find(value, w_sub.getdata(), start, end)
        elif isinstance(w_sub, W_BytesObject):
            res = find(value, w_sub._value, start, end)
        else:
            buffer = _get_buffer(space, w_sub)
            res = find(value, buffer, start, end)

        if res < 0:
            raise oefmt(space.w_ValueError,
                        "substring not found in string.index")
        if ofs is not None:
            res -= ofs
        return space.newint(res)

    def descr_rindex(self, space, w_sub, w_start=None, w_end=None):
        value, start, end, ofs = self._convert_idx_params(
            space, w_start, w_end)

        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        from pypy.objspace.std.bytesobject import W_BytesObject
        if self._use_rstr_ops(space, w_sub):
            res = value.rfind(self._op_val(space, w_sub), start, end)
        elif isinstance(w_sub, W_BytearrayObject):
            res = rfind(value, w_sub.getdata(), start, end)
        elif isinstance(w_sub, W_BytesObject):
            res = rfind(value, w_sub._value, start, end)
        else:
            buffer = _get_buffer(space, w_sub)
            res = rfind(value, buffer, start, end)

        if res < 0:
            raise oefmt(space.w_ValueError,
                        "substring not found in string.rindex")
        if ofs is not None:
            res -= ofs
        return space.newint(res)

    @specialize.arg(2)
    def _is_generic(self, space, func_name):
        func = getattr(self, func_name)
        v = self._val(space)
        if len(v) == 0:
            return space.w_False
        if len(v) == 1:
            c = v[0]
            return space.newbool(func(c))
        else:
            return self._is_generic_loop(space, v, func_name)

    @specialize.arg(3)
    def _is_generic_loop(self, space, v, func_name):
        func = getattr(self, func_name)
        for idx in range(len(v)):
            if not func(v[idx]):
                return space.w_False
        return space.w_True

    def descr_isalnum(self, space):
        return self._is_generic(space, '_isalnum')

    def descr_isalpha(self, space):
        return self._is_generic(space, '_isalpha')

    def descr_isdigit(self, space):
        return self._is_generic(space, '_isdigit')

    # this is only for bytes and bytesarray: unicodeobject overrides it
    def _descr_islower_slowpath(self, space, v):
        cased = False
        for idx in range(len(v)):
            if self._isupper(v[idx]):
                return False
            elif not cased and self._islower(v[idx]):
                cased = True
        return cased

    def descr_islower(self, space):
        v = self._val(space)
        if len(v) == 1:
            c = v[0]
            return space.newbool(self._islower(c))
        cased = self._descr_islower_slowpath(space, v)
        return space.newbool(cased)

    def descr_isspace(self, space):
        return self._is_generic(space, '_isspace')

    def descr_istitle(self, space):
        input = self._val(space)
        cased = False
        previous_is_cased = False

        for pos in range(0, len(input)):
            ch = input[pos]
            if self._istitle(ch):
                if previous_is_cased:
                    return space.w_False
                previous_is_cased = True
                cased = True
            elif self._islower(ch):
                if not previous_is_cased:
                    return space.w_False
                cased = True
            else:
                previous_is_cased = False

        return space.newbool(cased)

    # this is only for bytes and bytesarray: unicodeobject overrides it
    def _descr_isupper_slowpath(self, space, v):
        cased = False
        for idx in range(len(v)):
            if self._islower(v[idx]):
                return False
            elif not cased and self._isupper(v[idx]):
                cased = True
        return cased

    def descr_isupper(self, space):
        v = self._val(space)
        if len(v) == 1:
            c = v[0]
            return space.newbool(self._isupper(c))
        cased = self._descr_isupper_slowpath(space, v)
        return space.newbool(cased)

    def descr_join(self, space, w_list):
        list_w = space.listview(w_list)
        size = len(list_w)

        if size == 0:
            return self._empty()

        if size == 1:
            w_s = list_w[0]
            # only one item, return it if it's not a subclass of str
            if self._join_return_one(space, w_s):
                return w_s

        return self._str_join_many_items(space, list_w, size)

    @jit.look_inside_iff(lambda self, space, list_w, size: jit.
                         loop_unrolling_heuristic(list_w, size))
    def _str_join_many_items(self, space, list_w, size):
        value = self._val(space)

        prealloc_size = len(value) * (size - 1)
        unwrapped = newlist_hint(size)
        for i in range(size):
            w_s = list_w[i]
            check_item = self._join_check_item(space, w_s)
            if check_item == 1:
                raise oefmt(space.w_TypeError,
                            "sequence item %d: expected string, %T found", i,
                            w_s)
            elif check_item == 2:
                return self._join_autoconvert(space, list_w)
            # XXX Maybe the extra copy here is okay? It was basically going to
            #     happen anyway, what with being placed into the builder
            unwrapped.append(self._op_val(space, w_s))
            prealloc_size += len(unwrapped[i])

        sb = self._builder(prealloc_size)
        for i in range(size):
            if value and i != 0:
                sb.append(value)
            sb.append(unwrapped[i])
        return self._new(sb.build())

    def _join_autoconvert(self, space, list_w):
        assert False, 'unreachable'

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_ljust(self, space, width, w_fillchar):
        value = self._val(space)
        fillchar = self._op_val(space, w_fillchar)
        if len(fillchar) != 1:
            raise oefmt(space.w_TypeError,
                        "ljust() argument 2 must be a single character")
        d = width - len(value)
        if d > 0:
            fillchar = self._multi_chr(fillchar[0])
            value = value + fillchar * d

        return self._new(value)

    @unwrap_spec(width=int, w_fillchar=WrappedDefault(' '))
    def descr_rjust(self, space, width, w_fillchar):
        value = self._val(space)
        fillchar = self._op_val(space, w_fillchar)
        if len(fillchar) != 1:
            raise oefmt(space.w_TypeError,
                        "rjust() argument 2 must be a single character")
        d = width - len(value)
        if d > 0:
            fillchar = self._multi_chr(fillchar[0])
            value = d * fillchar + value

        return self._new(value)

    def descr_lower(self, space):
        value = self._val(space)
        builder = self._builder(len(value))
        for i in range(len(value)):
            builder.append(self._lower(value[i]))
        return self._new(builder.build())

    def descr_partition(self, space, w_sub):
        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        value = self._val(space)

        if self._use_rstr_ops(space, w_sub):
            sub = self._op_val(space, w_sub)
            sublen = len(sub)
            if sublen == 0:
                raise oefmt(space.w_ValueError, "empty separator")

            pos = value.find(sub)
        else:
            sub = _get_buffer(space, w_sub)
            sublen = sub.getlength()
            if sublen == 0:
                raise oefmt(space.w_ValueError, "empty separator")

            pos = find(value, sub, 0, len(value))
            if pos != -1 and isinstance(self, W_BytearrayObject):
                w_sub = self._new_from_buffer(sub)

        if pos == -1:
            if isinstance(self, W_BytearrayObject):
                self = self._new(value)
            return space.newtuple([self, self._empty(), self._empty()])
        else:
            return space.newtuple([
                self._sliced(space, value, 0, pos, self), w_sub,
                self._sliced(space, value, pos + sublen, len(value), self)
            ])

    def descr_rpartition(self, space, w_sub):
        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
        value = self._val(space)

        if self._use_rstr_ops(space, w_sub):
            sub = self._op_val(space, w_sub)
            sublen = len(sub)
            if sublen == 0:
                raise oefmt(space.w_ValueError, "empty separator")

            pos = value.rfind(sub)
        else:
            sub = _get_buffer(space, w_sub)
            sublen = sub.getlength()
            if sublen == 0:
                raise oefmt(space.w_ValueError, "empty separator")

            pos = rfind(value, sub, 0, len(value))
            if pos != -1 and isinstance(self, W_BytearrayObject):
                w_sub = self._new_from_buffer(sub)

        if pos == -1:
            if isinstance(self, W_BytearrayObject):
                self = self._new(value)
            return space.newtuple([self._empty(), self._empty(), self])
        else:
            return space.newtuple([
                self._sliced(space, value, 0, pos, self), w_sub,
                self._sliced(space, value, pos + sublen, len(value), self)
            ])

    @unwrap_spec(count=int)
    def descr_replace(self, space, w_old, w_new, count=-1):
        input = self._val(space)

        sub = self._op_val(space, w_old)
        by = self._op_val(space, w_new)
        # the following two lines are for being bug-to-bug compatible
        # with CPython: see issue #2448
        if count >= 0 and len(input) == 0:
            return self._empty()
        try:
            res = replace(input, sub, by, count)
        except OverflowError:
            raise oefmt(space.w_OverflowError, "replace string is too long")

        return self._new(res)

    @unwrap_spec(maxsplit=int)
    def descr_split(self, space, w_sep=None, maxsplit=-1):
        res = []
        value = self._val(space)
        if space.is_none(w_sep):
            res = split(value, maxsplit=maxsplit)
            return self._newlist_unwrapped(space, res)

        by = self._op_val(space, w_sep)
        if len(by) == 0:
            raise oefmt(space.w_ValueError, "empty separator")
        res = split(value, by, maxsplit)

        return self._newlist_unwrapped(space, res)

    @unwrap_spec(maxsplit=int)
    def descr_rsplit(self, space, w_sep=None, maxsplit=-1):
        res = []
        value = self._val(space)
        if space.is_none(w_sep):
            res = rsplit(value, maxsplit=maxsplit)
            return self._newlist_unwrapped(space, res)

        by = self._op_val(space, w_sep)
        if len(by) == 0:
            raise oefmt(space.w_ValueError, "empty separator")
        res = rsplit(value, by, maxsplit)

        return self._newlist_unwrapped(space, res)

    @unwrap_spec(keepends=bool)
    def descr_splitlines(self, space, keepends=False):
        value = self._val(space)
        length = len(value)
        strs = []
        pos = 0
        while pos < length:
            sol = pos
            while pos < length and not self._islinebreak(value[pos]):
                pos += 1
            eol = pos
            pos += 1
            # read CRLF as one line break
            if pos < length and value[eol] == '\r' and value[pos] == '\n':
                pos += 1
            if keepends:
                eol = pos
            strs.append(value[sol:eol])
        if pos < length:
            strs.append(value[pos:length])
        return self._newlist_unwrapped(space, strs)

    def descr_startswith(self, space, w_prefix, w_start=None, w_end=None):
        value, start, end, _ = self._convert_idx_params(space, w_start, w_end)
        if space.isinstance_w(w_prefix, space.w_tuple):
            return self._startswith_tuple(space, value, w_prefix, start, end)
        return space.newbool(
            self._startswith(space, value, w_prefix, start, end))

    def _startswith_tuple(self, space, value, w_prefix, start, end):
        for w_prefix in space.fixedview(w_prefix):
            if self._startswith(space, value, w_prefix, start, end):
                return space.w_True
        return space.w_False

    def _startswith(self, space, value, w_prefix, start, end):
        prefix = self._op_val(space, w_prefix)
        if self._starts_ends_unicode:  # bug-to-bug compat
            if len(prefix) == 0:
                return True
        else:
            if start > len(value):
                return False
        return startswith(value, prefix, start, end)

    _starts_ends_unicode = False  # bug-to-bug compat: this is for strings and

    # bytearrays, but overridden for unicodes

    def descr_endswith(self, space, w_suffix, w_start=None, w_end=None):
        value, start, end, _ = self._convert_idx_params(space, w_start, w_end)
        if space.isinstance_w(w_suffix, space.w_tuple):
            return self._endswith_tuple(space, value, w_suffix, start, end)
        return space.newbool(self._endswith(space, value, w_suffix, start,
                                            end))

    def _endswith_tuple(self, space, value, w_suffix, start, end):
        for w_suffix in space.fixedview(w_suffix):
            if self._endswith(space, value, w_suffix, start, end):
                return space.w_True
        return space.w_False

    def _endswith(self, space, value, w_prefix, start, end):
        prefix = self._op_val(space, w_prefix)
        if self._starts_ends_unicode:  # bug-to-bug compat
            if len(prefix) == 0:
                return True
        else:
            if start > len(value):
                return False
        return endswith(value, prefix, start, end)

    def _strip(self, space, w_chars, left, right, name='strip'):
        "internal function called by str_xstrip methods"
        value = self._val(space)
        chars = self._op_val(space, w_chars, strict=name)

        lpos = 0
        rpos = len(value)

        if left:
            while lpos < rpos and value[lpos] in chars:
                lpos += 1

        if right:
            while rpos > lpos and value[rpos - 1] in chars:
                rpos -= 1

        assert rpos >= lpos  # annotator hint, don't remove
        return self._sliced(space, value, lpos, rpos, self)

    def _strip_none(self, space, left, right):
        "internal function called by str_xstrip methods"
        value = self._val(space)

        lpos = 0
        rpos = len(value)

        if left:
            while lpos < rpos and self._isspace(value[lpos]):
                lpos += 1

        if right:
            while rpos > lpos and self._isspace(value[rpos - 1]):
                rpos -= 1

        assert rpos >= lpos  # annotator hint, don't remove
        return self._sliced(space, value, lpos, rpos, self)

    def descr_strip(self, space, w_chars=None):
        if space.is_none(w_chars):
            return self._strip_none(space, left=1, right=1)
        return self._strip(space, w_chars, left=1, right=1, name='strip')

    def descr_lstrip(self, space, w_chars=None):
        if space.is_none(w_chars):
            return self._strip_none(space, left=1, right=0)
        return self._strip(space, w_chars, left=1, right=0, name='lstrip')

    def descr_rstrip(self, space, w_chars=None):
        if space.is_none(w_chars):
            return self._strip_none(space, left=0, right=1)
        return self._strip(space, w_chars, left=0, right=1, name='rstrip')

    def descr_swapcase(self, space):
        selfvalue = self._val(space)
        builder = self._builder(len(selfvalue))
        for i in range(len(selfvalue)):
            ch = selfvalue[i]
            if self._isupper(ch):
                builder.append(self._lower(ch))
            elif self._islower(ch):
                builder.append(self._upper(ch))
            else:
                builder.append(ch)
        return self._new(builder.build())

    def descr_title(self, space):
        selfval = self._val(space)
        if len(selfval) == 0:
            return self
        return self._new(self.title(selfval))

    @jit.elidable
    def title(self, value):
        builder = self._builder(len(value))
        previous_is_cased = False
        for ch in value:
            if not previous_is_cased:
                builder.append(self._title(ch))
            else:
                builder.append(self._lower(ch))
            previous_is_cased = self._iscased(ch)
        return builder.build()

    DEFAULT_NOOP_TABLE = ''.join([chr(i) for i in range(256)])

    # for bytes and bytearray, overridden by unicode
    @unwrap_spec(w_deletechars=WrappedDefault(''))
    def descr_translate(self, space, w_table, w_deletechars):
        if space.is_w(w_table, space.w_None):
            table = self.DEFAULT_NOOP_TABLE
        else:
            table = self._op_val(space, w_table)
            if len(table) != 256:
                raise oefmt(space.w_ValueError,
                            "translation table must be 256 characters long")

        string = self._val(space)
        deletechars = self._op_val(space, w_deletechars)
        if len(deletechars) == 0:
            buf = self._builder(len(string))
            for char in string:
                buf.append(table[ord(char)])
        else:
            # XXX Why not preallocate here too?
            buf = self._builder()
            deletion_table = [False] * 256
            for i in range(len(deletechars)):
                deletion_table[ord(deletechars[i])] = True
            for char in string:
                if not deletion_table[ord(char)]:
                    buf.append(table[ord(char)])
        return self._new(buf.build())

    def descr_upper(self, space):
        value = self._val(space)
        builder = self._builder(len(value))
        for i in range(len(value)):
            builder.append(self._upper(value[i]))
        return self._new(builder.build())

    @unwrap_spec(width=int)
    def descr_zfill(self, space, width):
        selfval = self._val(space)
        if len(selfval) == 0:
            return self._new(self._multi_chr(self._chr('0')) * width)
        num_zeros = width - len(selfval)
        if num_zeros <= 0:
            # cannot return self, in case it is a subclass of str
            return self._new(selfval)

        builder = self._builder(width)
        if len(selfval) > 0 and (selfval[0] == '+' or selfval[0] == '-'):
            # copy sign to first position
            builder.append(selfval[0])
            start = 1
        else:
            start = 0
        builder.append_multiple_char(self._chr('0'), num_zeros)
        builder.append_slice(selfval, start, len(selfval))
        return self._new(builder.build())

    def descr_getnewargs(self, space):
        return space.newtuple([self._new(self._val(space))])
Beispiel #18
0
@unwrap_spec(host='text')
def gethostbyaddr(space, host):
    """gethostbyaddr(host) -> (name, aliaslist, addresslist)

    Return the true host name, a list of aliases, and a list of IP addresses,
    for a host.  The host argument is a string giving a host name or IP number.
    """
    try:
        res = rsocket.gethostbyaddr(host)
    except SocketError as e:
        raise converted_error(space, e)
    return common_wrapgethost(space, res)


@unwrap_spec(name='text', w_proto=WrappedDefault(None))
def getservbyname(space, name, w_proto):
    """getservbyname(servicename[, protocolname]) -> integer

    Return a port number from a service name and protocol name.
    The optional protocol name, if given, should be 'tcp' or 'udp',
    otherwise any protocol will match.
    """
    if space.is_w(w_proto, space.w_None):
        proto = None
    else:
        proto = space.text_w(w_proto)
    try:
        port = rsocket.getservbyname(name, proto)
    except SocketError as e:
        raise converted_error(space, e)
Beispiel #19
0
        raise oefmt(space.w_ValueError, "step argument must not be zero")
    elif step < 0:
        lo, hi, step = hi, lo, -step
    if lo < hi:
        uhi = r_uint(hi)
        ulo = r_uint(lo)
        diff = uhi - ulo - 1
        n = intmask(diff // r_uint(step) + 1)
        if n < 0:
            raise oefmt(space.w_OverflowError, "result has too many items")
    else:
        n = 0
    return n


@unwrap_spec(w_step=WrappedDefault(1))
def range_int(space, w_x, w_y=None, w_step=None):
    """Return a list of integers in arithmetic position from start (defaults
to zero) to stop - 1 by step (defaults to 1).  Use a negative step to
get a list in decending order."""

    if w_y is None:
        w_start = space.newint(0)
        w_stop = w_x
    else:
        w_start = w_x
        w_stop = w_y

    if space.isinstance_w(w_stop, space.w_float):
        raise oefmt(space.w_TypeError,
                    "range() integer end argument expected, got float.")
Beispiel #20
0
class GetSetProperty(W_Root):
    _immutable_fields_ = ["fget", "fset", "fdel"]
    w_objclass = None

    @specialize.arg(7)
    def __init__(self,
                 fget,
                 fset=None,
                 fdel=None,
                 doc=None,
                 cls=None,
                 use_closure=False,
                 tag=None,
                 name=None):
        objclass_getter, cls = make_objclass_getter(tag, fget, cls)
        fget = make_descr_typecheck_wrapper((tag, 0),
                                            fget,
                                            cls=cls,
                                            use_closure=use_closure)
        fset = make_descr_typecheck_wrapper((tag, 1),
                                            fset, ('w_value', ),
                                            cls=cls,
                                            use_closure=use_closure)
        fdel = make_descr_typecheck_wrapper((tag, 2),
                                            fdel,
                                            cls=cls,
                                            use_closure=use_closure)
        self._init(fget, fset, fdel, doc, cls, objclass_getter, use_closure,
                   name)

    def _init(self, fget, fset, fdel, doc, cls, objclass_getter, use_closure,
              name):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        self.doc = doc
        self.reqcls = cls
        self.w_qualname = None
        self.objclass_getter = objclass_getter
        self.use_closure = use_closure
        self.name = name if name is not None else '<generic property>'

    def copy_for_type(self, w_objclass):
        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, 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):
        """property.__get__(obj[, type]) -> value
        Read the value of the property of the given obj."""
        # XXX HAAAAAAAAAAAACK (but possibly a good one)
        if (space.is_w(w_obj, space.w_None)
                and not space.is_w(w_cls, space.type(space.w_None))):
            #print self, w_obj, w_cls
            if space.is_w(w_cls, space.w_None):
                raise oefmt(space.w_TypeError,
                            "__get__(None, None) is invalid")
            return self
        else:
            try:
                return self.fget(self, space, w_obj)
            except DescrMismatch:
                return w_obj.descr_call_mismatch(
                    space, '__getattribute__', self.reqcls,
                    Arguments(space, [w_obj, space.newtext(self.name)]))

    def readonly_attribute(self, space):  # overwritten in cpyext
        if self.name == '<generic property>':
            raise oefmt(space.w_AttributeError, "readonly attribute")
        else:
            raise oefmt(space.w_AttributeError, "readonly attribute '%s'",
                        self.name)

    def descr_property_set(self, space, w_obj, w_value):
        """property.__set__(obj, value)
        Change the value of the property of the given obj."""
        fset = self.fset
        if fset is None:
            raise self.readonly_attribute(space)
        try:
            fset(self, space, w_obj, w_value)
        except DescrMismatch:
            w_obj.descr_call_mismatch(
                space, '__setattr__', self.reqcls,
                Arguments(space,
                          [w_obj, space.newtext(self.name), w_value]))

    def descr_property_del(self, space, w_obj):
        """property.__delete__(obj)
        Delete the value of the property from the given obj."""
        fdel = self.fdel
        if fdel is None:
            raise oefmt(space.w_AttributeError, "cannot delete attribute")
        try:
            fdel(self, space, w_obj)
        except DescrMismatch:
            w_obj.descr_call_mismatch(
                space, '__delattr__', self.reqcls,
                Arguments(space, [w_obj, space.newtext(self.name)]))

    def descr_get_qualname(self, space):
        if self.w_qualname is None:
            self.w_qualname = self._calculate_qualname(space)
        return self.w_qualname

    def _calculate_qualname(self, space):
        if self.reqcls is None:
            type_qualname = '?'
        else:
            w_type = space.gettypeobject(self.reqcls.typedef)
            type_qualname = space.text_w(
                space.getattr(w_type, space.newtext('__qualname__')))
        qualname = "%s.%s" % (type_qualname, self.name)
        return space.newtext(qualname)

    def descr_get_objclass(space, property):
        if property.w_objclass is not None:
            return property.w_objclass
        if property.objclass_getter is not None:
            return property.objclass_getter(space)
        # NB. this is an AttributeError to make inspect.py happy
        raise oefmt(space.w_AttributeError,
                    "generic property has no __objclass__")

    def spacebind(self, space):
        if hasattr(space, '_see_getsetproperty'):
            space._see_getsetproperty(self)  # only for fake/objspace.py
        return self
Beispiel #21
0
class W_SRE_Match(W_Root):
    flatten_cache = None

    def __init__(self, srepat, ctx):
        self.space = srepat.space
        self.srepat = srepat
        self.ctx = ctx

    def repr_w(self):
        space = self.space
        ctx = self.ctx
        start, end = ctx.match_start, ctx.match_end
        w_s = slice_w(space, ctx, start, end, space.w_None)
        # follow the same logic as CPython, repr'ing the whole match
        # before deciding to throw away everything beyond the 50th unichar
        # (which will leave the opening quote unbalanced, and might be
        # cutting in the middle of a '\' escape)
        w_s = space.repr(w_s)
        w_s = space.getslice(w_s, space.newint(0), space.newint(50))
        u = space.utf8_w(w_s)
        start = self.bytepos_to_charindex(start)
        end = self.bytepos_to_charindex(end)
        return space.newtext(
            '<_sre.SRE_Match object; span=(%d, %d), match=%s>' %
            (start, end, u))

    def cannot_copy_w(self):
        space = self.space
        raise oefmt(space.w_TypeError, "cannot copy this match object")

    def descr_getitem(self, space, w_index):
        start, end = self.do_span(w_index)
        return slice_w(space, self.ctx, start, end, space.w_None)

    @jit.look_inside_iff(lambda self, args_w: jit.isconstant(len(args_w)))
    def group_w(self, args_w):
        space = self.space
        ctx = self.ctx
        if len(args_w) <= 1:
            if len(args_w) == 0:
                start, end = ctx.match_start, ctx.match_end
            else:
                start, end = self.do_span(args_w[0])
            return slice_w(space, ctx, start, end, space.w_None)
        else:
            results = [None] * len(args_w)
            for i in range(len(args_w)):
                start, end = self.do_span(args_w[i])
                results[i] = slice_w(space, ctx, start, end, space.w_None)
            return space.newtuple(results)

    @unwrap_spec(w_default=WrappedDefault(None))
    def groups_w(self, w_default=None):
        fmarks = self.flatten_marks()
        num_groups = self.srepat.num_groups
        return allgroups_w(self.space, self.ctx, fmarks, num_groups, w_default)

    @unwrap_spec(w_default=WrappedDefault(None))
    def groupdict_w(self, w_default=None):
        space = self.space
        w_dict = space.newdict()
        w_groupindex = self.srepat.w_groupindex
        w_iterator = space.iter(w_groupindex)
        while True:
            try:
                w_key = space.next(w_iterator)
            except OperationError as e:
                if not e.match(space, space.w_StopIteration):
                    raise
                break  # done
            w_value = space.getitem(w_groupindex, w_key)
            start, end = self.do_span(w_value)
            w_grp = slice_w(space, self.ctx, start, end, w_default)
            space.setitem(w_dict, w_key, w_grp)
        return w_dict

    def expand_w(self, w_template):
        space = self.space
        w_re = import_re(space)
        return space.call_method(w_re, '_expand', self.srepat, self,
                                 w_template)

    @unwrap_spec(w_groupnum=WrappedDefault(0))
    def start_w(self, w_groupnum):
        start, end = self.do_span(w_groupnum)
        start = self.bytepos_to_charindex(start)
        return self.space.newint(start)

    @unwrap_spec(w_groupnum=WrappedDefault(0))
    def end_w(self, w_groupnum):
        start, end = self.do_span(w_groupnum)
        end = self.bytepos_to_charindex(end)
        return self.space.newint(end)

    @unwrap_spec(w_groupnum=WrappedDefault(0))
    def span_w(self, w_groupnum):
        start, end = self.do_span(w_groupnum)
        return self.new_charindex_tuple(start, end)

    def new_charindex_tuple(self, start, end):
        start = self.bytepos_to_charindex(start)
        end = self.bytepos_to_charindex(end)
        return self.space.newtuple(
            [self.space.newint(start),
             self.space.newint(end)])

    def bytepos_to_charindex(self, bytepos):
        # Transform a 'byte position', as returned by all methods from
        # rsre_core, back into a 'character index'.  This is for UTF8
        # handling.
        ctx = self.ctx
        if isinstance(ctx, rsre_utf8.Utf8MatchContext):
            return ctx.w_unicode_obj._byte_to_index(bytepos)
        else:
            return bytepos

    def flatten_marks(self):
        if self.flatten_cache is None:
            num_groups = self.srepat.num_groups
            self.flatten_cache = do_flatten_marks(self.ctx, num_groups)
        return self.flatten_cache

    def do_span(self, w_arg):
        # return a pair of integers, which are byte positions, not
        # character indexes (for utf8)
        space = self.space
        try:
            groupnum = space.getindex_w(w_arg, space.w_OverflowError)
        except OperationError as e:
            if not e.match(space, space.w_TypeError) and \
                    not e.match(space, space.w_OverflowError):
                raise
            try:
                w_groupnum = space.getitem(self.srepat.w_groupindex, w_arg)
            except OperationError as e:
                if not e.match(space, space.w_KeyError):
                    raise
                raise oefmt(space.w_IndexError, "no such group")
            groupnum = space.int_w(w_groupnum)
        if groupnum == 0:
            return self.ctx.match_start, self.ctx.match_end
        elif 1 <= groupnum <= self.srepat.num_groups:
            fmarks = self.flatten_marks()
            idx = 2 * (groupnum - 1)
            assert idx >= 0
            return fmarks[idx], fmarks[idx + 1]
        else:
            raise oefmt(space.w_IndexError, "no such group")

    def _last_index(self):
        mark = self.ctx.match_marks
        if mark is not None:
            return mark.gid // 2 + 1
        return -1

    def fget_lastgroup(self, space):
        lastindex = self._last_index()
        if lastindex < 0:
            return space.w_None
        w_result = space.finditem(self.srepat.w_indexgroup,
                                  space.newint(lastindex))
        if w_result is None:
            return space.w_None
        return w_result

    def fget_lastindex(self, space):
        lastindex = self._last_index()
        if lastindex >= 0:
            return space.newint(lastindex)
        return space.w_None

    def fget_pos(self, space):
        return space.newint(self.bytepos_to_charindex(self.ctx.original_pos))

    def fget_endpos(self, space):
        return space.newint(self.bytepos_to_charindex(self.ctx.end))

    def fget_regs(self, space):
        space = self.space
        fmarks = self.flatten_marks()
        num_groups = self.srepat.num_groups
        result_w = [None] * (num_groups + 1)
        ctx = self.ctx
        result_w[0] = self.new_charindex_tuple(ctx.match_start, ctx.match_end)
        for i in range(num_groups):
            result_w[i + 1] = self.new_charindex_tuple(fmarks[i * 2],
                                                       fmarks[i * 2 + 1])
        return space.newtuple(result_w)

    def fget_string(self, space):
        ctx = self.ctx
        if isinstance(ctx, rsre_core.BufMatchContext):
            return space.newbytes(ctx._buffer.as_str())
        elif isinstance(ctx, UnicodeAsciiMatchContext):
            return space.newutf8(ctx._string, len(ctx._string))
        elif isinstance(ctx, rsre_core.StrMatchContext):
            return space.newbytes(ctx._string)
        elif isinstance(ctx, rsre_utf8.Utf8MatchContext):
            lgt = rutf8.codepoints_in_utf8(ctx._utf8)
            return space.newutf8(ctx._utf8, lgt)
        else:
            raise SystemError
Beispiel #22
0
class W_BytearrayObject(W_Root):
    import_from_mixin(StringMethods)

    def __init__(self, data):
        check_list_of_chars(data)
        self.data = resizable_list_supporting_raw_ptr(data)

    def __repr__(self):
        """representation for debugging purposes"""
        return "%s(%s)" % (self.__class__.__name__, ''.join(self.data))

    def buffer_w(self, space, flags):
        return BytearrayBuffer(self.data, False)

    def readbuf_w(self, space):
        return BytearrayBuffer(self.data, True)

    def writebuf_w(self, space):
        return BytearrayBuffer(self.data, False)

    def charbuf_w(self, space):
        return ''.join(self.data)

    def bytearray_list_of_chars_w(self, space):
        return self.data

    def nonmovable_carray(self, space):
        return BytearrayBuffer(self.data, False).get_raw_address()

    def _new(self, value):
        if value is self.data:
            value = value[:]
        return W_BytearrayObject(value)

    def _new_from_buffer(self, buffer):
        return W_BytearrayObject([buffer[i] for i in range(len(buffer))])

    def _new_from_list(self, value):
        return W_BytearrayObject(value)

    def _empty(self):
        return W_BytearrayObject([])

    def _len(self):
        return len(self.data)

    def _getitem_result(self, space, index):
        try:
            character = self.data[index]
        except IndexError:
            raise oefmt(space.w_IndexError, "bytearray index out of range")
        return space.newint(ord(character))

    def _val(self, space):
        return self.data

    @staticmethod
    def _use_rstr_ops(space, w_other):
        return False

    @staticmethod
    def _op_val(space, w_other, strict=None):
        # bytearray does not enforce the strict restriction (on strip at least)
        return space.buffer_w(w_other, space.BUF_SIMPLE).as_str()

    def _chr(self, char):
        assert len(char) == 1
        return str(char)[0]

    def _multi_chr(self, char):
        return [char]

    @staticmethod
    def _builder(size=100):
        return ByteListBuilder(size)

    def _newlist_unwrapped(self, space, res):
        return space.newlist([W_BytearrayObject(i) for i in res])

    def _isupper(self, ch):
        return ch.isupper()

    def _islower(self, ch):
        return ch.islower()

    def _istitle(self, ch):
        return ch.isupper()

    def _isspace(self, ch):
        return ch.isspace()

    def _isalpha(self, ch):
        return ch.isalpha()

    def _isalnum(self, ch):
        return ch.isalnum()

    def _isdigit(self, ch):
        return ch.isdigit()

    _iscased = _isalpha

    def _islinebreak(self, ch):
        return (ch == '\n') or (ch == '\r')

    def _upper(self, ch):
        if ch.islower():
            o = ord(ch) - 32
            return chr(o)
        else:
            return ch

    def _lower(self, ch):
        if ch.isupper():
            o = ord(ch) + 32
            return chr(o)
        else:
            return ch

    _title = _upper

    def _join_return_one(self, space, w_obj):
        return False

    def _join_check_item(self, space, w_obj):
        if (space.isinstance_w(w_obj, space.w_bytes) or
            space.isinstance_w(w_obj, space.w_bytearray)):
            return 0
        return 1

    def ord(self, space):
        if len(self.data) != 1:
            raise oefmt(space.w_TypeError,
                        "ord() expected a character, but string of length %d "
                        "found", len(self.data))
        return space.newint(ord(self.data[0]))

    @staticmethod
    def descr_new(space, w_bytearraytype, __args__):
        return new_bytearray(space, w_bytearraytype, [])

    def descr_reduce(self, space):
        assert isinstance(self, W_BytearrayObject)
        w_dict = self.getdict(space)
        if w_dict is None:
            w_dict = space.w_None
        return space.newtuple([
            space.type(self), space.newtuple([
                space.newunicode(''.join(self.data).decode('latin-1')),
                space.newtext('latin-1')]),
            w_dict])

    @staticmethod
    def descr_fromhex(space, w_bytearraytype, w_hexstring):
        hexstring = space.text_w(w_hexstring)
        data = _hexstring_to_array(space, hexstring)
        # in CPython bytearray.fromhex is a staticmethod, so
        # we ignore w_type and always return a bytearray
        return new_bytearray(space, space.w_bytearray, data)

    @unwrap_spec(encoding='text_or_none', errors='text_or_none')
    def descr_init(self, space, w_source=None, encoding=None, errors=None):
        if w_source is None:
            w_source = space.newbytes('')
        if encoding is not None:
            from pypy.objspace.std.unicodeobject import encode_object
            # if w_source is an integer this correctly raises a
            # TypeError the CPython error message is: "encoding or
            # errors without a string argument" ours is: "expected
            # unicode, got int object"
            w_source = encode_object(space, w_source, encoding, errors)

        # Is it an int?
        try:
            count = space.int_w(w_source)
        except OperationError as e:
            if not e.match(space, space.w_TypeError):
                raise
        else:
            if count < 0:
                raise oefmt(space.w_ValueError, "bytearray negative count")
            self.data = resizable_list_supporting_raw_ptr(['\0'] * count)
            return

        data = makebytearraydata_w(space, w_source)
        self.data = resizable_list_supporting_raw_ptr(data)

    def descr_repr(self, space):
        s = self.data

        # Good default if there are no replacements.
        buf = StringBuilder(len("bytearray(b'')") + len(s))

        buf.append("bytearray(b")
        quote = "'"
        for c in s:
            if c == '"':
                quote = "'"
                break
            elif c == "'":
                quote = '"'
        buf.append(quote)

        for i in range(len(s)):
            c = s[i]

            if c == '\\' or c == "'":
                buf.append('\\')
                buf.append(c)
            elif c == '\t':
                buf.append('\\t')
            elif c == '\r':
                buf.append('\\r')
            elif c == '\n':
                buf.append('\\n')
            elif not '\x20' <= c < '\x7f':
                n = ord(c)
                buf.append('\\x')
                buf.append("0123456789abcdef"[n >> 4])
                buf.append("0123456789abcdef"[n & 0xF])
            else:
                buf.append(c)

        buf.append(quote)
        buf.append(")")

        return space.newtext(buf.build())

    def descr_str(self, space):
        return space.newtext(''.join(self.data))

    def descr_eq(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            return space.newbool(self.data == w_other.data)

        try:
            buffer = _get_buffer(space, w_other)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise

        value = self._val(space)
        buffer_len = buffer.getlength()

        if len(value) != buffer_len:
            return space.newbool(False)

        min_length = min(len(value), buffer_len)
        return space.newbool(_memcmp(value, buffer, min_length) == 0)

    def descr_ne(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            return space.newbool(self.data != w_other.data)

        try:
            buffer = _get_buffer(space, w_other)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise

        value = self._val(space)
        buffer_len = buffer.getlength()

        if len(value) != buffer_len:
            return space.newbool(True)

        min_length = min(len(value), buffer_len)
        return space.newbool(_memcmp(value, buffer, min_length) != 0)

    def _comparison_helper(self, space, w_other):
        value = self._val(space)

        if isinstance(w_other, W_BytearrayObject):
            other = w_other.data
            other_len = len(other)
            cmp = _memcmp(value, other, min(len(value), len(other)))
        elif isinstance(w_other, W_BytesObject):
            other = self._op_val(space, w_other)
            other_len = len(other)
            cmp = _memcmp(value, other, min(len(value), len(other)))
        else:
            try:
                buffer = _get_buffer(space, w_other)
            except OperationError as e:
                if e.match(space, space.w_TypeError):
                    return False, 0, 0
                raise
            other_len = len(buffer)
            cmp = _memcmp(value, buffer, min(len(value), len(buffer)))

        return True, cmp, other_len

    def descr_lt(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp < 0 or (cmp == 0 and self._len() < other_len))

    def descr_le(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp < 0 or (cmp == 0 and self._len() <= other_len))

    def descr_gt(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp > 0 or (cmp == 0 and self._len() > other_len))

    def descr_ge(self, space, w_other):
        success, cmp, other_len = self._comparison_helper(space, w_other)
        if not success:
            return space.w_NotImplemented
        return space.newbool(cmp > 0 or (cmp == 0 and self._len() >= other_len))

    def descr_iter(self, space):
        return space.newseqiter(self)

    def descr_inplace_add(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            self.data += w_other.data
            return self

        if isinstance(w_other, W_BytesObject):
            self._inplace_add(self._op_val(space, w_other))
        else:
            self._inplace_add(_get_buffer(space, w_other))
        return self

    @specialize.argtype(1)
    def _inplace_add(self, other):
        for i in range(len(other)):
            self.data.append(other[i])

    def descr_inplace_mul(self, space, w_times):
        try:
            times = space.getindex_w(w_times, space.w_OverflowError)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise
        self.data *= times
        return self

    def descr_setitem(self, space, w_index, w_other):
        if isinstance(w_index, W_SliceObject):
            oldsize = len(self.data)
            start, stop, step, slicelength = w_index.indices4(space, oldsize)
            sequence2 = makebytearraydata_w(space, w_other)
            _setitem_slice_helper(space, self.data, start, step,
                                  slicelength, sequence2, empty_elem='\x00')
        else:
            idx = space.getindex_w(w_index, space.w_IndexError,
                                   "bytearray index")
            try:
                self.data[idx] = getbytevalue(space, w_other)
            except IndexError:
                raise oefmt(space.w_IndexError, "bytearray index out of range")

    def descr_delitem(self, space, w_idx):
        if isinstance(w_idx, W_SliceObject):
            start, stop, step, slicelength = w_idx.indices4(space,
                                                            len(self.data))
            _delitem_slice_helper(space, self.data, start, step, slicelength)
        else:
            idx = space.getindex_w(w_idx, space.w_IndexError,
                                   "bytearray index")
            try:
                del self.data[idx]
            except IndexError:
                raise oefmt(space.w_IndexError,
                            "bytearray deletion index out of range")

    def descr_append(self, space, w_item):
        self.data.append(getbytevalue(space, w_item))

    def descr_extend(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            self.data += w_other.data
        else:
            self.data += makebytearraydata_w(space, w_other)
        return self

    def descr_insert(self, space, w_idx, w_other):
        where = space.int_w(w_idx)
        length = len(self.data)
        index = get_positive_index(where, length)
        val = getbytevalue(space, w_other)
        self.data.insert(index, val)
        return space.w_None

    @unwrap_spec(w_idx=WrappedDefault(-1))
    def descr_pop(self, space, w_idx):
        index = space.int_w(w_idx)
        try:
            result = self.data.pop(index)
        except IndexError:
            if not self.data:
                raise oefmt(space.w_IndexError, "pop from empty bytearray")
            raise oefmt(space.w_IndexError, "pop index out of range")
        return space.newint(ord(result))

    def descr_remove(self, space, w_char):
        char = space.int_w(space.index(w_char))
        try:
            self.data.remove(chr(char))
        except ValueError:
            raise oefmt(space.w_ValueError, "value not found in bytearray")

    _StringMethods_descr_contains = descr_contains
    def descr_contains(self, space, w_sub):
        if space.isinstance_w(w_sub, space.w_int):
            char = space.int_w(w_sub)
            return _descr_contains_bytearray(self.data, space, char)

        return self._StringMethods_descr_contains(space, w_sub)

    def descr_add(self, space, w_other):
        if isinstance(w_other, W_BytearrayObject):
            return self._new(self.data + w_other.data)

        if isinstance(w_other, W_BytesObject):
            return self._add(self._op_val(space, w_other))

        try:
            buffer = _get_buffer(space, w_other)
        except OperationError as e:
            if e.match(space, space.w_TypeError):
                return space.w_NotImplemented
            raise
        return self._add(buffer)

    @specialize.argtype(1)
    def _add(self, other):
        return self._new(self.data + [other[i] for i in range(len(other))])

    def descr_reverse(self, space):
        self.data.reverse()
Beispiel #23
0
class W_IntObject(W_AbstractIntObject):

    __slots__ = 'intval'
    _immutable_fields_ = ['intval']

    def __init__(self, intval):
        assert is_valid_int(intval)
        self.intval = intval

    def __repr__(self):
        """representation for debugging purposes"""
        return "%s(%d)" % (self.__class__.__name__, self.intval)

    def int_w(self, space, allow_conversion=True):
        return int(self.intval)

    def _int_w(self, space):
        return int(self.intval)

    unwrap = _int_w

    def uint_w(self, space):
        intval = self.intval
        if intval < 0:
            raise oefmt(space.w_ValueError,
                        "cannot convert negative integer to unsigned")
        return r_uint(intval)

    def bigint_w(self, space, allow_conversion=True):
        return rbigint.fromint(self.intval)

    def _bigint_w(self, space):
        return rbigint.fromint(self.intval)

    def float_w(self, space, allow_conversion=True):
        return float(self.intval)

    # note that we do NOT implement _float_w, because __float__ cannot return
    # an int

    def int(self, space):
        if type(self) is W_IntObject:
            return self
        if not space.is_overloaded(self, space.w_int, '__int__'):
            return space.newint(self.intval)
        return W_Root.int(self, space)

    @staticmethod
    @unwrap_spec(w_x=WrappedDefault(0))
    def descr_new(space, w_inttype, w_x, w_base=None):
        """T.__new__(S, ...) -> a new object with type S, a subtype of T"""
        return _new_int(space, w_inttype, w_x, w_base)

    def descr_hash(self, space):
        # unlike CPython, we don't special-case the value -1 in most of
        # our hash functions, so there is not much sense special-casing
        # it here either.  Make sure this is consistent with the hash of
        # floats and longs.
        return self.int(space)

    def _int(self, space):
        return self.int(space)

    descr_pos = func_with_new_name(_int, 'descr_pos')
    descr_index = func_with_new_name(_int, 'descr_index')
    descr_trunc = func_with_new_name(_int, 'descr_trunc')
    descr_conjugate = func_with_new_name(_int, 'descr_conjugate')

    descr_get_numerator = func_with_new_name(_int, 'descr_get_numerator')
    descr_get_real = func_with_new_name(_int, 'descr_get_real')

    def descr_get_denominator(self, space):
        return wrapint(space, 1)

    def descr_get_imag(self, space):
        return wrapint(space, 0)

    def descr_coerce(self, space, w_other):
        if not isinstance(w_other, W_AbstractIntObject):
            return space.w_NotImplemented
        return space.newtuple([self, w_other])

    def descr_long(self, space):
        # XXX: should try smalllong
        from pypy.objspace.std.longobject import W_LongObject
        return W_LongObject.fromint(space, self.intval)

    def descr_nonzero(self, space):
        return space.newbool(self.intval != 0)

    def descr_invert(self, space):
        return wrapint(space, ~self.intval)

    def descr_neg(self, space):
        a = self.intval
        try:
            b = ovfcheck(-a)
        except OverflowError:
            if _recover_with_smalllong(space):
                from pypy.objspace.std.smalllongobject import W_SmallLongObject
                x = r_longlong(a)
                return W_SmallLongObject(-x)
            return self.descr_long(space).descr_neg(space)
        return wrapint(space, b)

    def descr_abs(self, space):
        pos = self.intval >= 0
        return self.int(space) if pos else self.descr_neg(space)

    def descr_float(self, space):
        a = self.intval
        x = float(a)
        return space.newfloat(x)

    def descr_oct(self, space):
        return space.wrap(oct(self.intval))

    def descr_hex(self, space):
        return space.wrap(hex(self.intval))

    def descr_getnewargs(self, space):
        return space.newtuple([wrapint(space, self.intval)])

    def descr_bit_length(self, space):
        val = self.intval
        bits = 0
        if val < 0:
            # warning, "-val" overflows here
            val = -((val + 1) >> 1)
            bits = 1
        while val:
            bits += 1
            val >>= 1
        return space.wrap(bits)

    def descr_repr(self, space):
        res = str(self.intval)
        return space.wrap(res)

    descr_str = func_with_new_name(descr_repr, 'descr_str')

    def descr_format(self, space, w_format_spec):
        return newformat.run_formatter(space, w_format_spec,
                                       "format_int_or_long", self,
                                       newformat.INT_KIND)

    @unwrap_spec(w_modulus=WrappedDefault(None))
    def descr_pow(self, space, w_exponent, w_modulus=None):
        if not isinstance(w_exponent, W_IntObject):
            return space.w_NotImplemented

        x = self.intval
        y = w_exponent.intval

        if space.is_none(w_modulus):
            z = 0
        elif isinstance(w_modulus, W_IntObject):
            z = w_modulus.intval
            if z == 0:
                raise oefmt(space.w_ValueError,
                            "pow() 3rd argument cannot be 0")
        else:
            # can't return NotImplemented (space.pow doesn't do full
            # ternary, i.e. w_modulus.__zpow__(self, w_exponent)), so
            # handle it ourselves
            return _pow_ovf2long(space, x, y, w_modulus)

        try:
            result = _pow(space, x, y, z)
        except (OverflowError, ValueError):
            return _pow_ovf2long(space, x, y, w_modulus)
        return space.wrap(result)

    @unwrap_spec(w_modulus=WrappedDefault(None))
    def descr_rpow(self, space, w_base, w_modulus=None):
        if not isinstance(w_base, W_IntObject):
            return space.w_NotImplemented
        return w_base.descr_pow(space, self, w_modulus)

    def _make_descr_cmp(opname):
        op = getattr(operator, opname)

        @func_renamer('descr_' + opname)
        def descr_cmp(self, space, w_other):
            if not isinstance(w_other, W_IntObject):
                return space.w_NotImplemented
            i = self.intval
            j = w_other.intval
            return space.newbool(op(i, j))

        return descr_cmp

    descr_lt = _make_descr_cmp('lt')
    descr_le = _make_descr_cmp('le')
    descr_eq = _make_descr_cmp('eq')
    descr_ne = _make_descr_cmp('ne')
    descr_gt = _make_descr_cmp('gt')
    descr_ge = _make_descr_cmp('ge')

    def _make_generic_descr_binop(opname, ovf=True):
        op = getattr(operator,
                     opname + '_' if opname in ('and', 'or') else opname)
        descr_rname = 'descr_r' + opname
        if ovf:
            ovf2long = _make_ovf2long(opname)

        @func_renamer('descr_' + opname)
        def descr_binop(self, space, w_other):
            if not isinstance(w_other, W_IntObject):
                return space.w_NotImplemented

            x = self.intval
            y = w_other.intval
            if ovf:
                try:
                    z = ovfcheck(op(x, y))
                except OverflowError:
                    return ovf2long(space, x, y)
            else:
                z = op(x, y)
            return wrapint(space, z)

        if opname in COMMUTATIVE_OPS:

            @func_renamer(descr_rname)
            def descr_rbinop(self, space, w_other):
                return descr_binop(self, space, w_other)

            return descr_binop, descr_rbinop

        @func_renamer(descr_rname)
        def descr_rbinop(self, space, w_other):
            if not isinstance(w_other, W_IntObject):
                return space.w_NotImplemented

            x = self.intval
            y = w_other.intval
            if ovf:
                try:
                    z = ovfcheck(op(y, x))
                except OverflowError:
                    return ovf2long(space, y, x)
            else:
                z = op(y, x)
            return wrapint(space, z)

        return descr_binop, descr_rbinop

    descr_add, descr_radd = _make_generic_descr_binop('add')
    descr_sub, descr_rsub = _make_generic_descr_binop('sub')
    descr_mul, descr_rmul = _make_generic_descr_binop('mul')

    descr_and, descr_rand = _make_generic_descr_binop('and', ovf=False)
    descr_or, descr_ror = _make_generic_descr_binop('or', ovf=False)
    descr_xor, descr_rxor = _make_generic_descr_binop('xor', ovf=False)

    def _make_descr_binop(func, ovf=True, ovf2small=None):
        opname = func.__name__[1:]
        if ovf:
            ovf2long = _make_ovf2long(opname, ovf2small)

        @func_renamer('descr_' + opname)
        def descr_binop(self, space, w_other):
            if not isinstance(w_other, W_IntObject):
                return space.w_NotImplemented

            x = self.intval
            y = w_other.intval
            if ovf:
                try:
                    return func(space, x, y)
                except OverflowError:
                    return ovf2long(space, x, y)
            else:
                return func(space, x, y)

        @func_renamer('descr_r' + opname)
        def descr_rbinop(self, space, w_other):
            if not isinstance(w_other, W_IntObject):
                return space.w_NotImplemented

            x = self.intval
            y = w_other.intval
            if ovf:
                try:
                    return func(space, y, x)
                except OverflowError:
                    return ovf2long(space, y, x)
            else:
                return func(space, y, x)

        return descr_binop, descr_rbinop

    descr_lshift, descr_rlshift = _make_descr_binop(
        _lshift, ovf2small=_lshift_ovf2small)
    descr_rshift, descr_rrshift = _make_descr_binop(_rshift, ovf=False)

    descr_floordiv, descr_rfloordiv = _make_descr_binop(_floordiv)
    descr_div, descr_rdiv = _make_descr_binop(_div)
    descr_truediv, descr_rtruediv = _make_descr_binop(_truediv)
    descr_mod, descr_rmod = _make_descr_binop(_mod)
    descr_divmod, descr_rdivmod = _make_descr_binop(
        _divmod, ovf2small=_divmod_ovf2small)
Beispiel #24
0
class W_SRE_Match(W_Root):
    flatten_cache = None

    def __init__(self, srepat, ctx):
        self.space = srepat.space
        self.srepat = srepat
        self.ctx = ctx

    def cannot_copy_w(self):
        space = self.space
        raise oefmt(space.w_TypeError, "cannot copy this match object")

    @jit.look_inside_iff(lambda self, args_w: jit.isconstant(len(args_w)))
    def group_w(self, args_w):
        space = self.space
        ctx = self.ctx
        if len(args_w) <= 1:
            if len(args_w) == 0:
                start, end = ctx.match_start, ctx.match_end
            else:
                start, end = self.do_span(args_w[0])
            return slice_w(space, ctx, start, end, space.w_None)
        else:
            results = [None] * len(args_w)
            for i in range(len(args_w)):
                start, end = self.do_span(args_w[i])
                results[i] = slice_w(space, ctx, start, end, space.w_None)
            return space.newtuple(results)

    @unwrap_spec(w_default=WrappedDefault(None))
    def groups_w(self, w_default=None):
        fmarks = self.flatten_marks()
        num_groups = self.srepat.num_groups
        return allgroups_w(self.space, self.ctx, fmarks, num_groups, w_default)

    @unwrap_spec(w_default=WrappedDefault(None))
    def groupdict_w(self, w_default=None):
        space = self.space
        w_dict = space.newdict()
        w_groupindex = self.srepat.w_groupindex
        w_iterator = space.iter(w_groupindex)
        while True:
            try:
                w_key = space.next(w_iterator)
            except OperationError as e:
                if not e.match(space, space.w_StopIteration):
                    raise
                break  # done
            w_value = space.getitem(w_groupindex, w_key)
            start, end = self.do_span(w_value)
            w_grp = slice_w(space, self.ctx, start, end, w_default)
            space.setitem(w_dict, w_key, w_grp)
        return w_dict

    def expand_w(self, w_template):
        space = self.space
        w_re = import_re(space)
        return space.call_method(w_re, '_expand', self.srepat, self,
                                 w_template)

    @unwrap_spec(w_groupnum=WrappedDefault(0))
    def start_w(self, w_groupnum):
        return self.space.newint(self.do_span(w_groupnum)[0])

    @unwrap_spec(w_groupnum=WrappedDefault(0))
    def end_w(self, w_groupnum):
        return self.space.newint(self.do_span(w_groupnum)[1])

    @unwrap_spec(w_groupnum=WrappedDefault(0))
    def span_w(self, w_groupnum):
        start, end = self.do_span(w_groupnum)
        return self.space.newtuple(
            [self.space.newint(start),
             self.space.newint(end)])

    def flatten_marks(self):
        if self.flatten_cache is None:
            num_groups = self.srepat.num_groups
            self.flatten_cache = do_flatten_marks(self.ctx, num_groups)
        return self.flatten_cache

    def do_span(self, w_arg):
        space = self.space
        try:
            groupnum = space.int_w(w_arg)
        except OperationError as e:
            if not e.match(space, space.w_TypeError) and \
                    not e.match(space, space.w_OverflowError):
                raise
            try:
                w_groupnum = space.getitem(self.srepat.w_groupindex, w_arg)
            except OperationError as e:
                if not e.match(space, space.w_KeyError):
                    raise
                raise oefmt(space.w_IndexError, "no such group")
            groupnum = space.int_w(w_groupnum)
        if groupnum == 0:
            return self.ctx.match_start, self.ctx.match_end
        elif 1 <= groupnum <= self.srepat.num_groups:
            fmarks = self.flatten_marks()
            idx = 2 * (groupnum - 1)
            assert idx >= 0
            return fmarks[idx], fmarks[idx + 1]
        else:
            raise oefmt(space.w_IndexError, "group index out of range")

    def _last_index(self):
        mark = self.ctx.match_marks
        if mark is not None:
            return mark.gid // 2 + 1
        return -1

    def fget_lastgroup(self, space):
        lastindex = self._last_index()
        if lastindex < 0:
            return space.w_None
        w_result = space.finditem(self.srepat.w_indexgroup,
                                  space.newint(lastindex))
        if w_result is None:
            return space.w_None
        return w_result

    def fget_lastindex(self, space):
        lastindex = self._last_index()
        if lastindex >= 0:
            return space.newint(lastindex)
        return space.w_None

    def fget_pos(self, space):
        return space.newint(self.ctx.original_pos)

    def fget_endpos(self, space):
        return space.newint(self.ctx.end)

    def fget_regs(self, space):
        space = self.space
        fmarks = self.flatten_marks()
        num_groups = self.srepat.num_groups
        result_w = [None] * (num_groups + 1)
        ctx = self.ctx
        result_w[0] = space.newtuple(
            [space.newint(ctx.match_start),
             space.newint(ctx.match_end)])
        for i in range(num_groups):
            result_w[i + 1] = space.newtuple(
                [space.newint(fmarks[i * 2]),
                 space.newint(fmarks[i * 2 + 1])])
        return space.newtuple(result_w)

    def fget_string(self, space):
        ctx = self.ctx
        if isinstance(ctx, rsre_core.BufMatchContext):
            return space.newbytes(ctx._buffer.as_str())
        elif isinstance(ctx, rsre_core.StrMatchContext):
            return space.newbytes(ctx._string)
        elif isinstance(ctx, rsre_core.UnicodeMatchContext):
            return space.newunicode(ctx._unicodestr)
        else:
            raise SystemError
Beispiel #25
0
    if encoding != 'ascii':
        return unicode_from_encoded_object(space, w_str, encoding, "strict")
    s = space.str_w(w_str)
    try:
        return W_UnicodeObject(s.decode("ascii"))
    except UnicodeDecodeError:
        # raising UnicodeDecodeError is messy, "please crash for me"
        return unicode_from_encoded_object(space, w_str, "ascii", "strict")

def unicode_decode__unitypedef_ANY_ANY(space, w_unicode, w_encoding=None,
                                       w_errors=None):
    return space.call_method(space.str(w_unicode), 'decode',
                             w_encoding, w_errors)


@unwrap_spec(w_string = WrappedDefault(""))
def descr_new_(space, w_unicodetype, w_string, w_encoding=None, w_errors=None):
    # NB. the default value of w_obj is really a *wrapped* empty string:
    #     there is gateway magic at work
    from pypy.objspace.std.unicodeobject import W_UnicodeObject
    w_obj = w_string

    encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors)
    # convoluted logic for the case when unicode subclass has a __unicode__
    # method, we need to call this method
    is_precisely_unicode = space.is_w(space.type(w_obj), space.w_unicode)
    if (is_precisely_unicode or
        (space.isinstance_w(w_obj, space.w_unicode) and
         space.findattr(w_obj, space.wrap('__unicode__')) is None)):
        if encoding is not None or errors is not None:
            raise OperationError(space.w_TypeError,
Beispiel #26
0
    if count == -1:
        count = length / itemsize
    if length % itemsize != 0:
        raise oefmt(space.w_ValueError,
                    "string length %d not divisable by item size %d",
                    length, itemsize)
    if count * itemsize > length:
        raise OperationError(space.w_ValueError, space.wrap(
            "string is smaller than requested size"))

    a = W_NDimArray.from_shape(space, [count], dtype=dtype)
    loop.fromstring_loop(space, a, dtype, itemsize, s)
    return space.wrap(a)


@unwrap_spec(s=str, count=int, sep=str, w_dtype=WrappedDefault(None))
def fromstring(space, s, w_dtype=None, count=-1, sep=''):
    dtype = space.interp_w(descriptor.W_Dtype,
        space.call_function(space.gettypefor(descriptor.W_Dtype), w_dtype))
    length = len(s)
    if sep == '':
        return _fromstring_bin(space, s, count, length, dtype)
    else:
        return _fromstring_text(space, s, count, sep, length, dtype)


def _getbuffer(space, w_buffer):
    try:
        return space.writebuf_w(w_buffer)
    except OperationError as e:
        if not e.match(space, space.w_TypeError):
Beispiel #27
0
            start += step
        return space.newtuple(subitems)

    def descr_getnewargs(self, space):
        return space.newtuple([space.newtuple(self.tolist())])

    @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self))
    def descr_count(self, space, w_obj):
        """count(obj) -> number of times obj appears in the tuple"""
        count = 0
        for w_item in self.tolist():
            if space.eq_w(w_item, w_obj):
                count += 1
        return space.wrap(count)

    @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint))
    @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self))
    def descr_index(self, space, w_obj, w_start, w_stop):
        """index(obj, [start, [stop]]) -> first index that obj appears in the
        tuple
        """
        length = self.length()
        start, stop = unwrap_start_stop(space, length, w_start, w_stop)
        for i in range(start, min(stop, length)):
            w_item = self.tolist()[i]
            if space.eq_w(w_item, w_obj):
                return space.wrap(i)
        raise OperationError(space.w_ValueError,
                             space.wrap("tuple.index(x): x not in tuple"))

Beispiel #28
0
    try:
        w_get_source = space.getattr(w_loader, space.newtext("get_source"))
    except OperationError as e:
        if not e.match(space, space.w_AttributeError):
            raise
        return None

    # Call get_source() to get the source code.
    w_source = space.call_function(w_get_source, w_module_name)
    if space.is_w(w_source, space.w_None):
        return None

    # Split the source into lines.
    w_source_list = space.call_method(w_source, "splitlines")

    # Get the source line.
    w_source_line = space.getitem(w_source_list, space.newint(lineno - 1))
    return w_source_line

@unwrap_spec(lineno=int, w_module = WrappedDefault(None),
             w_registry = WrappedDefault(None),
             w_module_globals = WrappedDefault(None))
def warn_explicit(space, w_message, w_category, w_filename, lineno,
                  w_module=None, w_registry=None, w_module_globals=None):

    w_source_line = get_source_line(space, w_module_globals, lineno)

    do_warn_explicit(space, w_category, w_message,
                     (w_filename, lineno, w_module, w_registry),
                     w_source_line)
Beispiel #29
0
        errors = 'strict'
    state = space.fromcache(CodecState)
    # NB. can't call unicode_encode_utf_8() directly because that's
    # an @elidable function nowadays.  Instead, we need the _impl().
    # (The problem is the errorhandler, which calls arbitrary Python.)
    result = runicode.unicode_encode_utf_8_impl(uni,
                                                len(uni),
                                                errors,
                                                state.encode_error_handler,
                                                allow_surrogates=True)
    return space.newtuple([space.newbytes(result), space.newint(len(uni))])


@unwrap_spec(string='bufferstr',
             errors='text_or_none',
             w_final=WrappedDefault(False))
def utf_8_decode(space, string, errors="strict", w_final=None):
    if errors is None:
        errors = 'strict'
    final = space.is_true(w_final)
    state = space.fromcache(CodecState)
    # NB. can't call str_decode_utf_8() directly because that's
    # an @elidable function nowadays.  Instead, we need the _impl().
    # (The problem is the errorhandler, which calls arbitrary Python.)
    result, consumed = runicode.str_decode_utf_8_impl(
        string,
        len(string),
        errors,
        final,
        state.decode_error_handler,
        allow_surrogates=True)
Beispiel #30
0
class W_FloatObject(W_Root):
    """This is a implementation of the app-level 'float' type.
    The constructor takes an RPython float as an argument."""
    _immutable_fields_ = ['floatval']

    def __init__(self, floatval):
        self.floatval = floatval

    def unwrap(self, space):
        return self.floatval

    def int_w(self, space, allow_conversion=True):
        self._typed_unwrap_error(space, "integer")

    def bigint_w(self, space, allow_conversion=True):
        self._typed_unwrap_error(space, "integer")

    def float_w(self, space, allow_conversion=True):
        return self.floatval

    def _float_w(self, space):
        return self.floatval

    def int(self, space):
        # this is a speed-up only, for space.int(w_float).
        if (type(self) is not W_FloatObject
                and space.is_overloaded(self, space.w_float, '__int__')):
            return W_Root.int(self, space)
        return self.descr_trunc(space)

    def is_w(self, space, w_other):
        from rpython.rlib.longlong2float import float2longlong
        if not isinstance(w_other, W_FloatObject):
            return False
        if self.user_overridden_class or w_other.user_overridden_class:
            return self is w_other
        one = float2longlong(space.float_w(self))
        two = float2longlong(space.float_w(w_other))
        return one == two

    def immutable_unique_id(self, space):
        if self.user_overridden_class:
            return None
        from rpython.rlib.longlong2float import float2longlong
        from pypy.objspace.std.util import IDTAG_FLOAT as tag
        from pypy.objspace.std.util import IDTAG_SHIFT
        val = float2longlong(space.float_w(self))
        b = rbigint.fromrarith_int(val)
        b = b.lshift(IDTAG_SHIFT).int_or_(tag)
        return space.newlong_from_rbigint(b)

    def __repr__(self):
        return "<W_FloatObject(%f)>" % self.floatval

    @staticmethod
    @unwrap_spec(w_x=WrappedDefault(0.0))
    def descr__new__(space, w_floattype, w_x):
        def _string_to_float(space, w_source, string):
            try:
                return rfloat.string_to_float(string)
            except ParseStringError as e:
                raise wrap_parsestringerror(space, e, w_source)

        w_value = w_x  # 'x' is the keyword argument name in CPython
        if space.lookup(w_value, "__float__") is not None:
            w_obj = space.float(w_value)
            if space.is_w(w_floattype, space.w_float):
                return w_obj
            value = space.float_w(w_obj)
        elif space.isinstance_w(w_value, space.w_unicode):
            from unicodeobject import unicode_to_decimal_w
            value = _string_to_float(space, w_value,
                                     unicode_to_decimal_w(space, w_value))
        else:
            try:
                value = space.charbuf_w(w_value)
            except OperationError as e:
                if e.match(space, space.w_TypeError):
                    raise oefmt(
                        space.w_TypeError,
                        "float() argument must be a string or a number")
                raise
            value = _string_to_float(space, w_value, value)
        w_obj = space.allocate_instance(W_FloatObject, w_floattype)
        W_FloatObject.__init__(w_obj, value)
        return w_obj

    @staticmethod
    @unwrap_spec(kind='text')
    def descr___getformat__(space, w_cls, kind):
        if kind == "float":
            return space.newtext(_float_format)
        elif kind == "double":
            return space.newtext(_double_format)
        raise oefmt(space.w_ValueError, "only float and double are valid")

    @staticmethod
    @unwrap_spec(s='text')
    def descr_fromhex(space, w_cls, s):
        length = len(s)
        i = 0
        value = 0.0
        while i < length and s[i].isspace():
            i += 1
        if i == length:
            raise oefmt(space.w_ValueError, "invalid hex string")
        sign = 1
        if s[i] == "-":
            sign = -1
            i += 1
        elif s[i] == "+":
            i += 1
        if length == i:
            raise oefmt(space.w_ValueError, "invalid hex string")
        if s[i] == "i" or s[i] == "I":
            i += 1
            if length - i >= 2 and s[i:i + 2].lower() == "nf":
                i += 2
                value = rfloat.INFINITY
                if length - i >= 5 and s[i:i + 5].lower() == "inity":
                    i += 5
        elif s[i] == "n" or s[i] == "N":
            i += 1
            if length - i >= 2 and s[i:i + 2].lower() == "an":
                i += 2
                value = rfloat.NAN
        else:
            if (s[i] == "0" and length - i > 1
                    and (s[i + 1] == "x" or s[i + 1] == "X")):
                i += 2
            co_start = i
            while i < length and _hex_from_char(s[i]) >= 0:
                i += 1
            whole_end = i
            if i < length and s[i] == ".":
                i += 1
                while i < length and _hex_from_char(s[i]) >= 0:
                    i += 1
                co_end = i - 1
            else:
                co_end = i
            total_digits = co_end - co_start
            float_digits = co_end - whole_end
            if not total_digits:
                raise oefmt(space.w_ValueError, "invalid hex string")
            const_one = rfloat.DBL_MIN_EXP - rfloat.DBL_MANT_DIG + sys.maxint // 2
            const_two = sys.maxint // 2 + 1 - rfloat.DBL_MAX_EXP
            if total_digits > min(const_one, const_two) // 4:
                raise oefmt(space.w_ValueError, "way too long")
            if i < length and (s[i] == "p" or s[i] == "P"):
                i += 1
                if i == length:
                    raise oefmt(space.w_ValueError, "invalid hex string")
                exp_sign = 1
                if s[i] == "-" or s[i] == "+":
                    if s[i] == "-":
                        exp_sign = -1
                    i += 1
                    if i == length:
                        raise oefmt(space.w_ValueError, "invalid hex string")
                if not s[i].isdigit():
                    raise oefmt(space.w_ValueError, "invalid hex string")
                exp = ord(s[i]) - ord('0')
                i += 1
                while i < length and s[i].isdigit():
                    exp = exp * 10 + (ord(s[i]) - ord('0'))
                    if exp >= (sys.maxint - 9) // 10:
                        if exp_sign > 0:
                            exp_sign = 2  # overflow in positive numbers
                        else:
                            exp_sign = -2  # overflow in negative numbers
                    i += 1
                if exp_sign == -1:
                    exp = -exp
                elif exp_sign == -2:
                    exp = -sys.maxint / 2
                elif exp_sign == 2:
                    exp = sys.maxint / 2
            else:
                exp = 0
            while (total_digits and _hex_digit(s, total_digits - 1, co_end,
                                               float_digits) == 0):
                total_digits -= 1
            if not total_digits or exp <= -sys.maxint / 2:
                value = 0.0
            elif exp >= sys.maxint // 2:
                raise oefmt(space.w_OverflowError, "too large")
            else:
                exp -= 4 * float_digits
                top_exp = exp + 4 * (total_digits - 1)
                digit = _hex_digit(s, total_digits - 1, co_end, float_digits)
                while digit:
                    top_exp += 1
                    digit //= 2
                if top_exp < rfloat.DBL_MIN_EXP - rfloat.DBL_MANT_DIG:
                    value = 0.0
                elif top_exp > rfloat.DBL_MAX_EXP:
                    raise oefmt(space.w_OverflowError, "too large")
                else:
                    lsb = max(top_exp,
                              rfloat.DBL_MIN_EXP) - rfloat.DBL_MANT_DIG
                    value = 0
                    if exp >= lsb:
                        for j in range(total_digits - 1, -1, -1):
                            value = 16.0 * value + _hex_digit(
                                s, j, co_end, float_digits)
                        value = math.ldexp(value, exp)
                    else:
                        half_eps = 1 << ((lsb - exp - 1) % 4)
                        key_digit = (lsb - exp - 1) // 4
                        for j in range(total_digits - 1, key_digit, -1):
                            value = 16.0 * value + _hex_digit(
                                s, j, co_end, float_digits)
                        digit = _hex_digit(s, key_digit, co_end, float_digits)
                        value = 16.0 * value + (digit & (16 - 2 * half_eps))
                        if digit & half_eps:
                            round_up = False
                            if (digit & (3 * half_eps - 1) or
                                (half_eps == 8 and key_digit + 1 < float_digits
                                 and _hex_digit(s, key_digit + 1, co_end,
                                                float_digits) & 1)):
                                round_up = True
                            else:
                                for j in range(key_digit - 1, -1, -1):
                                    if _hex_digit(s, j, co_end, float_digits):
                                        round_up = True
                                        break
                            if round_up:
                                value += 2 * half_eps
                                mant_dig = rfloat.DBL_MANT_DIG
                                if (top_exp == rfloat.DBL_MAX_EXP
                                        and value == math.ldexp(
                                            2 * half_eps, mant_dig)):
                                    raise oefmt(space.w_OverflowError,
                                                "too large")
                        value = math.ldexp(value, (exp + 4 * key_digit))
        while i < length and s[i].isspace():
            i += 1
        if i != length:
            raise oefmt(space.w_ValueError, "invalid hex string")
        w_float = space.newfloat(sign * value)
        return space.call_function(w_cls, w_float)

    def _to_float(self, space, w_obj):
        if isinstance(w_obj, W_FloatObject):
            return w_obj
        if space.isinstance_w(w_obj, space.w_int):
            return W_FloatObject(float(space.int_w(w_obj)))
        if space.isinstance_w(w_obj, space.w_long):
            return W_FloatObject(space.float_w(w_obj))

    def descr_repr(self, space):
        return space.newtext(float2string(self.floatval, 'r', 0))

    def descr_str(self, space):
        return space.newtext(
            float2string(self.floatval, 'g', DTSF_STR_PRECISION))

    def descr_hash(self, space):
        h = _hash_float(space, self.floatval)
        return space.newint(h)

    def descr_format(self, space, w_spec):
        return newformat.run_formatter(space, w_spec, "format_float", self)

    def descr_coerce(self, space, w_other):
        w_other = self._to_float(space, w_other)
        if w_other is None:
            return space.w_NotImplemented
        return space.newtuple2(self, w_other)

    def descr_nonzero(self, space):
        return space.newbool(self.floatval != 0.0)

    def descr_float(self, space):
        if space.is_w(space.type(self), space.w_float):
            return self
        a = self.floatval
        return W_FloatObject(a)

    def descr_long(self, space):
        try:
            return W_LongObject.fromfloat(space, self.floatval)
        except OverflowError:
            raise oefmt(space.w_OverflowError,
                        "cannot convert float infinity to integer")
        except ValueError:
            raise oefmt(space.w_ValueError,
                        "cannot convert float NaN to integer")

    def descr_trunc(self, space):
        try:
            value = ovfcheck_float_to_int(self.floatval)
        except OverflowError:
            return self.descr_long(space)
        else:
            return space.newint(value)

    def descr_neg(self, space):
        return W_FloatObject(-self.floatval)

    def descr_pos(self, space):
        return self.descr_float(space)

    def descr_abs(self, space):
        return W_FloatObject(abs(self.floatval))

    def descr_getnewargs(self, space):
        return space.newtuple([self.descr_float(space)])

    descr_eq = make_compare_func('eq')
    descr_ne = make_compare_func('ne')
    descr_lt = make_compare_func('lt')
    descr_le = make_compare_func('le')
    descr_gt = make_compare_func('gt')
    descr_ge = make_compare_func('ge')

    def descr_add(self, space, w_rhs):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        return W_FloatObject(self.floatval + w_rhs.floatval)

    def descr_radd(self, space, w_lhs):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        return W_FloatObject(w_lhs.floatval + self.floatval)

    def descr_sub(self, space, w_rhs):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        return W_FloatObject(self.floatval - w_rhs.floatval)

    def descr_rsub(self, space, w_lhs):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        return W_FloatObject(w_lhs.floatval - self.floatval)

    def descr_mul(self, space, w_rhs):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        return W_FloatObject(self.floatval * w_rhs.floatval)

    def descr_rmul(self, space, w_lhs):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        return W_FloatObject(w_lhs.floatval * self.floatval)

    def descr_div(self, space, w_rhs):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        rhs = w_rhs.floatval
        if rhs == 0.0:
            raise oefmt(space.w_ZeroDivisionError, "float division")
        return W_FloatObject(self.floatval / rhs)

    def descr_rdiv(self, space, w_lhs):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        selfval = self.floatval
        if selfval == 0.0:
            raise oefmt(space.w_ZeroDivisionError, "float division")
        return W_FloatObject(w_lhs.floatval / selfval)

    def descr_floordiv(self, space, w_rhs):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        return _divmod_w(space, self, w_rhs)[0]

    def descr_rfloordiv(self, space, w_lhs):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        return _divmod_w(space, w_lhs, self)[0]

    def descr_mod(self, space, w_rhs):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        x = self.floatval
        y = w_rhs.floatval
        if y == 0.0:
            raise oefmt(space.w_ZeroDivisionError, "float modulo")
        mod = math_fmod(x, y)
        if mod:
            # ensure the remainder has the same sign as the denominator
            if (y < 0.0) != (mod < 0.0):
                mod += y
        else:
            # the remainder is zero, and in the presence of signed zeroes
            # fmod returns different results across platforms; ensure
            # it has the same sign as the denominator; we'd like to do
            # "mod = y * 0.0", but that may get optimized away
            mod = math.copysign(0.0, y)

        return W_FloatObject(mod)

    def descr_rmod(self, space, w_lhs):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        return w_lhs.descr_mod(space, self)

    def descr_divmod(self, space, w_rhs):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        return space.newtuple(_divmod_w(space, self, w_rhs))

    def descr_rdivmod(self, space, w_lhs):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        return space.newtuple(_divmod_w(space, w_lhs, self))

    @unwrap_spec(w_third_arg=WrappedDefault(None))
    def descr_pow(self, space, w_rhs, w_third_arg):
        w_rhs = self._to_float(space, w_rhs)
        if w_rhs is None:
            return space.w_NotImplemented
        if not space.is_w(w_third_arg, space.w_None):
            raise oefmt(
                space.w_TypeError, "pow() 3rd argument not allowed "
                "unless all arguments are integers")
        x = self.floatval
        y = w_rhs.floatval

        try:
            result = _pow(space, x, y)
        except PowDomainError:
            raise oefmt(
                space.w_ValueError, "negative number cannot be raised "
                "to a fractional power")
        return W_FloatObject(result)

    @unwrap_spec(w_third_arg=WrappedDefault(None))
    def descr_rpow(self, space, w_lhs, w_third_arg):
        w_lhs = self._to_float(space, w_lhs)
        if w_lhs is None:
            return space.w_NotImplemented
        return w_lhs.descr_pow(space, self, w_third_arg)

    def descr_get_real(self, space):
        return space.float(self)

    def descr_get_imag(self, space):
        return space.newfloat(0.0)

    def descr_conjugate(self, space):
        return space.float(self)

    def descr_is_integer(self, space):
        v = self.floatval
        if not rfloat.isfinite(v):
            return space.w_False
        return space.newbool(math.floor(v) == v)

    def descr_as_integer_ratio(self, space):
        value = self.floatval
        try:
            num, den = float_as_rbigint_ratio(value)
        except OverflowError:
            raise oefmt(space.w_OverflowError,
                        "cannot pass infinity to as_integer_ratio()")
        except ValueError:
            raise oefmt(space.w_ValueError,
                        "cannot pass nan to as_integer_ratio()")

        w_num = space.newlong_from_rbigint(num)
        w_den = space.newlong_from_rbigint(den)
        # Try to return int
        return space.newtuple2(space.int(w_num), space.int(w_den))

    def descr_hex(self, space):
        TOHEX_NBITS = rfloat.DBL_MANT_DIG + 3 - (rfloat.DBL_MANT_DIG + 2) % 4
        value = self.floatval
        if not isfinite(value):
            return self.descr_str(space)
        if value == 0.0:
            if math.copysign(1., value) == -1.:
                return space.newtext("-0x0.0p+0")
            else:
                return space.newtext("0x0.0p+0")
        mant, exp = math.frexp(value)
        shift = 1 - max(rfloat.DBL_MIN_EXP - exp, 0)
        mant = math.ldexp(mant, shift)
        mant = abs(mant)
        exp -= shift
        result = ['\0'] * ((TOHEX_NBITS - 1) // 4 + 2)
        result[0] = _char_from_hex(int(mant))
        mant -= int(mant)
        result[1] = "."
        for i in range((TOHEX_NBITS - 1) // 4):
            mant *= 16.0
            result[i + 2] = _char_from_hex(int(mant))
            mant -= int(mant)
        if exp < 0:
            sign = "-"
        else:
            sign = "+"
        exp = abs(exp)
        s = ''.join(result)
        if value < 0.0:
            return space.newtext("-0x%sp%s%d" % (s, sign, exp))
        else:
            return space.newtext("0x%sp%s%d" % (s, sign, exp))