class_docstr: Transformer base class.
class_docstr_tok: ["Transformer","base","class","."]
docstr: Check and coerce X/y for fit/transform functions.
  
  Parameters
  ----------
  X : object of sktime compatible time series type
      can be Series, Panel, Hierarchical
  y : None (default), or object of sktime compatible time series type
      can be Series, Panel, Hierarchical
  return_metadata : bool, optional, default=False
      whether to return the metadata return object
  
  Returns
  -------
  X_inner : Series, Panel, or Hierarchical object, or VectorizedDF
          compatible with self.get_tag("X_inner_mtype") format
      Case 1: self.get_tag("X_inner_mtype") supports scitype of X, then
          converted/coerced version of X, mtype determined by "X_inner_mtype" tag
      Case 2: self.get_tag("X_inner_mtype") supports *higher* scitype than X
          then X converted to "one-Series" or "one-Panel" sub-case of that scitype
          always pd-multiindex (Panel) or pd_multiindex_hier (Hierarchical)
      Case 3: self.get_tag("X_inner_mtype") supports only *simpler* scitype than X
          then VectorizedDF of X, iterated as the most complex supported scitype
  y_inner : Series, Panel, or Hierarchical object, or VectorizedDF
          compatible with self.get_tag("y_inner_mtype") format
      Case 1: self.get_tag("y_inner_mtype") supports scitype of y, then
          converted/coerced version of y, mtype determined by "y_inner_mtype" tag
      Case 2: self.get_tag("y_inner_mtype") supports *higher* scitype than y
          then X converted to "one-Series" or "one-Panel" sub-case of that scitype
          always pd-multiindex (Panel) or pd_multiindex_hier (Hierarchical)
      Case 3: self.get_tag("y_inner_mtype") supports only *simpler* scitype than y
          then VectorizedDF of X, iterated as the most complex supported scitype
      Case 4: None if y was None, or self.get_tag("y_inner_mtype") is "None"
  
      Complexity order above: Hierarchical > Panel > Series
  
  metadata : dict, returned only if return_metadata=True
      dictionary with str keys, contents as follows
      _converter_store_X : dict, metadata from X conversion, for back-conversion
      _X_mtype_last_seen : str, mtype of X seen last
      _X_input_scitype : str, scitype of X seen last
      _convert_case : str, conversion case (see above), one of
          "case 1: scitype supported"
          "case 2: higher scitype supported"
          "case 3: requires vectorization"
  
  Raises
  ------
  TypeError if X is None
  TypeError if X or y is not one of the permissible Series mtypes
  TypeError if X is not compatible with self.get_tag("univariate_only")
      if tag value is "True", X must be univariate
  ValueError if self.get_tag("requires_y")=True but y is None
