docs: def import_obj(
      uri,
      mod_name=None,
      mod_attr_sep='::',
      attr_chain_sep='.',
      retn_mod=False,
  ):
      """Load an object from a module.
  
      @param uri: an uri specifying which object to load.
      An `uri` consists of two parts: module URI and attribute chain,
       e.g. `a/b/c.py::x.y.z` or `a.b.c::x.y.z`
  
      # Module URI
      E.g.  `a/b/c.py` or `a.b.c`.
      Can be either a module name or a file path.
      Whether it is a file path is determined by whether it ends with `.py`.
  
      # Attribute chain
      E.g. `x.y.z`.
  
      @param mod_name: module name.
      Must be given when `uri` specifies a module file path, not a module name.
  
      @param mod_attr_sep: the separator between module name and attribute name.
  
      @param attr_chain_sep: the separator between parts of attribute name.
  
      @retn_mod: whether return module object.
      """
      if mod_attr_sep is None:
          mod_attr_sep = '::'
  
      uri_parts = split_uri(uri=uri, mod_attr_sep=mod_attr_sep)
  
      protocol, mod_uri, attr_chain = uri_parts
  
      if protocol == 'py':
          mod_obj = import_name(mod_uri)
  
      else:
          if not mod_name:
              msg = (
                  'Argument `mod_name` must be given when loading by file path.'
              )
  
              raise ValueError(msg)
  
          mod_obj = import_path(mod_uri, mod_name=mod_name)
  
      if not attr_chain:
          if retn_mod:
              return mod_obj, None
          else:
              return mod_obj
  
      if attr_chain_sep is None:
          attr_chain_sep = '.'
  
      attr_obj = get_attr_chain(
          obj=mod_obj,
          attr_chain=attr_chain,
          sep=attr_chain_sep,
      )
  
      if retn_mod:
          return mod_obj, attr_obj
      else:
          return attr_obj