code: def _collect_repeated_tools(tool_objs: list[Tool]) -> Iterator[Tool]:
      @dataclass(frozen=True)
      class Item:
          obj: Tool
          properties: dict[str, Any]
  
      key: Callable[[Tool], str] = lambda obj: obj.__class__.__name__
  
      for _, group in itertools.groupby(
          sorted(tool_objs, key=key), key=key
      ):
          rest = [
              Item(obj, obj.properties_with_values()) for obj in group
          ]
          while len(rest) > 1:
              head, *rest = rest
              for item in rest:
                  if item.properties == head.properties:
                      yield item.obj
  
file_path: bokeh/src/bokeh/plotting/_tools.py
imports: from __future__ import annotations
  import logging
  import itertools
  import re
  from dataclasses import dataclass
  from typing import TYPE_CHECKING, Any, Callable, Iterator, Literal, Sequence, Union, cast
  from ..models import HoverTool, Plot, Tool, Toolbar
  from ..models.tools import Drag, GestureTool, InspectTool, Scroll, Tap
  from ..util.warnings import warn
label_desc: Use image node_id 4 for calling a global function with example usage: _collect_repeated_tools(tool_objs) without return types