Last active
September 19, 2021 03:03
-
-
Save MayankFawkes/6afc38ea16d15e6a8bacd2fa5bc61703 to your computer and use it in GitHub Desktop.
Permission based on bits
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
| 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