Skip to content

Instantly share code, notes, and snippets.

@MayankFawkes
Last active September 19, 2021 03:03
Show Gist options
  • Select an option

  • Save MayankFawkes/6afc38ea16d15e6a8bacd2fa5bc61703 to your computer and use it in GitHub Desktop.

Select an option

Save MayankFawkes/6afc38ea16d15e6a8bacd2fa5bc61703 to your computer and use it in GitHub Desktop.
Permission based on bits
from typing import (
Any,
TypeVar,
ClassVar,
Dict,
Type,
Optional
)
FV = TypeVar('FV', bound='Flag')
P = TypeVar('P', bound='Permissions')
BP = TypeVar('BP', bound='BaseFlags')
class Flag:
def __init__(self, func: object):
self.flag = func(None)
self.__doc__ = func.__doc__
def __repr__(self):
return f'<flag_value flag={self.flag!r}>'
def __get__(self, instance:Optional[BP], owner: Type[BP]) -> Any:
if instance is None:
return self
return instance._has_flag(self.flag)
def __set__(self, instance:BP, value: bool) -> None:
instance._set_flag(self.flag, value)
def fill_with_flags(*, inverted: bool = False):
def decorator(cls:object):
# fmt: off
cls.VALID_FLAGS = {
name: value.flag
for name, value in cls.__dict__.items()
if isinstance(value, Flag)
}
# fmt: on
if inverted:
max_bits = max(cls.VALID_FLAGS.values()).bit_length()
cls.DEFAULT_VALUE = -1 + (2 ** max_bits)
else:
cls.DEFAULT_VALUE = 0
return cls
return decorator
class BaseFlags:
VALID_FLAGS: ClassVar[Dict[str, int]]
DEFAULT_VALUE: ClassVar[int]
value: int
def _has_flag(self, o: int) -> bool:
return (self.value & o) == o
def _set_flag(self, o: int, toggle: bool) -> None:
if toggle is True:
self.value |= o
elif toggle is False:
self.value &= ~o
else:
raise TypeError(f'Value to set for {self.__class__.__name__} must be a bool.')
@fill_with_flags()
class Permissions(BaseFlags):
def __init__(self, permission:int=0, **kwargs):
if not isinstance(permission, int):
raise TypeError(
f'Expected int parameter, received {permissions.__class__.__name__} instead.'
)
self.value = permission
for key, value in kwargs.items():
if key in self.VALID_FLAGS:
setattr(self, key, value)
else:
raise TypeError(f'{key!r} is not a valid permission name.')
@classmethod
def all(cls) -> P:
bits = max(cls.VALID_FLAGS.values()).bit_length()
value = (1 << bits) - 1
self = cls.__new__(cls)
self.value = value
return self
@Flag
def super_admin(self):
'''Super admin user'''
return 1 << 0
@Flag
def admin(self):
'''Admin user'''
return 1 << 1
@Flag
def user(self):
'''Normal user'''
return 1 << 2
'''
f = Permissions.all()
print(f.super_admin) #True
print(f.admin) #True
print(f.value) #7
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment