Volity

Python: module zymb.xmlagent
 
 
zymb.xmlagent
index
zymb/xmlagent.py

 
Modules
       
logging
zymb.sched
xml
zymb.xmldata

 
Classes
       
zymb.sched.Agent
XML
zymb.xmldata.NodeGenerator
ClientNodeGenerator

 
class ClientNodeGenerator(zymb.xmldata.NodeGenerator)
    ClientNodeGenerator: A NodeGenerator which parses a sequence of
incoming character data, and dispatches stanzas (children of the
top-level XML node) as they are completed.
 
ClientNodeGenerator(owner, encoding='UTF-8') -- constructor.
 
The *owner* is an XML Agent on which to trigger events as stanzas
arrive.
 
By default, *encoding* is UTF-8, and so the data that arrives must be
in that encoding. You can specify other encodings. If *encoding* is
None, the data should be unicode objects (or convertible to
unicode). In all cases, the stanzas that are generated will be
unencoded -- they will contain Unicode elements where appropriate.
 
Public method:
 
parse() -- accept data, and push it into the expat parser.
 
  Methods defined here:
__init__(self, owner, encoding='UTF-8')
handle_data(self, data)
handle_data() -- expat parser callback. Do not call.
 
This ignores character data in between stanzas. Some Jabber servers
send whitespace between stanzas to exercise the connection, and we
don't want that accumulating in the XML tree.
handle_endelement(self, name)
handle_endelement() -- expat parser callback. Do not call.
 
This watches for completion of a stanza (child of the top-level
node), and triggers an event. The stanza is removed from the
XML tree before dispatching, so that the tree doesn't grow forever.
 
This also watches for the completion of the top-level document,
at which time it shuts down.
handle_startelement(self, name, attrs)
handle_startelement() -- expat parser callback. Do not call.
 
This watches for the initial top-level <tag> of the document,
and jumps to the 'body' state.
parse(self, data)
parse(data) -> None
 
Accept data, and push it into the expat parser. The *data* may
be a str in some encoding, or a unicode, depending on the original
*encoding* specified at construction time.

Methods inherited from zymb.xmldata.NodeGenerator:
close(self)
close() -> None
 
Shut down the NodeGenerator. You don't have to do this, but it
gets rid of the object without relying on garbage collection.
handle_startnamespace(self, prefix, uri)
handle_startnamespace() -- expat parser callback. Do not call.

 
class XML(zymb.sched.Agent)
    XML: An Agent which takes data from another Agent and parses it
into XML stanzas. This only deals with input. It has no code to
generate or send XML.
 
The XML document is assumed to have the form
    <tag><stanza /><stanza />...</tag>
In other words, children of the top-level tag are considered to be
the basic units, and an event is triggered each time one completes.
Character data between stanzas is ignored.
 
XML(agent, encoding='UTF-8') -- constructor.
 
The *agent* must be of a type that generates 'handle' string events.
(For example, tcp.TCP.) If the agent stops, or if it generates
an XML closing tag, the XML agent will itself stop.
 
If the *agent* generates an 'error' event, the XML agent will repeat it.
 
By default, *encoding* is UTF-8, and so the data that arrives must be
in that encoding. You can specify other encodings. If *encoding* is
None, the data should be unicode objects (or convertible to
unicode). In all cases, the stanzas that are generated will be
unencoded -- they will contain Unicode elements where appropriate.
 
Agent states and events:
 
state 'start': Begin parsing XML.
state 'body' (tag, namespace, attrs): The XML opening tag has been
    received. The handler arguments are the opening tag name,
    the xmlns attribute (if present), and a dict containing all the
    tag attributes (including xmlns).
event 'stanza' (node): A stanza has been received. The argument
    is a Node object representing the stanza.
event 'error' (exc, agent): An error was detected while parsing the XML.
    This is immediately followed by a jump to 'end'.
state 'end': Stop parsing. (No error is generated if the XML structure
    is incomplete.)
    
Publicly readable fields:
 
docname -- the top-level tag name (once received)
docattrs -- the top-level tag attributes, as a dict (once received)
 
Public methods:
 
basicstanza(nod) -- a simple event handler for 'stanza'.
 
Internal methods:
 
setup() -- 'start' state handler.
handle() -- handler for incoming 'handle' events.
endparse() -- 'end' state handler.
 
  Methods defined here:
__init__(self, stream, encoding='UTF-8')
basicstanza(self, nod)
basicstanza(nod) -> None
 
A simple event handler for 'stanza'. This simply writes the
received data to stdout:
 
    sys.stdout.write(str(nod))
 
This handler is not installed by default. You can enable it by
calling:
 
    tcp.addhandler('stanza', tcp.basicstanza)
endparse(self)
endparse() -- internal 'end' state handler. Do not call.
 
Shut down and delete self.xmlparse.
handle(self, input)
handle(input) -- internal handler for 'handle' events generated
by self.stream. Do not call.
 
Push the data into self.xmlparse. This will trigger 'stanza' events
for each XML stanza which is completed.
setup(self)
setup() -- internal 'start' state handler. Do not call.
 
Create the NodeBuilder parser object and initialize it.

Data and other attributes defined here:
logprefix = 'zymb.xml'

Methods inherited from zymb.sched.Agent:
__str__(self)
addcleanupaction(self, ac)
addcleanupaction(action) -> None
 
Add *action* to the list of actions to be removed when the agent
stops (i.e., jumps to the 'end' state).
 
This is intended for actions that an agent adds as handlers to
other agents. For example:
 
    ac = otheragent.addhandler('event', self.foreigneventhandler)
    # Ensure that ac is removed when *self* shuts down.
    addcleanupaction(ac)
 
