source: wokkel/compat.py @ 165:76a61f5aa343

Last change on this file since 165:76a61f5aa343 was 165:76a61f5aa343, checked in by Ralph Meijer <ralphm@…>, 11 years ago

Cleanups leading up to Wokkel 0.7.0.

As we now depend on Twisted 10.0.0 or higher, the following classes and
interfaces were deprecated:

This also resolves all Pyflakes warnings, changes links for www.xmpp.org to
xmpp.org and fixes the copyright notice in LICENSE to include 2012.

  • Property exe set to *
File size: 9.3 KB
RevLine 
[8]1# -*- test-case-name: wokkel.test.test_compat -*-
2#
[96]3# Copyright (c) Twisted Matrix Laboratories.
[8]4# See LICENSE for details.
5
[160]6"""
7Compatibility module to provide backwards compatibility with Twisted features.
8"""
9
10__all__ = ['BootstrapMixin', 'XmlStreamServerFactory', 'IQ',
11           'NamedConstant', 'ValueConstant', 'Names', 'Values']
12
13from itertools import count
14
[165]15from twisted.python.deprecate import deprecatedModuleAttribute
16from twisted.python.versions import Version
[34]17from twisted.words.protocols.jabber import xmlstream
[165]18from twisted.words.protocols.jabber.xmlstream import XmlStreamServerFactory
19from twisted.words.xish.xmlstream import BootstrapMixin
[8]20
[165]21deprecatedModuleAttribute(
22        Version("Wokkel", 0, 7, 0),
23        "Use twisted.words.xish.xmlstream.BootstrapMixin instead.",
24        __name__,
25        "BootstrapMixin")
[8]26
[165]27deprecatedModuleAttribute(
28        Version("Wokkel", 0, 7, 0),
29        "Use twisted.words.protocols.jabber.xmlstream.XmlStreamServerFactory "
30                "instead.",
31        __name__,
32        "XmlStreamServerFactory")
[63]33
34class IQ(xmlstream.IQ):
35    def __init__(self, *args, **kwargs):
36        # Make sure we have a reactor parameter
37        try:
38            reactor = kwargs['reactor']
39        except KeyError:
40            from twisted.internet import reactor
41        kwargs['reactor'] = reactor
42
43        # Check if IQ's init accepts the reactor parameter
44        try:
45            xmlstream.IQ.__init__(self, *args, **kwargs)
46        except TypeError:
47            # Guess not. Remove the reactor parameter and try again.
48            del kwargs['reactor']
49            xmlstream.IQ.__init__(self, *args, **kwargs)
50
51            # Patch the XmlStream instance so that it has a _callLater
52            self._xmlstream._callLater = reactor.callLater
[160]53
54
55
56_unspecified = object()
57_constantOrder = count().next
58
59
60class _Constant(object):
61    """
62    @ivar _index: A C{int} allocated from a shared counter in order to keep
63        track of the order in which L{_Constant}s are instantiated.
64
65    @ivar name: A C{str} giving the name of this constant; only set once the
66        constant is initialized by L{_ConstantsContainer}.
67
68    @ivar _container: The L{_ConstantsContainer} subclass this constant belongs
69        to; only set once the constant is initialized by that subclass.
[165]70
71    @since: Twisted 12.0.0.
[160]72    """
73    def __init__(self):
74        self._index = _constantOrder()
75
76
77    def __get__(self, oself, cls):
78        """
79        Ensure this constant has been initialized before returning it.
80        """
81        cls._initializeEnumerants()
82        return self
83
84
85    def __repr__(self):
86        """
87        Return text identifying both which constant this is and which collection
88        it belongs to.
89        """
90        return "<%s=%s>" % (self._container.__name__, self.name)
91
92
93    def _realize(self, container, name, value):
94        """
95        Complete the initialization of this L{_Constant}.
96
97        @param container: The L{_ConstantsContainer} subclass this constant is
98            part of.
99
100        @param name: The name of this constant in its container.
101
102        @param value: The value of this constant; not used, as named constants
103            have no value apart from their identity.
104        """
105        self._container = container
106        self.name = name
107
108
109
110class _EnumerantsInitializer(object):
111    """
112    L{_EnumerantsInitializer} is a descriptor used to initialize a cache of
113    objects representing named constants for a particular L{_ConstantsContainer}
114    subclass.
[165]115
116    @since: Twisted 12.0.0.
[160]117    """
118    def __get__(self, oself, cls):
119        """
120        Trigger the initialization of the enumerants cache on C{cls} and then
121        return it.
122        """
123        cls._initializeEnumerants()
124        return cls._enumerants
125
126
127
128class _ConstantsContainer(object):
129    """
130    L{_ConstantsContainer} is a class with attributes used as symbolic
131    constants.  It is up to subclasses to specify what kind of constants are
132    allowed.
133
134    @cvar _constantType: Specified by a L{_ConstantsContainer} subclass to
135        specify the type of constants allowed by that subclass.
136
137    @cvar _enumerantsInitialized: A C{bool} tracking whether C{_enumerants} has
138        been initialized yet or not.
139
140    @cvar _enumerants: A C{dict} mapping the names of constants (eg
141        L{NamedConstant} instances) found in the class definition to those
142        instances.  This is initialized via the L{_EnumerantsInitializer}
143        descriptor the first time it is accessed.
[165]144
145    @since: Twisted 12.0.0.
[160]146    """
147    _constantType = None
148
149    _enumerantsInitialized = False
150    _enumerants = _EnumerantsInitializer()
151
152    def __new__(cls):
153        """
154        Classes representing constants containers are not intended to be
155        instantiated.
156
157        The class object itself is used directly.
158        """
159        raise TypeError("%s may not be instantiated." % (cls.__name__,))
160
161
162    def _initializeEnumerants(cls):
163        """
164        Find all of the L{NamedConstant} instances in the definition of C{cls},
165        initialize them with constant values, and build a mapping from their
166        names to them to attach to C{cls}.
167        """
168        if not cls._enumerantsInitialized:
169            constants = []
170            for (name, descriptor) in cls.__dict__.iteritems():
171                if isinstance(descriptor, cls._constantType):
172                    constants.append((descriptor._index, name, descriptor))
173            enumerants = {}
174            for (index, enumerant, descriptor) in constants:
175                value = cls._constantFactory(enumerant)
176                descriptor._realize(cls, enumerant, value)
177                enumerants[enumerant] = descriptor
178            # Replace the _enumerants descriptor with the result so future
179            # access will go directly to the values.  The _enumerantsInitialized
180            # flag is still necessary because NamedConstant.__get__ may also
181            # call this method.
182            cls._enumerants = enumerants
183            cls._enumerantsInitialized = True
184    _initializeEnumerants = classmethod(_initializeEnumerants)
185
186
187    def _constantFactory(cls, name):
188        """
189        Construct the value for a new constant to add to this container.
190
191        @param name: The name of the constant to create.
192
193        @return: L{NamedConstant} instances have no value apart from identity,
194            so return a meaningless dummy value.
195        """
196        return _unspecified
197    _constantFactory = classmethod(_constantFactory)
198
199
200    def lookupByName(cls, name):
201        """
202        Retrieve a constant by its name or raise a C{ValueError} if there is no
203        constant associated with that name.
204
205        @param name: A C{str} giving the name of one of the constants defined by
206            C{cls}.
207
208        @raise ValueError: If C{name} is not the name of one of the constants
209            defined by C{cls}.
210
211        @return: The L{NamedConstant} associated with C{name}.
212        """
213        if name in cls._enumerants:
214            return getattr(cls, name)
215        raise ValueError(name)
216    lookupByName = classmethod(lookupByName)
217
218
219    def iterconstants(cls):
220        """
221        Iteration over a L{Names} subclass results in all of the constants it
222        contains.
223
224        @return: an iterator the elements of which are the L{NamedConstant}
225            instances defined in the body of this L{Names} subclass.
226        """
227        constants = cls._enumerants.values()
228        constants.sort(key=lambda descriptor: descriptor._index)
229        return iter(constants)
230    iterconstants = classmethod(iterconstants)
231
232
233
234class NamedConstant(_Constant):
235    """
236    L{NamedConstant} defines an attribute to be a named constant within a
237    collection defined by a L{Names} subclass.
238
239    L{NamedConstant} is only for use in the definition of L{Names}
240    subclasses.  Do not instantiate L{NamedConstant} elsewhere and do not
241    subclass it.
[165]242
243    @since: Twisted 12.0.0.
[160]244    """
245
246
247
248class Names(_ConstantsContainer):
249    """
250    A L{Names} subclass contains constants which differ only in their names and
251    identities.
[165]252
253    @since: Twisted 12.0.0.
[160]254    """
255    _constantType = NamedConstant
256
257
258
259class ValueConstant(_Constant):
260    """
261    L{ValueConstant} defines an attribute to be a named constant within a
262    collection defined by a L{Values} subclass.
263
264    L{ValueConstant} is only for use in the definition of L{Values} subclasses.
265    Do not instantiate L{ValueConstant} elsewhere and do not subclass it.
[165]266
267    @since: Twisted 12.0.0.
[160]268    """
269    def __init__(self, value):
270        _Constant.__init__(self)
271        self.value = value
272
273
274
275class Values(_ConstantsContainer):
276    """
277    A L{Values} subclass contains constants which are associated with arbitrary
278    values.
[165]279
280    @since: Twisted 12.0.0.
[160]281    """
282    _constantType = ValueConstant
283
284    def lookupByValue(cls, value):
285        """
286        Retrieve a constant by its value or raise a C{ValueError} if there is no
287        constant associated with that value.
288
289        @param value: The value of one of the constants defined by C{cls}.
290
291        @raise ValueError: If C{value} is not the value of one of the constants
292            defined by C{cls}.
293
294        @return: The L{ValueConstant} associated with C{value}.
295        """
296        for constant in cls.iterconstants():
297            if constant.value == value:
298                return constant
299        raise ValueError(value)
300    lookupByValue = classmethod(lookupByValue)
Note: See TracBrowser for help on using the repository browser.