code: def canon_cred_wql(query: dict) -> dict:
      
  
      for k in [qk for qk in query]:  # copy: iteration alters query keys
          attr_match = re.match('attr::([^:]+)::(marker|value)$', k)
          if isinstance(query[k], dict):  # only subqueries are dicts: recurse
              query[k] = canon_cred_wql(query[k])
          if k == '$or':
              if not isinstance(query[k], list):
                  raise BadWalletQuery('Bad WQL; $or value must be a list in {}'.format(json.dumps(query)))
              query[k] = [canon_cred_wql(subq) for subq in query[k]]
          if attr_match:
              qkey = 'attr::{}::{}'.format(canon(attr_match.group(1)), canon(attr_match.group(2)))
              query[qkey] = query.pop(k)
              tag_value = query[qkey]
              if isinstance(tag_value, dict) and len(tag_value) == 1:
                  if '$in' in tag_value:
                      tag_value['$in'] = [raw(val) for val in tag_value.pop('$in')]
                  else:
                      wql_op = set(tag_value.keys()).pop()  # $neq, $gt, $gte, etc.
                      tag_value[wql_op] = raw(tag_value[wql_op])
              else:  # equality
                  query[qkey] = raw(query[qkey])
  
      return query
docs: Canonicalize WQL attribute marker and value keys for input to indy-sdk wallet credential filtration.
      Canonicalize comparison values to proper indy-sdk raw values as per raw().
  
      Raise BadWalletQuery for WQL mapping '$or' to non-list.
  
      :param query: WQL query
      :return: canonicalized WQL query dict