Re: python object model

scharf@EMBL-Heidelberg.DE
Fri, 26 Aug 1994 19:00:20 +0100

I have extended my version of python some time ago to enable me to easily
inplement remote objects. It is much less general than the Meta-class objects,
but for my applications it has proven to be very useful. I included some
examples and the patch for classobject.c (it's mainly adding 200 lines).

This extension allows you to do the following things:

- Create classes that (pseudo-) inherit from buildin objects.
- Make interfaces to buildin objects (like tk) really python like.
- Create completely transparent remote objects.
- You can call a method whenever a variable is assigned to or its value is
requested.

New methods
===========

A class may define 3 new special methods:

__getattr__(self, name)
is called whenever an AttributeError would be raised
v = self.x
v = getattr(self,'x')
v = hasattr(self,'x')

__setattr__(self, name, v)
is called whenever an attribute is assigned to:
self.x = v
setattr(self,'x',v)

__delattr__(self, name)
is called whenever an attribute is deleted
del self.x

An instance objects will have 4 new special methods (I originally called these
methods __do__...attr__, but inspired by Mark Lutz I renamed them...):

__setslot__(self, name, value)
to set an instances attribute without calling self.__setattr__

__delslot__(self, name, value)
to delete the instances attribute without calling self.__delattr__

__hasslot__(self ,name)
to check if the instance itself has the attribute

__getslot__(self ,name)
to get the value of the attribute name of the instance

I have implemented this quite some time ago and played succsessfully.

The special method __getattr__
==============================

If a class defines __getattr__, it is called whenever an object would raise an
AttributeError exception, it calls its __getattr__ method. There is no
performace penalty introduced by this mechanism if the instance has the slot.

Example:

class TestGetattr:
ca="TestGetattr.ca"
def __getattr__(self, name):
# the attribute m is the method f :-)
if name == 'm':
return self.f
return "t.__getattr__(%s)" % `name`
def f(self):
return "t.f()"

t=TestGetattr()

print t.ca # TestGetattr.ca, the class defines ca
t.ca="t.ca"
print t.ca # t.ca, now t has a ca
del t.ca
print t.ca # TestGetattr.ca, again the class defines ca

print t.x # t.__getattr__('x'), because t doesn't have 'x'
t.x="t.x"
print t.x # t.x
del t.x
print t.x # t.__getattr__('x'), because t doesn't have 'x'

print t.f() # f()
print t.f # <method TestGetattr.f of TestGetattr instance at 10b4a0>

print t.m() # f(), because __getattr__ returns self.f !!!
print t.m # <method TestGetattr.f of TestGetattr instance at 10b4a0>

The special method __setattr__
==============================

If a class defines __setattr__, it is called when something is assigned to an
instance variable:
- self.x=some_value
- setattr(self,'x',some_value)

... I can't write anymore - look at the examples :-) ...

Michael

--
          __________________________________________________________
   ****    ___   _  _   ___   _    
  ******  | __) | \/ | |   ) | |   Michael Scharf
 ******** | _)  |    | | -<  | |_  Tel: +49 6221 387 305 Fax: 517
  * ****  |___) |_||_| |___) |___) EMail: scharf@EMBL-Heidelberg.de
   ****   __________________________________________________________

FILES: ====== README this file

types.py it's not from me - but useful

classobject.c.patch the patch in python-1.0.3/Objects - mainly additions

Test.py some tests of the new features Trace.py prints when one of the new functions is called Rename.py self.x is translated to self._x Wrapper.py forwards everything to a client TraceWrapper.py tells what is does and forwards everything to a client Composite.py forwards everything to multiple clients

Square.py a square class where the assignment has funny effects.. File.py a wrapper for the built-in file object

Proxy.py distributed Objects. Proxy is a general object that can replace any ordinary object with a remote version Connection.py Client/Server connectins with sockets client.py the client server.py the server (what else :-)

