code: def auto_label(
      name: str | label | None = None, scope: label_scope | None = None
  ) -> str:
      """Automatically generate a formatted and reproducible label.
  
      In case ``name`` is not set, the label name will use the uid sequence of ``scope``.
      If ``scope`` is not set, it will fetch the nearest scope.
      If no scope is found, it will use the global scope (:meth:`label_scope.global_`).
  
      If the scope is found and is not global scope, the scope's full name will be prepended to the label,
      i.e., the label will then be formatted as ``{scope}/{label}``.
      Otherwise, there are two cases. Firstly, if label is manually specified, it will be returned directly.
      Secondly, we rely on the global scope to generate the label name, and the scope name will still be prepended.
      The rules can be better explained with the examples below.
  
      Notes
      -----
      We always recommend specifying the label manually.
  
      Parameters
      ----------
      name
          The label name to use. If not specified, it will be generated by the scope.
      scope
          The scope to use. If not specified, the nearest scope will be used.
  
      Returns
      -------
      A string that represents the label.
      For advanced users, please be advised that
      the returned object would be a :class:`label` object, rather than a string.
      This is to make sure :func:`auto_label` is idempotent.
      We expect some side effects, but it should work seamlessly with most of the code.
  
      Examples
      --------
      >>> label1 = auto_label('bar')          # bar, because the scope is global
      >>> label2 = auto_label()               # global/1, because label is not provided
      >>> with label_scope('foo'):
      ...     label3 = auto_label()           # foo/1, because in the scope "foo"
      >>> with label_scope():                 # scope is global/2
      ...     label4 = auto_label()           # global/2/1
      >>> with label_scope('another'):
      ...     label5 = auto_label()           # another/1
      ...     label6 = auto_label('thing')    # another/thing
      ...     label7 = auto_label()           # another/2
      """
  
      if isinstance(name, label):
          # Already a label, no need to do anything.
          return cast(str, name)
  
      # Has scope is a special case, because it might not have been entered.
      if scope is not None:
          if not isinstance(scope, label_scope):
              raise TypeError(
                  "scope must be an instance of label_scope"
              )
          if name is None:
              name = scope.next_label()
          scope.check_entered()
          return cast(str, label([*cast(List[str], scope.path), name]))
  
      # Fake a label scope and return its name directly.
      with label_scope(name) as scope:
          assert scope.path is not None
          return cast(str, label(scope.path))
  
imports: from __future__ import annotations
  import logging
  from collections import defaultdict
  from typing import Any, List, cast
label_desc: Use image node_id 4 for calling a global function with example usage: auto_label(name, scope) and returns: cast, cast, cast