Changeset 160:33ef849a77d8 for wokkel/compat.py
- Timestamp:
- Jan 8, 2012, 9:26:02 AM (10 years ago)
- Branch:
- default
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
wokkel/compat.py
r96 r160 3 3 # Copyright (c) Twisted Matrix Laboratories. 4 4 # See LICENSE for details. 5 6 """ 7 Compatibility module to provide backwards compatibility with Twisted features. 8 """ 9 10 __all__ = ['BootstrapMixin', 'XmlStreamServerFactory', 'IQ', 11 'NamedConstant', 'ValueConstant', 'Names', 'Values'] 12 13 from itertools import count 5 14 6 15 from twisted.internet import protocol … … 116 125 # Patch the XmlStream instance so that it has a _callLater 117 126 self._xmlstream._callLater = reactor.callLater 127 128 129 130 _unspecified = object() 131 _constantOrder = count().next 132 133 134 class _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 182 class _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 198 class _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 302 class 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 314 class 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 323 class 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 337 class 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.