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
**** __________________________________________________________