Spaces:
Sleeping
Sleeping
File size: 5,370 Bytes
ffaa9fc |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
from ._common import *
__all__ = [
'NamedConstant', 'Constant',
]
# NamedConstant
NamedConstant = None
class NamedConstantDict(dict):
"""Track constant order and ensure names are not reused.
NamedConstantMeta will use the names found in self._names as the
Constant names.
"""
def __init__(self):
super(NamedConstantDict, self).__init__()
self._names = []
def __setitem__(self, key, value):
"""Changes anything not dundered or not a constant descriptor.
If an constant name is used twice, an error is raised; duplicate
values are not checked for.
Single underscore (sunder) names are reserved.
"""
if is_sunder(key):
raise ValueError(
'_sunder_ names, such as %r, are reserved for future NamedConstant use'
% (key, )
)
elif is_dunder(key):
pass
elif key in self._names:
# overwriting an existing constant?
raise TypeError('attempt to reuse name: %r' % (key, ))
elif isinstance(value, constant) or not is_descriptor(value):
if key in self:
# overwriting a descriptor?
raise TypeError('%s already defined as: %r' % (key, self[key]))
self._names.append(key)
super(NamedConstantDict, self).__setitem__(key, value)
class NamedConstantMeta(type):
"""
Block attempts to reassign NamedConstant attributes.
"""
@classmethod
def __prepare__(metacls, cls, bases, **kwds):
return NamedConstantDict()
def __new__(metacls, cls, bases, clsdict):
if type(clsdict) is dict:
original_dict = clsdict
clsdict = NamedConstantDict()
for k, v in original_dict.items():
clsdict[k] = v
newdict = {}
constants = {}
for name, obj in clsdict.items():
if name in clsdict._names:
constants[name] = obj
continue
elif isinstance(obj, nonmember):
obj = obj.value
newdict[name] = obj
newcls = super(NamedConstantMeta, metacls).__new__(metacls, cls, bases, newdict)
newcls._named_constant_cache_ = {}
newcls._members_ = {}
for name, obj in constants.items():
new_k = newcls.__new__(newcls, name, obj)
newcls._members_[name] = new_k
return newcls
def __bool__(cls):
return True
def __delattr__(cls, attr):
cur_obj = cls.__dict__.get(attr)
if NamedConstant is not None and isinstance(cur_obj, NamedConstant):
raise AttributeError('cannot delete constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_))
super(NamedConstantMeta, cls).__delattr__(attr)
def __iter__(cls):
return (k for k in cls._members_.values())
def __reversed__(cls):
return (k for k in reversed(cls._members_.values()))
def __len__(cls):
return len(cls._members_)
__nonzero__ = __bool__
def __setattr__(cls, name, value):
"""Block attempts to reassign NamedConstants.
"""
cur_obj = cls.__dict__.get(name)
if NamedConstant is not None and isinstance(cur_obj, NamedConstant):
raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_))
super(NamedConstantMeta, cls).__setattr__(name, value)
constant_dict = _Addendum(
dict=NamedConstantMeta.__prepare__('NamedConstant', (object, )),
doc="NamedConstants protection.\n\n Derive from this class to lock NamedConstants.\n\n",
ns=globals(),
)
@constant_dict
def __new__(cls, name, value=None, doc=None):
if value is None:
# lookup, name is value
value = name
for name, obj in cls.__dict__.items():
if isinstance(obj, cls) and obj._value_ == value:
return obj
else:
raise ValueError('%r does not exist in %r' % (value, cls.__name__))
cur_obj = cls.__dict__.get(name)
if isinstance(cur_obj, NamedConstant):
raise AttributeError('cannot rebind constant <%s.%s>' % (cur_obj.__class__.__name__, cur_obj._name_))
elif isinstance(value, constant):
doc = doc or value.__doc__
value = value.value
metacls = cls.__class__
if isinstance(value, NamedConstant):
# constants from other classes are reduced to their actual value
value = value._value_
actual_type = type(value)
value_type = cls._named_constant_cache_.get(actual_type)
if value_type is None:
value_type = type(cls.__name__, (cls, type(value)), {})
cls._named_constant_cache_[type(value)] = value_type
obj = actual_type.__new__(value_type, value)
obj._name_ = name
obj._value_ = value
obj.__doc__ = doc
cls._members_[name] = obj
metacls.__setattr__(cls, name, obj)
return obj
@constant_dict
def __repr__(self):
return "<%s.%s: %r>" % (
self.__class__.__name__, self._name_, self._value_)
@constant_dict
def __reduce_ex__(self, proto):
return getattr, (self.__class__, self._name_)
NamedConstant = NamedConstantMeta('NamedConstant', (object, ), constant_dict.resolve())
Constant = NamedConstant
del constant_dict
|