[Pipet Devel] J.W. Bizzaro; TODO 20000218
J.W. Bizzaro
bizzaro at geoserve.net
Thu Feb 24 10:46:02 EST 2000
Brad Chapman wrote:
>
> I started making the front talk to the middle via xml in the changes I
> just committed. I've started with connections, and I made the front
> send the middle the following XML:
>
> <front>
> <connect>
> <input id = 'workspace1/workspace2/container1.xml'/>
> <output id = 'workspace1/workspace2/viewer2.xml'/>
> </connect>
> </front>
>
> This is just a semi-modification on what you were talking about before
> (to make it valid XML so I can use DOM to work with it). I figured
> that other actions can be a modification of this.
That looks very nice, much better than my illegal XML hack.
> Right now I'm just passing the info as a big string o' XML and
> parsing it from this.
That's pretty much what I had in mind.
> I took a little look at the httplib library in
> the python distribution, and it seems like it might be useful (at
> least, there are send and reply functions to call). Maybe I'll try
> playing with this, but as you said, I'm not positive how to do it
> with "streaming" data. We'll see, I guess...
I have attached exploop.py (an Expect for Python) and eventloop.py (needed by
exploop.py). Perhaps these will be of some help in learning how to make a
streaming dialog.
> What kind of information do you want the middle to give to the front?
> Would something like:
>
> <middle>
> <connect_reply>Error: Loci cannot be connected</connect_reply>
> </middle>
>
> be sufficient.
Could we use a tag to identify the error, instead of a string?
<middle>
<connect_reply>
<error type = 13>
Loci cannot be connected.
</error>
</connect_reply>
</middle>
> I think we should keep the chatting to a minimum since
> we have
> to deal with everything we pass. So, if you send the middle a request
> to connect it either does it and returns "Success: Loci connected" or
> send an "Error" if it cannot. Then the front can decide what it wants
> to do. How does this sound?
Yeah, that sounds good.
> Even though it is a mess to untangle them, it will be pretty cool
> to have the middle and front finally free!
Yes.
You the man!
Cheers.
Jeff
--
+----------------------------------+
| J.W. Bizzaro |
| |
| http://bioinformatics.org/~jeff/ |
| |
| BIOINFORMATICS.ORG |
| The Open Lab |
| |
| http://bioinformatics.org/ |
+----------------------------------+
-------------- next part --------------
#! /usr/bin/env python
#
######
# $Id: exploop.py,v 1.5 1997/01/27 19:11:59 timo Exp $
#
# Depends on eventloop.py(c), which may be found at
# ftp://ftp.bbn.com/pub/timo/python/eventloop.py
#
######
# Inspired by pyexpect, "A Poor Man's Expect", from Mitch Chapman
#
######
"""
Need to document the Expect interface here.
"""
import eventloop
import regex
import fcntl, FCNTL
def _defaultCB(P,E):
return "break"
# end _defaultCB
class Pattern:
"""
Need to document the Pattern object's public interface.
I expect (no pun intended) that Pattern will often be subclassed
so that additional information can be stored with each
pattern.
"""
def __init__(self, regexp="", command=_defaultCB):
"""__init__(self, regexp="", command=<_defaultCB>)
The paramenter 'regexp' is a *compiled* regular expression.
The function 'command' will be called when a match is found.
The default command simply returns 'break'.
"""
self.pattern = regexp
self.command = command
# end __init__
# end class Pattern
ExpectError = "ExpectError"
ExpectTimeout = "ExpectTimeout"
ExpectEOF = "ExpectEOF"
class Expect(eventloop.EventLoop):
"""
Need to add documentation for the Expect class.
In particular, describe the public interface.
"""
def __init__(self, inf, outf):
"""__init__(self, infile, outfile)
Constructor for an Expect instance. This routine automatically
sets the input file for non-blocking.
"""
eventloop.EventLoop.__init__(self)
# Set up for non-blocking I/O, as otherwise handleInput
# will block until it has read a whole boatload of characters.
fcntl.fcntl(inf.fileno(), FCNTL.O_NDELAY, 1)
fcntl.fcntl(inf.fileno(), FCNTL.F_SETFL, FCNTL.O_NONBLOCK)
self.__inf = inf
self.__outf = outf
self.AddFile(inf, self.handleInput, inf, None)
# end of __init__
def send(self, str):
"""send(self, string)
Send characters from string out file.
"""
self.__outf.write(str)
self.__outf.flush()
# end of send
def expect(self, patterns=[], timeout=None):
"""expect(self, patterns=[], timeout=None)
The expect method is modeled after the select call. The
parameter 'patterns' is a list of Pattern instances. If a
'timeout' is specified, then expect() will wait at most
'timeout' seconds before returning, with a 'None' value.
If a pattern is matched, then its command is called. If that
command returns a true value, then expect() will return the
matching Pattern.
"""
if hasattr(self, "pats"):
raise ExpectError, "You're already expecting something."
self.pats = patterns
# Clear the rcvd buffer and set our default result.
self.__rcvd = ""
# Set a timer if given. Call Mainloop
self.__timerID = None
if timeout:
self.__timerID = self.AddTimer(timeout, self.doTimeout)
result = self.MainLoop()
if timeout:
self.DeleteTimer(self.__timerID)
del self.pats, self.__timerID
return result
# end expect()
def doTimeout(self, event=None):
"""doTimeout(self, event=None)
Timeout has expired for current expect() call.
"""
del self.pats, self.__timerID
raise ExpectTimeout
# end doTimeout
def handleInput(self, file, option):
"""handleInput(self, file, option)
Read all available characters on input file 'file' and
sequentially compare them to the current patterns. Once a
match is found, handleInput removes all text from the
beginning of the input string until the end of the match.
Matches are checked sequentially. If a pattern matches,
then we remove the appropriate text *BEFORE* checking
the next pattern.
Parameter 'option' is unused for now.
"""
str = file.read()
if not str:
raise ExpectEOF
self.__rcvd = self.__rcvd + str
# Ok, let's look for a match
for i in self.pats:
while 1:
result = i.pattern.search(self.__rcvd)
if result < 0: # no match found
break
matchlen = result + len(i.pattern.group(0)) + 1
result = apply(i.command, (i, self))
self.__rcvd = self.__rcvd[matchlen:]
if result:
self.Cancel(i)
# end of while loop
# end of for loop...
# end handleInput()
# end class Expect
######################################################################
##
# Example code
##
def _testCB(pat, exp):
reg = pat.pattern
exp.send("\nMatch Found: " + `reg.group(0)` + "\n")
# end testCB
if __name__ == "__main__":
import sys, os
# Get current terminal settings
p = os.popen("stty -g")
savedterm = p.read()
p.close()
del p
# Set terminal to (near) raw mode
# It allows the terminal to handle RETURNs appropriately
## this works on my Solaris machine. YMMV
os.system("stty cs8 -icanon min 1 time 0 -isig -xcase -inpck")
exp = Expect(sys.stdin, sys.stdout)
# Create our Patterns
pats = []
pats.append( Pattern(regex.compile("[Pp]ython"), _testCB) )
pats.append( Pattern(regex.compile("s+tar"), _testCB) )
# This pattern uses the default Pattern callback
pats.append( Pattern(regex.compile("[Bb]ye")))
# Output a prompt of sorts
exp.send("\nYou have 20 seconds. Type 'Bye' or 'bye' to exit sooner.\n")
# Call expect()...
try:
matcher = exp.expect(pats, 20)
print "\nGood Bye"
except ExpectTimeout:
print "\nTime has expired"
except ExpectEOF:
print "\nInput closed"
os.system("stty "+ savedterm)
-------------- next part --------------
#!/usr/bin/env python
#
#####
# $Id: eventloop.py,v 1.4 1997/08/01 20:33:12 timo Exp $
#
#####
import select, time
class Event:
"""Event class
A base class for different Event types."""
def __init__(self, func=None, arg=None):
self.func = func
self.arg = arg
def __call__(self):
apply(self.func, self.arg)
# end class Event
class FileEvent(Event):
"""A File Event
We keep a reference to the file object. File objects have a tendency
to close when deleted, so this reference prevents the user from
accidentally closing the file without telling the EventLoop.
"""
def __init__(self, file, func, arg):
Event.__init__(self, func, arg)
self.file = file
self.fileno = file.fileno
return
# end __init__
# end class FileEvent
class TimerEvent(Event):
"""A Timer Event
The only interesting thing here is the need to generate a unique-id
for each timer.
"""
next_id = 1
last_id = 65535
in_use = []
def __init__(self, expire, func, arg):
Event.__init__(self, func, arg)
self.expire = expire
self.id = N = TimerEvent.next_id
# Update in_use array
TimerEvent.in_use.append(N)
# Make sure the next_id is unique
if N == TimerEvent.last_id:
N = 1
else:
N = N + 1
while N in TimerEvent.in_use:
N = N + 1
TimerEvent.next_id = N + 1
return
# end __init__
def __del__(self):
TimerEvent.in_use.remove(self.id)
# end __del__
# end class TimerEvent
LoopExit = "LoopExit"
class EventLoop:
"""EventLoop creates a select-based mainloop. Events may be
added as either timers, which 'fire' after a specified period,
or as fileobjects, which "trigger" when available for reading.
Once a timer fires, it is removed from the Eventloop. If you
want your timer to fire every N seconds, then you must call
AddTimer from your callback. (See example below.)
A fileobject can be any object with a 'fileno' method. A
file event must be explicitly removed via DeleteFile. In this
respect, FileEvents differ from TimerEvents.
"""
###
### Internally:
###
### We have one structure to keep file objects:
### __filelist == { fileno : file_object }
###
### We have one structure to keep timers:
### __timerlist == { expiretime : [timer ...] }
###
def __init__(self):
self.__filelist = {}
self.__timerlist = {}
return
# end __init__
def Cancel(self, val=None):
raise LoopExit, val
def MainLoop(self):
sf = self.__filelist
st = self.__timerlist
try:
# while-loop implements the mainloop
while 1:
delay = None # Indicates no timers
if st:
when = min( st.keys() ) # Next timer
now = time.time() # Current time
if now >= when:
self.FireTimers(when) # Fire any expired timers
continue
# else
delay = when - now # Delay until next timer
# Although undocumented,
# delay==None results in a blocking select() call.
r,w,e = select.select( sf.values(), [], [], delay)
# For-Loop handles any file activity
for File in r:
File()
# end while loop
except LoopExit, val:
return val
# should never reach here
return
# end MainLoop
def AddFile(self, obj, callback, *arg):
sf = self.__filelist
f_no = obj.fileno()
# if sf.has_key(f_no):
# raise ValueError, "FileNo already used!"
sf[f_no] = FileEvent(obj, callback, arg)
return
# end AddFile
def DeleteFile(self, obj):
sf = self.__filelist
f_no = obj.fileno()
del sf[f_no]
return
# end DeleteFile
def AddTimer(self, seconds, callback, *arg):
st = self.__timerlist
when = time.time() + seconds
tobj = TimerEvent(when, callback, arg)
if st.has_key(when):
st[when].append(tobj)
else:
st[when] = [tobj]
return tobj.id
# end AddTimer
def DeleteTimer(self, identifier):
st = self.__timerlist
for T in st.values():
for Timer in T:
if Timer.id == identifier:
when = Timer.expire
T.remove(Timer)
if st[when] == []: del st[when]
return
# We didn't find it
raise ValueError, "No timer with identifier" + `identifier`
# end DeleteTimer
def FireTimers(self, which):
st = self.__timerlist
TL = st[which]
del st[which]
for Timer in TL:
Timer()
return
# end FireTimer
# end class EventLoop
def _timertest(endtime):
global Ev
t_minus = endtime - time.time()
if t_minus <= 0:
print "Boom!!!"
Ev.Cancel()
print
print "You have", `int(t_minus) +1`, "seconds to comply."
print
Ev.AddTimer(10, _timertest, end)
# end _timertest
def _filetest(str, endtime):
global Ev
ans = sys.stdin.readline()
if ans[:-1] == str:
print "Hooray!"
Ev.Cancel()
print "Wrong! Try again."
# end _filetest
if __name__ == "__main__":
import sys
global Ev
phrase = "Python is my favorite language"
Ev = EventLoop()
print "Please type:"
print " ", phrase
end = time.time() + 30
Ev.AddFile(sys.stdin, _filetest, phrase, end )
Ev.AddTimer(0, _timertest, end)
Ev.MainLoop()
More information about the Pipet-Devel
mailing list