code: def register(
      self,
      key: str | list[str] | tuple[str],
      description: str | list[str] | tuple[str],
      dim: int = -1,
      htype: str | None = None,
  ):
      # rename for function use, without changing api
      keys = key
      del key
  
      descriptions = description
      del description
  
      # ensure that keys are a tuple
      if isinstance(keys, list):
          keys = tuple(keys)
      elif not isinstance(keys, tuple):
          keys = (keys,)
  
      # ensure that description is a tuple
      if isinstance(descriptions, list):
          descriptions = tuple(descriptions)
      elif not isinstance(descriptions, tuple):
          descriptions = (descriptions,)
  
      def f(func: Callable):
          # function names should be unique
          if func.__name__ in self._func_name_to_properties:
              raise ValueError(
                  f"A function with the name '{func.__name__}' has already been registered."
              )
  
          # keys should unique correspond to a function
          for key in keys:
              if key in self._keys:
                  raise ValueError(
                      f"Key '{key}' has already been registered."
                  )
  
          # register properties
          self._keys += list(keys)
          self._func_name_to_properties[func.__name__] = (
              dim,
              htype,
              keys,
          )
          self._properties_to_func[dim][htype][keys] = func
          self._descriptions.update(dict(zip(keys, descriptions)))
  
          return func
  
      return f
  
file_path: popmon/popmon/base/registry.py
imports: from __future__ import annotations
  from collections import defaultdict
  from typing import Any, Callable
label_desc: Use image node_id 2 for calling the Registry obj's underlying member method code with example usage: obj.register(key, description, dim, htype) and returns: f, func