1"""Python version compatibility support for minidom."""
2
3# This module should only be imported using "import *".
4#
5# The following names are defined:
6#
7#   NodeList      -- lightest possible NodeList implementation
8#
9#   EmptyNodeList -- lightest possible NodeList that is guaranteed to
10#                    remain empty (immutable)
11#
12#   StringTypes   -- tuple of defined string types
13#
14#   defproperty   -- function used in conjunction with GetattrMagic;
15#                    using these together is needed to make them work
16#                    as efficiently as possible in both Python 2.2+
17#                    and older versions.  For example:
18#
19#                        class MyClass(GetattrMagic):
20#                            def _get_myattr(self):
21#                                return something
22#
23#                        defproperty(MyClass, "myattr",
24#                                    "return some value")
25#
26#                    For Python 2.2 and newer, this will construct a
27#                    property object on the class, which avoids
28#                    needing to override __getattr__().  It will only
29#                    work for read-only attributes.
30#
31#                    For older versions of Python, inheriting from
32#                    GetattrMagic will use the traditional
33#                    __getattr__() hackery to achieve the same effect,
34#                    but less efficiently.
35#
36#                    defproperty() should be used for each version of
37#                    the relevant _get_<property>() function.
38
39__all__ = ["NodeList", "EmptyNodeList", "StringTypes", "defproperty"]
40
41import xml.dom
42
43try:
44    unicode
45except NameError:
46    StringTypes = type(''),
47else:
48    StringTypes = type(''), type(unicode(''))
49
50
51class NodeList(list):
52    __slots__ = ()
53
54    def item(self, index):
55        if 0 <= index < len(self):
56            return self[index]
57
58    def _get_length(self):
59        return len(self)
60
61    def _set_length(self, value):
62        raise xml.dom.NoModificationAllowedErr(
63            "attempt to modify read-only attribute 'length'")
64
65    length = property(_get_length, _set_length,
66                      doc="The number of nodes in the NodeList.")
67
68    def __getstate__(self):
69        return list(self)
70
71    def __setstate__(self, state):
72        self[:] = state
73
74
75class EmptyNodeList(tuple):
76    __slots__ = ()
77
78    def __add__(self, other):
79        NL = NodeList()
80        NL.extend(other)
81        return NL
82
83    def __radd__(self, other):
84        NL = NodeList()
85        NL.extend(other)
86        return NL
87
88    def item(self, index):
89        return None
90
91    def _get_length(self):
92        return 0
93
94    def _set_length(self, value):
95        raise xml.dom.NoModificationAllowedErr(
96            "attempt to modify read-only attribute 'length'")
97
98    length = property(_get_length, _set_length,
99                      doc="The number of nodes in the NodeList.")
100
101
102def defproperty(klass, name, doc):
103    get = getattr(klass, ("_get_" + name)).im_func
104    def set(self, value, name=name):
105        raise xml.dom.NoModificationAllowedErr(
106            "attempt to modify read-only attribute " + repr(name))
107    assert not hasattr(klass, "_set_" + name), \
108           "expected not to find _set_" + name
109    prop = property(get, set, doc=doc)
110    setattr(klass, name, prop)
111