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 # ____________________________________________________________
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
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)
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
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)
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) ] #
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:
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"))
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')
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)
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
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
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))])
@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)
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.")
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
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
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()
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)
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
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,
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):
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"))
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)
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)
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))