Created
May 31, 2015 17:50
-
-
Save apinsard/676742d26666783d33f8 to your computer and use it in GitHub Desktop.
sample.py
This file contains hidden or 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
class FlagsSet(object): | |
"""A bit field wrapper. | |
See: http://en.wikipedia.org/wiki/Bit_field if you don't know what a | |
bit field is. | |
""" | |
def __init__(self, flags=0, max_nb_flags=64): | |
"""Create a flags set with the given flags already set.""" | |
assert type(flags) is int | |
self._flags = flags | |
self._max_nb_flags = max_nb_flags | |
def set(self, flags): | |
"""Set all given flags.""" | |
self._flags |= flags | |
def unset(self, flags): | |
"""Unset all given flags.""" | |
self._flags &= ~flags | |
def is_set(self, flags): | |
"""Return True if at least one of the given flags is set.""" | |
return (self._flags & flags) != 0 | |
def __getitem__(self, flag_id): | |
"""Return True if the `flag_id`th flag is set. | |
Please not that IDs start at 0. | |
""" | |
if not 0 <= flag_id < self._max_nb_flags: | |
raise IndexError | |
return self.is_set(2**flag_id) | |
def __setitem__(self, flag_id, value): | |
"""Set the `flag_id`th flag. | |
Please not that IDs start at 0. | |
""" | |
if not 0 <= flag_id < self._max_nb_flags: | |
raise IndexError | |
if value: | |
self.set(2**flag_id) | |
else: | |
self.unset(2**flag_id) | |
def __delitem__(self, flag_id): | |
"""Unset the `flag_id`th flag. | |
Please not that IDs start at 0. | |
""" | |
if 0 <= flag_id < self._max_nb_flags: | |
raise IndexError | |
self.unset(2**flag_id) | |
def __iadd__(self, flag_ids): | |
"""Set multiple flag IDs in a row.""" | |
self.set(sum(2**i for i in flag_ids)) | |
def __isub__(self, flag_ids): | |
"""Unset multiple flag IDs in a row.""" | |
self.unset(sum(2**i for i in flag_ids)) | |
def __int__(self): | |
"""Return the actual value of the bit field as int.""" | |
return self._flags | |
def __iter__(self): | |
self.it_val = 0 | |
return self | |
def __next__(self): | |
while self.it_val < self._max_nb_flags: | |
self.it_val += 1 | |
if self[self.it_val-1]: | |
return self.it_val-1 | |
raise StopIteration | |
class FlagsField(models.Field, metaclass=models.SubfieldBase): | |
"""Up to 64 flags stored as a big integer.""" | |
description = _("Un jeu de 64 flags sous forme d'un entier.") | |
def __init__(self, *args, **kwargs): | |
self.flag_names = {} | |
if 'choices' in kwargs: | |
self.flag_names = dict(kwargs['choices']) | |
super(FlagsField, self).__init__(*args, **kwargs) | |
def get_internal_type(self): | |
return 'BigIntegerField' | |
def to_python(self, value): | |
if value is None or isinstance(value, FlagsSet): | |
return value | |
elif isinstance(value, list): | |
return FlagsSet(sum(2**int(x) for x in value)) | |
else: | |
return FlagsSet(int(value)) | |
def get_prep_value(self, value): | |
if value is None: | |
return value | |
else: | |
return int(value) | |
def formfield(self, **kwargs): | |
defaults = {'choices_form_class': FlagsFormField} | |
defaults.update(kwargs) | |
if self.flag_names: | |
defaults['choices'] = self.flag_names.items() | |
return super(FlagsField, self).formfield(**defaults) | |
class FlagsFormField(fields.TypedMultipleChoiceField): | |
widget = widgets.CheckboxSelectMultiple | |
def __init__(self, *args, **kwargs): | |
kwargs['coerce'] = int | |
kwargs['empty_value'] = [] | |
super(FlagsFormField, self).__init__(*args, **kwargs) | |
def prepare_value(self, value): | |
if isinstance(value, FlagsSet): | |
return list(value) | |
elif isinstance(value, list): | |
return value | |
else: | |
return [] | |
def to_python(self, value): | |
print("to_python %r" % value) | |
if value is None or isinstance(value, FlagsSet): | |
return value | |
elif isinstance(value, list): | |
return FlagsSet(sum(2**int(x) for x in value)) | |
else: | |
return FlagsSet(int(value)) | |
def clean(self, value): | |
value = self.to_python(value) | |
self.validate(value) | |
self.run_validators(value) | |
return value | |
def validate(self, value): | |
print("validate %r" % value) | |
if self.required and not value: | |
raise ValidationError(self.error_messages['required'], | |
code='required') | |
for val in value: | |
print("val %r" % val) | |
if not self.valid_value(val): | |
print("not valid value") | |
raise ValidationError( | |
"C'est nul", | |
code='invalid_choice', | |
params={'value': val}, | |
) | |
def valid_value(self, value): | |
print("valid_value %r" % value) | |
print(dict(self.choices).keys()) | |
return value in dict(self.choices).keys() | |
#def _coerce(self, value): | |
# print("_coerce %r" % value) | |
# if value == self.empty_value or value in self.empty_values: | |
# return self.empty_value | |
# new_value = [] | |
# for choice in value: | |
# print("\tchoice: %r" % choice) | |
# try: | |
# new_value.append(self.coerce(choice)) | |
# except (ValueError, TypeError, ValidationError): | |
# raise ValidationError( | |
# self.error_messages['invalid_choice'], | |
# code='invalid_choice', | |
# params={'value': choice}, | |
# ) | |
# return new_value |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment