code: def parse_sharded_file_spec(spec):
      """Parse a sharded file specification.
  
      Args:
        spec: str. The sharded file specification. A sharded file spec is one like
          'gs://some/file@200.txt'. Here, '@200' specifies the number of shards.
  
      Returns:
        basename: str. The basename for the files.
        num_shards: int >= 0. The number of shards.
        suffix: str. The suffix if there is one, or '' if not.
      Raises:
        ShardError: If the spec is not a valid sharded specification.
      """
      m = SHARD_SPEC_PATTERN.match(spec)
      if not m:
          raise ShardError(
              (
                  "The file specification {0} is not a sharded file "
                  "specification because it did not match the regex "
                  "{1}"
              ).format(spec, SHARD_SPEC_PATTERN.pattern)
          )
  
      # If there's a non-empty suffix, we need to prepend '.' so we get files like
      # foo@20.ext instead of foo@ext. The original C++ parser version has:
      # string ext = StrCat(suff.empty() ? "" : ".", suff);
      suffix = "." + m.group(4) if m.group(4) else ""
  
      return m.group(2), int(m.group(3)), suffix
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import math
  import os
  import re
  from typing import List, Tuple
  from etils import epath
  import six
label_desc: Use image node_id 1 for calling a global function with example usage: parse_sharded_file_spec(spec) and returns: m,  int,  suffix