You do not need to list pollers or socket-checkers as cleanup
actions. Nor do you need to list handlers that an agent adds
to itself. (All these are automatically removed when the agent
shuts down.) You also don't have to worry about the case of
*otheragent* shutting down; when that happens, all handlers added
to it are removed.
addhandler(self, state, op, *args)
addhandler(eventname, op, *args) -> action
 
Add a state or event handler. The *eventname* is a string naming
the state or event you want to handle. The *op* and *args* are
the operation to perform when that state or event occurs.
(See queueaction() for the use of *op* and *args*.)
 
Handlers are invoked in last-added-first-run order. If an agent
has a built-in handler, it is added first, so it runs last. Handlers
that you add on later run earlier.
 
Returns the Action. (You can cancel the handler by calling
ac.remove().)
addtimer(self, op, *args, **dic)
addtimer(op, *args, delay=num, when=num, periodic=bool) -> action
 
Add a timed event. You must supply exactly one of the keyword
arguments *delay* and *when*. A *when* is an absolute time,
expressed as a number of seconds since the epoch (e.g., the kind
of value returned by time.time()). A *delay* is a relative time,
expressed as a number of seconds in the future.
 
It is legal to give a time in the past (or a negative *delay*).
In that case, this is similar to queueaction() -- the operation
will occur very soon. (Although it's still a "low priority"
action.)
 
If you supply *periodic*=True, the event will occur repeatedly,
every *delay* seconds. (The interval is inferred if you give
*when*.) In this case, you may NOT give a negative *delay* or
a time in the past -- it is meaningless for a periodic event to
have a period less than or equal to zero.
 
You can also create a periodic timer by calling addtimer with
a PeriodicAction, which is a subclass of Action. This is slightly
more flexible; the interval between calls is specified when
you create the PeriodicAction, but the delay before the first
call may be specified with *delay* or *when*.
 
See queueaction() for the use of *op* and *args*.
 
Returns the Action. (You can cancel the timer by calling
ac.remove().)
basicerror(self, exc, agent)
basicerror(exc, agent) -> None
 
        A simple event handler for 'error'. This simply writes the
        received data to stdout:
        
            sys.stdout.write('Error: ' + str(agent) + ': ' + str(exc) + '
')
 
        This handler is not installed by default. You can enable it by
        calling:
        
            ag.addhandler('error', ag.basicerror)
jump(self, st, *exargs)
jump(state, *args) -> None
 
Jump to a different operating state. (If the agent is already
in the given state, nothing happens.)
 
This queues up all the state transition handlers registered
for the new state. If you provide *args*, they are passed to the
handlers when they are called.
perform(self, name, *exargs)
perform(eventname, *args) -> None
 
Trigger an event.
 
This queues up all the event handlers registered for the given
event. If you provide *args*, they are passed to the handlers when
they are called.
queueaction(self, op, *args)
queueaction(op, *args) -> action
 
Invoke an action. The action will be handed to the scheduler, which
will run it very soon.
 
("Very soon" means "before the next timed event or network message
is handled." However, if you queue several actions, they will be
handled in the order you queued them.)
 
You can pass any callable as *op*; the (optional) *args* will be
passed to it as arguments. You can also, if you like, create
an Action object and pass it as *op*. You can still pass *args*
in this case; they'll be appended to the arguments bound into
the Action.
 
Returns the Action.
registerpoll(self, op, *args, **dic)
registerpoll(op, *args, interval=num) -> action
 
Add a repeating activity check. *interval* is a (mandatory) keyword
argument; the scheduler will invoke your operation at least every
*interval* seconds. (And at least once per sched.process() call.)
 
See queueaction() for the use of *op* and *args*. Your operation
should not do any work except for absorbing input and queueing
actions. Typically, it will collect the input and then call
perform(), triggering an event, so that the agent's event
handlers can do something with the input.
 
Returns the Action. (You can cancel it by calling ac.remove().)
registersocket(self, fileno, op, *args)
registersocket(socket, op, *args) -> action
 
Add a socket-based activity check. The *socket* may be a socket
object, or a number representing a fileno, or any object which
provides a fileno() method. 
 
See queueaction() for the use of *op* and *args*. Your operation
should not do any work except for absorbing input and queueing
actions. Typically, it will collect the input and then call
perform(), triggering an event, so that the agent's event
handlers can do something with the input.
 
Returns the Action. (You can cancel it by calling ac.remove().)
shutdown(self)
shutdown() -- internal 'end' state handler. Do not call.
 
This is the final 'end' handler. It removes the agent from the
scheduler, and cancels all its remaining actions, timed events,
etc.
start(self)
start() -> None
 
Begin activity. The agent adds itself to the scheduler and moves
to the 'start' state. It does not actually begin doing work in
this call; that happens the next time the scheduler is invoked
(sched.process).
 
You should only call this once per agent.
stop(self)
stop() -> None
 
Stop activity. The agent moves to the 'end' state. Its 'end'
state handlers will take care of shutting it down and removing
it from the scheduler.
 
It is safe to call this on an agent which is already in 'end',
or which is completely shut down. (Nothing further will happen.)
 
(Remember, state handlers are not called as part of the stop()
method. They are run by the scheduler "soon" after stop() is
called. If you want to be sure the agent is completely stopped,
you can check the agent.live field. However, it is better to
register your own 'end' state handler, and consider the agent
stopped when that it called.)

Data and other attributes inherited from zymb.sched.Agent:
agentcounter = 1
hidden = False