diff --git a/src/common/xmpp/protocol.py b/src/common/xmpp/protocol.py
index ff19678d8..17e2096a3 100644
--- a/src/common/xmpp/protocol.py
+++ b/src/common/xmpp/protocol.py
@@ -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):
diff --git a/src/common/xmpp/proxy_connectors.py b/src/common/xmpp/proxy_connectors.py
index e4fb4dbd8..b4e7acfcd 100644
--- a/src/common/xmpp/proxy_connectors.py
+++ b/src/common/xmpp/proxy_connectors.py
@@ -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:
diff --git a/src/common/xmpp/roster_nb.py b/src/common/xmpp/roster_nb.py
index 715476b9e..bf5600cb7 100644
--- a/src/common/xmpp/roster_nb.py
+++ b/src/common/xmpp/roster_nb.py
@@ -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
- 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
diff --git a/src/common/xmpp/simplexml.py b/src/common/xmpp/simplexml.py
index f47142c46..2ace6657a 100644
--- a/src/common/xmpp/simplexml.py
+++ b/src/common/xmpp/simplexml.py
@@ -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 "text1 text2" will be returned list:
- ['text1', , , ' text2']. '''
- ret=[]
+ """
+ Return the payload of node i.e. list of child nodes and CDATA entries.
+ F.e. for "text1 text2" will be returned
+ list: ['text1', , , ' 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. "some text
some more text". Will raise xml.parser.expat.parsererror on misplaced
- tags though. F.e. "some text
some more text" will not work.'''
+ """
+ Convert supplied textual string into XML node. Survives if xml data is
+ cutted half way round. I.e. "some text
some more text". Will raise
+ xml.parser.expat.parsererror on misplaced tags though. F.e. "some text
+
some more text" will not work
+ """
return NodeBuilder(xml).getDom()
# vim: se ts=3: