One more portion of doc-string and formatting refactoring
This commit is contained in:
parent
6d0f28c47d
commit
f084a1f78b
|
@ -476,7 +476,7 @@ class Protocol(Node):
|
|||
self.setTo(self['to'])
|
||||
if self['from']:
|
||||
self.setFrom(self['from'])
|
||||
if node and type(self )== type(node) and self.__class__ == node.__class__ and self.attrs.has_key('id'):
|
||||
if node and type(self) == type(node) and self.__class__ == node.__class__ and self.attrs.has_key('id'):
|
||||
del self.attrs['id']
|
||||
self.timestamp = None
|
||||
for d in self.getTags('delay', namespace=NS_DELAY2):
|
||||
|
|
|
@ -14,27 +14,30 @@
|
|||
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
'''
|
||||
Module containing classes for proxy connecting. So far its HTTP CONNECT
|
||||
and SOCKS5 proxy.
|
||||
|
||||
"""
|
||||
Module containing classes for proxy connecting. So far its HTTP CONNECT and
|
||||
SOCKS5 proxy
|
||||
|
||||
Authentication to NTLM (Microsoft implementation) proxies can be next.
|
||||
'''
|
||||
"""
|
||||
|
||||
import struct, socket, base64
|
||||
import logging
|
||||
log = logging.getLogger('gajim.c.x.proxy_connectors')
|
||||
|
||||
class ProxyConnector:
|
||||
'''
|
||||
"""
|
||||
Interface for proxy-connecting object - when tunnneling XMPP over proxies,
|
||||
some connecting process usually has to be done before opening stream.
|
||||
Proxy connectors are used right after TCP connection is estabilished.
|
||||
'''
|
||||
some connecting process usually has to be done before opening stream. Proxy
|
||||
connectors are used right after TCP connection is estabilished
|
||||
"""
|
||||
|
||||
def __init__(self, send_method, onreceive, old_on_receive, on_success,
|
||||
on_failure, xmpp_server, proxy_creds=(None,None)):
|
||||
'''
|
||||
on_failure, xmpp_server, proxy_creds=(None,None)):
|
||||
"""
|
||||
Creates proxy connector, starts connecting immediately and gives control
|
||||
back to transport afterwards.
|
||||
back to transport afterwards
|
||||
|
||||
:param send_method: transport send method
|
||||
:param onreceive: method to set on_receive callbacks
|
||||
|
@ -44,7 +47,7 @@ class ProxyConnector:
|
|||
:param on_failure: called when errors occured while connecting
|
||||
:param xmpp_server: tuple of (hostname, port)
|
||||
:param proxy_creds: tuple of (proxy_user, proxy_credentials)
|
||||
'''
|
||||
"""
|
||||
self.send = send_method
|
||||
self.onreceive = onreceive
|
||||
self.old_on_receive = old_on_receive
|
||||
|
@ -58,12 +61,12 @@ class ProxyConnector:
|
|||
|
||||
@classmethod
|
||||
def get_instance(cls, *args, **kwargs):
|
||||
'''
|
||||
Factory Method for object creation.
|
||||
"""
|
||||
Factory Method for object creation
|
||||
|
||||
Use this instead of directly initializing the class in order to make
|
||||
unit testing much easier.
|
||||
'''
|
||||
Use this instead of directly initializing the class in order to make unit
|
||||
testing much easier.
|
||||
"""
|
||||
return cls(*args, **kwargs)
|
||||
|
||||
def start_connecting(self):
|
||||
|
@ -75,11 +78,11 @@ class ProxyConnector:
|
|||
|
||||
class HTTPCONNECTConnector(ProxyConnector):
|
||||
def start_connecting(self):
|
||||
'''
|
||||
Connects to proxy, supplies login and password to it
|
||||
(if were specified while creating instance). Instructs proxy to make
|
||||
connection to the target server.
|
||||
'''
|
||||
"""
|
||||
Connect to a proxy, supply login and password to it (if were specified
|
||||
while creating instance). Instruct proxy to make connection to the target
|
||||
server.
|
||||
"""
|
||||
log.info('Proxy server contacted, performing authentification')
|
||||
connector = ['CONNECT %s:%s HTTP/1.1' % self.xmpp_server,
|
||||
'Proxy-Connection: Keep-Alive',
|
||||
|
@ -115,10 +118,11 @@ class HTTPCONNECTConnector(ProxyConnector):
|
|||
|
||||
|
||||
class SOCKS5Connector(ProxyConnector):
|
||||
'''
|
||||
"""
|
||||
SOCKS5 proxy connection class. Allows to use SOCKS5 proxies with
|
||||
(optionally) simple authentication (only USERNAME/PASSWORD auth).
|
||||
'''
|
||||
(optionally) simple authentication (only USERNAME/PASSWORD auth)
|
||||
"""
|
||||
|
||||
def start_connecting(self):
|
||||
log.info('Proxy server contacted, performing authentification')
|
||||
if self.proxy_user and self.proxy_pass:
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
|
||||
# $Id: roster.py,v 1.17 2005/05/02 08:38:49 snakeru Exp $
|
||||
|
||||
'''
|
||||
|
||||
"""
|
||||
Simple roster implementation. Can be used though for different tasks like
|
||||
mass-renaming of contacts.
|
||||
'''
|
||||
"""
|
||||
|
||||
from protocol import JID, Iq, Presence, Node, NodeProcessed, NS_MUC_USER, NS_ROSTER
|
||||
from plugin import PlugIn
|
||||
|
@ -29,15 +30,18 @@ log = logging.getLogger('gajim.c.x.roster_nb')
|
|||
|
||||
|
||||
class NonBlockingRoster(PlugIn):
|
||||
''' Defines a plenty of methods that will allow you to manage roster.
|
||||
Also automatically track presences from remote JIDs taking into
|
||||
account that every JID can have multiple resources connected. Does not
|
||||
currently support 'error' presences.
|
||||
You can also use mapping interface for access to the internal representation of
|
||||
contacts in roster.
|
||||
'''
|
||||
"""
|
||||
Defines a plenty of methods that will allow you to manage roster. Also
|
||||
automatically track presences from remote JIDs taking into account that
|
||||
every JID can have multiple resources connected. Does not currently support
|
||||
'error' presences. You can also use mapping interface for access to the
|
||||
internal representation of contacts in roster
|
||||
"""
|
||||
|
||||
def __init__(self, version=''):
|
||||
''' Init internal variables. '''
|
||||
"""
|
||||
Init internal variables
|
||||
"""
|
||||
PlugIn.__init__(self)
|
||||
self.version = version
|
||||
self._data = {}
|
||||
|
@ -45,11 +49,15 @@ class NonBlockingRoster(PlugIn):
|
|||
self._exported_methods=[self.getRoster]
|
||||
self.received_from_server = False
|
||||
|
||||
def Request(self,force=0):
|
||||
''' Request roster from server if it were not yet requested
|
||||
(or if the 'force' argument is set). '''
|
||||
if self.set is None: self.set=0
|
||||
elif not force: return
|
||||
def Request(self, force=0):
|
||||
"""
|
||||
Request roster from server if it were not yet requested (or if the
|
||||
'force' argument is set)
|
||||
"""
|
||||
if self.set is None:
|
||||
self.set = 0
|
||||
elif not force:
|
||||
return
|
||||
|
||||
iq = Iq('get',NS_ROSTER)
|
||||
iq.setTagAttr('query', 'ver', self.version)
|
||||
|
@ -59,9 +67,11 @@ class NonBlockingRoster(PlugIn):
|
|||
log.info('Roster requested from server')
|
||||
return id_
|
||||
|
||||
def RosterIqHandler(self,dis,stanza):
|
||||
''' Subscription tracker. Used internally for setting items state in
|
||||
internal roster representation. '''
|
||||
def RosterIqHandler(self, dis, stanza):
|
||||
"""
|
||||
Subscription tracker. Used internally for setting items state in internal
|
||||
roster representation
|
||||
"""
|
||||
sender = stanza.getAttr('from')
|
||||
if not sender is None and not sender.bareMatch(
|
||||
self._owner.User + '@' + self._owner.Server):
|
||||
|
@ -91,9 +101,11 @@ class NonBlockingRoster(PlugIn):
|
|||
# Looks like we have a workaround
|
||||
# raise NodeProcessed # a MUST. Otherwise you'll get back an <iq type='error'/>
|
||||
|
||||
def PresenceHandler(self,dis,pres):
|
||||
''' Presence tracker. Used internally for setting items' resources state in
|
||||
internal roster representation. '''
|
||||
def PresenceHandler(self, dis, pres):
|
||||
"""
|
||||
Presence tracker. Used internally for setting items' resources state in
|
||||
internal roster representation
|
||||
"""
|
||||
if pres.getTag('x', namespace=NS_MUC_USER):
|
||||
return
|
||||
jid=pres.getFrom()
|
||||
|
@ -118,112 +130,204 @@ class NonBlockingRoster(PlugIn):
|
|||
elif typ=='unavailable' and item['resources'].has_key(jid.getResource()): del item['resources'][jid.getResource()]
|
||||
# Need to handle type='error' also
|
||||
|
||||
def _getItemData(self,jid,dataname):
|
||||
''' Return specific jid's representation in internal format. Used internally. '''
|
||||
jid=jid[:(jid+'/').find('/')]
|
||||
def _getItemData(self, jid, dataname):
|
||||
"""
|
||||
Return specific jid's representation in internal format. Used internally
|
||||
"""
|
||||
jid = jid[:(jid+'/').find('/')]
|
||||
return self._data[jid][dataname]
|
||||
def _getResourceData(self,jid,dataname):
|
||||
''' Return specific jid's resource representation in internal format. Used internally. '''
|
||||
if jid.find('/')+1:
|
||||
jid,resource=jid.split('/',1)
|
||||
if self._data[jid]['resources'].has_key(resource): return self._data[jid]['resources'][resource][dataname]
|
||||
elif self._data[jid]['resources'].keys():
|
||||
lastpri=-129
|
||||
for r in self._data[jid]['resources'].keys():
|
||||
if int(self._data[jid]['resources'][r]['priority'])>lastpri: resource,lastpri=r,int(self._data[jid]['resources'][r]['priority'])
|
||||
return self._data[jid]['resources'][resource][dataname]
|
||||
def delItem(self,jid):
|
||||
''' Delete contact 'jid' from roster.'''
|
||||
self._owner.send(Iq('set',NS_ROSTER,payload=[Node('item',{'jid':jid,'subscription':'remove'})]))
|
||||
def getAsk(self,jid):
|
||||
''' Returns 'ask' value of contact 'jid'.'''
|
||||
return self._getItemData(jid,'ask')
|
||||
def getGroups(self,jid):
|
||||
''' Returns groups list that contact 'jid' belongs to.'''
|
||||
return self._getItemData(jid,'groups')
|
||||
def getName(self,jid):
|
||||
''' Returns name of contact 'jid'.'''
|
||||
return self._getItemData(jid,'name')
|
||||
def getPriority(self,jid):
|
||||
''' Returns priority of contact 'jid'. 'jid' should be a full (not bare) JID.'''
|
||||
return self._getResourceData(jid,'priority')
|
||||
def getRawRoster(self):
|
||||
''' Returns roster representation in internal format. '''
|
||||
return self._data
|
||||
def getRawItem(self,jid):
|
||||
''' Returns roster item 'jid' representation in internal format. '''
|
||||
return self._data[jid[:(jid+'/').find('/')]]
|
||||
def getShow(self, jid):
|
||||
''' Returns 'show' value of contact 'jid'. 'jid' should be a full (not bare) JID.'''
|
||||
return self._getResourceData(jid,'show')
|
||||
def getStatus(self, jid):
|
||||
''' Returns 'status' value of contact 'jid'. 'jid' should be a full (not bare) JID.'''
|
||||
return self._getResourceData(jid,'status')
|
||||
def getSubscription(self,jid):
|
||||
''' Returns 'subscription' value of contact 'jid'.'''
|
||||
return self._getItemData(jid,'subscription')
|
||||
def getResources(self,jid):
|
||||
''' Returns list of connected resources of contact 'jid'.'''
|
||||
return self._data[jid[:(jid+'/').find('/')]]['resources'].keys()
|
||||
def setItem(self,jid,name=None,groups=[]):
|
||||
''' Renames contact 'jid' and sets the groups list that it now belongs to.'''
|
||||
iq=Iq('set',NS_ROSTER)
|
||||
query=iq.getTag('query')
|
||||
attrs={'jid':jid}
|
||||
if name: attrs['name']=name
|
||||
item=query.setTag('item',attrs)
|
||||
for group in groups: item.addChild(node=Node('group',payload=[group]))
|
||||
self._owner.send(iq)
|
||||
def setItemMulti(self,items):
|
||||
''' Renames multiple contacts and sets their group lists.'''
|
||||
iq=Iq('set',NS_ROSTER)
|
||||
query=iq.getTag('query')
|
||||
for i in items:
|
||||
attrs={'jid':i['jid']}
|
||||
if i['name']: attrs['name']=i['name']
|
||||
item=query.setTag('item',attrs)
|
||||
for group in i['groups']: item.addChild(node=Node('group',payload=[group]))
|
||||
self._owner.send(iq)
|
||||
def getItems(self):
|
||||
''' Return list of all [bare] JIDs that the roster is currently tracks.'''
|
||||
return self._data.keys()
|
||||
def keys(self):
|
||||
''' Same as getItems. Provided for the sake of dictionary interface.'''
|
||||
return self._data.keys()
|
||||
def __getitem__(self,item):
|
||||
''' Get the contact in the internal format. Raises KeyError if JID 'item' is not in roster.'''
|
||||
return self._data[item]
|
||||
def getItem(self,item):
|
||||
''' Get the contact in the internal format (or None if JID 'item' is not in roster).'''
|
||||
if self._data.has_key(item): return self._data[item]
|
||||
def Subscribe(self,jid):
|
||||
''' Send subscription request to JID 'jid'.'''
|
||||
self._owner.send(Presence(jid,'subscribe'))
|
||||
def Unsubscribe(self,jid):
|
||||
''' Ask for removing our subscription for JID 'jid'.'''
|
||||
self._owner.send(Presence(jid,'unsubscribe'))
|
||||
def Authorize(self,jid):
|
||||
''' Authorise JID 'jid'. Works only if these JID requested auth previously. '''
|
||||
self._owner.send(Presence(jid,'subscribed'))
|
||||
def Unauthorize(self,jid):
|
||||
''' Unauthorise JID 'jid'. Use for declining authorisation request
|
||||
or for removing existing authorization. '''
|
||||
self._owner.send(Presence(jid,'unsubscribed'))
|
||||
def getRaw(self):
|
||||
'''Returns the internal data representation of the roster.'''
|
||||
return self._data
|
||||
def setRaw(self, data):
|
||||
'''Returns the internal data representation of the roster.'''
|
||||
self._data = data
|
||||
self._data[self._owner.User+'@'+self._owner.Server]={'resources':{},'name':None,'ask':None,'subscription':None,'groups':None,}
|
||||
self.set=1
|
||||
# copypasted methods for roster.py from constructor to here
|
||||
|
||||
def _getResourceData(self, jid, dataname):
|
||||
"""
|
||||
Return specific jid's resource representation in internal format. Used
|
||||
internally
|
||||
"""
|
||||
if jid.find('/') + 1:
|
||||
jid, resource = jid.split('/', 1)
|
||||
if self._data[jid]['resources'].has_key(resource):
|
||||
return self._data[jid]['resources'][resource][dataname]
|
||||
elif self._data[jid]['resources'].keys():
|
||||
lastpri = -129
|
||||
for r in self._data[jid]['resources'].keys():
|
||||
if int(self._data[jid]['resources'][r]['priority']) > lastpri:
|
||||
resource,lastpri=r,int(self._data[jid]['resources'][r]['priority'])
|
||||
return self._data[jid]['resources'][resource][dataname]
|
||||
|
||||
def delItem(self, jid):
|
||||
"""
|
||||
Delete contact 'jid' from roster
|
||||
"""
|
||||
self._owner.send(Iq('set', NS_ROSTER, payload=[Node('item', {'jid': jid, 'subscription': 'remove'})]))
|
||||
|
||||
def getAsk(self, jid):
|
||||
"""
|
||||
Return 'ask' value of contact 'jid'
|
||||
"""
|
||||
return self._getItemData(jid, 'ask')
|
||||
|
||||
def getGroups(self, jid):
|
||||
"""
|
||||
Return groups list that contact 'jid' belongs to
|
||||
"""
|
||||
return self._getItemData(jid, 'groups')
|
||||
|
||||
def getName(self, jid):
|
||||
"""
|
||||
Return name of contact 'jid'
|
||||
"""
|
||||
return self._getItemData(jid, 'name')
|
||||
|
||||
def getPriority(self, jid):
|
||||
"""
|
||||
Return priority of contact 'jid'. 'jid' should be a full (not bare) JID
|
||||
"""
|
||||
return self._getResourceData(jid, 'priority')
|
||||
|
||||
def getRawRoster(self):
|
||||
"""
|
||||
Return roster representation in internal format
|
||||
"""
|
||||
return self._data
|
||||
|
||||
def getRawItem(self, jid):
|
||||
"""
|
||||
Return roster item 'jid' representation in internal format
|
||||
"""
|
||||
return self._data[jid[:(jid+'/').find('/')]]
|
||||
|
||||
def getShow(self, jid):
|
||||
"""
|
||||
Return 'show' value of contact 'jid'. 'jid' should be a full (not bare)
|
||||
JID
|
||||
"""
|
||||
return self._getResourceData(jid, 'show')
|
||||
|
||||
def getStatus(self, jid):
|
||||
"""
|
||||
Return 'status' value of contact 'jid'. 'jid' should be a full (not bare)
|
||||
JID
|
||||
"""
|
||||
return self._getResourceData(jid, 'status')
|
||||
|
||||
def getSubscription(self, jid):
|
||||
"""
|
||||
Return 'subscription' value of contact 'jid'
|
||||
"""
|
||||
return self._getItemData(jid, 'subscription')
|
||||
|
||||
def getResources(self, jid):
|
||||
"""
|
||||
Return list of connected resources of contact 'jid'
|
||||
"""
|
||||
return self._data[jid[:(jid+'/').find('/')]]['resources'].keys()
|
||||
|
||||
def setItem(self, jid, name=None, groups=[]):
|
||||
"""
|
||||
Rename contact 'jid' and sets the groups list that it now belongs to
|
||||
"""
|
||||
iq = Iq('set',NS_ROSTER)
|
||||
query = iq.getTag('query')
|
||||
attrs = {'jid': jid}
|
||||
if name:
|
||||
attrs['name'] = name
|
||||
item = query.setTag('item' ,attrs)
|
||||
for group in groups:
|
||||
item.addChild(node=Node('group', payload=[group]))
|
||||
self._owner.send(iq)
|
||||
|
||||
def setItemMulti(self, items):
|
||||
"""
|
||||
Rename multiple contacts and sets their group lists
|
||||
"""
|
||||
iq = Iq('set', NS_ROSTER)
|
||||
query = iq.getTag('query')
|
||||
for i in items:
|
||||
attrs = {'jid': i['jid']}
|
||||
if i['name']:
|
||||
attrs['name'] = i['name']
|
||||
item = query.setTag('item', attrs)
|
||||
for group in i['groups']:
|
||||
item.addChild(node=Node('group', payload=[group]))
|
||||
self._owner.send(iq)
|
||||
|
||||
def getItems(self):
|
||||
"""
|
||||
Return list of all [bare] JIDs that the roster is currently tracks
|
||||
"""
|
||||
return self._data.keys()
|
||||
|
||||
def keys(self):
|
||||
"""
|
||||
Same as getItems. Provided for the sake of dictionary interface
|
||||
"""
|
||||
return self._data.keys()
|
||||
|
||||
def __getitem__(self, item):
|
||||
"""
|
||||
Get the contact in the internal format. Raises KeyError if JID 'item' is
|
||||
not in roster
|
||||
"""
|
||||
return self._data[item]
|
||||
|
||||
def getItem(self,item):
|
||||
"""
|
||||
Get the contact in the internal format (or None if JID 'item' is not in
|
||||
roster)
|
||||
"""
|
||||
if self._data.has_key(item):
|
||||
return self._data[item]
|
||||
|
||||
def Subscribe(self, jid):
|
||||
"""
|
||||
Send subscription request to JID 'jid'
|
||||
"""
|
||||
self._owner.send(Presence(jid, 'subscribe'))
|
||||
|
||||
def Unsubscribe(self,jid):
|
||||
"""
|
||||
Ask for removing our subscription for JID 'jid'
|
||||
"""
|
||||
self._owner.send(Presence(jid, 'unsubscribe'))
|
||||
|
||||
def Authorize(self, jid):
|
||||
"""
|
||||
Authorize JID 'jid'. Works only if these JID requested auth previously
|
||||
"""
|
||||
self._owner.send(Presence(jid, 'subscribed'))
|
||||
|
||||
def Unauthorize(self, jid):
|
||||
"""
|
||||
Unauthorise JID 'jid'. Use for declining authorisation request or for
|
||||
removing existing authorization
|
||||
"""
|
||||
self._owner.send(Presence(jid, 'unsubscribed'))
|
||||
|
||||
def getRaw(self):
|
||||
"""
|
||||
Return the internal data representation of the roster
|
||||
"""
|
||||
return self._data
|
||||
|
||||
def setRaw(self, data):
|
||||
"""
|
||||
Return the internal data representation of the roster
|
||||
"""
|
||||
self._data = data
|
||||
self._data[self._owner.User + '@' + self._owner.Server] = {
|
||||
'resources': {},
|
||||
'name': None,
|
||||
'ask': None,
|
||||
'subscription': None,
|
||||
'groups': None
|
||||
}
|
||||
self.set = 1
|
||||
|
||||
def plugin(self, owner, request=1):
|
||||
''' Register presence and subscription trackers in the owner's dispatcher.
|
||||
Also request roster from server if the 'request' argument is set.
|
||||
Used internally.'''
|
||||
"""
|
||||
Register presence and subscription trackers in the owner's dispatcher.
|
||||
Also request roster from server if the 'request' argument is set. Used
|
||||
internally
|
||||
"""
|
||||
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'result', NS_ROSTER, makefirst = 1)
|
||||
self._owner.RegisterHandler('iq', self.RosterIqHandler, 'set', NS_ROSTER)
|
||||
self._owner.RegisterHandler('presence', self.PresenceHandler)
|
||||
|
@ -242,7 +346,9 @@ class NonBlockingRoster(PlugIn):
|
|||
return True
|
||||
|
||||
def getRoster(self, on_ready=None, force=False):
|
||||
''' Requests roster from server if neccessary and returns self. '''
|
||||
"""
|
||||
Request roster from server if neccessary and returns self
|
||||
"""
|
||||
return_self = True
|
||||
if not self.set:
|
||||
self.on_ready = on_ready
|
||||
|
|
|
@ -14,64 +14,96 @@
|
|||
|
||||
# $Id: simplexml.py,v 1.27 2005/04/30 07:20:27 snakeru Exp $
|
||||
|
||||
'''Simplexml module provides xmpppy library with all needed tools to handle XML nodes and XML streams.
|
||||
I'm personally using it in many other separate projects. It is designed to be as standalone as possible.'''
|
||||
"""
|
||||
Simplexml module provides xmpppy library with all needed tools to handle XML
|
||||
nodes and XML streams. I'm personally using it in many other separate
|
||||
projects. It is designed to be as standalone as possible
|
||||
"""
|
||||
|
||||
import xml.parsers.expat
|
||||
import logging
|
||||
log = logging.getLogger('gajim.c.x.simplexml')
|
||||
|
||||
def XMLescape(txt):
|
||||
'''Returns provided string with symbols & < > " replaced by their respective XML entities.'''
|
||||
"""
|
||||
Return provided string with symbols & < > " replaced by their respective XML
|
||||
entities
|
||||
"""
|
||||
# replace also FORM FEED and ESC, because they are not valid XML chars
|
||||
return txt.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """).replace(u'\x0C', "").replace(u'\x1B', "")
|
||||
|
||||
ENCODING='utf-8'
|
||||
|
||||
def ustr(what):
|
||||
'''Converts object "what" to unicode string using it's own __str__ method if accessible or unicode method otherwise.'''
|
||||
if isinstance(what, unicode): return what
|
||||
try: r=what.__str__()
|
||||
except AttributeError: r=str(what)
|
||||
if not isinstance(r, unicode): return unicode(r,ENCODING)
|
||||
"""
|
||||
Converts object "what" to unicode string using it's own __str__ method if
|
||||
accessible or unicode method otherwise
|
||||
"""
|
||||
if isinstance(what, unicode):
|
||||
return what
|
||||
try:
|
||||
r = what.__str__()
|
||||
except AttributeError:
|
||||
r = str(what)
|
||||
if not isinstance(r, unicode):
|
||||
return unicode(r, ENCODING)
|
||||
return r
|
||||
|
||||
class Node(object):
|
||||
''' Node class describes syntax of separate XML Node. It have a constructor that permits node creation
|
||||
from set of "namespace name", attributes and payload of text strings and other nodes.
|
||||
It does not natively support building node from text string and uses NodeBuilder class for that purpose.
|
||||
After creation node can be mangled in many ways so it can be completely changed.
|
||||
Also node can be serialised into string in one of two modes: default (where the textual representation
|
||||
of node describes it exactly) and "fancy" - with whitespace added to make indentation and thus make
|
||||
result more readable by human.
|
||||
"""
|
||||
Node class describes syntax of separate XML Node. It have a constructor that
|
||||
permits node creation from set of "namespace name", attributes and payload
|
||||
of text strings and other nodes. It does not natively support building node
|
||||
from text string and uses NodeBuilder class for that purpose. After
|
||||
creation node can be mangled in many ways so it can be completely changed.
|
||||
Also node can be serialised into string in one of two modes: default (where
|
||||
the textual representation of node describes it exactly) and "fancy" - with
|
||||
whitespace added to make indentation and thus make result more readable by
|
||||
human.
|
||||
|
||||
Node class have attribute FORCE_NODE_RECREATION that is defaults to False thus enabling fast node
|
||||
replication from the some other node. The drawback of the fast way is that new node shares some
|
||||
info with the "original" node that is changing the one node may influence the other. Though it is
|
||||
rarely needed (in xmpppy it is never needed at all since I'm usually never using original node after
|
||||
replication (and using replication only to move upwards on the classes tree).
|
||||
'''
|
||||
FORCE_NODE_RECREATION=0
|
||||
def __init__(self, tag=None, attrs={}, payload=[], parent=None, nsp=None, node_built=False, node=None):
|
||||
''' Takes "tag" argument as the name of node (prepended by namespace, if needed and separated from it
|
||||
by a space), attrs dictionary as the set of arguments, payload list as the set of textual strings
|
||||
and child nodes that this node carries within itself and "parent" argument that is another node
|
||||
that this one will be the child of. Also the __init__ can be provided with "node" argument that is
|
||||
either a text string containing exactly one node or another Node instance to begin with. If both
|
||||
"node" and other arguments is provided then the node initially created as replica of "node"
|
||||
provided and then modified to be compliant with other arguments.'''
|
||||
Node class have attribute FORCE_NODE_RECREATION that is defaults to False
|
||||
thus enabling fast node replication from the some other node. The drawback
|
||||
of the fast way is that new node shares some info with the "original" node
|
||||
that is changing the one node may influence the other. Though it is rarely
|
||||
needed (in xmpppy it is never needed at all since I'm usually never using
|
||||
original node after replication (and using replication only to move upwards
|
||||
on the classes tree).
|
||||
"""
|
||||
|
||||
FORCE_NODE_RECREATION = 0
|
||||
|
||||
def __init__(self, tag=None, attrs={}, payload=[], parent=None, nsp=None,
|
||||
node_built=False, node=None):
|
||||
"""
|
||||
Takes "tag" argument as the name of node (prepended by namespace, if
|
||||
needed and separated from it by a space), attrs dictionary as the set of
|
||||
arguments, payload list as the set of textual strings and child nodes
|
||||
that this node carries within itself and "parent" argument that is
|
||||
another node that this one will be the child of. Also the __init__ can be
|
||||
provided with "node" argument that is either a text string containing
|
||||
exactly one node or another Node instance to begin with. If both "node"
|
||||
and other arguments is provided then the node initially created as
|
||||
replica of "node" provided and then modified to be compliant with other
|
||||
arguments.
|
||||
"""
|
||||
if node:
|
||||
if self.FORCE_NODE_RECREATION and isinstance(node, Node):
|
||||
node=str(node)
|
||||
node = str(node)
|
||||
if not isinstance(node, Node):
|
||||
node=NodeBuilder(node,self)
|
||||
node = NodeBuilder(node,self)
|
||||
node_built = True
|
||||
else:
|
||||
self.name,self.namespace,self.attrs,self.data,self.kids,self.parent,self.nsd = node.name,node.namespace,{},[],[],node.parent,{}
|
||||
for key in node.attrs.keys(): self.attrs[key]=node.attrs[key]
|
||||
for data in node.data: self.data.append(data)
|
||||
for kid in node.kids: self.kids.append(kid)
|
||||
for k,v in node.nsd.items(): self.nsd[k] = v
|
||||
else: self.name,self.namespace,self.attrs,self.data,self.kids,self.parent,self.nsd = 'tag','',{},[],[],None,{}
|
||||
self.name, self.namespace, self.attrs, self.data, self.kids, self.parent, self.nsd = node.name, node.namespace, {}, [], [], node.parent, {}
|
||||
for key in node.attrs.keys():
|
||||
self.attrs[key] = node.attrs[key]
|
||||
for data in node.data:
|
||||
self.data.append(data)
|
||||
for kid in node.kids:
|
||||
self.kids.append(kid)
|
||||
for k,v in node.nsd.items():
|
||||
self.nsd[k] = v
|
||||
else:
|
||||
self.name, self.namespace, self.attrs, self.data, self.kids, self.parent, self.nsd = 'tag', '', {}, [], [], None, {}
|
||||
if parent:
|
||||
self.parent = parent
|
||||
self.nsp_cache = {}
|
||||
|
@ -94,10 +126,12 @@ class Node(object):
|
|||
self.name = tag
|
||||
if isinstance(payload, basestring): payload=[payload]
|
||||
for i in payload:
|
||||
if isinstance(i, Node): self.addChild(node=i)
|
||||
else: self.data.append(ustr(i))
|
||||
if isinstance(i, Node):
|
||||
self.addChild(node=i)
|
||||
else:
|
||||
self.data.append(ustr(i))
|
||||
|
||||
def lookup_nsp(self,pfx=''):
|
||||
def lookup_nsp(self, pfx=''):
|
||||
ns = self.nsd.get(pfx,None)
|
||||
if ns is None:
|
||||
ns = self.nsp_cache.get(pfx,None)
|
||||
|
@ -109,9 +143,11 @@ class Node(object):
|
|||
return 'http://www.gajim.org/xmlns/undeclared'
|
||||
return ns
|
||||
|
||||
def __str__(self,fancy=0):
|
||||
''' Method used to dump node into textual representation.
|
||||
if "fancy" argument is set to True produces indented output for readability.'''
|
||||
def __str__(self, fancy=0):
|
||||
"""
|
||||
Method used to dump node into textual representation. If "fancy" argument
|
||||
is set to True produces indented output for readability
|
||||
"""
|
||||
s = (fancy-1) * 2 * ' ' + "<" + self.name
|
||||
if self.namespace:
|
||||
if not self.parent or self.parent.namespace!=self.namespace:
|
||||
|
@ -142,9 +178,12 @@ class Node(object):
|
|||
s = s + "</" + self.name + ">"
|
||||
if fancy: s = s + "\n"
|
||||
return s
|
||||
|
||||
def addChild(self, name=None, attrs={}, payload=[], namespace=None, node=None):
|
||||
''' If "node" argument is provided, adds it as child node. Else creates new node from
|
||||
the other arguments' values and adds it as well.'''
|
||||
"""
|
||||
If "node" argument is provided, adds it as child node. Else creates new
|
||||
node from the other arguments' values and adds it as well
|
||||
"""
|
||||
if 'xmlns' in attrs:
|
||||
raise AttributeError("Use namespace=x instead of attrs={'xmlns':x}")
|
||||
if node:
|
||||
|
@ -155,196 +194,338 @@ class Node(object):
|
|||
newnode.setNamespace(namespace)
|
||||
self.kids.append(newnode)
|
||||
return newnode
|
||||
|
||||
def addData(self, data):
|
||||
''' Adds some CDATA to node. '''
|
||||
"""
|
||||
Add some CDATA to node
|
||||
"""
|
||||
self.data.append(ustr(data))
|
||||
|
||||
def clearData(self):
|
||||
''' Removes all CDATA from the node. '''
|
||||
self.data=[]
|
||||
"""
|
||||
Remove all CDATA from the node
|
||||
"""
|
||||
self.data = []
|
||||
|
||||
def delAttr(self, key):
|
||||
''' Deletes an attribute "key" '''
|
||||
"""
|
||||
Delete an attribute "key"
|
||||
"""
|
||||
del self.attrs[key]
|
||||
|
||||
def delChild(self, node, attrs={}):
|
||||
''' Deletes the "node" from the node's childs list, if "node" is an instance.
|
||||
Else deletes the first node that have specified name and (optionally) attributes. '''
|
||||
if not isinstance(node, Node): node=self.getTag(node,attrs)
|
||||
"""
|
||||
Delete the "node" from the node's childs list, if "node" is an instance.
|
||||
Else delete the first node that have specified name and (optionally)
|
||||
attributes
|
||||
"""
|
||||
if not isinstance(node, Node):
|
||||
node = self.getTag(node,attrs)
|
||||
self.kids.remove(node)
|
||||
return node
|
||||
|
||||
def getAttrs(self):
|
||||
''' Returns all node's attributes as dictionary. '''
|
||||
"""
|
||||
Return all node's attributes as dictionary
|
||||
"""
|
||||
return self.attrs
|
||||
|
||||
def getAttr(self, key):
|
||||
''' Returns value of specified attribute. '''
|
||||
"""
|
||||
Return value of specified attribute
|
||||
"""
|
||||
return self.attrs.get(key)
|
||||
|
||||
def getChildren(self):
|
||||
''' Returns all node's child nodes as list. '''
|
||||
"""
|
||||
Return all node's child nodes as list
|
||||
"""
|
||||
return self.kids
|
||||
|
||||
def getData(self):
|
||||
''' Returns all node CDATA as string (concatenated). '''
|
||||
"""
|
||||
Return all node CDATA as string (concatenated)
|
||||
"""
|
||||
return ''.join(self.data)
|
||||
|
||||
def getName(self):
|
||||
''' Returns the name of node '''
|
||||
"""
|
||||
Return the name of node
|
||||
"""
|
||||
return self.name
|
||||
|
||||
def getNamespace(self):
|
||||
''' Returns the namespace of node '''
|
||||
"""
|
||||
Return the namespace of node
|
||||
"""
|
||||
return self.namespace
|
||||
|
||||
def getParent(self):
|
||||
''' Returns the parent of node (if present). '''
|
||||
"""
|
||||
Returns the parent of node (if present)
|
||||
"""
|
||||
return self.parent
|
||||
|
||||
def getPayload(self):
|
||||
''' Return the payload of node i.e. list of child nodes and CDATA entries.
|
||||
F.e. for "<node>text1<nodea/><nodeb/> text2</node>" will be returned list:
|
||||
['text1', <nodea instance>, <nodeb instance>, ' text2']. '''
|
||||
ret=[]
|
||||
"""
|
||||
Return the payload of node i.e. list of child nodes and CDATA entries.
|
||||
F.e. for "<node>text1<nodea/><nodeb/> text2</node>" will be returned
|
||||
list: ['text1', <nodea instance>, <nodeb instance>, ' text2']
|
||||
"""
|
||||
ret = []
|
||||
for i in range(len(self.kids)+len(self.data)+1):
|
||||
try:
|
||||
if self.data[i]: ret.append(self.data[i])
|
||||
except IndexError: pass
|
||||
try: ret.append(self.kids[i])
|
||||
except IndexError: pass
|
||||
if self.data[i]:
|
||||
ret.append(self.data[i])
|
||||
except IndexError:
|
||||
pass
|
||||
try:
|
||||
ret.append(self.kids[i])
|
||||
except IndexError:
|
||||
pass
|
||||
return ret
|
||||
|
||||
def getTag(self, name, attrs={}, namespace=None):
|
||||
''' Filters all child nodes using specified arguments as filter.
|
||||
Returns the first found or None if not found. '''
|
||||
"""
|
||||
Filter all child nodes using specified arguments as filter. Return the
|
||||
first found or None if not found
|
||||
"""
|
||||
return self.getTags(name, attrs, namespace, one=1)
|
||||
def getTagAttr(self,tag,attr):
|
||||
''' Returns attribute value of the child with specified name (or None if no such attribute).'''
|
||||
|
||||
def getTagAttr(self, tag, attr):
|
||||
"""
|
||||
Return attribute value of the child with specified name (or None if no
|
||||
such attribute)
|
||||
"""
|
||||
try:
|
||||
return self.getTag(tag).attrs[attr]
|
||||
except:
|
||||
return None
|
||||
|
||||
def getTagData(self,tag):
|
||||
''' Returns cocatenated CDATA of the child with specified name.'''
|
||||
"""
|
||||
Return cocatenated CDATA of the child with specified name
|
||||
"""
|
||||
try:
|
||||
return self.getTag(tag).getData()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def getTags(self, name, attrs={}, namespace=None, one=0):
|
||||
''' Filters all child nodes using specified arguments as filter.
|
||||
Returns the list of nodes found. '''
|
||||
nodes=[]
|
||||
"""
|
||||
Filter all child nodes using specified arguments as filter. Returns the
|
||||
list of nodes found
|
||||
"""
|
||||
nodes = []
|
||||
for node in self.kids:
|
||||
if namespace and namespace!=node.getNamespace(): continue
|
||||
if namespace and namespace != node.getNamespace():
|
||||
continue
|
||||
if node.getName() == name:
|
||||
for key in attrs.keys():
|
||||
if key not in node.attrs or node.attrs[key]!=attrs[key]: break
|
||||
else: nodes.append(node)
|
||||
if one and nodes: return nodes[0]
|
||||
if not one: return nodes
|
||||
if key not in node.attrs or node.attrs[key]!=attrs[key]:
|
||||
break
|
||||
else:
|
||||
nodes.append(node)
|
||||
if one and nodes:
|
||||
return nodes[0]
|
||||
if not one:
|
||||
return nodes
|
||||
|
||||
def iterTags(self, name, attrs={}, namespace=None):
|
||||
''' Iterate over all children using specified arguments as filter. '''
|
||||
"""
|
||||
Iterate over all children using specified arguments as filter
|
||||
"""
|
||||
for node in self.kids:
|
||||
if namespace is not None and namespace!=node.getNamespace(): continue
|
||||
if namespace is not None and namespace != node.getNamespace():
|
||||
continue
|
||||
if node.getName() == name:
|
||||
for key in attrs.keys():
|
||||
if key not in node.attrs or \
|
||||
node.attrs[key]!=attrs[key]: break
|
||||
node.attrs[key]!=attrs[key]:
|
||||
break
|
||||
else:
|
||||
yield node
|
||||
|
||||
def setAttr(self, key, val):
|
||||
''' Sets attribute "key" with the value "val". '''
|
||||
self.attrs[key]=val
|
||||
"""
|
||||
Set attribute "key" with the value "val"
|
||||
"""
|
||||
self.attrs[key] = val
|
||||
|
||||
def setData(self, data):
|
||||
''' Sets node's CDATA to provided string. Resets all previous CDATA!'''
|
||||
self.data=[ustr(data)]
|
||||
def setName(self,val):
|
||||
''' Changes the node name. '''
|
||||
"""
|
||||
Set node's CDATA to provided string. Resets all previous CDATA!
|
||||
"""
|
||||
self.data = [ustr(data)]
|
||||
|
||||
def setName(self, val):
|
||||
"""
|
||||
Change the node name
|
||||
"""
|
||||
self.name = val
|
||||
|
||||
def setNamespace(self, namespace):
|
||||
''' Changes the node namespace. '''
|
||||
self.namespace=namespace
|
||||
"""
|
||||
Changes the node namespace
|
||||
"""
|
||||
self.namespace = namespace
|
||||
|
||||
def setParent(self, node):
|
||||
''' Sets node's parent to "node". WARNING: do not checks if the parent already present
|
||||
and not removes the node from the list of childs of previous parent. '''
|
||||
"""
|
||||
Set node's parent to "node". WARNING: do not checks if the parent already
|
||||
present and not removes the node from the list of childs of previous
|
||||
parent
|
||||
"""
|
||||
self.parent = node
|
||||
def setPayload(self,payload,add=0):
|
||||
''' Sets node payload according to the list specified. WARNING: completely replaces all node's
|
||||
previous content. If you wish just to add child or CDATA - use addData or addChild methods. '''
|
||||
if isinstance(payload, basestring): payload=[payload]
|
||||
if add: self.kids+=payload
|
||||
else: self.kids=payload
|
||||
|
||||
def setPayload(self, payload, add=0):
|
||||
"""
|
||||
Set node payload according to the list specified. WARNING: completely
|
||||
replaces all node's previous content. If you wish just to add child or
|
||||
CDATA - use addData or addChild methods
|
||||
"""
|
||||
if isinstance(payload, basestring):
|
||||
payload = [payload]
|
||||
if add:
|
||||
self.kids += payload
|
||||
else:
|
||||
self.kids = payload
|
||||
|
||||
def setTag(self, name, attrs={}, namespace=None):
|
||||
''' Same as getTag but if the node with specified namespace/attributes not found, creates such
|
||||
node and returns it. '''
|
||||
node=self.getTags(name, attrs, namespace=namespace, one=1)
|
||||
if node: return node
|
||||
else: return self.addChild(name, attrs, namespace=namespace)
|
||||
def setTagAttr(self,tag,attr,val):
|
||||
''' Creates new node (if not already present) with name "tag"
|
||||
and sets it's attribute "attr" to value "val". '''
|
||||
"""
|
||||
Same as getTag but if the node with specified namespace/attributes not
|
||||
found, creates such node and returns it
|
||||
"""
|
||||
node = self.getTags(name, attrs, namespace=namespace, one=1)
|
||||
if node:
|
||||
return node
|
||||
else:
|
||||
return self.addChild(name, attrs, namespace=namespace)
|
||||
|
||||
def setTagAttr(self, tag, attr, val):
|
||||
"""
|
||||
Create new node (if not already present) with name "tag" and set it's
|
||||
attribute "attr" to value "val"
|
||||
"""
|
||||
try:
|
||||
self.getTag(tag).attrs[attr]=val
|
||||
self.getTag(tag).attrs[attr] = val
|
||||
except Exception:
|
||||
self.addChild(tag,attrs={attr:val})
|
||||
def setTagData(self,tag,val,attrs={}):
|
||||
''' Creates new node (if not already present) with name "tag" and (optionally) attributes "attrs"
|
||||
and sets it's CDATA to string "val". '''
|
||||
self.addChild(tag, attrs={attr: val})
|
||||
|
||||
def setTagData(self, tag, val, attrs={}):
|
||||
"""
|
||||
Creates new node (if not already present) with name "tag" and
|
||||
(optionally) attributes "attrs" and sets it's CDATA to string "val"
|
||||
"""
|
||||
try:
|
||||
self.getTag(tag,attrs).setData(ustr(val))
|
||||
except Exception:
|
||||
self.addChild(tag,attrs,payload=[ustr(val)])
|
||||
def has_attr(self,key):
|
||||
''' Checks if node have attribute "key".'''
|
||||
self.addChild(tag,attrs,payload = [ustr(val)])
|
||||
|
||||
def has_attr(self, key):
|
||||
"""
|
||||
Check if node have attribute "key"
|
||||
"""
|
||||
return key in self.attrs
|
||||
def __getitem__(self,item):
|
||||
''' Returns node's attribute "item" value. '''
|
||||
|
||||
def __getitem__(self, item):
|
||||
"""
|
||||
Return node's attribute "item" value
|
||||
"""
|
||||
return self.getAttr(item)
|
||||
def __setitem__(self,item,val):
|
||||
''' Sets node's attribute "item" value. '''
|
||||
return self.setAttr(item,val)
|
||||
def __delitem__(self,item):
|
||||
''' Deletes node's attribute "item". '''
|
||||
|
||||
def __setitem__(self, item, val):
|
||||
"""
|
||||
Set node's attribute "item" value
|
||||
"""
|
||||
return self.setAttr(item, val)
|
||||
|
||||
def __delitem__(self, item):
|
||||
"""
|
||||
Delete node's attribute "item"
|
||||
"""
|
||||
return self.delAttr(item)
|
||||
def __contains__(self,item):
|
||||
""" Checks if node has attribute "item" """
|
||||
|
||||
def __contains__(self, item):
|
||||
"""
|
||||
Check if node has attribute "item"
|
||||
"""
|
||||
return self.has_attr(item)
|
||||
def __getattr__(self,attr):
|
||||
''' Reduce memory usage caused by T/NT classes - use memory only when needed. '''
|
||||
if attr=='T':
|
||||
self.T=T(self)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""
|
||||
Reduce memory usage caused by T/NT classes - use memory only when needed
|
||||
"""
|
||||
if attr == 'T':
|
||||
self.T = T(self)
|
||||
return self.T
|
||||
if attr=='NT':
|
||||
self.NT=NT(self)
|
||||
if attr == 'NT':
|
||||
self.NT = NT(self)
|
||||
return self.NT
|
||||
raise AttributeError
|
||||
|
||||
class T:
|
||||
''' Auxiliary class used to quick access to node's child nodes. '''
|
||||
def __init__(self,node): self.__dict__['node']=node
|
||||
def __getattr__(self,attr): return self.node.setTag(attr)
|
||||
def __setattr__(self,attr,val):
|
||||
if isinstance(val,Node): Node.__init__(self.node.setTag(attr),node=val)
|
||||
else: return self.node.setTagData(attr,val)
|
||||
def __delattr__(self,attr): return self.node.delChild(attr)
|
||||
"""
|
||||
Auxiliary class used to quick access to node's child nodes
|
||||
"""
|
||||
|
||||
def __init__(self, node):
|
||||
self.__dict__['node'] = node
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return self.node.setTag(attr)
|
||||
|
||||
def __setattr__(self, attr, val):
|
||||
if isinstance(val,Node):
|
||||
Node.__init__(self.node.setTag(attr), node=val)
|
||||
else:
|
||||
return self.node.setTagData(attr, val)
|
||||
|
||||
def __delattr__(self, attr):
|
||||
return self.node.delChild(attr)
|
||||
|
||||
class NT(T):
|
||||
''' Auxiliary class used to quick create node's child nodes. '''
|
||||
def __getattr__(self,attr): return self.node.addChild(attr)
|
||||
def __setattr__(self,attr,val):
|
||||
if isinstance(val,Node): self.node.addChild(attr,node=val)
|
||||
else: return self.node.addChild(attr,payload=[val])
|
||||
"""
|
||||
Auxiliary class used to quick create node's child nodes
|
||||
"""
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return self.node.addChild(attr)
|
||||
|
||||
def __setattr__(self, attr, val):
|
||||
if isinstance(val,Node):
|
||||
self.node.addChild(attr,node=val)
|
||||
else:
|
||||
return self.node.addChild(attr, payload=[val])
|
||||
|
||||
class NodeBuilder:
|
||||
''' Builds a Node class minidom from data parsed to it. This class used for two purposes:
|
||||
1. Creation an XML Node from a textual representation. F.e. reading a config file. See an XML2Node method.
|
||||
2. Handling an incoming XML stream. This is done by mangling
|
||||
the __dispatch_depth parameter and redefining the dispatch method.
|
||||
You do not need to use this class directly if you do not designing your own XML handler.'''
|
||||
def __init__(self,data=None,initial_node=None):
|
||||
''' Takes two optional parameters: "data" and "initial_node".
|
||||
By default class initialised with empty Node class instance.
|
||||
Though, if "initial_node" is provided it used as "starting point".
|
||||
You can think about it as of "node upgrade".
|
||||
"data" (if provided) feeded to parser immidiatedly after instance init.
|
||||
'''
|
||||
"""
|
||||
Builds a Node class minidom from data parsed to it. This class used for two
|
||||
purposes:
|
||||
1. Creation an XML Node from a textual representation. F.e. reading a
|
||||
config file. See an XML2Node method.
|
||||
2. Handling an incoming XML stream. This is done by mangling the
|
||||
__dispatch_depth parameter and redefining the dispatch method.
|
||||
|
||||
You do not need to use this class directly if you do not designing your own
|
||||
XML handler
|
||||
"""
|
||||
|
||||
def __init__(self, data=None, initial_node=None):
|
||||
"""
|
||||
Take two optional parameters: "data" and "initial_node"
|
||||
|
||||
By default class initialised with empty Node class instance. Though, if
|
||||
"initial_node" is provided it used as "starting point". You can think
|
||||
about it as of "node upgrade". "data" (if provided) feeded to parser
|
||||
immidiatedly after instance init.
|
||||
"""
|
||||
log.debug("Preparing to handle incoming XML stream.")
|
||||
self._parser = xml.parsers.expat.ParserCreate()
|
||||
self._parser.StartElementHandler = self.starttag
|
||||
self._parser.EndElementHandler = self.endtag
|
||||
self._parser.StartElementHandler = self.starttag
|
||||
self._parser.EndElementHandler = self.endtag
|
||||
self._parser.StartNamespaceDeclHandler = self.handle_namespace_start
|
||||
self._parser.CharacterDataHandler = self.handle_cdata
|
||||
self._parser.CharacterDataHandler = self.handle_cdata
|
||||
self._parser.buffer_text = True
|
||||
self.Parse = self._parser.Parse
|
||||
|
||||
|
@ -369,15 +550,19 @@ class NodeBuilder:
|
|||
self.data_buffer = None
|
||||
|
||||
def destroy(self):
|
||||
''' Method used to allow class instance to be garbage-collected. '''
|
||||
"""
|
||||
Method used to allow class instance to be garbage-collected
|
||||
"""
|
||||
self.check_data_buffer()
|
||||
self._parser.StartElementHandler = None
|
||||
self._parser.EndElementHandler = None
|
||||
self._parser.CharacterDataHandler = None
|
||||
self._parser.StartElementHandler = None
|
||||
self._parser.EndElementHandler = None
|
||||
self._parser.CharacterDataHandler = None
|
||||
self._parser.StartNamespaceDeclHandler = None
|
||||
|
||||
def starttag(self, tag, attrs):
|
||||
'''XML Parser callback. Used internally'''
|
||||
"""
|
||||
XML Parser callback. Used internally
|
||||
"""
|
||||
self.check_data_buffer()
|
||||
self._inc_depth()
|
||||
log.info("STARTTAG.. DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`))
|
||||
|
@ -410,8 +595,11 @@ class NodeBuilder:
|
|||
if not self.last_is_data and self._ptr.parent:
|
||||
self._ptr.parent.data.append('')
|
||||
self.last_is_data = 0
|
||||
|
||||
def endtag(self, tag ):
|
||||
'''XML Parser callback. Used internally'''
|
||||
"""
|
||||
XML Parser callback. Used internally
|
||||
"""
|
||||
log.info("DEPTH -> %i , tag -> %s" % (self.__depth, tag))
|
||||
self.check_data_buffer()
|
||||
if self.__depth == self._dispatch_depth:
|
||||
|
@ -439,25 +627,42 @@ class NodeBuilder:
|
|||
self.last_is_data = 1
|
||||
|
||||
def handle_namespace_start(self, prefix, uri):
|
||||
'''XML Parser callback. Used internally'''
|
||||
"""
|
||||
XML Parser callback. Used internally
|
||||
"""
|
||||
self.check_data_buffer()
|
||||
|
||||
def getDom(self):
|
||||
''' Returns just built Node. '''
|
||||
"""
|
||||
Return just built Node
|
||||
"""
|
||||
self.check_data_buffer()
|
||||
return self._mini_dom
|
||||
def dispatch(self,stanza):
|
||||
''' Gets called when the NodeBuilder reaches some level of depth on it's way up with the built
|
||||
node as argument. Can be redefined to convert incoming XML stanzas to program events. '''
|
||||
def stream_header_received(self,ns,tag,attrs):
|
||||
''' Method called when stream just opened. '''
|
||||
|
||||
def dispatch(self, stanza):
|
||||
"""
|
||||
Get called when the NodeBuilder reaches some level of depth on it's way
|
||||
up with the built node as argument. Can be redefined to convert incoming
|
||||
XML stanzas to program events
|
||||
"""
|
||||
pass
|
||||
|
||||
def stream_header_received(self, ns, tag, attrs):
|
||||
"""
|
||||
Method called when stream just opened
|
||||
"""
|
||||
self.check_data_buffer()
|
||||
|
||||
def stream_footer_received(self):
|
||||
''' Method called when stream just closed. '''
|
||||
"""
|
||||
Method called when stream just closed
|
||||
"""
|
||||
self.check_data_buffer()
|
||||
|
||||
def has_received_endtag(self, level=0):
|
||||
''' Return True if at least one end tag was seen (at level) '''
|
||||
"""
|
||||
Return True if at least one end tag was seen (at level)
|
||||
"""
|
||||
return self.__depth <= level and self.__max_depth > level
|
||||
|
||||
def _inc_depth(self):
|
||||
|
@ -470,14 +675,20 @@ class NodeBuilder:
|
|||
self.__depth -= 1
|
||||
|
||||
def XML2Node(xml):
|
||||
''' Converts supplied textual string into XML node. Handy f.e. for reading configuration file.
|
||||
Raises xml.parser.expat.parsererror if provided string is not well-formed XML. '''
|
||||
"""
|
||||
Convert supplied textual string into XML node. Handy f.e. for reading
|
||||
configuration file. Raises xml.parser.expat.parsererror if provided string
|
||||
is not well-formed XML
|
||||
"""
|
||||
return NodeBuilder(xml).getDom()
|
||||
|
||||
def BadXML2Node(xml):
|
||||
''' Converts supplied textual string into XML node. Survives if xml data is cutted half way round.
|
||||
I.e. "<html>some text <br>some more text". Will raise xml.parser.expat.parsererror on misplaced
|
||||
tags though. F.e. "<b>some text <br>some more text</b>" will not work.'''
|
||||
"""
|
||||
Convert supplied textual string into XML node. Survives if xml data is
|
||||
cutted half way round. I.e. "<html>some text <br>some more text". Will raise
|
||||
xml.parser.expat.parsererror on misplaced tags though. F.e. "<b>some text
|
||||
<br>some more text</b>" will not work
|
||||
"""
|
||||
return NodeBuilder(xml).getDom()
|
||||
|
||||
# vim: se ts=3:
|
||||
|
|
Loading…
Reference in New Issue