code: def _check_X_y(self, X=None, y=None, return_metadata=False):
      """Check and coerce X/y for fit/transform functions.
  
      Parameters
      ----------
      X : object of sktime compatible time series type
          can be Series, Panel, Hierarchical
      y : None (default), or object of sktime compatible time series type
          can be Series, Panel, Hierarchical
      return_metadata : bool, optional, default=False
          whether to return the metadata return object
  
      Returns
      -------
      X_inner : Series, Panel, or Hierarchical object, or VectorizedDF
              compatible with self.get_tag("X_inner_mtype") format
          Case 1: self.get_tag("X_inner_mtype") supports scitype of X, then
              converted/coerced version of X, mtype determined by "X_inner_mtype" tag
          Case 2: self.get_tag("X_inner_mtype") supports *higher* scitype than X
              then X converted to "one-Series" or "one-Panel" sub-case of that scitype
              always pd-multiindex (Panel) or pd_multiindex_hier (Hierarchical)
          Case 3: self.get_tag("X_inner_mtype") supports only *simpler* scitype than X
              then VectorizedDF of X, iterated as the most complex supported scitype
      y_inner : Series, Panel, or Hierarchical object, or VectorizedDF
              compatible with self.get_tag("y_inner_mtype") format
          Case 1: self.get_tag("y_inner_mtype") supports scitype of y, then
              converted/coerced version of y, mtype determined by "y_inner_mtype" tag
          Case 2: self.get_tag("y_inner_mtype") supports *higher* scitype than y
              then X converted to "one-Series" or "one-Panel" sub-case of that scitype
              always pd-multiindex (Panel) or pd_multiindex_hier (Hierarchical)
          Case 3: self.get_tag("y_inner_mtype") supports only *simpler* scitype than y
              then VectorizedDF of X, iterated as the most complex supported scitype
          Case 4: None if y was None, or self.get_tag("y_inner_mtype") is "None"
  
          Complexity order above: Hierarchical > Panel > Series
  
      metadata : dict, returned only if return_metadata=True
          dictionary with str keys, contents as follows
          _converter_store_X : dict, metadata from X conversion, for back-conversion
          _X_mtype_last_seen : str, mtype of X seen last
          _X_input_scitype : str, scitype of X seen last
          _convert_case : str, conversion case (see above), one of
              "case 1: scitype supported"
              "case 2: higher scitype supported"
              "case 3: requires vectorization"
  
      Raises
      ------
      TypeError if X is None
      TypeError if X or y is not one of the permissible Series mtypes
      TypeError if X is not compatible with self.get_tag("univariate_only")
          if tag value is "True", X must be univariate
      ValueError if self.get_tag("requires_y")=True but y is None
      """
      if X is None:
          if return_metadata:
              return X, y, {}
          else:
              return X, y
  
      # skip conversion if it is turned off
      if self.get_config()["input_conversion"] != "on":
          if return_metadata:
              return X, y, None
          else:
              return X, y
  
      metadata = dict()
      metadata["_converter_store_X"] = dict()
  
      def _most_complex_scitype(scitypes, smaller_equal_than=None):
          """Return most complex scitype in a list of str."""
          if (
              "Hierarchical" in scitypes
              and smaller_equal_than == "Hierarchical"
          ):
              return "Hierarchical"
          elif "Panel" in scitypes and smaller_equal_than != "Series":
              return "Panel"
          elif "Series" in scitypes:
              return "Series"
          elif smaller_equal_than is not None:
              return _most_complex_scitype(scitypes)
          else:
              raise ValueError(
                  "no series scitypes supported, bug in estimator"
              )
  
      def _scitype_A_higher_B(scitypeA, scitypeB):
          """Compare two scitypes regarding complexity."""
          if scitypeA == "Series":
              return False
          if scitypeA == "Panel" and scitypeB == "Series":
              return True
          if scitypeA == "Hierarchical" and scitypeB != "Hierarchical":
              return True
          return False
  
      # retrieve supported mtypes
      X_inner_mtype = _coerce_to_list(self.get_tag("X_inner_mtype"))
      y_inner_mtype = _coerce_to_list(self.get_tag("y_inner_mtype"))
      X_inner_scitype = mtype_to_scitype(
          X_inner_mtype, return_unique=True
      )
      y_inner_scitype = mtype_to_scitype(
          y_inner_mtype, return_unique=True
      )
  
      ALLOWED_SCITYPES = ["Series", "Panel", "Hierarchical"]
      ALLOWED_MTYPES = self.ALLOWED_INPUT_MTYPES
  
      # checking X
      X_metadata_required = ["is_univariate"]
  
      X_valid, msg, X_metadata = check_is_scitype(
          X,
          scitype=ALLOWED_SCITYPES,
          return_metadata=X_metadata_required,
          var_name="X",
      )
  
      X_scitype = X_metadata["scitype"]
      X_mtype = X_metadata["mtype"]
      # remember these for potential back-conversion (in transform etc)
      metadata["_X_mtype_last_seen"] = X_mtype
      metadata["_X_input_scitype"] = X_scitype
  
      # raise informative error message if X is in wrong format
      allowed_msg = (
          f"Allowed scitypes for X in transformations are "
          f"Series, Panel or Hierarchical, "
          f"for instance a pandas.DataFrame with sktime compatible time indices, "
          f"or with MultiIndex and last(-1) level an sktime compatible time index. "
          f"Allowed compatible mtype format specifications are: {ALLOWED_MTYPES} ."
      )
      if not X_valid or X_mtype not in ALLOWED_MTYPES:
          msg = {k: v for k, v in msg.items() if k in ALLOWED_MTYPES}
          check_is_error_msg(
              msg,
              var_name="X",
              allowed_msg=allowed_msg,
              raise_exception=True,
          )
  
      if X_scitype in X_inner_scitype:
          case = "case 1: scitype supported"
          req_vec_because_rows = False
      elif any(
          _scitype_A_higher_B(x, X_scitype) for x in X_inner_scitype
      ):
          case = "case 2: higher scitype supported"
          req_vec_because_rows = False
      else:
          case = "case 3: requires vectorization"
          req_vec_because_rows = True
      metadata["_convert_case"] = case
  
      # checking X vs tags
      inner_univariate = self.get_tag("univariate-only")
      # we remember whether we need to vectorize over columns, and at all
      req_vec_because_cols = (
          inner_univariate and not X_metadata["is_univariate"]
      )
      requires_vectorization = (
          req_vec_because_rows or req_vec_because_cols
      )
      # end checking X
  
      if y_inner_mtype != ["None"] and y is not None:
          if "Table" in y_inner_scitype:
              y_possible_scitypes = "Table"
          elif X_scitype == "Series":
              y_possible_scitypes = "Series"
          elif X_scitype == "Panel":
              y_possible_scitypes = "Panel"
          elif X_scitype == "Hierarchical":
              y_possible_scitypes = ["Panel", "Hierarchical"]
  
          y_valid, msg, y_metadata = check_is_scitype(
              y,
              scitype=y_possible_scitypes,
              return_metadata=[],
              var_name="y",
          )
          y_scitype = y_metadata["scitype"]
          y_mtype = y_metadata["mtype"]
  
          # raise informative error message if y is is in wrong format
          if not y_valid:
              allowed_msg = (
                  f"Allowed scitypes for y in transformations depend on X passed. "
                  f"Passed X scitype was {X_scitype}, "
                  f"so allowed scitypes for y are {y_possible_scitypes}. "
              )
              check_is_error_msg(
                  msg,
                  var_name="y",
                  allowed_msg=allowed_msg,
                  raise_exception=True,
              )
  
      else:
          # y_scitype is used below - set to None if y is None
          y_scitype = None
      # end checking y
  
      # no compatibility checks between X and y
      # end compatibility checking X and y
  
      # convert X & y to supported inner type, if necessary
      #####################################################
  
      # convert X and y to a supported internal mtype
      #  it X/y mtype is already supported, no conversion takes place
      #  if X/y is None, then no conversion takes place (returns None)
      #  if vectorization is required, we wrap in VectorizedDF
  
      # case 2. internal only has higher scitype, e.g., inner is Panel and X Series
      #       or inner is Hierarchical and X is Panel or Series
      #   then, consider X as one-instance Panel or Hierarchical
      if case == "case 2: higher scitype supported":
          if X_scitype == "Series" and "Panel" in X_inner_scitype:
              as_scitype = "Panel"
          else:
              as_scitype = "Hierarchical"
          X, X_mtype = convert_to_scitype(
              X,
              to_scitype=as_scitype,
              from_scitype=X_scitype,
              return_to_mtype=True,
          )
          X_scitype = as_scitype
          # then pass to case 1, which we've reduced to, X now has inner scitype
  
      # case 1. scitype of X is supported internally
      # case in ["case 1: scitype supported", "case 2: higher scitype supported"]
      #   and does not require vectorization because of cols (multivariate)
      if not requires_vectorization:
          # converts X
          X_inner = convert(
              X,
              from_type=X_mtype,
              to_type=X_inner_mtype,
              store=metadata["_converter_store_X"],
              store_behaviour="reset",
          )
  
          # converts y, returns None if y is None
          if y_inner_mtype != ["None"] and y is not None:
              y_inner = convert(
                  y,
                  from_type=y_mtype,
                  to_type=y_inner_mtype,
                  as_scitype=y_scitype,
              )
          else:
              y_inner = None
  
      # case 3. scitype of X is not supported, only lower complexity one is
      #   then apply vectorization, loop method execution over series/panels
      # elif case == "case 3: requires vectorization":
      else:  # if requires_vectorization
          iterate_X = _most_complex_scitype(X_inner_scitype, X_scitype)
          X_inner = VectorizedDF(
              X=X,
              iterate_as=iterate_X,
              is_scitype=X_scitype,
              iterate_cols=req_vec_because_cols,
          )
          # we also assume that y must be vectorized in this case
          if y_inner_mtype != ["None"] and y is not None:
              # raise ValueError(
              #     f"{type(self).__name__} does not support Panel X if y is not "
              #     f"None, since {type(self).__name__} supports only Series. "
              #     "Auto-vectorization to extend Series X to Panel X can only be "
              #     'carried out if y is None, or "y_inner_mtype" tag is "None". '
              #     "Consider extending _fit and _transform to handle the following "
              #     "input types natively: Panel X and non-None y."
              # )
              iterate_y = _most_complex_scitype(
                  y_inner_scitype, y_scitype
              )
              y_inner = VectorizedDF(
                  X=y, iterate_as=iterate_y, is_scitype=y_scitype
              )
          else:
              y_inner = None
  
      if return_metadata:
          return X_inner, y_inner, metadata
      else:
          return X_inner, y_inner
  
imports: from itertools import product
  from typing import Union
  import numpy
  import pandas
  from sktime.base import BaseEstimator
  from sktime.datatypes import VectorizedDF, check_is_error_msg, check_is_mtype, check_is_scitype, convert, convert_to, mtype_to_scitype, update_data
  from sktime.datatypes._series_as_panel import convert_to_scitype
  from sktime.utils.sklearn import is_sklearn_classifier, is_sklearn_clusterer, is_sklearn_regressor, is_sklearn_transformer
  from sktime.utils.validation._dependencies import _check_estimator_deps
label_desc: Use image node_id 16 for calling the BaseTransformer obj's underlying member method code with example usage: obj._check_X_y(X, y, return_metadata) and returns: False, X_inner,  y_inner,  metadata, X_inner,  y_inner, X,  y,  dict, X,  y, X,  y,  None, X,  y, str, False, True, True, str, str, _most_complex_scitype