@classmethod
  def semver(cls, rev):
    """Attempts to parse a Revision from a semantic version.

    See http://semver.org/ for the full specification.

    :API: public
    """
    def parse_extra(delimiter, value):
      if not value:
        return None, None
      else:
        components = value.split(delimiter, 1)
        return components[0], None if len(components) == 1 else components[1]

    def parse_patch(patch):
      patch, pre_release = parse_extra('-', patch)
      if pre_release:
        pre_release, build = parse_extra('+', pre_release)
      else:
        patch, build = parse_extra('+', patch)
      return patch, pre_release, build

    def parse_components(value):
      if not value:
        yield None
      else:
        for atom in value.split('.'):
          yield cls._parse_atom(atom)

    try:
      major, minor, patch = rev.split('.', 2)
      patch, pre_release, build = parse_patch(patch)
      components = [int(major), int(minor), int(patch)]
      components.extend(parse_components(pre_release))
      components.extend(parse_components(build))
      return cls(*components)
    except __HOLE__:
      raise cls.BadRevision("Failed to parse '{}' as a semantic version number".format(rev))
dataset/ETHPy150Open pantsbuild/pants/src/python/pants/base/revision.py/Revision.semver