"""
@author Thomas Lehmann
@file enum.py
@note The singleton example is taken from:
http://www.python.org/dev/peps/pep-0318/#examples
@note I don't use TAB's and indentation is 4.
@note epydoc wrongly interprets the class as a function.
Probably because of the decorator (without it works).
"""
__docformat__ = "javadoc en"
import inspect
import unittest
def singleton(theClass):
""" decorator for a class to make a singleton out of it """
classInstances = {}
def getInstance():
""" creating or just return the one and only class instance """
if theClass not in classInstances:
classInstances[theClass] = theClass()
return classInstances[theClass]
return getInstance
@singleton
class Enum(object):
""" class for providing enum functionality. An enum in C++ usually looks
like this: enum { A, B, C }; and the results are 0, 1 and 2 for A, B and C.
We provide similar functionality means auto incrementing of values for constants
added to an enum...
>>> TOP = enum("direction") # or enum(Direction) when Direction is a class
>>> LEFT = enum("direction") # or enum(Direction) when Direction is a class
>>> RIGHT = enum("direction") # or enum(Direction) when Direction is a class
>>> BOTTOM = enum("direction") # or enum(Direction) when Direction is a class
>>> assert TOP < LEFT < RIGHT < BOTTOM
- You still can assign an individual value.
- You can place constants inside the class (if you like) -> Direction.TOP
- Same to C++: you have to pay attention where new constants are added. When
you insert it inbetween then you will 'move' the other values.
"""
def __init__(self):
""" registered enums """
self.contexts = {}
def getNextId(self, context):
""" providing next id >= 0 on each call per context
@param context is a string
@return is an integer value being unique for given context
"""
if not context in self.contexts:
self.contexts[context] = -1
self.contexts[context] += 1
return self.contexts[context]
def enum(context):
""" wrapper for calling the singleton. Documentation is placed
at the class Enum.
@param context can be a string or a class
@return is an integer value being unique for given context
"""
if inspect.isclass(context):
return Enum().getNextId(context.__name__)
return Enum().getNextId(context)
class EnumTestCase(unittest.TestCase):
""" testing of class Enum """
def testSingleton(self):
""" testing the singleton mechanism """
instanceA = Enum()
instanceB = Enum()
self.assertEqual(instanceA, instanceB)
def testGetNextId(self):
""" example of creating two constants """
instance = Enum()
HORIZONTAL = instance.getNextId("orientation")
VERTICAL = instance.getNextId("orientation")
self.assertTrue(HORIZONTAL < VERTICAL)
def testEnumFunctionWithStringContext(self):
""" example of creating four constants with string as context """
class Direction:
TOP = enum("direction")
LEFT = enum("direction")
RIGHT = enum("direction")
BOTTOM = enum("direction")
self.assertTrue(Direction.TOP < Direction.LEFT < Direction.RIGHT < Direction.BOTTOM)
def testEnumFunctionWithClassContext(self):
""" example of creating four constants with a class as context
@note I have tried to move the enum code to the class but this
seems not to work """
class Vector:
def __init__(self):
self.vector = [0, 0]
X = enum(Vector)
Y = enum(Vector)
self.assertTrue(X < Y)
self.assertEqual(X, 0)
self.assertEqual(Y, 1)
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromTestCase(EnumTestCase)
unittest.TextTestRunner(verbosity=3).run(suite)