importoperatorfrompypy.interpreter.errorimportOperationError,operationerrfmtfrompypy.interpreter.baseobjspaceimportObjSpacefrompypy.interpreter.functionimportFunction,Method,FunctionWithFixedCodefrompypy.interpreter.argumentimportArgumentsfrompypy.interpreter.typedefimportdefault_identity_hashfromrpython.tool.sourcetoolsimportcompile2,func_with_new_namefrompypy.module.__builtin__.interp_classobjimportW_InstanceObjectfromrpython.rlib.objectmodelimportspecializedefobject_getattribute(space):"Utility that returns the app-level descriptor object.__getattribute__."w_src,w_getattribute=space.lookup_in_type_where(space.w_object,'__getattribute__')returnw_getattributeobject_getattribute._annspecialcase_='specialize:memo'defobject_setattr(space):"Utility that returns the app-level descriptor object.__setattr__."w_src,w_setattr=space.lookup_in_type_where(space.w_object,'__setattr__')returnw_setattrobject_setattr._annspecialcase_='specialize:memo'defobject_delattr(space):"Utility that returns the app-level descriptor object.__delattr__."w_src,w_delattr=space.lookup_in_type_where(space.w_object,'__delattr__')returnw_delattrobject_delattr._annspecialcase_='specialize:memo'defobject_hash(space):"Utility that returns the app-level descriptor object.__hash__."w_src,w_hash=space.lookup_in_type_where(space.w_object,'__hash__')returnw_hashobject_hash._annspecialcase_='specialize:memo'deftype_eq(space):"Utility that returns the app-level descriptor type.__eq__."w_src,w_eq=space.lookup_in_type_where(space.w_type,'__eq__')returnw_eqtype_eq._annspecialcase_='specialize:memo'deflist_iter(space):"Utility that returns the app-level descriptor list.__iter__."w_src,w_iter=space.lookup_in_type_where(space.w_list,'__iter__')returnw_iterlist_iter._annspecialcase_='specialize:memo'defraiseattrerror(space,w_obj,name,w_descr=None):w_type=space.type(w_obj)typename=w_type.getname(space)ifw_descrisNone:raiseoperationerrfmt(space.w_AttributeError,"'%s' object has no attribute '%s'",typename,name)else:raiseoperationerrfmt(space.w_AttributeError,"'%s' object attribute '%s' is read-only",typename,name)# Helpers for old-style and mix-style mixupdef_same_class_w(space,w_obj1,w_obj2,w_typ1,w_typ2):if(space.is_oldstyle_instance(w_obj1)andspace.is_oldstyle_instance(w_obj2)):assertisinstance(w_obj1,W_InstanceObject)assertisinstance(w_obj2,W_InstanceObject)returnspace.is_w(w_obj1.w_class,w_obj2.w_class)returnspace.is_w(w_typ1,w_typ2)classObject(object):defdescr__getattribute__(space,w_obj,w_name):name=space.str_w(w_name)w_descr=space.lookup(w_obj,name)ifw_descrisnotNone:ifspace.is_data_descr(w_descr):# Only override if __get__ is defined, too, for compatibility# with CPython.w_get=space.lookup(w_descr,"__get__")ifw_getisnotNone:w_type=space.type(w_obj)returnspace.get_and_call_function(w_get,w_descr,w_obj,w_type)w_value=w_obj.getdictvalue(space,name)ifw_valueisnotNone:returnw_valueifw_descrisnotNone:returnspace.get(w_descr,w_obj)raiseattrerror(space,w_obj,name)defdescr__setattr__(space,w_obj,w_name,w_value):name=space.str_w(w_name)w_descr=space.lookup(w_obj,name)ifw_descrisnotNone:ifspace.is_data_descr(w_descr):space.set(w_descr,w_obj,w_value)returnifw_obj.setdictvalue(space,name,w_value):returnraiseattrerror(space,w_obj,name,w_descr)defdescr__delattr__(space,w_obj,w_name):name=space.str_w(w_name)w_descr=space.lookup(w_obj,name)ifw_descrisnotNone:ifspace.is_data_descr(w_descr):space.delete(w_descr,w_obj)returnifw_obj.deldictvalue(space,name):returnraiseattrerror(space,w_obj,name,w_descr)defdescr__init__(space,w_obj,__args__):passclassDescrOperation(object):_mixin_=Truedefis_data_descr(space,w_obj):returnspace.lookup(w_obj,'__set__')isnotNonedefget_and_call_args(space,w_descr,w_obj,args):descr=space.interpclass_w(w_descr)# a special case for performance and to avoid infinite recursionifisinstance(descr,Function):returndescr.call_obj_args(w_obj,args)else:w_impl=space.get(w_descr,w_obj)returnspace.call_args(w_impl,args)defget_and_call_function(space,w_descr,w_obj,*args_w):descr=space.interpclass_w(w_descr)typ=type(descr)# a special case for performance and to avoid infinite recursioniftypisFunctionortypisFunctionWithFixedCode:# isinstance(typ, Function) would not be correct here:# for a BuiltinFunction we must not use that shortcut, because a# builtin function binds differently than a normal function# see test_builtin_as_special_method_is_not_bound# in interpreter/test/test_function.py# the fastcall paths are purely for performance, but the resulting# increase of speed is hugereturndescr.funccall(w_obj,*args_w)else:args=Arguments(space,list(args_w))w_impl=space.get(w_descr,w_obj)returnspace.call_args(w_impl,args)defcall_args(space,w_obj,args):# two special cases for performanceifisinstance(w_obj,Function):returnw_obj.call_args(args)ifisinstance(w_obj,Method):returnw_obj.call_args(args)w_descr=space.lookup(w_obj,'__call__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object is not callable",typename)returnspace.get_and_call_args(w_descr,w_obj,args)defget(space,w_descr,w_obj,w_type=None):w_get=space.lookup(w_descr,'__get__')ifw_getisNone:returnw_descrifw_typeisNone:w_type=space.type(w_obj)returnspace.get_and_call_function(w_get,w_descr,w_obj,w_type)defset(space,w_descr,w_obj,w_val):w_set=space.lookup(w_descr,'__set__')ifw_setisNone:typename=space.type(w_descr).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object is not a descriptor with set",typename)returnspace.get_and_call_function(w_set,w_descr,w_obj,w_val)defdelete(space,w_descr,w_obj):w_delete=space.lookup(w_descr,'__delete__')ifw_deleteisNone:typename=space.type(w_descr).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object is not a descriptor with delete",typename)returnspace.get_and_call_function(w_delete,w_descr,w_obj)defgetattr(space,w_obj,w_name):# may be overridden in StdObjSpacew_descr=space.lookup(w_obj,'__getattribute__')returnspace._handle_getattribute(w_descr,w_obj,w_name)def_handle_getattribute(space,w_descr,w_obj,w_name):try:ifw_descrisNone:# obscure caseraiseOperationError(space.w_AttributeError,space.w_None)returnspace.get_and_call_function(w_descr,w_obj,w_name)exceptOperationError,e:ifnote.match(space,space.w_AttributeError):raisew_descr=space.lookup(w_obj,'__getattr__')ifw_descrisNone:raisereturnspace.get_and_call_function(w_descr,w_obj,w_name)defsetattr(space,w_obj,w_name,w_val):w_descr=space.lookup(w_obj,'__setattr__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_AttributeError,"'%s' object is readonly",typename)returnspace.get_and_call_function(w_descr,w_obj,w_name,w_val)defdelattr(space,w_obj,w_name):w_descr=space.lookup(w_obj,'__delattr__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_AttributeError,"'%s' object does not support attribute removal",typename)returnspace.get_and_call_function(w_descr,w_obj,w_name)defis_true(space,w_obj):w_descr=space.lookup(w_obj,"__nonzero__")ifw_descrisNone:w_descr=space.lookup(w_obj,"__len__")ifw_descrisNone:returnTrue# call __len__w_res=space.get_and_call_function(w_descr,w_obj)returnspace._check_len_result(w_res)!=0# call __nonzero__w_res=space.get_and_call_function(w_descr,w_obj)# more shortcuts for common casesifspace.is_w(w_res,space.w_False):returnFalseifspace.is_w(w_res,space.w_True):returnTruew_restype=space.type(w_res)# Note there is no check for bool here because the only possible# instances of bool are w_False and w_True, which are checked above.ifspace.is_w(w_restype,space.w_int):returnspace.int_w(w_res)!=0else:msg="__nonzero__ should return bool or integer"raiseOperationError(space.w_TypeError,space.wrap(msg))defnonzero(space,w_obj):ifspace.is_true(w_obj):returnspace.w_Trueelse:returnspace.w_Falsedeflen(space,w_obj):w_descr=space.lookup(w_obj,'__len__')ifw_descrisNone:name=space.type(w_obj).getname(space)msg="'%s' has no length"%(name,)raiseOperationError(space.w_TypeError,space.wrap(msg))w_res=space.get_and_call_function(w_descr,w_obj)returnspace.wrap(space._check_len_result(w_res))def_check_len_result(space,w_obj):# Will complain if result is too big.result=space.int_w(space.int(w_obj))ifresult<0:raiseOperationError(space.w_ValueError,space.wrap("__len__() should return >= 0"))returnresultdefiter(space,w_obj):w_descr=space.lookup(w_obj,'__iter__')ifw_descrisNone:w_descr=space.lookup(w_obj,'__getitem__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object is not iterable",typename)returnspace.newseqiter(w_obj)w_iter=space.get_and_call_function(w_descr,w_obj)w_next=space.lookup(w_iter,'next')ifw_nextisNone:raiseOperationError(space.w_TypeError,space.wrap("iter() returned non-iterator"))returnw_iterdefnext(space,w_obj):w_descr=space.lookup(w_obj,'next')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object is not an iterator",typename)returnspace.get_and_call_function(w_descr,w_obj)defgetitem(space,w_obj,w_key):w_descr=space.lookup(w_obj,'__getitem__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object is not subscriptable",typename)returnspace.get_and_call_function(w_descr,w_obj,w_key)defsetitem(space,w_obj,w_key,w_val):w_descr=space.lookup(w_obj,'__setitem__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object does not support item assignment",typename)returnspace.get_and_call_function(w_descr,w_obj,w_key,w_val)defdelitem(space,w_obj,w_key):w_descr=space.lookup(w_obj,'__delitem__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object does not support item deletion",typename)returnspace.get_and_call_function(w_descr,w_obj,w_key)defgetslice(space,w_obj,w_start,w_stop):w_descr=space.lookup(w_obj,'__getslice__')ifw_descrisNone:w_slice=space.newslice(w_start,w_stop,space.w_None)returnspace.getitem(w_obj,w_slice)w_start,w_stop=old_slice_range(space,w_obj,w_start,w_stop)returnspace.get_and_call_function(w_descr,w_obj,w_start,w_stop)defsetslice(space,w_obj,w_start,w_stop,w_sequence):w_descr=space.lookup(w_obj,'__setslice__')ifw_descrisNone:w_slice=space.newslice(w_start,w_stop,space.w_None)returnspace.setitem(w_obj,w_slice,w_sequence)w_start,w_stop=old_slice_range(space,w_obj,w_start,w_stop)returnspace.get_and_call_function(w_descr,w_obj,w_start,w_stop,w_sequence)defdelslice(space,w_obj,w_start,w_stop):w_descr=space.lookup(w_obj,'__delslice__')ifw_descrisNone:w_slice=space.newslice(w_start,w_stop,space.w_None)returnspace.delitem(w_obj,w_slice)w_start,w_stop=old_slice_range(space,w_obj,w_start,w_stop)returnspace.get_and_call_function(w_descr,w_obj,w_start,w_stop)defformat(space,w_obj,w_format_spec):w_descr=space.lookup(w_obj,'__format__')ifw_descrisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' object does not define __format__",typename)w_res=space.get_and_call_function(w_descr,w_obj,w_format_spec)ifnotspace.is_true(space.isinstance(w_res,space.w_basestring)):typename=space.type(w_obj).getname(space)restypename=space.type(w_res).getname(space)raiseoperationerrfmt(space.w_TypeError,"%s.__format__ must return string or unicode, not %s",typename,restypename)returnw_resdefpow(space,w_obj1,w_obj2,w_obj3):w_typ1=space.type(w_obj1)w_typ2=space.type(w_obj2)w_left_src,w_left_impl=space.lookup_in_type_where(w_typ1,'__pow__')if_same_class_w(space,w_obj1,w_obj2,w_typ1,w_typ2):w_right_impl=Noneelse:w_right_src,w_right_impl=space.lookup_in_type_where(w_typ2,'__rpow__')# sse binop_implif(w_left_srcisnotw_right_srcandspace.is_true(space.issubtype(w_typ2,w_typ1))):if(w_left_srcandw_right_srcandnotspace.abstract_issubclass_w(w_left_src,w_right_src)andnotspace.abstract_issubclass_w(w_typ1,w_right_src)):w_obj1,w_obj2=w_obj2,w_obj1w_left_impl,w_right_impl=w_right_impl,w_left_implifw_left_implisnotNone:ifspace.is_w(w_obj3,space.w_None):w_res=space.get_and_call_function(w_left_impl,w_obj1,w_obj2)else:w_res=space.get_and_call_function(w_left_impl,w_obj1,w_obj2,w_obj3)if_check_notimplemented(space,w_res):returnw_resifw_right_implisnotNone:ifspace.is_w(w_obj3,space.w_None):w_res=space.get_and_call_function(w_right_impl,w_obj2,w_obj1)else:w_res=space.get_and_call_function(w_right_impl,w_obj2,w_obj1,w_obj3)if_check_notimplemented(space,w_res):returnw_resraiseOperationError(space.w_TypeError,space.wrap("operands do not support **"))definplace_pow(space,w_lhs,w_rhs):w_impl=space.lookup(w_lhs,'__ipow__')ifw_implisnotNone:w_res=space.get_and_call_function(w_impl,w_lhs,w_rhs)if_check_notimplemented(space,w_res):returnw_resreturnspace.pow(w_lhs,w_rhs,space.w_None)defcontains(space,w_container,w_item):w_descr=space.lookup(w_container,'__contains__')ifw_descrisnotNone:w_result=space.get_and_call_function(w_descr,w_container,w_item)returnspace.nonzero(w_result)returnspace._contains(w_container,w_item)def_contains(space,w_container,w_item):w_iter=space.iter(w_container)while1:try:w_next=space.next(w_iter)exceptOperationError,e:ifnote.match(space,space.w_StopIteration):raisereturnspace.w_Falseifspace.eq_w(w_next,w_item):returnspace.w_Truedefhash(space,w_obj):w_hash=space.lookup(w_obj,'__hash__')ifw_hashisNone:# xxx there used to be logic about "do we have __eq__ or __cmp__"# here, but it does not really make sense, as 'object' has a# default __hash__. This path should only be taken under very# obscure circumstances.returndefault_identity_hash(space,w_obj)ifspace.is_w(w_hash,space.w_None):typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,"'%s' objects are unhashable",typename)w_result=space.get_and_call_function(w_hash,w_obj)w_resulttype=space.type(w_result)ifspace.is_w(w_resulttype,space.w_int):returnw_resultelifspace.is_w(w_resulttype,space.w_long):returnspace.hash(w_result)elifspace.is_true(space.isinstance(w_result,space.w_int)):# be careful about subclasses of 'int'...returnspace.wrap(space.int_w(w_result))elifspace.is_true(space.isinstance(w_result,space.w_long)):# be careful about subclasses of 'long'...bigint=space.bigint_w(w_result)returnspace.wrap(bigint.hash())else:raiseOperationError(space.w_TypeError,space.wrap("__hash__() should return an int or long"))defuserdel(space,w_obj):w_del=space.lookup(w_obj,'__del__')ifw_delisnotNone:space.get_and_call_function(w_del,w_obj)defcmp(space,w_v,w_w):ifspace.is_w(w_v,w_w):returnspace.wrap(0)# The real comparisonifspace.is_w(space.type(w_v),space.type(w_w)):# for object of the same type, prefer __cmp__ over rich comparison.w_cmp=space.lookup(w_v,'__cmp__')w_res=_invoke_binop(space,w_cmp,w_v,w_w)ifw_resisnotNone:returnw_res# fall back to rich comparison.ifspace.eq_w(w_v,w_w):returnspace.wrap(0)elifspace.is_true(space.lt(w_v,w_w)):returnspace.wrap(-1)returnspace.wrap(1)defcoerce(space,w_obj1,w_obj2):w_typ1=space.type(w_obj1)w_typ2=space.type(w_obj2)w_left_src,w_left_impl=space.lookup_in_type_where(w_typ1,'__coerce__')ifspace.is_w(w_typ1,w_typ2):w_right_impl=Noneelse:w_right_src,w_right_impl=space.lookup_in_type_where(w_typ2,'__coerce__')if(w_left_srcisnotw_right_srcandspace.is_true(space.issubtype(w_typ2,w_typ1))):w_obj1,w_obj2=w_obj2,w_obj1w_left_impl,w_right_impl=w_right_impl,w_left_implw_res=_invoke_binop(space,w_left_impl,w_obj1,w_obj2)ifw_resisNoneorspace.is_w(w_res,space.w_None):w_res=_invoke_binop(space,w_right_impl,w_obj2,w_obj1)ifw_resisNoneorspace.is_w(w_res,space.w_None):raiseOperationError(space.w_TypeError,space.wrap("coercion failed"))if(notspace.is_true(space.isinstance(w_res,space.w_tuple))orspace.len_w(w_res)!=2):raiseOperationError(space.w_TypeError,space.wrap("coercion should return None or 2-tuple"))w_res=space.newtuple([space.getitem(w_res,space.wrap(1)),space.getitem(w_res,space.wrap(0))])elif(notspace.is_true(space.isinstance(w_res,space.w_tuple))orspace.len_w(w_res)!=2):raiseOperationError(space.w_TypeError,space.wrap("coercion should return None or 2-tuple"))returnw_resdefissubtype(space,w_sub,w_type):returnspace._type_issubtype(w_sub,w_type)@specialize.arg_or_var(2)defisinstance(space,w_inst,w_type):returnspace.wrap(space._type_isinstance(w_inst,w_type))defissubtype_allow_override(space,w_sub,w_type):w_check=space.lookup(w_type,"__subclasscheck__")ifw_checkisNone:raiseOperationError(space.w_TypeError,space.wrap("issubclass not supported here"))returnspace.get_and_call_function(w_check,w_type,w_sub)defisinstance_allow_override(space,w_inst,w_type):w_check=space.lookup(w_type,"__instancecheck__")ifw_checkisnotNone:returnspace.get_and_call_function(w_check,w_type,w_inst)else:returnspace.isinstance(w_inst,w_type)# helpersdef_check_notimplemented(space,w_obj):returnnotspace.is_w(w_obj,space.w_NotImplemented)def_invoke_binop(space,w_impl,w_obj1,w_obj2):ifw_implisnotNone:w_res=space.get_and_call_function(w_impl,w_obj1,w_obj2)if_check_notimplemented(space,w_res):returnw_resreturnNone# helper for invoking __cmp__def_conditional_neg(space,w_obj,flag):ifflag:returnspace.neg(w_obj)else:returnw_objdef_cmp(space,w_obj1,w_obj2,symbol):w_typ1=space.type(w_obj1)w_typ2=space.type(w_obj2)w_left_src,w_left_impl=space.lookup_in_type_where(w_typ1,'__cmp__')do_neg1=Falsedo_neg2=Trueifspace.is_w(w_typ1,w_typ2):w_right_impl=Noneelse:w_right_src,w_right_impl=space.lookup_in_type_where(w_typ2,'__cmp__')if(w_left_srcisnotw_right_srcandspace.is_true(space.issubtype(w_typ2,w_typ1))):w_obj1,w_obj2=w_obj2,w_obj1w_left_impl,w_right_impl=w_right_impl,w_left_impldo_neg1,do_neg2=do_neg2,do_neg1w_res=_invoke_binop(space,w_left_impl,w_obj1,w_obj2)ifw_resisnotNone:return_conditional_neg(space,w_res,do_neg1)w_res=_invoke_binop(space,w_right_impl,w_obj2,w_obj1)ifw_resisnotNone:return_conditional_neg(space,w_res,do_neg2)# fall back to internal rulesifspace.is_w(w_obj1,w_obj2):returnspace.wrap(0)ifspace.is_w(w_obj1,space.w_None):returnspace.wrap(-1)ifspace.is_w(w_obj2,space.w_None):returnspace.wrap(1)ifspace.is_w(w_typ1,w_typ2):#print "WARNING, comparison by address!"lt=_id_cmpr(space,w_obj1,w_obj2,symbol)else:#print "WARNING, comparison by type name!"# the CPython rule is to compare type names; numbers are# smaller. So we compare the types by the following key:# (not_a_number_flag, type_name, type_id)num1=number_check(space,w_obj1)num2=number_check(space,w_obj2)ifnum1!=num2:lt=num1# if obj1 is a number, it is Lower Than obj2else:name1=w_typ1.getname(space,"")name2=w_typ2.getname(space,"")ifname1!=name2:lt=name1<name2else:lt=_id_cmpr(space,w_typ1,w_typ2,symbol)iflt:returnspace.wrap(-1)else:returnspace.wrap(1)def_id_cmpr(space,w_obj1,w_obj2,symbol):ifsymbol=="==":returnnotspace.is_w(w_obj1,w_obj2)elifsymbol=="!=":returnspace.is_w(w_obj1,w_obj2)w_id1=space.id(w_obj1)w_id2=space.id(w_obj2)returnspace.is_true(space.lt(w_id1,w_id2))defnumber_check(space,w_obj):# avoid this as much as possible. It checks if w_obj "looks like"# it might be a number-ish thing.return(space.lookup(w_obj,'__int__')isnotNoneorspace.lookup(w_obj,'__float__')isnotNone)# what is the maximum value slices can get on CPython?# we need to stick to that value, because fake.py etc.classTemp(object):def__getslice__(self,i,j):returnjslice_max=Temp()[:]delTempdefold_slice_range_getlength(space,w_obj):# NB. the language ref is inconsistent with the new-style class# behavior when w_obj doesn't implement __len__(), so we just# follow cpython. Also note that CPython slots make it easier# to check for object implementing it or not. We just catch errors# so this behavior is slightly differenttry:returnspace.len(w_obj)exceptOperationError,e:ifnot((e.match(space,space.w_AttributeError)ore.match(space,space.w_TypeError))):raisereturnNonedefold_slice_range(space,w_obj,w_start,w_stop):"""Only for backward compatibility for __getslice__()&co methods."""w_length=Noneifspace.is_w(w_start,space.w_None):w_start=space.wrap(0)else:start=space.getindex_w(w_start,None)w_start=space.wrap(start)ifstart<0:w_length=old_slice_range_getlength(space,w_obj)ifw_lengthisnotNone:w_start=space.add(w_start,w_length)ifspace.is_w(w_stop,space.w_None):w_stop=space.wrap(slice_max)else:stop=space.getindex_w(w_stop,None)w_stop=space.wrap(stop)ifstop<0:ifw_lengthisNone:w_length=old_slice_range_getlength(space,w_obj)ifw_lengthisnotNone:w_stop=space.add(w_stop,w_length)returnw_start,w_stop# regular methods def helpersdef_make_binop_impl(symbol,specialnames):left,right=specialnameserrormsg="unsupported operand type(s) for %s: '%%s' and '%%s'"%(symbol.replace('%','%%'),)defbinop_impl(space,w_obj1,w_obj2):w_typ1=space.type(w_obj1)w_typ2=space.type(w_obj2)w_left_src,w_left_impl=space.lookup_in_type_where(w_typ1,left)if_same_class_w(space,w_obj1,w_obj2,w_typ1,w_typ2):w_right_impl=Noneelse:w_right_src,w_right_impl=space.lookup_in_type_where(w_typ2,right)# the logic to decide if the reverse operation should be tried# before the direct one is very obscure. For now, and for# sanity reasons, we just compare the two places where the# __xxx__ and __rxxx__ methods where found by identity.# Note that space.is_w() is potentially not happy if one of them# is None...ifw_left_srcisnotw_right_src:# XXX# -- cpython bug compatibility: see objspace/std/test/# -- test_unicodeobject.test_str_unicode_concat_overrides.# -- The following handles "unicode + string subclass" by# -- pretending that the unicode is a superclass of the# -- string, thus giving priority to the string subclass'# -- __radd__() method. The case "string + unicode subclass"# -- is handled directly by add__String_Unicode().ifsymbol=='+'andspace.is_w(w_typ1,space.w_unicode):w_typ1=space.w_basestring# -- end of bug compatibilityifspace.is_true(space.issubtype(w_typ2,w_typ1)):if(w_left_srcandw_right_srcandnotspace.abstract_issubclass_w(w_left_src,w_right_src)andnotspace.abstract_issubclass_w(w_typ1,w_right_src)):w_obj1,w_obj2=w_obj2,w_obj1w_left_impl,w_right_impl=w_right_impl,w_left_implw_res=_invoke_binop(space,w_left_impl,w_obj1,w_obj2)ifw_resisnotNone:returnw_resw_res=_invoke_binop(space,w_right_impl,w_obj2,w_obj1)ifw_resisnotNone:returnw_restypename1=w_typ1.getname(space)typename2=w_typ2.getname(space)raiseoperationerrfmt(space.w_TypeError,errormsg,typename1,typename2)returnfunc_with_new_name(binop_impl,"binop_%s_impl"%left.strip('_'))def_make_comparison_impl(symbol,specialnames):left,right=specialnamesop=getattr(operator,left)defcomparison_impl(space,w_obj1,w_obj2):w_typ1=space.type(w_obj1)w_typ2=space.type(w_obj2)w_left_src,w_left_impl=space.lookup_in_type_where(w_typ1,left)w_first=w_obj1w_second=w_obj2#ifleft==rightand_same_class_w(space,w_obj1,w_obj2,w_typ1,w_typ2):# for __eq__ and __ne__, if the objects have the same# (old-style or new-style) class, then don't try the# opposite method, which is the same one.w_right_impl=Noneelse:# in all other cases, try the opposite method.w_right_src,w_right_impl=space.lookup_in_type_where(w_typ2,right)ifspace.is_w(w_typ1,w_typ2):# if the type is the same, *or* if both are old-style classes,# then don't reverse: try left first, right next.passelifspace.is_true(space.issubtype(w_typ2,w_typ1)):# for new-style classes, if typ2 is a subclass of typ1.w_obj1,w_obj2=w_obj2,w_obj1w_left_impl,w_right_impl=w_right_impl,w_left_implw_res=_invoke_binop(space,w_left_impl,w_obj1,w_obj2)ifw_resisnotNone:returnw_resw_res=_invoke_binop(space,w_right_impl,w_obj2,w_obj1)ifw_resisnotNone:returnw_res# fallback: lt(a, b) <= lt(cmp(a, b), 0) ...w_res=_cmp(space,w_first,w_second,symbol)res=space.int_w(w_res)returnspace.wrap(op(res,0))returnfunc_with_new_name(comparison_impl,'comparison_%s_impl'%left.strip('_'))def_make_inplace_impl(symbol,specialnames):specialname,=specialnamesassertspecialname.startswith('__i')andspecialname.endswith('__')noninplacespacemethod=specialname[3:-2]ifnoninplacespacemethodin['or','and']:noninplacespacemethod+='_'# not too cleandefinplace_impl(space,w_lhs,w_rhs):w_impl=space.lookup(w_lhs,specialname)ifw_implisnotNone:w_res=space.get_and_call_function(w_impl,w_lhs,w_rhs)if_check_notimplemented(space,w_res):returnw_res# XXX fix the error message we get herereturngetattr(space,noninplacespacemethod)(w_lhs,w_rhs)returnfunc_with_new_name(inplace_impl,'inplace_%s_impl'%specialname.strip('_'))def_make_unaryop_impl(symbol,specialnames):specialname,=specialnameserrormsg="unsupported operand type for unary %s: '%%s'"%symboldefunaryop_impl(space,w_obj):w_impl=space.lookup(w_obj,specialname)ifw_implisNone:typename=space.type(w_obj).getname(space)raiseoperationerrfmt(space.w_TypeError,errormsg,typename)returnspace.get_and_call_function(w_impl,w_obj)returnfunc_with_new_name(unaryop_impl,'unaryop_%s_impl'%specialname.strip('_'))# the following seven operations are really better to generate with# string-templating (and maybe we should consider this for# more of the above manually-coded operations as well)fortargetname,specialname,checkerspecin[('int','__int__',("space.w_int","space.w_long")),('index','__index__',("space.w_int","space.w_long")),('long','__long__',("space.w_int","space.w_long")),('float','__float__',("space.w_float",))]:l=["space.is_true(space.isinstance(w_result, %s))"%xforxincheckerspec]checker=" or ".join(l)source="""if 1: def %(targetname)s(space, w_obj): w_impl = space.lookup(w_obj, %(specialname)r) if w_impl is None: typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "unsupported operand type for %(targetname)s(): '%%s'", typename) w_result = space.get_and_call_function(w_impl, w_obj) if %(checker)s: return w_result typename = space.type(w_result).getname(space) msg = "%(specialname)s returned non-%(targetname)s (type '%%s')" raise operationerrfmt(space.w_TypeError, msg, typename) assert not hasattr(DescrOperation, %(targetname)r) DescrOperation.%(targetname)s = %(targetname)s del %(targetname)s\n"""%locals()execcompile2(source)fortargetname,specialnamein[('str','__str__'),('repr','__repr__'),('oct','__oct__'),('hex','__hex__')]:source="""if 1: def %(targetname)s(space, w_obj): w_impl = space.lookup(w_obj, %(specialname)r) if w_impl is None: typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, "unsupported operand type for %(targetname)s(): '%%s'", typename) w_result = space.get_and_call_function(w_impl, w_obj) if space.is_true(space.isinstance(w_result, space.w_str)): return w_result try: result = space.str_w(w_result) except OperationError, e: if not e.match(space, space.w_TypeError): raise typename = space.type(w_result).getname(space) msg = "%(specialname)s returned non-%(targetname)s (type '%%s')" raise operationerrfmt(space.w_TypeError, msg, typename) else: # re-wrap the result as a real string return space.wrap(result) assert not hasattr(DescrOperation, %(targetname)r) DescrOperation.%(targetname)s = %(targetname)s del %(targetname)s\n"""%locals()execcompile2(source)# add default operation implementations for all still missing opsfor_name,_symbol,_arity,_specialnamesinObjSpace.MethodTable:ifnothasattr(DescrOperation,_name):_impl_maker=Noneif_arity==2and_namein['lt','le','gt','ge','ne','eq']:#print "comparison", _specialnames_impl_maker=_make_comparison_implelif_arity==2and_name.startswith('inplace_'):#print "inplace", _specialnames_impl_maker=_make_inplace_implelif_arity==2andlen(_specialnames)==2:#print "binop", _specialnames_impl_maker=_make_binop_implelif_arity==1andlen(_specialnames)==1:#print "unaryop", _specialnames_impl_maker=_make_unaryop_implif_impl_maker:setattr(DescrOperation,_name,_impl_maker(_symbol,_specialnames))elif_namenotin['is_','id','type','issubtype',# not really to be defined in DescrOperation'ord','unichr','unicode']:raiseException,"missing def for operation %s"%_name