Parse `schema`, either a string or a file-like object, and
    return a :class:`MessageRegistry` with the loaded messages.

def parse(schema):
    """
    Parse `schema`, either a string or a file-like object, and
    return a :class:`MessageRegistry` with the loaded messages.
    """
    if not isinstance(schema, basestring):
        # assume it is file-like
        schema = schema.read()

    message = re.compile(r'^\(([^,]+),\s*(\d+)\):\s*$')
    field = re.compile(r'^-\s*([^:]+):\s+(.+?)\s*$')

    registry = MessageRegistry({})
    messages = registry.messages
    curr = None
    names = None
    for lineno, line in enumerate(schema.split('\n')):
        line = line.strip()
        if '#' in line:
            line = line[:line.index('#')]
        if line == '':
            continue

        f = field.match(line)
        if f:
            if curr is None:
                raise ParseError(
                    'field definition outside of message at line %d' % lineno)
            name = f.group(1)
            type = f.group(2)
            if name not in names:
                f = Field(curr, name, type)
                curr.fields.append(f)
                names.add(name)
                continue
            else:
                raise ParseError(
                    'duplicate field name "%s" at line %d' % (name, lineno))

        m = message.match(line)
        if m:
            # new message definition
            name, vers = m.group(1), int(m.group(2))
            if (name, vers) in messages:
                raise ParseError('Duplicate message (%s, %d)' % (name, vers))
            curr = messages[(name, vers)] = Message(registry, name, vers, [])
            names = set()
            continue

    for message in registry.messages.values():
        message.fields = tuple(message.fields)

    return registry