8

I've been breaking my head on this and I can't seem to find a solution to the problem. I use an enum to manage my access in a flask server. Short story I need the enum to return a default value if a non-existent enum value is queried. First I created a meta class for the enum:

class AuthAccessMeta(enum.EnumMeta):
def __getattr__(self, item):
    try:
        return super().__getattr__(item)
    except Exception as _:
        if self == AuthAccess and item not in ['_subs_tree']:
            Loggers.SYS.warn('Access {} doesn\'t exist, substituting with MISSING.'.format(item))
            return AuthAccess.MISSING
@unique
class AuthAccess(str, AutoName, metaclass=AuthAccessMeta):
    ...

You can see I exclude the _subs_tree attribute since neither EnumMeta or Enum has it. Only place I found this method is in the typing module. Then I type an argument with AuthAcess elsewhere and it gives me this weird error:

C:\Users\[USER]\AppData\Local\Programs\Python\Python36\python.exe -m src.main
[SYS][INFO][11:18:54]: Instance 76cb0042196d4a75b3794ce0b9c1590c is running on project 'local/project1'
Traceback (most recent call last):
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\[USER]\Documents\code\sollumcloudplatform\src\main.py", line 19, in <module>
    from src.procedures import create_app
  File "C:\Users\[USER]\Documents\code\sollumcloudplatform\src\procedures.py", line 191, in <module>
    def satisfy_role(role: {}, access_need: Tuple[List[AuthAccess]]) -> bool:
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\typing.py", line 626, in inner
    return func(*args, **kwds)
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\typing.py", line 1062, in __getitem__
    orig_bases=self.__orig_bases__)
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\typing.py", line 965, in __new__
    self.__tree_hash__ = hash(self._subs_tree()) if origin else hash((self.__name__,))
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\typing.py", line 1007, in _subs_tree
    tree_args = _subs_tree(self, tvars, args)
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\typing.py", line 548, in _subs_tree
    tree_args.append(_replace_arg(arg, tvars, args))
  File "C:\Users\[USER]\AppData\Local\Programs\Python\Python36\lib\typing.py", line 517, in _replace_arg
    return arg._subs_tree(tvars, args)
TypeError: 'NoneType' object is not callable

I've tried returning the method from the typing module but Python tells me it doesn't exists either. Am I using the meta class wrong ? Should I just remove the typing on the argument ?

1 Answer 1

8

Returning a default value can be done with the right version of enum.

The problem you are having now, I suspect, is because in your except branch you do not return a value, nor raise an exception, if the if fails -- so None is returned instead.

class AuthAccessMeta(enum.EnumMeta):
def __getattr__(self, item):
    try:
        return super().__getattr__(item)
    except Exception as _:
        if self == AuthAccess and item not in ['_subs_tree']:
            Loggers.SYS.warn('Access {} doesn\'t exist, substituting with MISSING.'.format(item))
            return AuthAccess.MISSING
        # need something here, like simply reraising the exception
        raise
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you ! To my understanding, unless you raise an exception it tries to find the implementation inside the argument class. Raising here tells typing to use its own default one. Very insightful !
@BinarSkugga: Sadly, I don't know enough about the typing module to be insightful, but standard Python is that everything returns something, and if you don't specify what that is, then the something is None.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.