"""Function objects.In PyPy there is no difference between built-in and user-defined functionobjects; the difference lies in the code object found in their func_codeattribute."""frompypy.rlib.unrollimportunrolling_iterablefrompypy.interpreter.errorimportOperationError,operationerrfmtfrompypy.interpreter.baseobjspaceimportWrappablefrompypy.interpreter.evalimportCodefrompypy.interpreter.argumentimportArgumentsfrompypy.rlibimportjitfrompypy.rlib.debugimportmake_sure_not_resizedfunccallunrolling=unrolling_iterable(range(4))@jit.elidable_promote()def_get_immutable_code(func):assertnotfunc.can_change_codereturnfunc.codeclassFunction(Wrappable):"""A function is a code object captured with some environment: an object space, a dictionary of globals, default arguments, and an arbitrary 'closure' passed to the code object."""can_change_code=True_immutable_fields_=['code?','w_func_globals?','closure?[*]','defs_w?[*]','name?']def__init__(self,space,code,w_globals=None,defs_w=[],closure=None,forcename=None):self.space=spaceself.name=forcenameorcode.co_nameself.w_doc=None# lazily read from code.getdocstring()self.code=code# Code instanceself.w_func_globals=w_globals# the globals dictionaryself.closure=closure# normally, list of Cell instances or Noneself.defs_w=defs_wself.w_func_dict=None# filled out below if neededself.w_module=Nonedef__repr__(self):# return "function %s.%s" % (self.space, self.name)# maybe we want this shorter:name=getattr(self,'name',None)ifnotisinstance(name,str):name='?'return"<%s%s>"%(self.__class__.__name__,name)defcall_args(self,args):# delegate activation to codereturnself.getcode().funcrun(self,args)defcall_obj_args(self,w_obj,args):# delegate activation to codereturnself.getcode().funcrun_obj(self,w_obj,args)defgetcode(self):ifjit.we_are_jitted():ifnotself.can_change_code:return_get_immutable_code(self)returnjit.promote(self.code)returnself.codedeffunccall(self,*args_w):# speed hackfrompypy.interpreterimportgatewayfrompypy.interpreter.pycodeimportPyCodecode=self.getcode()# hook for the jitnargs=len(args_w)fast_natural_arity=code.fast_natural_arityifnargs==fast_natural_arity:ifnargs==0:assertisinstance(code,gateway.BuiltinCode0)returncode.fastcall_0(self.space,self)elifnargs==1:assertisinstance(code,gateway.BuiltinCode1)returncode.fastcall_1(self.space,self,args_w[0])elifnargs==2:assertisinstance(code,gateway.BuiltinCode2)returncode.fastcall_2(self.space,self,args_w[0],args_w[1])elifnargs==3:assertisinstance(code,gateway.BuiltinCode3)returncode.fastcall_3(self.space,self,args_w[0],args_w[1],args_w[2])elifnargs==4:assertisinstance(code,gateway.BuiltinCode4)returncode.fastcall_4(self.space,self,args_w[0],args_w[1],args_w[2],args_w[3])elif(nargs|PyCode.FLATPYCALL)==fast_natural_arity:assertisinstance(code,PyCode)ifnargs<5:new_frame=self.space.createframe(code,self.w_func_globals,self)foriinfunccallunrolling:ifi<nargs:new_frame.locals_stack_w[i]=args_w[i]returnnew_frame.run()elifnargs>=1andfast_natural_arity==Code.PASSTHROUGHARGS1:assertisinstance(code,gateway.BuiltinCodePassThroughArguments1)returncode.funcrun_obj(self,args_w[0],Arguments(self.space,list(args_w[1:])))returnself.call_args(Arguments(self.space,list(args_w)))deffunccall_valuestack(self,nargs,frame):# speed hackfrompypy.interpreterimportgatewayfrompypy.interpreter.pycodeimportPyCodecode=self.getcode()# hook for the jit#if(jit.we_are_jitted()andcodeisself.space._code_of_sys_exc_infoandnargs==0):frompypy.module.sys.vmimportexc_info_directreturnexc_info_direct(self.space,frame)#fast_natural_arity=code.fast_natural_arityifnargs==fast_natural_arity:ifnargs==0:assertisinstance(code,gateway.BuiltinCode0)returncode.fastcall_0(self.space,self)elifnargs==1:assertisinstance(code,gateway.BuiltinCode1)returncode.fastcall_1(self.space,self,frame.peekvalue(0))elifnargs==2:assertisinstance(code,gateway.BuiltinCode2)returncode.fastcall_2(self.space,self,frame.peekvalue(1),frame.peekvalue(0))elifnargs==3:assertisinstance(code,gateway.BuiltinCode3)returncode.fastcall_3(self.space,self,frame.peekvalue(2),frame.peekvalue(1),frame.peekvalue(0))elifnargs==4:assertisinstance(code,gateway.BuiltinCode4)returncode.fastcall_4(self.space,self,frame.peekvalue(3),frame.peekvalue(2),frame.peekvalue(1),frame.peekvalue(0))elif(nargs|Code.FLATPYCALL)==fast_natural_arity:assertisinstance(code,PyCode)returnself._flat_pycall(code,nargs,frame)eliffast_natural_arity&Code.FLATPYCALL:natural_arity=fast_natural_arity&0xffifnatural_arity>nargs>=natural_arity-len(self.defs_w):assertisinstance(code,PyCode)returnself._flat_pycall_defaults(code,nargs,frame,natural_arity-nargs)eliffast_natural_arity==Code.PASSTHROUGHARGS1andnargs>=1:assertisinstance(code,gateway.BuiltinCodePassThroughArguments1)w_obj=frame.peekvalue(nargs-1)args=frame.make_arguments(nargs-1)returncode.funcrun_obj(self,w_obj,args)args=frame.make_arguments(nargs)returnself.call_args(args)@jit.unroll_safedef_flat_pycall(self,code,nargs,frame):# code is a PyCodenew_frame=self.space.createframe(code,self.w_func_globals,self)foriinxrange(nargs):w_arg=frame.peekvalue(nargs-1-i)new_frame.locals_stack_w[i]=w_argresult=new_frame.run()result=self._wrap_await_result(result)returnresultdef_wrap_await_result(self,result):""" Python-extension for the 'await' keyword. Wrap the last iteration of an await-generator through executioncontext.w_await_schedular_func. """# Does the code object of this function contain the CO_AWAIT_GENERATOR# flag? (Set by the ast.)frompypy.interpreter.pycodeimportPyCodefrompypy.interpreter.astcompiler.constsimportCO_GENERATOR,CO_AWAIT_GENERATORis_await_generator=(self.getcode().co_flags&CO_AWAIT_GENERATOR)# If so, and if an I/O schedular is set, get the result through the# I/O schedular function.ifis_await_generator:context=self.space.getexecutioncontext()ifcontext.w_await_schedular_func:schedular=context.w_await_schedular_funcassertisinstance(schedular,Function)result=schedular.funccall(result)else:raiseOperationError(self.space.w_TypeError,self.space.wrap("Calling an asyncronous function (with an 'await'-keyword) while no I/O schedular has been set"))returnresult@jit.unroll_safedef_flat_pycall_defaults(self,code,nargs,frame,defs_to_load):# code is a PyCodenew_frame=self.space.createframe(code,self.w_func_globals,self)foriinxrange(nargs):w_arg=frame.peekvalue(nargs-1-i)new_frame.locals_stack_w[i]=w_argndefs=len(self.defs_w)start=ndefs-defs_to_loadi=nargsforjinxrange(start,ndefs):new_frame.locals_stack_w[i]=self.defs_w[j]i+=1returnnew_frame.run()defgetdict(self,space):ifself.w_func_dictisNone:self.w_func_dict=space.newdict(instance=True)returnself.w_func_dictdefsetdict(self,space,w_dict):ifnotspace.isinstance_w(w_dict,space.w_dict):raiseOperationError(space.w_TypeError,space.wrap("setting function's dictionary to a non-dict"))self.w_func_dict=w_dictdefdescr_function__new__(space,w_subtype,w_code,w_globals,w_name=None,w_argdefs=None,w_closure=None):code=space.interp_w(Code,w_code)ifnotspace.is_true(space.isinstance(w_globals,space.w_dict)):raiseOperationError(space.w_TypeError,space.wrap("expected dict"))ifnotspace.is_none(w_name):name=space.str_w(w_name)else:name=Noneifnotspace.is_none(w_argdefs):defs_w=space.fixedview(w_argdefs)else:defs_w=[]nfreevars=0frompypy.interpreter.pycodeimportPyCodeifisinstance(code,PyCode):nfreevars=len(code.co_freevars)ifspace.is_none(w_closure)andnfreevars==0:closure=Noneelifnotspace.is_w(space.type(w_closure),space.w_tuple):raiseOperationError(space.w_TypeError,space.wrap("invalid closure"))else:frompypy.interpreter.nestedscopeimportCellclosure_w=space.unpackiterable(w_closure)n=len(closure_w)ifnfreevars==0:raiseOperationError(space.w_ValueError,space.wrap("no closure needed"))elifnfreevars!=n:raiseOperationError(space.w_ValueError,space.wrap("closure is wrong size"))closure=[space.interp_w(Cell,w_cell)forw_cellinclosure_w]func=space.allocate_instance(Function,w_subtype)Function.__init__(func,space,code,w_globals,defs_w,closure,name)returnspace.wrap(func)defdescr_function_call(self,__args__):returnself.call_args(__args__)defdescr_function_repr(self):returnself.getrepr(self.space,'function %s'%(self.name,))# delicate_all={'':None}def_cleanup_(self):frompypy.interpreter.gatewayimportBuiltinCodeifisinstance(self.code,BuiltinCode):# we have been seen by other means so rtyping should not choke# on usidentifier=self.code.identifierprevious=Function._all.get(identifier,self)assertpreviousisself,("duplicate function ids with identifier=%r: %r and %r"%(identifier,previous,self))self.add_to_table()returnFalsedefadd_to_table(self):Function._all[self.code.identifier]=selfdeffind(identifier):returnFunction._all[identifier]find=staticmethod(find)defdescr_function__reduce__(self,space):frompypy.interpreter.gatewayimportBuiltinCodefrompypy.interpreter.mixedmoduleimportMixedModulew_mod=space.getbuiltinmodule('_pickle_support')mod=space.interp_w(MixedModule,w_mod)code=self.codeifisinstance(code,BuiltinCode):new_inst=mod.get('builtin_function')returnspace.newtuple([new_inst,space.newtuple([space.wrap(code.identifier)])])new_inst=mod.get('func_new')w=space.wrapifself.closureisNone:w_closure=space.w_Noneelse:w_closure=space.newtuple([w(cell)forcellinself.closure])ifself.w_docisNone:w_doc=space.w_Noneelse:w_doc=self.w_docifself.w_func_globalsisNone:w_func_globals=space.w_Noneelse:w_func_globals=self.w_func_globalsifself.w_func_dictisNone:w_func_dict=space.w_Noneelse:w_func_dict=self.w_func_dictnt=space.newtupletup_base=[]tup_state=[w(self.name),w_doc,w(self.code),w_func_globals,w_closure,nt(self.defs_w),w_func_dict,self.w_module,]returnnt([new_inst,nt(tup_base),nt(tup_state)])defdescr_function__setstate__(self,space,w_args):frompypy.interpreter.pycodeimportPyCodeargs_w=space.unpackiterable(w_args)try:(w_name,w_doc,w_code,w_func_globals,w_closure,w_defs,w_func_dict,w_module)=args_wexceptValueError:# wrong argsraiseOperationError(space.w_ValueError,space.wrap("Wrong arguments to function.__setstate__"))self.space=spaceself.name=space.str_w(w_name)self.code=space.interp_w(Code,w_code)ifnotspace.is_w(w_closure,space.w_None):frompypy.interpreter.nestedscopeimportCellclosure_w=space.unpackiterable(w_closure)self.closure=[space.interp_w(Cell,w_cell)forw_cellinclosure_w]else:self.closure=Noneifspace.is_w(w_doc,space.w_None):w_doc=Noneself.w_doc=w_docifspace.is_w(w_func_globals,space.w_None):w_func_globals=Noneself.w_func_globals=w_func_globalsifspace.is_w(w_func_dict,space.w_None):w_func_dict=Noneself.w_func_dict=w_func_dictself.defs_w=space.fixedview(w_defs)self.w_module=w_moduledeffget_func_defaults(self,space):values_w=self.defs_w# the `None in values_w` check here is to ensure that interp-level# functions with a default of None do not get their defaults# exposed at applevelifnotvalues_worNoneinvalues_w:returnspace.w_Nonereturnspace.newtuple(values_w)deffset_func_defaults(self,space,w_defaults):ifspace.is_w(w_defaults,space.w_None):self.defs_w=[]returnifnotspace.is_true(space.isinstance(w_defaults,space.w_tuple)):raiseOperationError(space.w_TypeError,space.wrap("func_defaults must be set to a tuple object or None"))self.defs_w=space.fixedview(w_defaults)deffdel_func_defaults(self,space):self.defs_w=[]deffget_func_doc(self,space):ifself.w_docisNone:self.w_doc=self.code.getdocstring(space)returnself.w_docdeffset_func_doc(self,space,w_doc):self.w_doc=w_docdeffget_func_name(self,space):returnspace.wrap(self.name)deffset_func_name(self,space,w_name):try:self.name=space.str_w(w_name)exceptOperationError,e:ife.match(space,space.w_TypeError):raiseOperationError(space.w_TypeError,space.wrap("func_name must be set ""to a string object"))raisedeffdel_func_doc(self,space):self.w_doc=space.w_Nonedeffget___module__(self,space):ifself.w_moduleisNone:ifself.w_func_globalsisnotNoneandnotspace.is_w(self.w_func_globals,space.w_None):self.w_module=space.call_method(self.w_func_globals,"get",space.wrap("__name__"))else:self.w_module=space.w_Nonereturnself.w_moduledeffset___module__(self,space,w_module):self.w_module=w_moduledeffdel___module__(self,space):self.w_module=space.w_Nonedeffget_func_code(self,space):returnspace.wrap(self.code)deffset_func_code(self,space,w_code):frompypy.interpreter.pycodeimportPyCodeifnotself.can_change_code:raiseOperationError(space.w_TypeError,space.wrap("Cannot change code attribute of builtin functions"))code=space.interp_w(Code,w_code)closure_len=0ifself.closure:closure_len=len(self.closure)ifisinstance(code,PyCode)andclosure_len!=len(code.co_freevars):raiseoperationerrfmt(space.w_ValueError,"%s() requires a code object with %d free vars, not %d",self.name,closure_len,len(code.co_freevars))self.fget_func_doc(space)# see test_issue1293self.code=codedeffget_func_closure(self,space):ifself.closureisnotNone:w_res=space.newtuple([space.wrap(i)foriinself.closure])else:w_res=space.w_Nonereturnw_resdefdescr_function_get(space,w_function,w_obj,w_cls=None):"""functionobject.__get__(obj[, type]) -> method"""# this is not defined as a method on Function because it's generally# useful logic: w_function can be any callable. It is used by Method too.asking_for_bound=(space.is_none(w_cls)ornotspace.is_w(w_obj,space.w_None)orspace.is_w(w_cls,space.type(space.w_None)))ifasking_for_bound:returnspace.wrap(Method(space,w_function,w_obj,w_cls))else:returnspace.wrap(Method(space,w_function,None,w_cls))classMethod(Wrappable):"""A method is a function bound to a specific instance or class."""_immutable_fields_=['w_function','w_instance','w_class']def__init__(self,space,w_function,w_instance,w_class):self.space=spaceself.w_function=w_functionself.w_instance=w_instance# or Noneifw_classisNone:w_class=space.w_Noneself.w_class=w_class# possibly space.w_Nonedefdescr_method__new__(space,w_subtype,w_function,w_instance,w_class=None):ifspace.is_w(w_instance,space.w_None):w_instance=Noneifw_instanceisNoneandspace.is_none(w_class):raiseOperationError(space.w_TypeError,space.wrap("unbound methods must have class"))method=space.allocate_instance(Method,w_subtype)Method.__init__(method,space,w_function,w_instance,w_class)returnspace.wrap(method)def__repr__(self):ifself.w_instance:pre="bound"else:pre="unbound"return"%s method %s"%(pre,self.w_function.getname(self.space))defcall_args(self,args):space=self.spaceifself.w_instanceisnotNone:# bound methodreturnspace.call_obj_args(self.w_function,self.w_instance,args)# unbound methodw_firstarg=args.firstarg()ifw_firstargisnotNoneand(space.abstract_isinstance_w(w_firstarg,self.w_class)):pass# okelse:myname=self.getname(space,"")clsdescr=self.w_class.getname(space,"")ifclsdescr:clsdescr+=" instance"else:clsdescr="instance"ifw_firstargisNone:instdescr="nothing"else:instname=space.abstract_getclass(w_firstarg).getname(space,"")ifinstname:instdescr=instname+" instance"else:instdescr="instance"msg=("unbound method %s() must be called with %s ""as first argument (got %s instead)")raiseoperationerrfmt(space.w_TypeError,msg,myname,clsdescr,instdescr)returnspace.call_args(self.w_function,args)defdescr_method_get(self,w_obj,w_cls=None):space=self.spaceifself.w_instanceisnotNone:returnspace.wrap(self)# already boundelse:# only allow binding to a more specific class than beforeif(w_clsisnotNoneandnotspace.is_w(w_cls,space.w_None)andnotspace.abstract_issubclass_w(w_cls,self.w_class,allow_override=True)):returnspace.wrap(self)# subclass test failedelse:returndescr_function_get(space,self.w_function,w_obj,w_cls)defdescr_method_call(self,__args__):returnself.call_args(__args__)defdescr_method_repr(self):space=self.spacename=self.w_function.getname(self.space)# XXX do we handle all cases sanely here?ifspace.is_w(self.w_class,space.w_None):w_class=space.type(self.w_instance)else:w_class=self.w_classtypename=w_class.getname(self.space)ifself.w_instanceisNone:s="<unbound method %s.%s>"%(typename,name)returnspace.wrap(s)else:objrepr=space.str_w(space.repr(self.w_instance))s='<bound method %s.%s of %s>'%(typename,name,objrepr)returnspace.wrap(s)defdescr_method_getattribute(self,w_attr):space=self.spaceifspace.str_w(w_attr)!='__doc__':try:returnspace.call_method(space.w_object,'__getattribute__',space.wrap(self),w_attr)exceptOperationError,e:ifnote.match(space,space.w_AttributeError):raise# fall-back to the attribute of the underlying 'im_func'returnspace.getattr(self.w_function,w_attr)defdescr_method_eq(self,w_other):space=self.spaceother=space.interpclass_w(w_other)ifnotisinstance(other,Method):returnspace.w_NotImplementedifself.w_instanceisNone:ifother.w_instanceisnotNone:returnspace.w_Falseelse:ifother.w_instanceisNone:returnspace.w_Falseifnotspace.eq_w(self.w_instance,other.w_instance):returnspace.w_Falsereturnspace.eq(self.w_function,other.w_function)defdescr_method_hash(self):space=self.spacew_result=space.hash(self.w_function)ifself.w_instanceisnotNone:w_result=space.xor(w_result,space.hash(self.w_instance))returnw_resultdefdescr_method__reduce__(self,space):frompypy.interpreter.mixedmoduleimportMixedModulefrompypy.interpreter.gatewayimportBuiltinCodew_mod=space.getbuiltinmodule('_pickle_support')mod=space.interp_w(MixedModule,w_mod)new_inst=mod.get('method_new')w=space.wrapw_instance=self.w_instanceorspace.w_Nonefunction=space.interpclass_w(self.w_function)ifisinstance(function,Function)andisinstance(function.code,BuiltinCode):new_inst=mod.get('builtin_method_new')ifspace.is_w(w_instance,space.w_None):tup=[self.w_class,space.wrap(function.name)]else:tup=[w_instance,space.wrap(function.name)]elifspace.is_w(self.w_class,space.w_None):tup=[self.w_function,w_instance]else:tup=[self.w_function,w_instance,self.w_class]returnspace.newtuple([new_inst,space.newtuple(tup)])classStaticMethod(Wrappable):"""The staticmethod objects."""_immutable_fields_=['w_function']def__init__(self,w_function):self.w_function=w_functiondefdescr_staticmethod_get(self,w_obj,w_cls=None):"""staticmethod(x).__get__(obj[, type]) -> x"""returnself.w_functiondefdescr_staticmethod__new__(space,w_subtype,w_function):instance=space.allocate_instance(StaticMethod,w_subtype)instance.__init__(w_function)returnspace.wrap(instance)classClassMethod(Wrappable):"""The classmethod objects."""_immutable_fields_=['w_function']def__init__(self,w_function):self.w_function=w_functiondefdescr_classmethod_get(self,space,w_obj,w_klass=None):ifspace.is_none(w_klass):w_klass=space.type(w_obj)returnspace.wrap(Method(space,self.w_function,w_klass,space.w_None))defdescr_classmethod__new__(space,w_subtype,w_function):instance=space.allocate_instance(ClassMethod,w_subtype)instance.__init__(w_function)returnspace.wrap(instance)classFunctionWithFixedCode(Function):can_change_code=FalseclassBuiltinFunction(Function):can_change_code=Falsedef__init__(self,func):assertisinstance(func,Function)Function.__init__(self,func.space,func.code,func.w_func_globals,func.defs_w,func.closure,func.name)self.w_doc=func.w_docself.w_func_dict=func.w_func_dictself.w_module=func.w_moduledefdescr_builtinfunction__new__(space,w_subtype):raiseOperationError(space.w_TypeError,space.wrap("cannot create 'builtin_function' instances"))defdescr_function_repr(self):returnself.space.wrap('<built-in function %s>'%(self.name,))defis_builtin_code(w_func):frompypy.interpreter.gatewayimportBuiltinCodeifisinstance(w_func,Method):w_func=w_func.w_functionifisinstance(w_func,Function):code=w_func.getcode()else:code=Nonereturnisinstance(code,BuiltinCode)