nodes: 0, module; 1, function_definition; 2, function_name:group_files; 3, parameters; 4, block; 5, identifier:files_to_sort; 6, default_parameter; 7, default_parameter; 8, default_parameter; 9, default_parameter; 10, default_parameter; 11, expression_statement; 12, comment:# FUTURE: Find the best reader for each filename using `find_files_and_readers`; 13, if_statement; 14, comment:# FUTURE: Handle multiple readers; 15, expression_statement; 16, expression_statement; 17, expression_statement; 18, try_statement; 19, if_statement; 20, expression_statement; 21, for_statement; 22, expression_statement; 23, expression_statement; 24, expression_statement; 25, for_statement; 26, expression_statement; 27, comment:# passable to Scene as 'filenames'; 28, return_statement; 29, identifier:reader; 30, None; 31, identifier:time_threshold; 32, integer:10; 33, identifier:group_keys; 34, None; 35, identifier:ppp_config_dir; 36, None; 37, identifier:reader_kwargs; 38, None; 39, comment:"""Group series of files by file pattern information.
  
      By default this will group files by their filename ``start_time``
      assuming it exists in the pattern. By passing the individual
      dictionaries returned by this function to the Scene classes'
      ``filenames``, a series `Scene` objects can be easily created.
  
      .. versionadded:: 0.12
  
      Args:
          files_to_sort (iterable): File paths to sort in to group
          reader (str): Reader whose file patterns should be used to sort files.
              This
          time_threshold (int): Number of seconds used to consider time elements
              in a group as being equal. For example, if the 'start_time' item
              is used to group files then any time within `time_threshold`
              seconds of the first file's 'start_time' will be seen as occurring
              at the same time.
          group_keys (list or tuple): File pattern information to use to group
              files. Keys are sorted in order and only the first key is used when
              comparing datetime elements with `time_threshold` (see above). This
              means it is recommended that datetime values should only come from
              the first key in ``group_keys``. Otherwise, there is a good chance
              that files will not be grouped properly (datetimes being barely
              unequal). Defaults to a reader's ``group_keys`` configuration (set
              in YAML), otherwise ``('start_time',)``.
          ppp_config_dir (str): Root usser configuration directory for Satpy.
              This will be deprecated in the future, but is here for consistency
              with other Satpy features.
          reader_kwargs (dict): Additional keyword arguments to pass to reader
              creation.
  
      Returns:
          List of dictionaries mapping 'reader' to a list of filenames.
          Each of these dictionaries can be passed as ``filenames`` to
          a `Scene` object.
  
      """; 40, comparison_operator:reader is None; 41, block; 42, elif_clause; 43, assignment; 44, assignment; 45, assignment; 46, block; 47, except_clause; 48, comparison_operator:group_keys is None; 49, block; 50, assignment; 51, pattern_list; 52, call; 53, block; 54, assignment; 55, assignment; 56, assignment; 57, pattern_list; 58, call; 59, comment:# use first element of key as time identifier (if datetime type); 60, block; 61, assignment; 62, list_comprehension; 63, identifier:reader; 64, None; 65, raise_statement; 66, not_operator; 67, block; 68, identifier:reader; 69, subscript; 70, identifier:reader_configs; 71, subscript; 72, identifier:reader_kwargs; 73, boolean_operator; 74, expression_statement; 75, as_pattern; 76, block; 77, identifier:group_keys; 78, None; 79, expression_statement; 80, identifier:file_keys; 81, list; 82, identifier:filetype; 83, identifier:filetype_info; 84, attribute; 85, argument_list; 86, for_statement; 87, identifier:prev_key; 88, None; 89, identifier:threshold; 90, call; 91, identifier:file_groups; 92, dictionary; 93, identifier:gk; 94, identifier:f; 95, identifier:sorted; 96, argument_list; 97, if_statement; 98, comment:# compare keys for those that are found for both the key and; 99, comment:# this is a generator and is not computed until the if statement below; 100, comment:# when we know that `prev_key` is not None; 101, expression_statement; 102, comment:# if this is a new group based on the first element; 103, if_statement; 104, identifier:sorted_group_keys; 105, call; 106, dictionary; 107, for_in_clause; 108, call; 109, call; 110, expression_statement; 111, identifier:reader; 112, integer:0; 113, call; 114, integer:0; 115, identifier:reader_kwargs; 116, dictionary; 117, assignment; 118, tuple; 119, as_pattern_target; 120, expression_statement; 121, expression_statement; 122, comment:# if reader and (isinstance(reader, str) or len(reader) == 1):; 123, comment:#     # if it is a single reader then give a more usable error; 124, comment:#     raise; 125, raise_statement; 126, assignment; 127, identifier:reader_instance; 128, identifier:sorted_filetype_items; 129, pattern_list; 130, call; 131, block; 132, identifier:timedelta; 133, argument_list; 134, identifier:file_keys; 135, comparison_operator:prev_key is None; 136, block; 137, elif_clause; 138, else_clause; 139, assignment; 140, boolean_operator; 141, block; 142, else_clause; 143, identifier:sorted; 144, argument_list; 145, pair; 146, identifier:group_key; 147, identifier:sorted_group_keys; 148, identifier:ValueError; 149, argument_list; 150, identifier:isinstance; 151, argument_list; 152, assignment; 153, identifier:list; 154, argument_list; 155, identifier:reader_instance; 156, call; 157, identifier:KeyError; 158, identifier:IOError; 159, attribute; 160, identifier:err; 161, call; 162, call; 163, identifier:group_keys; 164, call; 165, identifier:f; 166, identifier:file_info; 167, attribute; 168, argument_list; 169, expression_statement; 170, expression_statement; 171, keyword_argument; 172, identifier:prev_key; 173, None; 174, expression_statement; 175, expression_statement; 176, call; 177, comment:# datetimes within threshold difference are "the same time"; 178, block; 179, block; 180, identifier:vals_not_equal; 181, generator_expression; 182, identifier:is_new_group; 183, call; 184, expression_statement; 185, expression_statement; 186, block; 187, identifier:file_groups; 188, identifier:reader; 189, subscript; 190, string:"'reader' keyword argument is required."; 191, identifier:reader; 192, tuple; 193, identifier:reader; 194, list; 195, call; 196, identifier:load_reader; 197, argument_list; 198, identifier:yaml; 199, identifier:YAMLError; 200, attribute; 201, argument_list; 202, attribute; 203, argument_list; 204, attribute; 205, argument_list; 206, identifier:reader_instance; 207, identifier:filename_items_for_filetype; 208, identifier:files_to_sort; 209, identifier:filetype_info; 210, assignment; 211, call; 212, identifier:seconds; 213, identifier:time_threshold; 214, assignment; 215, assignment; 216, identifier:isinstance; 217, argument_list; 218, expression_statement; 219, expression_statement; 220, comparison_operator:this_val != prev_val; 221, for_in_clause; 222, if_clause; 223, identifier:any; 224, argument_list; 225, assignment; 226, assignment; 227, expression_statement; 228, identifier:file_groups; 229, identifier:group_key; 230, identifier:list; 231, identifier:tuple; 232, identifier:reader; 233, identifier:configs_for_reader; 234, argument_list; 235, identifier:reader_configs; 236, dictionary_splat; 237, identifier:LOG; 238, identifier:info; 239, string; 240, call; 241, identifier:LOG; 242, identifier:debug; 243, call; 244, attribute; 245, identifier:get; 246, string; 247, tuple; 248, identifier:group_key; 249, call; 250, attribute; 251, argument_list; 252, identifier:is_new_group; 253, True; 254, identifier:prev_key; 255, identifier:gk; 256, subscript; 257, identifier:datetime; 258, assignment; 259, assignment; 260, identifier:this_val; 261, identifier:prev_val; 262, pattern_list; 263, call; 264, boolean_operator; 265, identifier:vals_not_equal; 266, subscript; 267, list; 268, identifier:prev_key; 269, identifier:gk; 270, call; 271, identifier:reader; 272, identifier:ppp_config_dir; 273, identifier:reader_kwargs; 274, string_content:Cannot use %s; 275, identifier:str; 276, argument_list; 277, identifier:str; 278, argument_list; 279, identifier:reader_instance; 280, identifier:info; 281, string_content:group_keys; 282, string; 283, identifier:tuple; 284, generator_expression; 285, identifier:file_keys; 286, identifier:append; 287, tuple; 288, identifier:gk; 289, integer:0; 290, identifier:is_new_group; 291, comparison_operator:(gk[0] - prev_key[0]) > threshold; 292, identifier:is_new_group; 293, comparison_operator:gk[0] != prev_key[0]; 294, identifier:this_val; 295, identifier:prev_val; 296, identifier:zip; 297, argument_list; 298, comparison_operator:this_val is not None; 299, comparison_operator:prev_val is not None; 300, identifier:file_groups; 301, identifier:gk; 302, identifier:f; 303, attribute; 304, argument_list; 305, identifier:reader_configs; 306, identifier:err; 307, string_content:start_time; 308, call; 309, for_in_clause; 310, identifier:group_key; 311, identifier:f; 312, parenthesized_expression; 313, identifier:threshold; 314, subscript; 315, subscript; 316, subscript; 317, subscript; 318, identifier:this_val; 319, None; 320, identifier:prev_val; 321, None; 322, subscript; 323, identifier:append; 324, identifier:f; 325, attribute; 326, argument_list; 327, identifier:k; 328, identifier:group_keys; 329, binary_operator:gk[0] - prev_key[0]; 330, identifier:gk; 331, integer:0; 332, identifier:prev_key; 333, integer:0; 334, identifier:gk; 335, slice; 336, identifier:prev_key; 337, slice; 338, identifier:file_groups; 339, identifier:prev_key; 340, identifier:file_info; 341, identifier:get; 342, identifier:k; 343, subscript; 344, subscript; 345, integer:1; 346, integer:1; 347, identifier:gk; 348, integer:0; 349, identifier:prev_key; 350, integer:0
code: def group_files(files_to_sort, reader=None, time_threshold=10,
                  group_keys=None, ppp_config_dir=None, reader_kwargs=None):
      """Group series of files by file pattern information.
  
      By default this will group files by their filename ``start_time``
      assuming it exists in the pattern. By passing the individual
      dictionaries returned by this function to the Scene classes'
      ``filenames``, a series `Scene` objects can be easily created.
  
      .. versionadded:: 0.12
  
      Args:
          files_to_sort (iterable): File paths to sort in to group
          reader (str): Reader whose file patterns should be used to sort files.
              This
          time_threshold (int): Number of seconds used to consider time elements
              in a group as being equal. For example, if the 'start_time' item
              is used to group files then any time within `time_threshold`
              seconds of the first file's 'start_time' will be seen as occurring
              at the same time.
          group_keys (list or tuple): File pattern information to use to group
              files. Keys are sorted in order and only the first key is used when
              comparing datetime elements with `time_threshold` (see above). This
              means it is recommended that datetime values should only come from
              the first key in ``group_keys``. Otherwise, there is a good chance
              that files will not be grouped properly (datetimes being barely
              unequal). Defaults to a reader's ``group_keys`` configuration (set
              in YAML), otherwise ``('start_time',)``.
          ppp_config_dir (str): Root usser configuration directory for Satpy.
              This will be deprecated in the future, but is here for consistency
              with other Satpy features.
          reader_kwargs (dict): Additional keyword arguments to pass to reader
              creation.
  
      Returns:
          List of dictionaries mapping 'reader' to a list of filenames.
          Each of these dictionaries can be passed as ``filenames`` to
          a `Scene` object.
  
      """
      # FUTURE: Find the best reader for each filename using `find_files_and_readers`
      if reader is None:
          raise ValueError("'reader' keyword argument is required.")
      elif not isinstance(reader, (list, tuple)):
          reader = [reader]
  
      # FUTURE: Handle multiple readers
      reader = reader[0]
      reader_configs = list(configs_for_reader(reader, ppp_config_dir))[0]
      reader_kwargs = reader_kwargs or {}
      try:
          reader_instance = load_reader(reader_configs, **reader_kwargs)
      except (KeyError, IOError, yaml.YAMLError) as err:
          LOG.info('Cannot use %s', str(reader_configs))
          LOG.debug(str(err))
          # if reader and (isinstance(reader, str) or len(reader) == 1):
          #     # if it is a single reader then give a more usable error
          #     raise
          raise
  
      if group_keys is None:
          group_keys = reader_instance.info.get('group_keys', ('start_time',))
      file_keys = []
      for filetype, filetype_info in reader_instance.sorted_filetype_items():
          for f, file_info in reader_instance.filename_items_for_filetype(files_to_sort, filetype_info):
              group_key = tuple(file_info.get(k) for k in group_keys)
              file_keys.append((group_key, f))
  
      prev_key = None
      threshold = timedelta(seconds=time_threshold)
      file_groups = {}
      for gk, f in sorted(file_keys):
          # use first element of key as time identifier (if datetime type)
          if prev_key is None:
              is_new_group = True
              prev_key = gk
          elif isinstance(gk[0], datetime):
              # datetimes within threshold difference are "the same time"
              is_new_group = (gk[0] - prev_key[0]) > threshold
          else:
              is_new_group = gk[0] != prev_key[0]
  
          # compare keys for those that are found for both the key and
          # this is a generator and is not computed until the if statement below
          # when we know that `prev_key` is not None
          vals_not_equal = (this_val != prev_val for this_val, prev_val in zip(gk[1:], prev_key[1:])
                            if this_val is not None and prev_val is not None)
          # if this is a new group based on the first element
          if is_new_group or any(vals_not_equal):
              file_groups[gk] = [f]
              prev_key = gk
          else:
              file_groups[prev_key].append(f)
      sorted_group_keys = sorted(file_groups)
      # passable to Scene as 'filenames'
      return [{reader: file_groups[group_key]} for group_key in sorted_group_keys]