Blame telepathy-account-widgets/tools/libtpcodegen.py

Packit 79f644
"""Library code for language-independent D-Bus-related code generation.
Packit 79f644
Packit 79f644
The master copy of this library is in the telepathy-glib repository -
Packit 79f644
please make any changes there.
Packit 79f644
"""
Packit 79f644
Packit 79f644
# Copyright (C) 2006-2008 Collabora Limited
Packit 79f644
#
Packit 79f644
# This library is free software; you can redistribute it and/or
Packit 79f644
# modify it under the terms of the GNU Lesser General Public
Packit 79f644
# License as published by the Free Software Foundation; either
Packit 79f644
# version 2.1 of the License, or (at your option) any later version.
Packit 79f644
#
Packit 79f644
# This library is distributed in the hope that it will be useful,
Packit 79f644
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 79f644
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 79f644
# Lesser General Public License for more details.
Packit 79f644
#
Packit 79f644
# You should have received a copy of the GNU Lesser General Public
Packit 79f644
# License along with this library; if not, write to the Free Software
Packit 79f644
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 79f644
Packit 79f644
import os
Packit 79f644
import sys
Packit 79f644
from string import ascii_letters, digits
Packit 79f644
Packit 79f644
Packit 79f644
NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
Packit 79f644
Packit 79f644
_ASCII_ALNUM = ascii_letters + digits
Packit 79f644
Packit 79f644
if sys.version_info[0] >= 3:
Packit 79f644
    def u(s):
Packit 79f644
        """Return s, which must be a str literal with no non-ASCII characters.
Packit 79f644
        This is like a more restricted form of the Python 2 u'' syntax.
Packit 79f644
        """
Packit 79f644
        return s.encode('ascii').decode('ascii')
Packit 79f644
else:
Packit 79f644
    def u(s):
Packit 79f644
        """Return a Unicode version of s, which must be a str literal
Packit 79f644
        (a bytestring) in which each byte is an ASCII character.
Packit 79f644
        This is like a more restricted form of the u'' syntax.
Packit 79f644
        """
Packit 79f644
        return s.decode('ascii')
Packit 79f644
Packit 79f644
def file_set_contents(filename, contents):
Packit 79f644
    try:
Packit 79f644
        os.remove(filename)
Packit 79f644
    except OSError:
Packit 79f644
        pass
Packit 79f644
    try:
Packit 79f644
        os.remove(filename + '.tmp')
Packit 79f644
    except OSError:
Packit 79f644
        pass
Packit 79f644
Packit 79f644
    open(filename + '.tmp', 'wb').write(contents)
Packit 79f644
    os.rename(filename + '.tmp', filename)
Packit 79f644
Packit 79f644
def cmp_by_name(node1, node2):
Packit 79f644
    return cmp(node1.getAttributeNode("name").nodeValue,
Packit 79f644
               node2.getAttributeNode("name").nodeValue)
Packit 79f644
Packit 79f644
def key_by_name(node):
Packit 79f644
    return node.getAttributeNode("name").nodeValue
Packit 79f644
Packit 79f644
def escape_as_identifier(identifier):
Packit 79f644
    """Escape the given string to be a valid D-Bus object path or service
Packit 79f644
    name component, using a reversible encoding to ensure uniqueness.
Packit 79f644
Packit 79f644
    The reversible encoding is as follows:
Packit 79f644
Packit 79f644
    * The empty string becomes '_'
Packit 79f644
    * Otherwise, each non-alphanumeric character is replaced by '_' plus
Packit 79f644
      two lower-case hex digits; the same replacement is carried out on
Packit 79f644
      the first character, if it's a digit
Packit 79f644
    """
Packit 79f644
    # '' -> '_'
Packit 79f644
    if not identifier:
Packit 79f644
        return '_'
Packit 79f644
Packit 79f644
    # A bit of a fast path for strings which are already OK.
Packit 79f644
    # We deliberately omit '_' because, for reversibility, that must also
Packit 79f644
    # be escaped.
Packit 79f644
    if (identifier.strip(_ASCII_ALNUM) == '' and
Packit 79f644
        identifier[0] in ascii_letters):
Packit 79f644
        return identifier
Packit 79f644
Packit 79f644
    # The first character may not be a digit
Packit 79f644
    if identifier[0] not in ascii_letters:
Packit 79f644
        ret = ['_%02x' % ord(identifier[0])]
Packit 79f644
    else:
Packit 79f644
        ret = [identifier[0]]
Packit 79f644
Packit 79f644
    # Subsequent characters may be digits or ASCII letters
Packit 79f644
    for c in identifier[1:]:
Packit 79f644
        if c in _ASCII_ALNUM:
Packit 79f644
            ret.append(c)
Packit 79f644
        else:
Packit 79f644
            ret.append('_%02x' % ord(c))
Packit 79f644
Packit 79f644
    return ''.join(ret)
Packit 79f644
Packit 79f644
Packit 79f644
def get_by_path(element, path):
Packit 79f644
    branches = path.split('/')
Packit 79f644
    branch = branches[0]
Packit 79f644
Packit 79f644
    # Is the current branch an attribute, if so, return the attribute value
Packit 79f644
    if branch[0] == '@':
Packit 79f644
        return element.getAttribute(branch[1:])
Packit 79f644
Packit 79f644
    # Find matching children for the branch
Packit 79f644
    children = []
Packit 79f644
    if branch == '..':
Packit 79f644
        children.append(element.parentNode)
Packit 79f644
    else:
Packit 79f644
        for x in element.childNodes:
Packit 79f644
            if x.localName == branch:
Packit 79f644
                children.append(x)
Packit 79f644
Packit 79f644
    ret = []
