Created
June 17, 2014 10:49
-
-
Save gjbagrowski/91add6f9ddf84fccd830 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
from __future__ import absolute_import, print_function, unicode_literals | |
from six import string_types, integer_types | |
from itertools import chain | |
class EnumMetaclass(type): | |
"""Metaclass for enumerations. | |
You must define the values using UPPERCASE names and having value in one of | |
allowed_types. | |
Generates: | |
cls.names - reverse dictionary mapping value to name | |
cls.pairs - sorted list of (id, name) pairs suitable for model choices | |
cls.values - list of values defined by the enumeration | |
cls.trans_name - reverse dictionary mapping value to string ready for | |
translation | |
cls.display_names - reverse dictionary mapping value to string ready to | |
display as a human-readable text | |
cls.display_pairs - sorted list of (id, display_name) pairs suitable for | |
model choices | |
Example: | |
class X(object): | |
__metaclass__ = EnumMetaclass | |
A = 1 | |
B = 2 | |
CCC = 3 | |
>>> X.names | |
{1: 'A', 2: 'B', 3: 'CCC'} | |
>>> X.values | |
[1, 2, 3] | |
>>> X.pairs | |
[(1, 'A'), (2, 'B'), (3, 'CCC')] | |
>>> X.trans_names | |
{1: 'X.A', 2: 'X.B', 3: 'X.CCC'} | |
>>> X.display_names | |
[(1, 'A'), (2, 'B'), (3, 'Ccc')] | |
>>> X.display_pairs | |
[(1, 'A'), (2, 'B'), (3, 'Ccc')] | |
""" | |
allowed_types = tuple(chain(string_types, integer_types, [float])) | |
def __new__(cls, name, bases, attrs): | |
def make_display_name(name): | |
return name.replace('_', ' ').capitalize() | |
def make_trans_name(attrname): | |
return "{}.{}".format(name, attrname) | |
def is_enum_val(item): | |
key, val = item | |
return ( | |
key.isupper() and | |
not key.startswith('__') and | |
isinstance(val, cls.allowed_types) | |
) | |
def map_name(fun, items): | |
return dict([(item[0], fun(item[1])) for item in items.items()]) | |
attrs['names'] = names = dict([ | |
i[::-1] for i in filter(is_enum_val, attrs.items()) | |
]) | |
attrs['values'] = sorted(names.keys()) | |
attrs['trans_names'] = map_name(make_trans_name, names) | |
attrs['display_names'] = map_name(make_display_name, names) | |
attrs['pairs'] = sorted(names.items()) | |
attrs['display_pairs'] = sorted(attrs['display_names'].items()) | |
return type.__new__(cls, name, bases, attrs) | |
class Enum(object): | |
__metaclass = EnumMetaclass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment