revamp how Flags works

instead of pulling a hack and injecting from_int() in `__init_subclass__`, we
just make an actual function, and cache the wanted attributes in the subclass
at its creation

this fixes statis analyzers claiming from_int() doesn't exist on
subclasses, for good reason, as they'd be turing-complete to do so, lol

 - auth: fix some mypy issues about reusing same variable
This commit is contained in:
Luna 2019-10-25 10:00:35 -03:00
parent 7278c15d9c
commit 420646e76f
2 changed files with 27 additions and 33 deletions

View File

@ -56,20 +56,20 @@ async def raw_token_check(token: str, db=None) -> int:
# just try by fragments instead of # just try by fragments instead of
# unpacking # unpacking
fragments = token.split(".") fragments = token.split(".")
user_id = fragments[0] user_id_str = fragments[0]
try: try:
user_id = base64.b64decode(user_id.encode()) user_id_decoded = base64.b64decode(user_id_str.encode())
user_id = int(user_id) user_id = int(user_id_decoded)
except (ValueError, binascii.Error): except (ValueError, binascii.Error):
raise Unauthorized("Invalid user ID type") raise Unauthorized("Invalid user ID type")
pwd_hash = await db.fetchval( pwd_hash = await db.fetchval(
""" """
SELECT password_hash SELECT password_hash
FROM users FROM users
WHERE id = $1 WHERE id = $1
""", """,
user_id, user_id,
) )
@ -88,10 +88,10 @@ async def raw_token_check(token: str, db=None) -> int:
# with people leaving their clients open forever) # with people leaving their clients open forever)
await db.execute( await db.execute(
""" """
UPDATE users UPDATE users
SET last_session = (now() at time zone 'utc') SET last_session = (now() at time zone 'utc')
WHERE id = $1 WHERE id = $1
""", """,
user_id, user_id,
) )
@ -128,10 +128,10 @@ async def admin_check() -> int:
flags = await app.db.fetchval( flags = await app.db.fetchval(
""" """
SELECT flags SELECT flags
FROM users FROM users
WHERE id = $1 WHERE id = $1
""", """,
user_id, user_id,
) )

View File

@ -54,27 +54,21 @@ class Flags:
""" """
def __init_subclass__(cls, **_kwargs): def __init_subclass__(cls, **_kwargs):
attrs = inspect.getmembers(cls, lambda x: not inspect.isroutine(x)) # get only the members that represent a field
cls._attrs = inspect.getmembers(cls, lambda x: isinstance(x, int))
def _make_int(value): @classmethod
res = Flags() def from_int(cls, value: int):
"""Create a Flags from a given int value."""
res = Flags()
setattr(res, "value", value)
setattr(res, "value", value) for attr, val in cls._attrs:
has_attr = (value & val) == val
# set attributes dynamically
setattr(res, f"is_{attr}", has_attr)
for attr, val in attrs: return res
# get only the ones that represent a field in the
# number's bits
if not isinstance(val, int):
continue
has_attr = (value & val) == val
# set each attribute
setattr(res, f"is_{attr}", has_attr)
return res
cls.from_int = _make_int
class ChannelType(EasyEnum): class ChannelType(EasyEnum):