Packit 79f644
    # If this is not the last path element, recursively gather results from
Packit 79f644
    # children
Packit 79f644
    if len(branches) > 1:
Packit 79f644
        for x in children:
Packit 79f644
            add = get_by_path(x, '/'.join(branches[1:]))
Packit 79f644
            if isinstance(add, list):
Packit 79f644
                ret += add
Packit 79f644
            else:
Packit 79f644
                return add
Packit 79f644
    else:
Packit 79f644
        ret = children
Packit 79f644
Packit 79f644
    return ret
Packit 79f644
Packit 79f644
Packit 79f644
def get_docstring(element):
Packit 79f644
    docstring = None
Packit 79f644
    for x in element.childNodes:
Packit 79f644
        if x.namespaceURI == NS_TP and x.localName == 'docstring':
Packit 79f644
            docstring = x
Packit 79f644
    if docstring is not None:
Packit 79f644
        docstring = docstring.toxml().replace('\n', ' ').strip()
Packit 79f644
        if docstring.startswith('<tp:docstring>'):
Packit 79f644
            docstring = docstring[14:].lstrip()
Packit 79f644
        if docstring.endswith('</tp:docstring>'):
Packit 79f644
            docstring = docstring[:-15].rstrip()
Packit 79f644
        if docstring in ('<tp:docstring/>', ''):
Packit 79f644
            docstring = ''
Packit 79f644
    return docstring
Packit 79f644
Packit 79f644
def get_deprecated(element):
Packit 79f644
    text = []
Packit 79f644
    for x in element.childNodes:
Packit 79f644
        if hasattr(x, 'data'):
Packit 79f644
            text.append(x.data.replace('\n', ' ').strip())
Packit 79f644
        else:
Packit 79f644
            # This caters for tp:dbus-ref elements, but little else.
Packit 79f644
            if x.childNodes and hasattr(x.childNodes[0], 'data'):
Packit 79f644
                text.append(x.childNodes[0].data.replace('\n', ' ').strip())
Packit 79f644
    return ' '.join(text)
Packit 79f644
Packit 79f644
def get_descendant_text(element_or_elements):
Packit 79f644
    if not element_or_elements:
Packit 79f644
        return ''
Packit 79f644
    if isinstance(element_or_elements, list):
Packit 79f644
        return ''.join(map(get_descendant_text, element_or_elements))
Packit 79f644
    parts = []
Packit 79f644
    for x in element_or_elements.childNodes:
Packit 79f644
        if x.nodeType == x.TEXT_NODE:
Packit 79f644
            parts.append(x.nodeValue)
Packit 79f644
        elif x.nodeType == x.ELEMENT_NODE:
Packit 79f644
            parts.append(get_descendant_text(x))
Packit 79f644
        else:
Packit 79f644
            pass
Packit 79f644
    return ''.join(parts)
Packit 79f644
Packit 79f644
Packit 79f644
class _SignatureIter:
Packit 79f644
    """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
Packit 79f644
    can run genginterface in a limited environment with only Python
Packit 79f644
    (like Scratchbox).
Packit 79f644
    """
Packit 79f644
    def __init__(self, string):
Packit 79f644
        self.remaining = string
Packit 79f644
Packit 79f644
    def next(self):
Packit 79f644
        return self.__next__()
Packit 79f644
Packit 79f644
    def __next__(self):
Packit 79f644
        if self.remaining == '':
Packit 79f644
            raise StopIteration
Packit 79f644
Packit 79f644
        signature = self.remaining
Packit 79f644
        block_depth = 0
Packit 79f644
        block_type = None
Packit 79f644
        end = len(signature)
Packit 79f644
Packit 79f644
        for marker in range(0, end):
Packit 79f644
            cur_sig = signature[marker]
Packit 79f644
Packit 79f644
            if cur_sig == 'a':
Packit 79f644
                pass
Packit 79f644
            elif cur_sig == '{' or cur_sig == '(':
Packit 79f644
                if block_type == None:
Packit 79f644
                    block_type = cur_sig
Packit 79f644
Packit 79f644
                if block_type == cur_sig:
Packit 79f644
                    block_depth = block_depth + 1
Packit 79f644
Packit 79f644
            elif cur_sig == '}':
Packit 79f644
                if block_type == '{':
Packit 79f644
                    block_depth = block_depth - 1
Packit 79f644
Packit 79f644
                if block_depth == 0:
Packit 79f644
                    end = marker
Packit 79f644
                    break
Packit 79f644
Packit 79f644
            elif cur_sig == ')':
Packit 79f644
                if block_type == '(':
Packit 79f644
                    block_depth = block_depth - 1
Packit 79f644
Packit 79f644
                if block_depth == 0:
Packit 79f644
                    end = marker
Packit 79f644
                    break
Packit 79f644
Packit 79f644
            else:
Packit 79f644
                if block_depth == 0:
Packit 79f644
                    end = marker
Packit 79f644
                    break
Packit 79f644
Packit 79f644
        end = end + 1
Packit 79f644
        self.remaining = signature[end:]
Packit 79f644
        return Signature(signature[0:end])
Packit 79f644
Packit 79f644
Packit 79f644
class Signature(str):
Packit 79f644
    """A string, iteration over which is by D-Bus single complete types
Packit 79f644
    rather than characters.
Packit 79f644
    """
Packit 79f644
    def __iter__(self):
Packit 79f644
        return _SignatureIter(self)
Packit 79f644
Packit 79f644
Packit 79f644
def xml_escape(s):
Packit 79f644
    s = s.replace('&', '&').replace("'", ''').replace('"', '"')
Packit 79f644
    return s.replace('<', '<').replace('>', '>')