def parse(cls, gvid, exception=True):
        if gvid == 'invalid':
            return cls.get_class('null')(0)
        if not bool(gvid):
            return None
        if not isinstance(gvid, six.string_types):
            raise TypeError("Can't parse; not a string. Got a '{}' ".format(type(gvid)))
        try:
            if not cls.sl:
                if six.PY3:
                    fn = cls.decode
                else:
                    fn = cls.decode.__func__
                sl = fn(gvid[0:cls.sl_width])
            else:
                sl = cls.sl
        except ValueError as e:
            if exception:
                raise ValueError("Failed to parse gvid '{}': {}".format(gvid, str(e)))
            else:
                return cls.get_class('null')(0)
        try:
            cls = cls.sl_map[sl]
        except KeyError:
            if exception:
                raise ValueError("Failed to parse gvid '{}': Unknown summary level '{}' ".format(gvid, sl))
            else:
                return cls.get_class('null')(0)
        m = cls.regex.match(gvid)
        if not m:
            raise ValueError("Failed to match '{}' to '{}' ".format(gvid, cls.regex_str))
        d = m.groupdict()
        if not d:
            return None
        if six.PY3:
            fn = cls.decode
        else:
            fn = cls.decode.__func__
        d = {k: fn(v) for k, v in d.items()}
        try:
            del d['sl']
        except KeyError:
            pass
        return cls(**d)