Ignore:
Timestamp:
Jan 8, 2012, 9:26:02 AM (9 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Message:

Use symbolic constants instead of integers MUC status code.

Instead of using normal constant values for representing MUC status codes,
UserPresence now uses twisted.python.constants to define these. This
makes code better to understand and helps debugging.

If a user presence includes one or more status codes, they are stored in the
mucStatuses attribute, as an instance of Statuses. This replaces the
former statusCodes attribute.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wokkel/compat.py

    r96 r160  
    33# Copyright (c) Twisted Matrix Laboratories.
    44# See LICENSE for details.
     5
     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
    514
    615from twisted.internet import protocol
     
    116125            # Patch the XmlStream instance so that it has a _callLater
    117126            self._xmlstream._callLater = reactor.callLater
     127
     128
     129
     130_unspecified = object()
     131_constantOrder = count().next
     132
     133
     134class _Constant(object):
     135    """
     136    @ivar _index: A C{int} allocated from a shared counter in order to keep
     137        track of the order in which L{_Constant}s are instantiated.
     138
     139    @ivar name: A C{str} giving the name of this constant; only set once the
     140        constant is initialized by L{_ConstantsContainer}.
     141
     142    @ivar _container: The L{_ConstantsContainer} subclass this constant belongs
     143        to; only set once the constant is initialized by that subclass.
     144    """
     145    def __init__(self):
     146        self._index = _constantOrder()
     147
     148
     149    def __get__(self, oself, cls):
     150        """
     151        Ensure this constant has been initialized before returning it.
     152        """
     153        cls._initializeEnumerants()
     154        return self
     155
     156
     157    def __repr__(self):
     158        """
     159        Return text identifying both which constant this is and which collection
     160        it belongs to.
     161        """
     162        return "<%s=%s>" % (self._container.__name__, self.name)
     163
     164
     165    def _realize(self, container, name, value):
     166        """
     167        Complete the initialization of this L{_Constant}.
     168
     169        @param container: The L{_ConstantsContainer} subclass this constant is
     170            part of.
     171
     172        @param name: The name of this constant in its container.
     173
     174        @param value: The value of this constant; not used, as named constants
     175            have no value apart from their identity.
     176        """
     177        self._container = container
     178        self.name = name
     179
     180
     181
     182class _EnumerantsInitializer(object):
     183    """
     184    L{_EnumerantsInitializer} is a descriptor used to initialize a cache of
     185    objects representing named constants for a particular L{_ConstantsContainer}
     186    subclass.
     187    """
     188    def __get__(self, oself, cls):
     189        """
     190        Trigger the initialization of the enumerants cache on C{cls} and then
     191        return it.
     192        """
     193        cls._initializeEnumerants()
     194        return cls._enumerants
     195
     196
     197
     198class _ConstantsContainer(object):
     199    """
     200    L{_ConstantsContainer} is a class with attributes used as symbolic
     201    constants.  It is up to subclasses to specify what kind of constants are
     202    allowed.
     203
     204    @cvar _constantType: Specified by a L{_ConstantsContainer} subclass to
     205        specify the type of constants allowed by that subclass.
     206
     207    @cvar _enumerantsInitialized: A C{bool} tracking whether C{_enumerants} has
     208        been initialized yet or not.
     209
     210    @cvar _enumerants: A C{dict} mapping the names of constants (eg
     211        L{NamedConstant} instances) found in the class definition to those
     212        instances.  This is initialized via the L{_EnumerantsInitializer}
     213        descriptor the first time it is accessed.
     214    """
     215    _constantType = None
     216
     217    _enumerantsInitialized = False
     218    _enumerants = _EnumerantsInitializer()
     219
     220    def __new__(cls):
     221        """
     222        Classes representing constants containers are not intended to be
     223        instantiated.
     224
     225        The class object itself is used directly.
     226        """
     227        raise TypeError("%s may not be instantiated." % (cls.__name__,))
     228
     229
     230    def _initializeEnumerants(cls):
     231        """
     232        Find all of the L{NamedConstant} instances in the definition of C{cls},
     233        initialize them with constant values, and build a mapping from their
     234        names to them to attach to C{cls}.
     235        """
     236        if not cls._enumerantsInitialized:
     237            constants = []
     238            for (name, descriptor) in cls.__dict__.iteritems():
     239                if isinstance(descriptor, cls._constantType):
     240                    constants.append((descriptor._index, name, descriptor))
     241            enumerants = {}
     242            for (index, enumerant, descriptor) in constants:
     243                value = cls._constantFactory(enumerant)
     244                descriptor._realize(cls, enumerant, value)
     245                enumerants[enumerant] = descriptor
     246            # Replace the _enumerants descriptor with the result so future
     247            # access will go directly to the values.  The _enumerantsInitialized
     248            # flag is still necessary because NamedConstant.__get__ may also
     249            # call this method.
     250            cls._enumerants = enumerants
     251            cls._enumerantsInitialized = True
     252    _initializeEnumerants = classmethod(_initializeEnumerants)
     253
     254
     255    def _constantFactory(cls, name):
     256        """
     257        Construct the value for a new constant to add to this container.
     258
     259        @param name: The name of the constant to create.
     260
     261        @return: L{NamedConstant} instances have no value apart from identity,
     262            so return a meaningless dummy value.
     263        """
     264        return _unspecified
     265    _constantFactory = classmethod(_constantFactory)
     266
     267
     268    def lookupByName(cls, name):
     269        """
     270        Retrieve a constant by its name or raise a C{ValueError} if there is no
     271        constant associated with that name.
     272
     273        @param name: A C{str} giving the name of one of the constants defined by
     274            C{cls}.
     275
     276        @raise ValueError: If C{name} is not the name of one of the constants
     277            defined by C{cls}.
     278
     279        @return: The L{NamedConstant} associated with C{name}.
     280        """
     281        if name in cls._enumerants:
     282            return getattr(cls, name)
     283        raise ValueError(name)
     284    lookupByName = classmethod(lookupByName)
     285
     286
     287    def iterconstants(cls):
     288        """
     289        Iteration over a L{Names} subclass results in all of the constants it
     290        contains.
     291
     292        @return: an iterator the elements of which are the L{NamedConstant}
     293            instances defined in the body of this L{Names} subclass.
     294        """
     295        constants = cls._enumerants.values()
     296        constants.sort(key=lambda descriptor: descriptor._index)
     297        return iter(constants)
     298    iterconstants = classmethod(iterconstants)
     299
     300
     301
     302class NamedConstant(_Constant):
     303    """
     304    L{NamedConstant} defines an attribute to be a named constant within a
     305    collection defined by a L{Names} subclass.
     306
     307    L{NamedConstant} is only for use in the definition of L{Names}
     308    subclasses.  Do not instantiate L{NamedConstant} elsewhere and do not
     309    subclass it.
     310    """
     311
     312
     313
     314class Names(_ConstantsContainer):
     315    """
     316    A L{Names} subclass contains constants which differ only in their names and
     317    identities.
     318    """
     319    _constantType = NamedConstant
     320
     321
     322
     323class ValueConstant(_Constant):
     324    """
     325    L{ValueConstant} defines an attribute to be a named constant within a
     326    collection defined by a L{Values} subclass.
     327
     328    L{ValueConstant} is only for use in the definition of L{Values} subclasses.
     329    Do not instantiate L{ValueConstant} elsewhere and do not subclass it.
     330    """
     331    def __init__(self, value):
     332        _Constant.__init__(self)
     333        self.value = value
     334
     335
     336
     337class Values(_ConstantsContainer):
     338    """
     339    A L{Values} subclass contains constants which are associated with arbitrary
     340    values.
     341    """
     342    _constantType = ValueConstant
     343
     344    def lookupByValue(cls, value):
     345        """
     346        Retrieve a constant by its value or raise a C{ValueError} if there is no
     347        constant associated with that value.
     348
     349        @param value: The value of one of the constants defined by C{cls}.
     350
     351        @raise ValueError: If C{value} is not the value of one of the constants
     352            defined by C{cls}.
     353
     354        @return: The L{ValueConstant} associated with C{value}.
     355        """
     356        for constant in cls.iterconstants():
     357            if constant.value == value:
     358                return constant
     359        raise ValueError(value)
     360    lookupByValue = classmethod(lookupByValue)
Note: See TracChangeset for help on using the changeset viewer.