def parse_scopes(scope_list):
    """
    Parses scopes and filters in something akin to JSON style

    For instance, scope list ["users", "groups!group=foo", "servers!server=user/bar", "servers!server=user/baz"]
    would lead to scope model
    {
       "users":scope.ALL,
       "admin:users":{
          "user":[
             "alice"
          ]
       },
       "servers":{
          "server":[
             "user/bar",
             "user/baz"
          ]
       }
    }
    """
    parsed_scopes = {}
    for scope in scope_list:
        base_scope, _, filter_ = scope.partition('!')
        if not filter_:
            parsed_scopes[base_scope] = Scope.ALL
        elif base_scope not in parsed_scopes:
            parsed_scopes[base_scope] = {}

        if parsed_scopes[base_scope] != Scope.ALL:
            key, _, value = filter_.partition('=')
            if not value:
                raise ValueError(f"Empty string is not a valid filter: {scope}")
            if key not in parsed_scopes[base_scope]:
                parsed_scopes[base_scope][key] = {value}
            else:
                parsed_scopes[base_scope][key].add(value)
    # return immutable FrozenDict because the result is cached
    return FrozenDict(parsed_scopes)
Parses scopes and filters in something akin to JSON style

For instance, scope list ["users", "groups!group=foo", "servers!server=user/bar", "servers!server=user/baz"]
would lead to scope model
{
"users":scope.ALL,
"admin:users":{
"user":[
"alice"
]
},
"servers":{
"server":[
"user/bar",
"user/baz"
]
}
}
jupyterhub/scopes.py