Skip to content

Instantly share code, notes, and snippets.

@apinsard
Created May 31, 2015 17:50
Show Gist options
  • Save apinsard/676742d26666783d33f8 to your computer and use it in GitHub Desktop.
Save apinsard/676742d26666783d33f8 to your computer and use it in GitHub Desktop.
sample.py
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