~anitanayak/charms/trusty/ibm-wxs-catalog/ibm-wxs-catalog-branch

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/py/_xmlgen.py

  • Committer: Anita Nayak
  • Date: 2016-10-21 09:34:00 UTC
  • Revision ID: anitanayak@in.ibm.com-20161021093400-fv05mg22l496a0l6
lint fix-in for IBM WXS Catalog

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
module for generating and serializing xml and html structures
 
3
by using simple python objects.
 
4
 
 
5
(c) holger krekel, holger at merlinux eu. 2009
 
6
"""
 
7
import sys, re
 
8
 
 
9
if sys.version_info >= (3,0):
 
10
    def u(s):
 
11
        return s
 
12
    def unicode(x, errors=None):
 
13
        if hasattr(x, '__unicode__'):
 
14
            return x.__unicode__()
 
15
        return str(x)
 
16
else:
 
17
    def u(s):
 
18
        return unicode(s)
 
19
    unicode = unicode
 
20
 
 
21
 
 
22
class NamespaceMetaclass(type):
 
23
    def __getattr__(self, name):
 
24
        if name[:1] == '_':
 
25
            raise AttributeError(name)
 
26
        if self == Namespace:
 
27
            raise ValueError("Namespace class is abstract")
 
28
        tagspec = self.__tagspec__
 
29
        if tagspec is not None and name not in tagspec:
 
30
            raise AttributeError(name)
 
31
        classattr = {}
 
32
        if self.__stickyname__:
 
33
            classattr['xmlname'] = name
 
34
        cls = type(name, (self.__tagclass__,), classattr)
 
35
        setattr(self, name, cls)
 
36
        return cls
 
37
 
 
38
class Tag(list):
 
39
    class Attr(object):
 
40
        def __init__(self, **kwargs):
 
41
            self.__dict__.update(kwargs)
 
42
 
 
43
    def __init__(self, *args, **kwargs):
 
44
        super(Tag, self).__init__(args)
 
45
        self.attr = self.Attr(**kwargs)
 
46
 
 
47
    def __unicode__(self):
 
48
        return self.unicode(indent=0)
 
49
    __str__ = __unicode__
 
50
 
 
51
    def unicode(self, indent=2):
 
52
        l = []
 
53
        SimpleUnicodeVisitor(l.append, indent).visit(self)
 
54
        return u("").join(l)
 
55
 
 
56
    def __repr__(self):
 
57
        name = self.__class__.__name__
 
58
        return "<%r tag object %d>" % (name, id(self))
 
59
 
 
60
Namespace = NamespaceMetaclass('Namespace', (object, ), {
 
61
    '__tagspec__': None,
 
62
    '__tagclass__': Tag,
 
63
    '__stickyname__': False,
 
64
})
 
65
 
 
66
class HtmlTag(Tag):
 
67
    def unicode(self, indent=2):
 
68
        l = []
 
69
        HtmlVisitor(l.append, indent, shortempty=False).visit(self)
 
70
        return u("").join(l)
 
71
 
 
72
# exported plain html namespace
 
73
class html(Namespace):
 
74
    __tagclass__ = HtmlTag
 
75
    __stickyname__ = True
 
76
    __tagspec__ = dict([(x,1) for x in (
 
77
        'a,abbr,acronym,address,applet,area,b,bdo,big,blink,'
 
78
        'blockquote,body,br,button,caption,center,cite,code,col,'
 
79
        'colgroup,comment,dd,del,dfn,dir,div,dl,dt,em,embed,'
 
80
        'fieldset,font,form,frameset,h1,h2,h3,h4,h5,h6,head,html,'
 
81
        'i,iframe,img,input,ins,kbd,label,legend,li,link,listing,'
 
82
        'map,marquee,menu,meta,multicol,nobr,noembed,noframes,'
 
83
        'noscript,object,ol,optgroup,option,p,pre,q,s,script,'
 
84
        'select,small,span,strike,strong,style,sub,sup,table,'
 
85
        'tbody,td,textarea,tfoot,th,thead,title,tr,tt,u,ul,xmp,'
 
86
        'base,basefont,frame,hr,isindex,param,samp,var'
 
87
    ).split(',') if x])
 
88
 
 
89
    class Style(object):
 
90
        def __init__(self, **kw):
 
91
            for x, y in kw.items():
 
92
                x = x.replace('_', '-')
 
93
                setattr(self, x, y)
 
94
 
 
95
 
 
96
class raw(object):
 
97
    """just a box that can contain a unicode string that will be
 
98
    included directly in the output"""
 
99
    def __init__(self, uniobj):
 
100
        self.uniobj = uniobj
 
101
 
 
102
class SimpleUnicodeVisitor(object):
 
103
    """ recursive visitor to write unicode. """
 
104
    def __init__(self, write, indent=0, curindent=0, shortempty=True):
 
105
        self.write = write
 
106
        self.cache = {}
 
107
        self.visited = {} # for detection of recursion
 
108
        self.indent = indent
 
109
        self.curindent = curindent
 
110
        self.parents = []
 
111
        self.shortempty = shortempty  # short empty tags or not
 
112
 
 
113
    def visit(self, node):
 
114
        """ dispatcher on node's class/bases name. """
 
115
        cls = node.__class__
 
116
        try:
 
117
            visitmethod = self.cache[cls]
 
118
        except KeyError:
 
119
            for subclass in cls.__mro__:
 
120
                visitmethod = getattr(self, subclass.__name__, None)
 
121
                if visitmethod is not None:
 
122
                    break
 
123
            else:
 
124
                visitmethod = self.__object
 
125
            self.cache[cls] = visitmethod
 
126
        visitmethod(node)
 
127
 
 
128
    # the default fallback handler is marked private
 
129
    # to avoid clashes with the tag name object
 
130
    def __object(self, obj):
 
131
        #self.write(obj)
 
132
        self.write(escape(unicode(obj)))
 
133
 
 
134
    def raw(self, obj):
 
135
        self.write(obj.uniobj)
 
136
 
 
137
    def list(self, obj):
 
138
        assert id(obj) not in self.visited
 
139
        self.visited[id(obj)] = 1
 
140
        for elem in obj:
 
141
            self.visit(elem)
 
142
 
 
143
    def Tag(self, tag):
 
144
        assert id(tag) not in self.visited
 
145
        try:
 
146
            tag.parent = self.parents[-1]
 
147
        except IndexError:
 
148
            tag.parent = None
 
149
        self.visited[id(tag)] = 1
 
150
        tagname = getattr(tag, 'xmlname', tag.__class__.__name__)
 
151
        if self.curindent and not self._isinline(tagname):
 
152
            self.write("\n" + u(' ') * self.curindent)
 
153
        if tag:
 
154
            self.curindent += self.indent
 
155
            self.write(u('<%s%s>') % (tagname, self.attributes(tag)))
 
156
            self.parents.append(tag)
 
157
            for x in tag:
 
158
                self.visit(x)
 
159
            self.parents.pop()
 
160
            self.write(u('</%s>') % tagname)
 
161
            self.curindent -= self.indent
 
162
        else:
 
163
            nameattr = tagname+self.attributes(tag)
 
164
            if self._issingleton(tagname):
 
165
                self.write(u('<%s/>') % (nameattr,))
 
166
            else:
 
167
                self.write(u('<%s></%s>') % (nameattr, tagname))
 
168
 
 
169
    def attributes(self, tag):
 
170
        # serialize attributes
 
171
        attrlist = dir(tag.attr)
 
172
        attrlist.sort()
 
173
        l = []
 
174
        for name in attrlist:
 
175
            res = self.repr_attribute(tag.attr, name)
 
176
            if res is not None:
 
177
                l.append(res)
 
178
        l.extend(self.getstyle(tag))
 
179
        return u("").join(l)
 
180
 
 
181
    def repr_attribute(self, attrs, name):
 
182
        if name[:2] != '__':
 
183
            value = getattr(attrs, name)
 
184
            if name.endswith('_'):
 
185
                name = name[:-1]
 
186
            if isinstance(value, raw):
 
187
                insert = value.uniobj
 
188
            else:
 
189
                insert = escape(unicode(value))
 
190
            return ' %s="%s"' % (name, insert)
 
191
 
 
192
    def getstyle(self, tag):
 
193
        """ return attribute list suitable for styling. """
 
194
        try:
 
195
            styledict = tag.style.__dict__
 
196
        except AttributeError:
 
197
            return []
 
198
        else:
 
199
            stylelist = [x+': ' + y for x,y in styledict.items()]
 
200
            return [u(' style="%s"') % u('; ').join(stylelist)]
 
201
 
 
202
    def _issingleton(self, tagname):
 
203
        """can (and will) be overridden in subclasses"""
 
204
        return self.shortempty
 
205
 
 
206
    def _isinline(self, tagname):
 
207
        """can (and will) be overridden in subclasses"""
 
208
        return False
 
209
 
 
210
class HtmlVisitor(SimpleUnicodeVisitor):
 
211
 
 
212
    single = dict([(x, 1) for x in
 
213
                ('br,img,area,param,col,hr,meta,link,base,'
 
214
                    'input,frame').split(',')])
 
215
    inline = dict([(x, 1) for x in
 
216
                ('a abbr acronym b basefont bdo big br cite code dfn em font '
 
217
                 'i img input kbd label q s samp select small span strike '
 
218
                 'strong sub sup textarea tt u var'.split(' '))])
 
219
 
 
220
    def repr_attribute(self, attrs, name):
 
221
        if name == 'class_':
 
222
            value = getattr(attrs, name)
 
223
            if value is None:
 
224
                return
 
225
        return super(HtmlVisitor, self).repr_attribute(attrs, name)
 
226
 
 
227
    def _issingleton(self, tagname):
 
228
        return tagname in self.single
 
229
 
 
230
    def _isinline(self, tagname):
 
231
        return tagname in self.inline
 
232
 
 
233
 
 
234
class _escape:
 
235
    def __init__(self):
 
236
        self.escape = {
 
237
            u('"') : u('&quot;'), u('<') : u('&lt;'), u('>') : u('&gt;'),
 
238
            u('&') : u('&amp;'), u("'") : u('&apos;'),
 
239
            }
 
240
        self.charef_rex = re.compile(u("|").join(self.escape.keys()))
 
241
 
 
242
    def _replacer(self, match):
 
243
        return self.escape[match.group(0)]
 
244
 
 
245
    def __call__(self, ustring):
 
246
        """ xml-escape the given unicode string. """
 
247
        try:
 
248
            ustring = unicode(ustring)
 
249
        except UnicodeDecodeError:
 
250
            ustring = unicode(ustring, 'utf-8', errors='replace')
 
251
        return self.charef_rex.sub(self._replacer, ustring)
 
252
 
 
253
escape = _escape()