----------------------------------------------------------------------------- #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: AINDEX Composite.py Connection.py File.py Proxy.py # Rename.py Square.py Test.py Trace.py TraceWrapper.py Wrapper.py # classobject.c.patch client.py server.py types.py # Wrapped by scharf@zinc@EMBL-Heidelberg.DE on Fri Aug 26 07:48:35 1994 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'AINDEX' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'AINDEX'\" else echo shar: Extracting \"'AINDEX'\" \(724 characters\) sed "s/^X//" >'AINDEX' <<'END_OF_FILE' XFILES: X====== XREADME this file X Xtypes.py it's not from me - but useful X Xclassobject.c.patch the patch in python-1.0.3/Objects - mainly additions X XTest.py some tests of the new features XTrace.py prints when one of the new functions is called XRename.py self.x is translated to self._x XWrapper.py forwards everything to a client XTraceWrapper.py tells what is does and forwards everything to a client XComposite.py forwards everything to multiple clients X XSquare.py a square class where the assignment has funny effects.. XFile.py a wrapper for the built-in file object X X XProxy.py distributed Objects XConnection.py Client/Server connectins with sockets Xclient.py the client Xserver.py the server (what else :-) X X X END_OF_FILE if test 724 -ne `wc -c <'AINDEX'`; then echo shar: \"'AINDEX'\" unpacked with wrong size! fi # end of 'AINDEX' fi if test -f 'Composite.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Composite.py'\" else echo shar: Extracting \"'Composite.py'\" \(1398 characters\) sed "s/^X//" >'Composite.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X# this class just forwards any call to the client X Xclass Object: X def __init__(self,name="Object"): X self.name=name X X def Task1(self): X print self.name, "Task1" X X def Task2(self,x,y): X print self.name, "Task2(%s,%s)"%(`x`,`y`) X X def Task3(self,x): X return x+1 X X############################################################################# X Xclass Composite: X def __init__(self,*components): X self.components=[] X for c in components: X self.components.append(c) X def append(self,component): X self.components.append(component) X X def __getattr__(self,name): X return Forall(self,name).Method X X # X # here the composite needs to do something else.... X def Task3(self,x): X for c in self.components: X x=c.Task3(x) X return x X Xclass Forall: X def __init__(self,comp,methname): X self.comp=comp X self.methname=methname X X def Method(self,*args): X for c in self.comp.components: X apply(getattr(c,self.methname),args) X X############################################################################# X Xtests=""" Xp.PrintName() Xp.Task1() Xp.Task2(1,2) Xprint p.Task3(1) X""" X Xdef test(): X from Test import DoTest,TestClass X # let's wrap the composite... X DoTest(Object(),tests) X composite=Composite(Object("O1"),Object("O2")) X composite.Task1() X DoTest(composite,tests); X composite1=Composite(Object("O3"),composite) X DoTest(composite1,tests); X Xif __name__ == "__main__": X test() END_OF_FILE if test 1398 -ne `wc -c <'Composite.py'`; then echo shar: \"'Composite.py'\" unpacked with wrong size! fi # end of 'Composite.py' fi if test -f 'Connection.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Connection.py'\" else echo shar: Extracting \"'Connection.py'\" \(1940 characters\) sed "s/^X//" >'Connection.py' <<'END_OF_FILE' Ximport string,socket Ximport marshal X X_headerlen=8 XPORT=54321 X_HOST='localhost' X Xclass Connection: X def Send(self,message): X socket=self.socket X message=marshal.dumps(message) X length=string.zfill("%d" % len(message),_headerlen) X socket.send(length+message) X X def Receive(self): X length=self.socket.recv(_headerlen) X length=string.atoi(length) X if length<0: X return None X result=self.socket.recv(length) X return marshal.loads(result) X X def Request(self,message): X self.Send(message); X return self.Receive() X X def Serve(self,request): X result=self.HandleRequest(request) X self.Send(result) X X def HandleRequest(self,request): X print request X return request X X Xclass ServerConn(Connection): X def Start(self,port=None): X if port is None: X port=PORT X # Echo server program X HOST = '' # Symbolic name meaning the local host X s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) X print 'port=',port X s.bind(HOST, port) X s.listen(1) X while 1: X try: X self.socket, addr = s.accept() X while 1: X request=self.Receive() X self.Serve(request) X except (socket.error,SystemError): X import sys X print sys.exc_type,sys.exc_value X print "close" X s.close() X X X Xclass ClientConn(Connection): X def Start(self,host=None,port=None): X if host is None: X host=_HOST X if port is None: X port=PORT X s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); X s.connect(host,port); X self.socket=s X X X############################################################################# Xfrom Proxy import Client X Xclass ProxyClient(Client): X def __init__(self,connection): X self.conn=connection X def CallRemote(self,command,args): X return self.conn.Request((command,args)) X Xclass ProxyServerConn(ServerConn): X def __init__(self,server): X self.server=server X X def HandleRequest(self,request): X print request X (command,args)=request X result= self.server.Dispatch(command,args) X# print result X return result X X X X END_OF_FILE if test 1940 -ne `wc -c <'Connection.py'`; then echo shar: \"'Connection.py'\" unpacked with wrong size! fi # end of 'Connection.py' fi if test -f 'File.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'File.py'\" else echo shar: Extracting \"'File.py'\" \(794 characters\) sed "s/^X//" >'File.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X# This is a simple wrapper-class for the built-in objects file X# Xclass File: X def __init__(self,name,acc='r'): X self.file=open(name,acc) X def __getattr__(self,name): X return getattr(self.file,name) X # X # let's add a simple method to read n lines X # X def readn(self,n): X result=[] X for i in range(n): X result.append(self.readline()) X return result X # X # 'overwrite' the read method of file X # This is a 'half' overwrite - meaning from the client site X # it is overwritten, but internally it is not used... X # Meaning readline() doesn't use this X # X def read(self,n): X return self.readn(n) X Xdef test(): X global f # so that we can play... X f=File('File.py') X print 'first line:',`f.readline()` X print f.readn(3) X print f.read(3) X Xif __name__ == "__main__": X test() X END_OF_FILE if test 794 -ne `wc -c <'File.py'`; then echo shar: \"'File.py'\" unpacked with wrong size! fi # end of 'File.py' fi if test -f 'Proxy.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Proxy.py'\" else echo shar: Extracting \"'Proxy.py'\" \(3661 characters\) sed "s/^X//" >'Proxy.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X X############################################################################# X# this class simply gives any setattr and getattr to the next object Xclass Proxy: X def __init__(self,forwarder): X # force to set our own member forwarder X self.__setslot__('forwarder',forwarder) X X def __setattr__(self,name,v): X self.forwarder.SetAttr(name,v) X X def __getattr__(self,name): X return self.forwarder.GetAttr(name) X############################################################################# X Xfrom types import MethodType,FunctionType X# some constants ... XcSetAttr="SetAttr" XcGetAttr="GetAttr" XcCall="Call" XcIsMethod="IsMethod" XcResult="Result" XcError="Error" X Xclass Client: X def SetAttr(self,name,v): X self.Remote(cSetAttr,(name,v)) X X def GetAttr(self,name): X if self.IsMethod(name): X return self.GetMethod(name) X return self.Remote(cGetAttr,(name,)) X X def GetMethod(self,name): X return RemoteFunc(self,name).Method X X def Call(self,methname,args): X return self.Remote(cCall,(methname,args)) X X def IsMethod(self,name): X return self.Remote(cIsMethod,(name,)) X X def Remote(self,command,args): X (what,result)=self.CallRemote(command,args) X if what == cError: X raise result[0],result[1] X else: X return result X X def CallRemote(self,command,args): X raise RuntimeError,"AbstractMethod CallRemote" X Xclass RemoteFunc: X def __init__(self,forw,methname): X self.methname=methname X self.forw=forw X X def Method(self,*args): X return self.forw.Call(self.methname,args) X X############################################################################# Ximport sys Xclass Server: X def __init__(self,child): X self.child=child X X def SetChild(self,child): X self.child=child X X def DoSetAttr(self,name,v): X return setattr(self.child,name,v) X X def DoGetAttr(self,name): X return getattr(self.child,name) X X def DoCall(self,methname,args): X m=getattr(self.child,methname) X return apply(m,args) X X def DoIsMethod(self,name): X t=type(getattr(self.child,name)) X if t==MethodType or t==FunctionType: X return 1 X return 0 X X def DoDispatch(self,command,args): X if command==cGetAttr: X return apply(self.DoGetAttr,args) X if command==cSetAttr: X return apply(self.DoSetAttr,args) X if command==cIsMethod: X return apply(self.DoIsMethod,args) X if command==cCall: X return apply(self.DoCall,args) X X def Dispatch(self,command,args): X try: X result=self.DoDispatch(command,args) X return (cResult,result) X except: X return (cError,(sys.exc_type,sys.exc_value)) X X def DoCallRemote(self,command,args): X return self.Dispatch(command,args) X Xclass VServer(Server): X def __init__(self,child): X self.child=child X def DoCallRemote(self,command,args): X print "%s%s"%(command,`args`) X return self.Dispatch(command,args) X X############################################################################# Xclass LocalClient(Client): X server=None X def __init__(self,server): X self.server=server X def CallRemote(self,command,args): X return self.server.DoCallRemote(command,args) X X############################################################################# Ximport marshal Xclass MClient(Client): X def __init__(self,server): X self.server=server X def CallRemote(self,command,args): X args=marshal.dumps(args) X result= self.server.DoCallRemote(command,args) X return marshal.loads(result) X Xclass MServer(Server): X def __init__(self,child): X self.child=child X def DoCallRemote(self,command,args): X args=marshal.loads(args) X result=self.Dispatch(command,args) X result=marshal.dumps(result) X return result X X Xdef test(): X from Test import TestClass,DoTest X DoTest(TestClass()) X DoTest(Proxy(MClient(MServer(TestClass())))) X Xif __name__ == "__main__": X test() END_OF_FILE if test 3661 -ne `wc -c <'Proxy.py'`; then echo shar: \"'Proxy.py'\" unpacked with wrong size! fi # end of 'Proxy.py' fi if test -f 'Rename.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Rename.py'\" else echo shar: Extracting \"'Rename.py'\" \(647 characters\) sed "s/^X//" >'Rename.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X# this class renames all its attributes to '_' + attributename X Xclass Rename: X c=42 X def __getattr__(self,name): X print '__getattr__(%s)' %name X if name=='f': X return self._f X if name=='g': X return self._g X return self.__getslot__('_'+name) X X def __setattr__(self,name,v): X print '__setattr__(%s,%s)' %(name,v) X self.__setslot__('_' + name,v) X X def __delattr__(self,name): X print '__delattr__(%s)' %name X self.__delslot__('_' + name) X X def _f(self,*args): X return ("f:",args) X def _g(self,*args): X return ("g:",args) X Xdef test(): X from Test import DoTest X DoTest(Rename()) X Xif __name__ == "__main__": X test() END_OF_FILE if test 647 -ne `wc -c <'Rename.py'`; then echo shar: \"'Rename.py'\" unpacked with wrong size! fi # end of 'Rename.py' fi if test -f 'Square.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Square.py'\" else echo shar: Extracting \"'Square.py'\" \(2366 characters\) sed "s/^X//" >'Square.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X# The class Square has two 'special' variable: side and area: X# area is always calculated on the fly. If area is set, it modifies side! X# X Xfrom math import sqrt Xclass Square: X side=0 X def __setattr__(self,name,v): X if name=='side': X # let's check if side is what we think is should be: X # side may only be positive number.... X if v < 0: X raise RuntimeError, "%s%d < 0" %(name,v) X if name=='area': X # area may only be positive number.... X if v < 0: X raise RuntimeError, "%s=%d < 0" %(name,v) X # we don't set area but side :-) X self.__setslot__('side',sqrt(v)) X else: X self.__setslot__(name,v) X X def __getattr__(self,name): X if name=='area': X # area is a pseudo attribute, it's calculated on the fly X return self.side * self.side X else: X raise AttributeError, name X# X# The same as Square, but another, more generic implementation X# Xclass Square1: X side=0 X set_specials={} # holds attribute names with special __getattr__ X get_specials={} # holds attribute names with special __setattr__ X def __init__(self): X self.set_specials={'area':Square1.SetArea, X 'side':Square1.SetSide} X self.get_specials={'area':Square1.GetArea} X X def __setattr__(self,name,v): X # is this name in the special list? X if self.set_specials.has_key(name): X # yes, so let's call the special function... X apply(self.set_specials[name],(self,v)) X else: X self.__setslot__(name,v) X X def __getattr__(self,name): X if self.get_specials.has_key(name): X return apply(self.get_specials[name],(self,)) X else: X return self.__getslot__(name) X X def SetSide(self,side): X # side may only be positive number.... X if side < 0: X raise RuntimeError, "side=%d < 0" %side X # WARNING: here we MUST use __setslot__ else we would get an X # infinite loop. Think about it! X self.__setslot__('side',side) X X def GetSide(self): X return self.side X X def SetArea(self,area): X # area may only be positive number.... X if area < 0: X raise RuntimeError, "area=%d < 0" %area X self.SetSide(sqrt(area)) X X def GetArea(self): X return self.side*self.side X X## Xtest=""" Xsquare.side=10 Xprint square.side Xprint square.area Xsquare.area=10 Xprint square.side Xprint square.area Xsquare.area=-1 X""" X Xdef TestSquare(square): X from Test import DoTest X DoTest(square,test,'square') X X Xif __name__ == "__main__": X TestSquare(Square()) X TestSquare(Square1()) X END_OF_FILE if test 2366 -ne `wc -c <'Square.py'`; then echo shar: \"'Square.py'\" unpacked with wrong size! fi # end of 'Square.py' fi if test -f 'Test.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Test.py'\" else echo shar: Extracting \"'Test.py'\" \(1517 characters\) sed "s/^X//" >'Test.py' <<'END_OF_FILE' X#!/usr/pub/bin/python Ximport sys,string X Xclass TestClass: X c=42 X def f(self,*args): X return ("f:",args) X def g(self,*args): X reverse=() X for i in args: X reverse=((i,)+reverse) X return ("g:",reverse) X XdefaultTest="""\ Xprint p.c # Getattr.c, the class defines c Xp.c="Hello world" Xprint p.c # p.c, now t has a c Xdel p.c Xprint p.c # Getattr.c, again the class defines c Xdel p.c X Xprint p.x # p.__getattr__('x'), because t doesn't have 'x' X Xp.x="p.x" Xprint p.x # p.x Xprint `p.x` Xprint getattr(p,'x') Xsetattr(p,'x',"X") Xprint p.x X Xp.x=[1,2,{'a':0,'b':1},(3,4)] Xprint p.x X Xdel p.x Xprint p.x Xprint getattr(p,'x') X X# let's save two method pointers Xpf=p.f Xpg=p.g Xprint type(p.f) Xprint p.f() Xprint p.f(1,2,3) Xprint p.g("hello","world") Xprint apply(p.f,(1,2,3)) X Xprint apply(pf,(1,2,3)) Xprint pf([1,2,3]) Xprint pg(1,2,3,4,5,6,7,8,9,10) X""" X Xclass Tester: X def Test(self,object, tests=None, name=None): X if tests is None: X tests=defaultTest X if name is None: X name='p' X self.dict={name: object} X self.DoTests(tests) X X def DoComment(self,c): X print c X X def DoTest(self,test): X print ">> %s" % test X try: X exec(test,self.dict,self.dict) X except: X print "*****",sys.exc_type,sys.exc_value X X X def DoTests(self,test): X for t in string.splitfields(test,'\n'): X t=string.strip(t) X if t == "" or t[0]=='#': X self.DoComment(t) X else: X self.DoTest(t) X X Xdef DoTest(object,tests=None, name=None): X t=Tester() X t.Test(object,tests,name) X Xif __name__ == "__main__": X t=Tester() X t.Test(TestClass()) END_OF_FILE if test 1517 -ne `wc -c <'Test.py'`; then echo shar: \"'Test.py'\" unpacked with wrong size! fi # end of 'Test.py' fi if test -f 'Trace.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Trace.py'\" else echo shar: Extracting \"'Trace.py'\" \(515 characters\) sed "s/^X//" >'Trace.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X# this class prints out whenever one of the new functions is called Xfrom Test import TestClass X Xclass Trace(TestClass): X def __getattr__(self,name): X print '__getattr__(%s)' %name X return self.__getslot__(name) X X def __setattr__(self,name,v): X print '__setattr__(%s,%s)' %(name,`v`) X self.__setslot__(name,v) X X def __delattr__(self,name): X print '__delattr__(%s)' %name X self.__delslot__(name) X Xdef test(): X from Test import DoTest X DoTest(Trace()) X Xif __name__ == "__main__": X test() END_OF_FILE if test 515 -ne `wc -c <'Trace.py'`; then echo shar: \"'Trace.py'\" unpacked with wrong size! fi # end of 'Trace.py' fi if test -f 'TraceWrapper.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'TraceWrapper.py'\" else echo shar: Extracting \"'TraceWrapper.py'\" \(775 characters\) sed "s/^X//" >'TraceWrapper.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X X# this class prints out whenever an attribute of the client is gotten, assigned X# to or deleted. X Xclass TraceWrapper: X def __init__(self,client): X # we have to call __setslot__ here to avoid infinite recursion... X self.__setslot__('_client_',client) X X def __getattr__(self,name): X print '__getattr__(%s)' %name X return getattr(self._client_,name) X X def __setattr__(self,name,v): X print '__setattr__(%s,%s)' %(name,`v`) X setattr(self._client_,name,v) X X def __delattr__(self,name): X print '__delattr__(%s)' %name X # how else to delete a named attribute of the clinet?? X exec('del client.%s' % name,{'client':self._client_}) X Xdef test(): X from Test import DoTest,TestClass X DoTest(TraceWrapper(TestClass())) X Xif __name__ == "__main__": X test() END_OF_FILE if test 775 -ne `wc -c <'TraceWrapper.py'`; then echo shar: \"'TraceWrapper.py'\" unpacked with wrong size! fi # end of 'TraceWrapper.py' fi if test -f 'Wrapper.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Wrapper.py'\" else echo shar: Extracting \"'Wrapper.py'\" \(680 characters\) sed "s/^X//" >'Wrapper.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X# this class just forwards any call to the client X Xclass Wrapper: X def __init__(self,client): X # we have to call __setslot__ here to avoid infinite recursion... X self.__setslot__('_client_',client) X X def __getattr__(self,name): X return getattr(self._client_,name) X X def __setattr__(self,name,v): X setattr(self._client_,name,v) X X def __delattr__(self,name): X # how else to delete a named attribute of the clinet?? X exec('del client.%s' % name,{'client':self._client_}) X Xdef test(): X from Test import DoTest,TestClass X DoTest(Wrapper(TestClass())) X # let's wrap the wrapper... X DoTest(Wrapper(Wrapper(TestClass()))) X Xif __name__ == "__main__": X test() END_OF_FILE if test 680 -ne `wc -c <'Wrapper.py'`; then echo shar: \"'Wrapper.py'\" unpacked with wrong size! fi # end of 'Wrapper.py' fi if test -f 'classobject.c.patch' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'classobject.c.patch'\" else echo shar: Extracting \"'classobject.c.patch'\" \(4920 characters\) sed "s/^X//" >'classobject.c.patch' <<'END_OF_FILE' X--- classobject.c.orig Tue Aug 23 18:40:17 1994 X+++ classobject.c Fri Aug 26 07:10:16 1994 X@@ -348,8 +348,78 @@ X free((ANY *)inst); X } X X+static object *instance_getattr1(); X+static int instance_setattr1(); X+ X static object * X-instance_getattr(inst, name) X+instance_getslot_meth(self, args) X+ instanceobject *self; X+ object *args; X+{ X+ object *v; X+ char *name; X+ if (!getargs(args, "s", &name)) X+ return NULL; X+ return instance_getattr1(self, name); X+} X+ X+static object * X+instance_hasslot_meth(self, args) X+ instanceobject *self; X+ object *args; X+{ X+ object *v; X+ char *name; X+ if (!getargs(args, "s", &name)) X+ return NULL; X+ v = instance_getattr1(self, name); X+ if (v == NULL) { X+ err_clear(); X+ return newintobject(0L); X+ } X+ DECREF(v); X+ return newintobject(1L); X+} X+ X+static object * X+instance_setslot_meth(self, args) X+ instanceobject *self; X+ object *args; X+{ X+ char*name; X+ object*value; X+ value = NULL; X+ if (!getargs(args, "s", &name)) { X+ err_clear(); X+ if (!getargs(args, "(sO)", &name, &value)) X+ return NULL; X+ } X+ if(instance_setattr1(self, name, value)<0) { X+ return NULL; X+ } X+ INCREF(None); X+ return None; X+} X+ X+static object * X+instance_delslot_meth(self, args) X+ instanceobject *self; X+ object *args; X+{ X+ char*name; X+ if (!getargs(args, "s", &name)) { X+ return NULL; X+ } X+ if(instance_setattr1(self, name, 0)<0) { X+ return NULL; X+ } X+ INCREF(None); X+ return None; X+} X+ X+ X+static object * X+instance_getattr1(inst, name) X register instanceobject *inst; X register char *name; X { X@@ -403,8 +473,71 @@ X return v; X } X X+static object * X+instance_getattr(inst, name) X+ register instanceobject *inst; X+ register char *name; X+{ X+ register object *func, *res; X+ if (name[0] == '_' && name[1] == '_') { X+ /* Let's not compare the first "__": */ X+ /* use &name[2] :-) */ X+ if (strcmp(&name[2], "setslot__") == 0) { X+ return newmethodobject(name, X+ (method)instance_setslot_meth, X+ (object*)inst, X+ 0); X+ } X+ if (strcmp(&name[2], "getslot__") == 0) { X+ return newmethodobject(name, X+ (method)instance_getslot_meth, X+ (object*)inst, X+ 0); X+ } X+ if (strcmp(&name[2], "hasslot__") == 0) { X+ return newmethodobject(name, X+ (method)instance_hasslot_meth, X+ (object*)inst, X+ 0); X+ } X+ if (strcmp(&name[2], "delslot__") == 0) { X+ return newmethodobject(name, X+ (method)instance_delslot_meth, X+ (object*)inst, X+ 0); X+ } X+ /* The following methods should not be forwarded! */ X+ if ( strcmp(&name[2], "init__") == 0 X+ || strcmp(&name[2], "del__") == 0) { X+ return instance_getattr1(inst,name); X+ } X+ } X+ res=instance_getattr1(inst,name); X+ if (res == NULL) { X+ /* Self doesn't have this attribute, */ X+ /* so let's try to call self.__getattr__(name) */ X+ object* func; X+ object *arg; X+ /* Well, lets get a funcobject for __getattr__ ...*/ X+ func = instance_getattr1(inst,"__getattr__"); X+ if (func == NULL) { X+ /* OOPS, we don't have a __getattr__. */ X+ /* Set the error ... */ X+ err_clear(); X+ err_setstr(AttributeError, name); X+ return NULL; X+ } X+ arg = newstringobject(name); X+ /*... and call it */ X+ res = call_object(func,arg); X+ DECREF(arg); X+ DECREF(func); X+ } X+ return res; X+} X+ X static int X-instance_setattr(inst, name, v) X+instance_setattr1(inst, name, v) X instanceobject *inst; X char *name; X object *v; X@@ -429,6 +562,58 @@ X } X else X return dictinsert(inst->in_dict, name, v); X+} X+ X+static int X+instance_setattr(inst, name, v) X+ instanceobject *inst; X+ char *name; X+ object *v; X+{ X+ object *ac, *func; X+ classobject *class; X+ char* setattrname; X+ /* I think I saw something in the news, that deletion of an attribute */ X+ /* is done by setattr with the value being NULL. */ X+ /* Let's be prepared for this case :-)*/ X+ if (v != NULL) X+ setattrname = "__setattr__"; X+ else X+ setattrname = "__delattr__"; X+ X+ /* Here is the only performance loss: */ X+ /* We have to check if there is a method __setattr__.*/ X+ /* Only class can have a __setattr__ because it's forbidden to */ X+ /* assign to self.__setattr__.*/ X+ /* So, lets do a class_lookup which is (hopefully) cheap */ X+ class = NULL; X+ func = class_lookup(inst->in_class, setattrname, &class); X+ if (func == NULL) { X+ /* Call the original instance_setattr */ X+ return instance_setattr1(inst,name,v); X+ } else { X+ object *arg, *res; X+ /* class_lookup did'nt REF(func) - so we won't UNREF(func). */ X+ /* Let's get the function (could be optimized....) */ X+ func = instance_getattr(inst,setattrname); X+ if (func == 0) X+ return -1; X+ /* Deleting an attribute is done by v==NULL */ X+ if (v == NULL) X+ /* __delattr__ has only one argument: the name */ X+ arg = mkvalue("s",name); X+ else X+ arg = mkvalue("(sO)",name,v); X+ res = call_object(func,arg); X+ DECREF(func); X+ DECREF(arg); X+ if (res == NULL) { X+ /* Oops, something went wrong :-( */ X+ return -1; X+ } X+ DECREF(res); X+ } X+ return 0; X } X X static object * END_OF_FILE if test 4920 -ne `wc -c <'classobject.c.patch'`; then echo shar: \"'classobject.c.patch'\" unpacked with wrong size! fi # end of 'classobject.c.patch' fi if test -f 'client.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'client.py'\" else echo shar: Extracting \"'client.py'\" \(362 characters\) sed "s/^X//" >'client.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X Ximport sys, Connection,Test Xfrom Connection import ClientConn, ProxyClient Xfrom Proxy import Proxy X Xconn=ClientConn() Xfor i in range(5): X try: X conn.Start(None,Connection.PORT+i) X break X except: X print "*****",sys.exc_type,sys.exc_value Xc=ProxyClient(conn) Xp=Proxy(c) X Xdef test(p): X Test.DoTest(p) X Xif __name__ == "__main__": X test(p) END_OF_FILE if test 362 -ne `wc -c <'client.py'`; then echo shar: \"'client.py'\" unpacked with wrong size! fi chmod +x 'client.py' # end of 'client.py' fi if test -f 'server.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'server.py'\" else echo shar: Extracting \"'server.py'\" \(394 characters\) sed "s/^X//" >'server.py' <<'END_OF_FILE' X#!/usr/pub/bin/python X Xfrom sys import argv Ximport string,sys, Trace Xfrom Connection import ProxyServerConn,PORT Xfrom Proxy import Server X Xport=PORT Xserver=Server(Trace.Trace()) X Xconn=ProxyServerConn(server) X Xif len(argv)>=2: X port=string.atoi(argv[1]) Xfor i in range(5): X try: X conn.Start(port+i) X break X except KeyboardInterrupt: X break X except: X print "*****",sys.exc_type,sys.exc_value END_OF_FILE if test 394 -ne `wc -c <'server.py'`; then echo shar: \"'server.py'\" unpacked with wrong size! fi chmod +x 'server.py' # end of 'server.py' fi if test -f 'types.py' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'types.py'\" else echo shar: Extracting \"'types.py'\" \(888 characters\) sed "s/^X//" >'types.py' <<'END_OF_FILE' X# Define names for all type symbols known in the standard interpreter. X# Types that are part of optional modules (e.g. array) are not listed. X Ximport sys X XNoneType = type(None) XTypeType = type(NoneType) X XIntType = type(0) XLongType = type(0L) XFloatType = type(0.0) X XStringType = type('') X XTupleType = type(()) XListType = type([]) XDictionaryType = type({}) X Xdef func(): pass XFunctionType = type(func) X Xclass C: X def meth(self): pass XClassType = type(C) XUnboundMethodType = type(C.meth) # Same as MethodType Xx = C() XInstanceType = type(x) XMethodType = type(x.meth) X XBuiltinFunctionType = type(len) # Also used for built-in methods X XModuleType = type(sys) X XFileType = type(sys.stdin) XXRangeType = type(xrange(0)) X Xtry: X raise TypeError Xexcept TypeError: X TracebackType = type(sys.exc_traceback) X FrameType = type(sys.exc_traceback.tb_frame) X Xdel sys, func, C, x # These are not for export END_OF_FILE if test 888 -ne `wc -c <'types.py'`; then echo shar: \"'types.py'\" unpacked with wrong size! fi # end of 'types.py' fi echo shar: End of shell archive. exit 0

-- 
         __________________________________________________________
   ****    ___   _  _   ___   _    
  ******  | __) | \/ | |   ) | |   Michael Scharf
 ******** | _)  |    | | -<  | |_  Tel: +49 6221 387 305 Fax: 517
  * ****  |___) |_||_| |___) |___) EMail: scharf@EMBL-Heidelberg.de
   ****   __________________________________________________________