Repository: sktime/sktime
Pull request #7816 (2025-02-13 16:52:59)

[ENH] refactor `datatypes` registry to `scikit-base` records
This PR refactors the `datatypes` registry to the new, programmatic `scikit-base` records, deduplicating the points of extension.

The manually popultated records in the `_registry` folders are removed in favour of the records currently in the `_check` folders.

In a future PR, we may rename `_check` to `_registry`, as these contain the primary records now.


Patch:
diff --git a/sktime/datatypes/__init__.py b/sktime/datatypes/__init__.py
index acc6a3e34..9281f4805 100644
--- a/sktime/datatypes/__init__.py
+++ b/sktime/datatypes/__init__.py
@@ -11,15 +11,11 @@ from sktime.datatypes._check import (
 from sktime.datatypes._convert import convert, convert_to
 from sktime.datatypes._examples import get_examples
 from sktime.datatypes._registry import (
-    ALL_TIME_SERIES_MTYPES,
-    MTYPE_LIST_HIERARCHICAL,
-    MTYPE_LIST_PANEL,
-    MTYPE_LIST_PROBA,
-    MTYPE_LIST_SERIES,
-    MTYPE_LIST_TABLE,
-    MTYPE_REGISTER,
+    AMBIGUOUS_MTYPES,
     SCITYPE_LIST,
     SCITYPE_REGISTER,
+    generate_mtype_list,
+    generate_mtype_register,
     mtype_to_scitype,
     scitype_to_mtype,
 )
@@ -51,3 +47,29 @@ __all__ = [
     "update_data",
     "VectorizedDF",
 ]
+
+
+def __getattr__(name):
+    getter_dict = {
+        "MTYPE_LIST_ALIGNMENT": "Alignment",
+        "MTYPE_LIST_HIERARCHICAL": "Hierarchical",
+        "MTYPE_LIST_PANEL": "Panel",
+        "MTYPE_LIST_PROBA": "Proba",
+        "MTYPE_LIST_SERIES": "Series",
+        "MTYPE_LIST_TABLE": "Table",
+    }
+    if name in getter_dict:
+        return generate_mtype_list(scitype=getter_dict[name])
+
+    if name == "MTYPE_REGISTER":
+        return generate_mtype_register()
+
+    if name == "ALL_TIME_SERIES_MTYPES":
+        series = generate_mtype_list(scitype="Series")
+        panel = generate_mtype_list(scitype="Panel")
+        hierarchical = generate_mtype_list(scitype="Hierarchical")
+        all_tsm = series + panel + hierarchical
+        ALL_TIME_SERIES_MTYPES = list(set(all_tsm).difference(AMBIGUOUS_MTYPES))
+        return ALL_TIME_SERIES_MTYPES
+
+    raise AttributeError(f"module {__name__} has no attribute {name}")
diff --git a/sktime/datatypes/_alignment/__init__.py b/sktime/datatypes/_alignment/__init__.py
index bedd16709..64a925efa 100644
--- a/sktime/datatypes/_alignment/__init__.py
+++ b/sktime/datatypes/_alignment/__init__.py
@@ -1,11 +1,1 @@
-"""Module exports: Alignment type checkers and mtype inference."""
-
-from sktime.datatypes._alignment._registry import (
-    MTYPE_LIST_ALIGNMENT,
-    MTYPE_REGISTER_ALIGNMENT,
-)
-
-__all__ = [
-    "MTYPE_LIST_ALIGNMENT",
-    "MTYPE_REGISTER_ALIGNMENT",
-]
+"""Module: Alignment type checkers and mtype inference."""
diff --git a/sktime/datatypes/_alignment/_check.py b/sktime/datatypes/_alignment/_check.py
index b8044e32a..e86e5a460 100644
--- a/sktime/datatypes/_alignment/_check.py
+++ b/sktime/datatypes/_alignment/_check.py
@@ -155,6 +155,7 @@ class AlignmentIloc(ScitypeAlignment):
         "name": "alignment",  # any string
         "name_python": "alignment_iloc",  # lower_snake_case
         "name_aliases": [],
+        "description": "alignment in pd.DataFrame format, values are iloc index references",  # noqa: E501
         "python_version": None,
         "python_dependencies": "pandas",
     }
@@ -223,6 +224,7 @@ class AlignmentLoc(ScitypeAlignment):
         "name": "alignment_loc",  # any string
         "name_python": "alignment_loc",  # lower_snake_case
         "name_aliases": [],
+        "description": "alignment in pd.DataFrame format, values are loc index references",  # noqa: E501
         "python_version": None,
         "python_dependencies": "pandas",
     }
diff --git a/sktime/datatypes/_alignment/_registry.py b/sktime/datatypes/_alignment/_registry.py
deleted file mode 100644
index ae5c9cd57..000000000
--- a/sktime/datatypes/_alignment/_registry.py
+++ /dev/null
@@ -1,25 +0,0 @@
-"""Registry of mtypes for Alignment scitype.
-
-See datatypes._registry for API.
-"""
-
-__all__ = [
-    "MTYPE_REGISTER_ALIGNMENT",
-    "MTYPE_LIST_ALIGNMENT",
-]
-
-
-MTYPE_REGISTER_ALIGNMENT = [
-    (
-        "alignment",
-        "Alignment",
-        "pd.DataFrame in alignment format, values are iloc index references",
-    ),
-    (
-        "alignment_loc",
-        "Alignment",
-        "pd.DataFrame in alignment format, values are loc index references",
-    ),
-]
-
-MTYPE_LIST_ALIGNMENT = [x[0] for x in MTYPE_REGISTER_ALIGNMENT]
diff --git a/sktime/datatypes/_base/_base.py b/sktime/datatypes/_base/_base.py
index 9a48f4501..608efb5d5 100644
--- a/sktime/datatypes/_base/_base.py
+++ b/sktime/datatypes/_base/_base.py
@@ -24,6 +24,8 @@ class BaseDatatype(BaseObject):
         "python_version": None,
         "python_dependencies": None,
         "python_type": "object",  # implied python type (lowest)
+        "internal_only": False,  # whether type is for internal use only
+        "skip_in_checks": False,  # whether to skip in inference checks (check_dict)
     }
 
     def __init__(self):
diff --git a/sktime/datatypes/_check.py b/sktime/datatypes/_check.py
index 79657c67d..f8ca8de89 100644
--- a/sktime/datatypes/_check.py
+++ b/sktime/datatypes/_check.py
@@ -27,9 +27,13 @@ from functools import lru_cache
 
 import numpy as np
 
-from sktime.datatypes._base import BaseDatatype
 from sktime.datatypes._base._common import _metadata_requested, _ret
-from sktime.datatypes._registry import AMBIGUOUS_MTYPES, SCITYPE_LIST, mtype_to_scitype
+from sktime.datatypes._registry import (
+    AMBIGUOUS_MTYPES,
+    SCITYPE_LIST,
+    generate_mtype_cls_list,
+    mtype_to_scitype,
+)
 
 
 def get_check_dict(soft_deps="present"):
@@ -43,6 +47,12 @@ def get_check_dict(soft_deps="present"):
     soft_deps : str, optional - one of "present", "all"
         "present" - only checks with soft dependencies present are included
         "all" - all checks are included
+
+    Returns
+    -------
+    check_dict : dict of (str, str) : object (mtype registry class)
+        dictionary of check classes, with keys being tuples of (mtype, scitype)
+        and values an instance of the check class for that mtype/scitype combination
     """
     if soft_deps not in ["present", "all"]:
         raise ValueError(
@@ -56,25 +66,14 @@ def get_check_dict(soft_deps="present"):
 @lru_cache(maxsize=1)
 def generate_check_dict(soft_deps="present"):
     """Generate check_dict using lookup."""
-    from skbase.utils.dependencies import _check_estimator_deps
-
-    from sktime.utils.retrieval import _all_classes
-
-    classes = _all_classes("sktime.datatypes")
-    classes = [x[1] for x in classes]
-    classes = [x for x in classes if issubclass(x, BaseDatatype)]
-    classes = [x for x in classes if not x.__name__.startswith("Base")]
-    classes = [x for x in classes if not x.__name__.startswith("Scitype")]
-
-    # subset only to data types with soft dependencies present
-    if soft_deps == "present":
-        classes = [x for x in classes if _check_estimator_deps(x, severity="none")]
+    classes = generate_mtype_cls_list(soft_deps=soft_deps)
 
     check_dict = dict()
     for cls in classes:
         k = cls()
-        key = k._get_key()
-        check_dict[key] = k
+        if not k.get_tag("skip_in_checks", False):
+            key = k._get_key()
+            check_dict[key] = k
 
     return check_dict
 
diff --git a/sktime/datatypes/_hierarchical/__init__.py b/sktime/datatypes/_hierarchical/__init__.py
index d262e59f0..42feed418 100644
--- a/sktime/datatypes/_hierarchical/__init__.py
+++ b/sktime/datatypes/_hierarchical/__init__.py
@@ -3,13 +3,5 @@
 from sktime.datatypes._hierarchical._convert import (
     convert_dict as convert_dict_Hierarchical,
 )
-from sktime.datatypes._hierarchical._registry import (
-    MTYPE_LIST_HIERARCHICAL,
-    MTYPE_REGISTER_HIERARCHICAL,
-)
 
-__all__ = [
-    "convert_dict_Hierarchical",
-    "MTYPE_LIST_HIERARCHICAL",
-    "MTYPE_REGISTER_HIERARCHICAL",
-]
+__all__ = ["convert_dict_Hierarchical"]
diff --git a/sktime/datatypes/_hierarchical/_check.py b/sktime/datatypes/_hierarchical/_check.py
index dfedfbadb..e6086e064 100644
--- a/sktime/datatypes/_hierarchical/_check.py
+++ b/sktime/datatypes/_hierarchical/_check.py
@@ -143,6 +143,7 @@ class HierarchicalPdMultiIndex(ScitypeHierarchical):
         "name": "pd_multiindex_hier",  # any string
         "name_python": "hier_pd_df",  # lower_snake_case
         "name_aliases": [],
+        "description": "pandas.DataFrame with hierarchical MultiIndex",
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "pandas.DataFrame",
@@ -264,6 +265,7 @@ class HierarchicalDask(ScitypeHierarchical):
         "name": "dask_hierarchical",  # any string
         "name_python": "hier_dask",  # lower_snake_case
         "name_aliases": [],
+        "description": "dask frame with multiple hierarchical indices, as per dask_to_pd convention",  # noqa: E501
         "python_version": None,
         "python_dependencies": "dask",
         "python_type": "dask.dataframe",
@@ -345,6 +347,7 @@ class HierarchicalPolarsEager(ScitypeHierarchical):
         "name": "polars_hierarchical",  # any string
         "name_python": "hier_polars_eager",  # lower_snake_case
         "name_aliases": [],
+        "description": "polars frame with multiple hierarchical indices, as per polars_to_pd convention",  # noqa: E501
         "python_version": None,
         "python_dependencies": "polars",
         "python_type": "polars.DataFrame",
diff --git a/sktime/datatypes/_hierarchical/_convert.py b/sktime/datatypes/_hierarchical/_convert.py
index 308cf9f25..1951cc2bd 100644
--- a/sktime/datatypes/_hierarchical/_convert.py
+++ b/sktime/datatypes/_hierarchical/_convert.py
@@ -4,9 +4,15 @@ __all__ = [
 
 from sktime.datatypes._convert_utils._coerce import _coerce_df_dtypes
 from sktime.datatypes._convert_utils._convert import _extend_conversions
-from sktime.datatypes._hierarchical._registry import MTYPE_LIST_HIERARCHICAL
 from sktime.utils.dependencies import _check_soft_dependencies
 
+# this needs to be refactored with the convert module
+MTYPE_LIST_HIERARCHICAL = [
+    "pd_multiindex_hier",
+    "dask_hierarchical",
+    "polars_hierarchical",
+]
+
 # dictionary indexed by triples of types
 #  1st element = convert from - type
 #  2nd element = convert to - type
diff --git a/sktime/datatypes/_hierarchical/_registry.py b/sktime/datatypes/_hierarchical/_registry.py
deleted file mode 100644
index 81882ba67..000000000
--- a/sktime/datatypes/_hierarchical/_registry.py
+++ /dev/null
@@ -1,37 +0,0 @@
-"""Registry of mtypes for Hierarchical scitype.
-
-See datatypes._registry for API.
-"""
-
-__all__ = [
-    "MTYPE_REGISTER_HIERARCHICAL",
-    "MTYPE_LIST_HIERARCHICAL",
-    "MTYPE_SOFT_DEPS_HIERARCHICAL",
-]
-
-
-MTYPE_REGISTER_HIERARCHICAL = [
-    (
-        "pd_multiindex_hier",
-        "Hierarchical",
-        "pd.DataFrame with MultiIndex",
-    ),
-    (
-        "dask_hierarchical",
-        "Hierarchical",
-        "dask frame with multiple hierarchical indices, as per dask_to_pd convention",
-    ),
-    (
-        "polars_hierarchical",
-        "Hierarchical",
-        "polars frame with multiple hierarchical indices, "
-        "as per polars_to_pd convention",
-    ),
-]
-
-MTYPE_SOFT_DEPS_HIERARCHICAL = {
-    "dask_hierarchical": "dask",
-    "polars_hierarchical": "polars",
-}
-
-MTYPE_LIST_HIERARCHICAL = [x[0] for x in MTYPE_REGISTER_HIERARCHICAL]
diff --git a/sktime/datatypes/_panel/__init__.py b/sktime/datatypes/_panel/__init__.py
index 6fc3dfe94..b582c5f46 100644
--- a/sktime/datatypes/_panel/__init__.py
+++ b/sktime/datatypes/_panel/__init__.py
@@ -1,10 +1,5 @@
 """Module exports: Panel type checkers, converters and mtype inference."""
 
 from sktime.datatypes._panel._convert import convert_dict as convert_dict_Panel
-from sktime.datatypes._panel._registry import MTYPE_LIST_PANEL, MTYPE_REGISTER_PANEL
 
-__all__ = [
-    "convert_dict_Panel",
-    "MTYPE_LIST_PANEL",
-    "MTYPE_REGISTER_PANEL",
-]
+__all__ = ["convert_dict_Panel"]
diff --git a/sktime/datatypes/_panel/_check.py b/sktime/datatypes/_panel/_check.py
index e05a9a774..6b642939d 100644
--- a/sktime/datatypes/_panel/_check.py
+++ b/sktime/datatypes/_panel/_check.py
@@ -156,6 +156,7 @@ class PanelDfList(ScitypePanel):
         "name": "df-list",  # any string
         "name_python": "panel_df_list",  # lower_snake_case
         "name_aliases": [],
+        "description": "list of pd.DataFrame",
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "list",
@@ -318,6 +319,7 @@ class PanelNp3D(ScitypePanel):
         "name": "numpy3D",  # any string
         "name_python": "panel_np_3d",  # lower_snake_case
         "name_aliases": [],
+        "description": "3D np.array of format (n_instances, n_columns, n_timepoints)",
         "python_version": None,
         "python_dependencies": "numpy",
         "python_type": "numpy.ndarray",
@@ -474,6 +476,7 @@ class PanelPdMultiIndex(ScitypePanel):
         "name": "pd-multiindex",  # any string
         "name_python": "panel_pd_df",  # lower_snake_case
         "name_aliases": [],
+        "description": "pd.DataFrame with multi-index (instances, timepoints)",
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "pandas.DataFrame",
@@ -746,6 +749,7 @@ class PanelNestedDf(ScitypePanel):
         "name": "nested_univ",  # any string
         "name_python": "panel_pd_nested",  # lower_snake_case
         "name_aliases": [],
+        "description": "pd.DataFrame with one column per variable, pd.Series in cells",
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "pandas.DataFrame",
@@ -895,12 +899,17 @@ class PanelNumpyFlat(ScitypePanel):
         "name": "numpyflat",  # any string
         "name_python": "panel_np_flat",  # lower_snake_case
         "name_aliases": [],
+        "description": (
+            "WARNING: only for internal use, not a fully supported Panel mtype. "
+            "2D np.array of format (n_instances, n_columns*n_timepoints)"
+        ),
         "python_version": None,
         "python_dependencies": "numpy",
         "python_type": "numpy.ndarray",
         "capability:multivariate": False,
         "capability:unequally_spaced": False,
         "capability:missing_values": True,
+        "internal_only": True,
     }
 
     def _check(self, obj, return_metadata=False, var_name="obj"):
@@ -1009,6 +1018,7 @@ class PanelDask(ScitypePanel):
         "name": "dask_panel",  # any string
         "name_python": "panel_dask",  # lower_snake_case
         "name_aliases": [],
+        "description": "dask DataFrame based panel of time series",
         "python_version": None,
         "python_dependencies": "dask",
         "python_type": "dask.dataframe",
@@ -1084,6 +1094,7 @@ class PanelPolarsEager(ScitypePanel):
         "name": "polars_panel",  # any string
         "name_python": "panel_polars",  # lower_snake_case
         "name_aliases": [],
+        "description": "polars.DataFrame based panel of time series",
         "python_version": None,
         "python_dependencies": "polars",
         "python_type": "polars.DataFrame",
@@ -1277,6 +1288,7 @@ class PanelGluontsList(ScitypePanel):
         "name": "gluonts_ListDataset_panel",  # any string
         "name_python": "panel_gluonts_list",  # lower_snake_case
         "name_aliases": [],
+        "description": "gluonts list based panel of time series",
         "python_version": None,
         "python_dependencies": None,
         "python_type": "list",
@@ -1428,6 +1440,7 @@ class PanelGluontsPandas(ScitypePanel):
         "name": "gluonts_PandasDataset_panel",  # any string
         "name_python": "panel_gluonts_pandas",  # lower_snake_case
         "name_aliases": [],
+        "description": "gluonts PandasDataset based panel of time series",
         "python_version": None,
         "python_dependencies": "gluonts",
         "python_type": "gluonts.PandasDataset",
@@ -1468,8 +1481,10 @@ class PanelGluontsPandas(ScitypePanel):
             return _ret(False, msg, None, return_metadata)
 
         if not hasattr(obj._data_entries.iterable, "iterable"):
-            msg = f"{var_name} must be formed with a multiindex DataFrame to "
-            +"be a valid `pandasDataset_panel`"
+            msg = (
+                f"{var_name} must be formed with a multiindex DataFrame to "
+                "be a valid `pandasDataset_panel`"
+            )
             return _ret(False, msg, None, return_metadata)
 
         # Convert to a pandas DF for easier checks
@@ -1519,3 +1534,153 @@ class PanelGluontsPandas(ScitypePanel):
             metadata["has_nans"] = False
 
         return _ret(True, None, metadata, return_metadata)
+
+
+class PanelPdWide(ScitypePanel):
+    """Data type: panel of time series in pandas wide format.
+
+    Parameters
+    ----------
+    is_univariate: bool
+        True iff table has one variable
+    is_equally_spaced : bool
+        True iff series index is equally spaced
+    is_equal_length: bool
+        True iff all series in panel are of equal length
+    is_empty: bool
+        True iff table has no variables or no instances
+    is_one_series: bool
+        True iff there is only one series in the panel of time series
+    has_nans: bool
+        True iff the table contains NaN values
+    n_instances: int
+        number of instances in the panel of time series
+    n_features: int
+        number of variables in table
+    feature_names: list of int or object
+        names of variables in table
+    dtypekind_dfip: list of DtypeKind enum
+        list of DtypeKind enum values for each feature in the panel,
+        following the data frame interface protocol
+    feature_kind: list of str
+        list of feature kind strings for each feature in the panel,
+        coerced to FLOAT or CATEGORICAL type
+    """
+
+    _tags = {
+        "scitype": "Panel",
+        "name": "pd-wide",  # any string
+        "name_python": "panel_pd_wide",  # lower_snake_case
+        "name_aliases": [],
+        "description": (
+            "WARNING: only for internal use, not a fully supported Panel mtype. "
+            "pd.DataFrame in wide format, cols = (instance*timepoints)"
+        ),
+        "python_version": None,
+        "python_dependencies": "pandas",
+        "python_type": "pandas.DataFrame",
+        "capability:multivariate": False,
+        "capability:unequally_spaced": False,
+        "capability:missing_values": True,
+        "internal_only": True,
+        "skip_in_checks": True,
+    }
+
+    def _check(self, obj, return_metadata=False, var_name="obj"):
+        """Check if obj is of this data type.
+
+        Parameters
+        ----------
+        obj : any
+            Object to check.
+        return_metadata : bool, optional (default=False)
+            Whether to return metadata.
+        var_name : str, optional (default="obj")
+            Name of the variable to check, for use in error messages.
+
+        Returns
+        -------
+        valid : bool
+            Whether obj is of this data type.
+        msg : str, only returned if return_metadata is True.
+            Error message if obj is not of this data type.
+        metadata : dict, only returned if return_metadata is True.
+            Metadata dictionary.
+        """
+        # no checker defined, only used in conversions
+        pass
+
+
+class PanelPdLong(ScitypePanel):
+    """Data type: panel of time series in pandas long format.
+
+    Parameters
+    ----------
+    is_univariate: bool
+        True iff table has one variable
+    is_equally_spaced : bool
+        True iff series index is equally spaced
+    is_equal_length: bool
+        True iff all series in panel are of equal length
+    is_empty: bool
+        True iff table has no variables or no instances
+    is_one_series: bool
+        True iff there is only one series in the panel of time series
+    has_nans: bool
+        True iff the table contains NaN values
+    n_instances: int
+        number of instances in the panel of time series
+    n_features: int
+        number of variables in table
+    feature_names: list of int or object
+        names of variables in table
+    dtypekind_dfip: list of DtypeKind enum
+        list of DtypeKind enum values for each feature in the panel,
+        following the data frame interface protocol
+    feature_kind: list of str
+        list of feature kind strings for each feature in the panel,
+        coerced to FLOAT or CATEGORICAL type
+    """
+
+    _tags = {
+        "scitype": "Panel",
+        "name": "pd-long",  # any string
+        "name_python": "panel_pd_long",  # lower_snake_case
+        "name_aliases": [],
+        "description": (
+            "WARNING: only for internal use, not a fully supported Panel mtype. "
+            "pd.DataFrame in long format, cols = (index, time_index, column)"
+        ),
+        "python_version": None,
+        "python_dependencies": "pandas",
+        "python_type": "pandas.DataFrame",
+        "capability:multivariate": True,
+        "capability:unequally_spaced": True,
+        "capability:missing_values": True,
+        "internal_only": True,
+        "skip_in_checks": True,
+    }
+
+    def _check(self, obj, return_metadata=False, var_name="obj"):
+        """Check if obj is of this data type.
+
+        Parameters
+        ----------
+        obj : any
+            Object to check.
+        return_metadata : bool, optional (default=False)
+            Whether to return metadata.
+        var_name : str, optional (default="obj")
+            Name of the variable to check, for use in error messages.
+
+        Returns
+        -------
+        valid : bool
+            Whether obj is of this data type.
+        msg : str, only returned if return_metadata is True.
+            Error message if obj is not of this data type.
+        metadata : dict, only returned if return_metadata is True.
+            Metadata dictionary.
+        """
+        # no checker defined, only used in conversions
+        pass
diff --git a/sktime/datatypes/_panel/_convert.py b/sktime/datatypes/_panel/_convert.py
index d5283e637..fb2882a99 100644
--- a/sktime/datatypes/_panel/_convert.py
+++ b/sktime/datatypes/_panel/_convert.py
@@ -35,10 +35,23 @@ __all__ = [
 
 from sktime.datatypes._convert_utils._coerce import _coerce_df_dtypes
 from sktime.datatypes._convert_utils._convert import _extend_conversions
-from sktime.datatypes._panel._registry import MTYPE_LIST_PANEL
 from sktime.utils.dependencies import _check_soft_dependencies
 from sktime.utils.pandas import df_map
 
+# this needs to be refactored with the convert module
+MTYPE_LIST_PANEL = [
+    "nested_univ",
+    "numpy3D",
+    "numpyflat",
+    "pd-multiindex",
+    "pd-wide",
+    "pd-long",
+    "df-list",
+    "gluonts_ListDataset_panel",
+    "gluonts_PandasDataset_panel",
+    "polars_panel",
+]
+
 # dictionary indexed by triples of types
 #  1st element = convert from - type
 #  2nd element = convert to - type
diff --git a/sktime/datatypes/_panel/_registry.py b/sktime/datatypes/_panel/_registry.py
deleted file mode 100644
index 344326eef..000000000
--- a/sktime/datatypes/_panel/_registry.py
+++ /dev/null
@@ -1,63 +0,0 @@
-"""Registry of mtypes for Panel scitype.
-
-See datatypes._registry for API.
-"""
-
-__all__ = [
-    "MTYPE_REGISTER_PANEL",
-    "MTYPE_LIST_PANEL",
-    "MTYPE_SOFT_DEPS_PANEL",
-]
-
-
-MTYPE_REGISTER_PANEL = [
-    (
-        "nested_univ",
-        "Panel",
-        "pd.DataFrame with one column per variable, pd.Series in cells",
-    ),
-    (
-        "numpy3D",
-        "Panel",
-        "3D np.array of format (n_instances, n_columns, n_timepoints)",
-    ),
-    (
-        "numpyflat",
-        "Panel",
-        "WARNING: only for internal use, not a fully supported Panel mtype. "
-        "2D np.array of format (n_instances, n_columns*n_timepoints)",
-    ),
-    ("pd-multiindex", "Panel", "pd.DataFrame with multi-index (instances, timepoints)"),
-    ("pd-wide", "Panel", "pd.DataFrame in wide format, cols = (instance*timepoints)"),
-    (
-        "pd-long",
-        "Panel",
-        "pd.DataFrame in long format, cols = (index, time_index, column)",
-    ),
-    ("df-list", "Panel", "list of pd.DataFrame"),
-    (
-        "gluonts_ListDataset_panel",
-        "Panel",
-        "gluonTS representation of univariate and multivariate time series",
-    ),
-    (
-        "gluonts_PandasDataset_panel",
-        "Panel",
-        "gluonTS representation of a pandas DataFrame",
-    ),
-    (
-        "polars_panel",
-        "Panel",
-        "Polars frame representing a Panel, with one instance and one time index",
-    ),
-]
-
-MTYPE_SOFT_DEPS_PANEL = {
-    "xr.DataArray": "xarray",
-    "dask_panel": "dask",
-    "gluonts_ListDataset_panel": "gluonts",
-    "gluonts_PandasDataset_panel": "gluonts",
-    "polars_panel": "polars",
-}
-
-MTYPE_LIST_PANEL = [x[0] for x in MTYPE_REGISTER_PANEL]
diff --git a/sktime/datatypes/_proba/__init__.py b/sktime/datatypes/_proba/__init__.py
index 5f166c037..4098a2dec 100644
--- a/sktime/datatypes/_proba/__init__.py
+++ b/sktime/datatypes/_proba/__init__.py
@@ -1,10 +1,5 @@
 """Type checkers, converters and mtype inference for probabilistic return types."""
 
 from sktime.datatypes._proba._convert import convert_dict as convert_dict_Proba
-from sktime.datatypes._proba._registry import MTYPE_LIST_PROBA, MTYPE_REGISTER_PROBA
 
-__all__ = [
-    "convert_dict_Proba",
-    "MTYPE_LIST_PROBA",
-    "MTYPE_REGISTER_PROBA",
-]
+__all__ = ["convert_dict_Proba"]
diff --git a/sktime/datatypes/_proba/_check.py b/sktime/datatypes/_proba/_check.py
index bc7f18d33..de06fe70f 100644
--- a/sktime/datatypes/_proba/_check.py
+++ b/sktime/datatypes/_proba/_check.py
@@ -68,6 +68,7 @@ class ProbaPredQuantiles(ScitypeProba):
         "name": "pred_quantiles",  # any string
         "name_python": "proba_pred_quantiles",  # lower_snake_case
         "name_aliases": [],
+        "description": "pandas.DataFrame based specification of predictive quantiles",
         "python_version": None,
         "python_dependencies": "pandas",
     }
@@ -176,6 +177,7 @@ class ProbaPredInterval(ScitypeProba):
         "name": "pred_interval",  # any string
         "name_python": "proba_pred_interval",  # lower_snake_case
         "name_aliases": [],
+        "description": "pandas.DataFrame based specification of predictive intervals",
         "python_version": None,
         "python_dependencies": "pandas",
     }
diff --git a/sktime/datatypes/_proba/_convert.py b/sktime/datatypes/_proba/_convert.py
index e8345d7c7..3b95130b3 100644
--- a/sktime/datatypes/_proba/_convert.py
+++ b/sktime/datatypes/_proba/_convert.py
@@ -33,7 +33,8 @@ __all__ = ["convert_dict"]
 import numpy as np
 import pandas as pd
 
-from sktime.datatypes._proba._registry import MTYPE_LIST_PROBA
+# this needs to be refactored with the convert module
+MTYPE_LIST_PROBA = ["pred_interval", "pred_quantiles"]
 
 ##############################################################
 # methods to convert one machine type to another machine type
diff --git a/sktime/datatypes/_proba/_registry.py b/sktime/datatypes/_proba/_registry.py
deleted file mode 100644
index 98f4245e0..000000000
--- a/sktime/datatypes/_proba/_registry.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""Registry of mtypes for Proba scitype.
-
-See datatypes._registry for API.
-"""
-
-__all__ = [
-    "MTYPE_REGISTER_PROBA",
-    "MTYPE_LIST_PROBA",
-]
-
-
-MTYPE_REGISTER_PROBA = [
-    ("pred_interval", "Proba", "predictive intervals"),
-    ("pred_quantiles", "Proba", "quantile predictions"),
-    ("pred_var", "Proba", "variance predictions"),
-    # ("pred_dost", "Proba", "full distribution predictions, tensorflow-probability"),
-]
-
-MTYPE_LIST_PROBA = [x[0] for x in MTYPE_REGISTER_PROBA]
diff --git a/sktime/datatypes/_registry.py b/sktime/datatypes/_registry.py
index 461a07551..651b1e419 100644
--- a/sktime/datatypes/_registry.py
+++ b/sktime/datatypes/_registry.py
@@ -38,60 +38,199 @@ mtype_to_scitype(mtype: str) - convenience function that returns scitype for an
 ---
 """
 
-from sktime.datatypes._alignment._registry import (
-    MTYPE_LIST_ALIGNMENT,
-    MTYPE_REGISTER_ALIGNMENT,
-)
-from sktime.datatypes._hierarchical._registry import (
-    MTYPE_LIST_HIERARCHICAL,
-    MTYPE_REGISTER_HIERARCHICAL,
-    MTYPE_SOFT_DEPS_HIERARCHICAL,
-)
-from sktime.datatypes._panel._registry import (
-    MTYPE_LIST_PANEL,
-    MTYPE_REGISTER_PANEL,
-    MTYPE_SOFT_DEPS_PANEL,
-)
-from sktime.datatypes._proba._registry import MTYPE_LIST_PROBA, MTYPE_REGISTER_PROBA
-from sktime.datatypes._series._registry import (
-    MTYPE_LIST_SERIES,
-    MTYPE_REGISTER_SERIES,
-    MTYPE_SOFT_DEPS_SERIES,
-)
-from sktime.datatypes._table._registry import MTYPE_LIST_TABLE, MTYPE_REGISTER_TABLE
-
-MTYPE_REGISTER = []
-MTYPE_REGISTER += MTYPE_REGISTER_SERIES
-MTYPE_REGISTER += MTYPE_REGISTER_PANEL
-MTYPE_REGISTER += MTYPE_REGISTER_HIERARCHICAL
-MTYPE_REGISTER += MTYPE_REGISTER_ALIGNMENT
-MTYPE_REGISTER += MTYPE_REGISTER_TABLE
-MTYPE_REGISTER += MTYPE_REGISTER_PROBA
+from functools import lru_cache
+
+
+def _only_core_deps(cls):
+    """Return True if the class has only core dependencies."""
+    # dependencies implied by the core requirements
+    # that may appear in the classes as python_dependencies tag
+    # it is assumed that only simple dependency strings, no version requirements appear
+    DEPS_PRESENT_IN_ENV = ["numpy", "pandas"]
+
+    deps_tag = cls.get_tag("python_dependencies")
+
+    if deps_tag is None:
+        return True
+    if not isinstance(deps_tag, (list, tuple)) and deps_tag in DEPS_PRESENT_IN_ENV:
+        return True
+    if isinstance(deps_tag, (list, tuple)):
+        return all([x in DEPS_PRESENT_IN_ENV for x in deps_tag])
+    return False
+
+
+def generate_mtype_cls_list(soft_deps="present"):
+    """Generate list of mtype classes using lookup.
+
+    Parameters
+    ----------
+    softdeps : str, optional, default = "present"
+        how inclusion in relation to presence of soft dependencies is handled
+
+        * "exclude" = only classes that do not require soft dependencies are returned
+        * "present" = only classes with soft deps satisfied by the current python
+        environment are returned
+        * "all" = all classes, irrespective of soft deps satisfied or required, returned
+        any other value defaults to "all"
+
+    Returns
+    -------
+    classes : list of classes
+        all classes that are mtypes, i.e. subclasses of BaseDatatype
+        and not starting with "Base" or "Scitype"
+    """
+    if soft_deps not in ["exclude", "present", "all"]:
+        raise ValueError(
+            "Error in soft_deps argument in generate_scitype_cls_list: "
+            "soft_deps must be one of 'exclude', 'present', 'all', "
+            f"but got {soft_deps}"
+        )
+    return _generate_mtype_cls_list(soft_deps=soft_deps).copy()
+
+
+@lru_cache(maxsize=3)
+def _generate_mtype_cls_list(soft_deps="present"):
+    """Generate list of scitype classes using lookup, cached function."""
+    from skbase.utils.dependencies import _check_estimator_deps
+
+    from sktime.datatypes._base import BaseDatatype
+    from sktime.utils.retrieval import _all_classes
+
+    classes = _all_classes("sktime.datatypes")
+    classes = [x[1] for x in classes]
+    classes = [x for x in classes if issubclass(x, BaseDatatype)]
+    classes = [x for x in classes if not x.__name__.startswith("Base")]
+    classes = [x for x in classes if not x.__name__.startswith("Scitype")]
+
+    # subset only to data types with soft dependencies present
+    if soft_deps == "present":
+        classes = [x for x in classes if _check_estimator_deps(x, severity="none")]
+    elif soft_deps == "exclude":
+        classes = [x for x in classes if _only_core_deps(x)]
+    # elif soft_deps=="all", no filtering happens
+
+    return classes
+
+
+def generate_mtype_register(scitype=None, soft_deps="all"):
+    """Generate mtype class register using lookup.
+
+    Parameters
+    ----------
+    scitype str or None, optional, default = None
+        optional scitype to restrict the mtypes to
+
+        * if None, all mtypes are returned
+        * if str, must be scitype string, only mtypes for the scitype are returned
+
+    softdeps : str, optional, default = "all"
+        how inclusion in relation to presence of soft dependencies is handled
+
+        * "exclude" = only classes that do not require soft dependencies are returned
+        * "present" = only classes with soft deps satisfied by the current python
+        environment are returned
+        * "all" = all classes, irrespective of soft deps satisfied or required, returned
+        any other value defaults to "all"
+
+    Returns
+    -------
+    register : list of tuples
+        each tuple corresponds to an mtype, elements as follows:
+
+        0 : string - name of the mtype as used throughout sktime and in datatypes
+
+        1 : string - name of the scitype the mtype is for, must be in SCITYPE_REGISTER
+
+        2 : string - plain English description of the scitype
+    """
+    return _generate_mtype_register_subset(scitype=scitype, soft_deps=soft_deps)
+
+
+@lru_cache(maxsize=256)
+def _generate_mtype_register_subset(scitype=None, soft_deps="all"):
+    """Generate mtype class register using lookup, cached function."""
+    full_register = _generate_mtype_register(soft_deps=soft_deps)
+    if scitype is None:
+        return full_register.copy()
+    else:
+        return [x for x in full_register if x[1] == scitype]
+
+
+@lru_cache(maxsize=3)
+def _generate_mtype_register(soft_deps="all"):
+    """Generate mtype class register using lookup, cached function."""
+    classes = _generate_mtype_cls_list(soft_deps=soft_deps)
+
+    def to_tuple(cls):
+        """Return tuple of mtype register elements."""
+        mtype = cls.get_class_tag("name")
+        scitype = cls.get_class_tag("scitype")
+        desc = cls.get_class_tag("description")
+        return mtype, scitype, desc
+
+    register = [to_tuple(x) for x in classes]
+    return register
+
+
+def generate_mtype_list(scitype=None, soft_deps="all"):
+    """Generate mtype list using lookup.
+
+    Parameters
+    ----------
+    scitype str or None, optional, default = None
+        optional scitype to restrict the mtypes to
+
+        * if None, all mtypes are returned
+        * if str, must be scitype string, only mtypes for the scitype are returned
+
+    softdeps : str, optional, default = "all"
+        how inclusion in relation to presence of soft dependencies is handled
+
+        * "exclude" = only classes that do not require soft dependencies are returned
+        * "present" = only classes with soft deps satisfied by the current python
+        environment are returned
+        * "all" = all classes, irrespective of soft deps satisfied or required, returned
+        any other value defaults to "all"
+
+    Returns
+    -------
+    register : list of string
+        entries are name of the mtype as used throughout sktime and in datatypes
+    """
+    return [x[0] for x in generate_mtype_register(scitype=scitype, soft_deps=soft_deps)]
+
+
+MTYPE_SOFT_DEPS_SERIES = {
+    "xr.DataArray": "xarray",
+    "dask_series": "dask",
+    "pl.DataFrame": "polars",
+    "gluonts_ListDataset_series": "gluonts",
+    "gluonts_PandasDataset_series": "gluonts",
+}
+
+MTYPE_SOFT_DEPS_PANEL = {
+    "xr.DataArray": "xarray",
+    "dask_panel": "dask",
+    "gluonts_ListDataset_panel": "gluonts",
+    "gluonts_PandasDataset_panel": "gluonts",
+    "polars_panel": "polars",
+}
+
+MTYPE_SOFT_DEPS_HIERARCHICAL = {
+    "dask_hierarchical": "dask",
+    "polars_hierarchical": "polars",
+}
 
 MTYPE_SOFT_DEPS = {}
 MTYPE_SOFT_DEPS.update(MTYPE_SOFT_DEPS_SERIES)
 MTYPE_SOFT_DEPS.update(MTYPE_SOFT_DEPS_PANEL)
 MTYPE_SOFT_DEPS.update(MTYPE_SOFT_DEPS_HIERARCHICAL)
 
-
 # mtypes to exclude in checking since they are ambiguous and rare
-AMBIGUOUS_MTYPES = ["numpyflat", "alignment_loc"]
-
-# all time series mtypes excluding ambiguous ones
-ALL_TIME_SERIES_MTYPES = (
-    list(MTYPE_LIST_PANEL) + list(MTYPE_LIST_SERIES) + list(MTYPE_LIST_HIERARCHICAL)
-)
-ALL_TIME_SERIES_MTYPES = list(set(ALL_TIME_SERIES_MTYPES).difference(AMBIGUOUS_MTYPES))
+AMBIGUOUS_MTYPES = ["numpyflat", "alignment_loc", "pd-long", "pd-wide"]
 
 
 __all__ = [
-    "MTYPE_REGISTER",
-    "MTYPE_LIST_HIERARCHICAL",
-    "MTYPE_LIST_PANEL",
-    "MTYPE_LIST_SERIES",
-    "MTYPE_LIST_ALIGNMENT",
-    "MTYPE_LIST_TABLE",
-    "MTYPE_LIST_PROBA",
     "MTYPE_SOFT_DEPS",
     "SCITYPE_REGISTER",
 ]
@@ -153,7 +292,7 @@ def mtype_to_scitype(mtype: str, return_unique=False, coerce_to_list=False):
             "mtype must be str, or list of str, nested list/str object, or None"
         )
 
-    scitype = [k[1] for k in MTYPE_REGISTER if k[0] == mtype]
+    scitype = [k[1] for k in generate_mtype_register() if k[0] == mtype]
 
     if len(scitype) > 1:
         raise ValueError("multiple scitypes match the mtype, specify scitype")
@@ -215,7 +354,7 @@ def scitype_to_mtype(scitype: str, softdeps: str = "exclude"):
             f'"{scitype}" is not a valid scitype string, see datatypes.SCITYPE_REGISTER'
         )
 
-    mtypes = [k[0] for k in MTYPE_REGISTER if k[1] == scitype]
+    mtypes = [k[0] for k in generate_mtype_register() if k[1] == scitype]
 
     if len(mtypes) == 0:
         # if there are no mtypes, this must have been reached by mistake/bug
diff --git a/sktime/datatypes/_series/__init__.py b/sktime/datatypes/_series/__init__.py
index 5f6e59d94..b45d1816c 100644
--- a/sktime/datatypes/_series/__init__.py
+++ b/sktime/datatypes/_series/__init__.py
@@ -1,10 +1,5 @@
 """Module exports: Series type checkers, converters and mtype inference."""
 
 from sktime.datatypes._series._convert import convert_dict as convert_dict_Series
-from sktime.datatypes._series._registry import MTYPE_LIST_SERIES, MTYPE_REGISTER_SERIES
 
-__all__ = [
-    "convert_dict_Series",
-    "MTYPE_LIST_SERIES",
-    "MTYPE_REGISTER_SERIES",
-]
+__all__ = ["convert_dict_Series"]
diff --git a/sktime/datatypes/_series/_check.py b/sktime/datatypes/_series/_check.py
index 4e3904cf6..1de2d801a 100644
--- a/sktime/datatypes/_series/_check.py
+++ b/sktime/datatypes/_series/_check.py
@@ -112,6 +112,7 @@ class SeriesPdDataFrame(ScitypeSeries):
         "name": "pd.DataFrame",  # any string
         "name_python": "series_pd_df",  # lower_snake_case
         "name_aliases": [],
+        "description": "pandas.DataFrame representation of a uni- or multivariate series",  # noqa: E501
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "pandas.DataFrame",
@@ -272,6 +273,7 @@ class SeriesPdSeries(ScitypeSeries):
         "name": "pd.Series",  # any string
         "name_python": "series_pd_sr",  # lower_snake_case
         "name_aliases": [],
+        "description": "pandas.Series representation of a univariate series",
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "pandas.Series",
@@ -417,6 +419,7 @@ class SeriesNp2D(ScitypeSeries):
         "name": "np.ndarray",  # any string
         "name_python": "series_pd_np",  # lower_snake_case
         "name_aliases": [],
+        "description": "2D numpy.ndarray with rows=samples, cols=variables, index=integers",  # noqa: E501
         "python_version": None,
         "python_dependencies": "numpy",
         "python_type": "numpy.ndarray",
@@ -632,6 +635,7 @@ class SeriesXarray(ScitypeSeries):
         "name": "xr.DataArray",  # any string
         "name_python": "series_xarray",  # lower_snake_case
         "name_aliases": [],
+        "description": "xarray.DataArray representation of a uni- or multivariate time series",  # noqa: E501
         "python_version": None,
         "python_dependencies": "xarray",
         "python_type": "xarray.DataArray",
@@ -765,6 +769,7 @@ class SeriesDask(ScitypeSeries):
         "name": "dask_series",  # any string
         "name_python": "series_dask",  # lower_snake_case
         "name_aliases": [],
+        "description": "dask.DataFrame representation of a uni- or multivariate series",
         "python_version": None,
         "python_dependencies": "dask",
         "python_type": "dask.dataframe",
@@ -835,6 +840,7 @@ class SeriesPolarsEager(ScitypeSeries):
         "name": "pl.DataFrame",  # any string
         "name_python": "series_polars_eager",  # lower_snake_case
         "name_aliases": [],
+        "description": "polars.DataFrame representation of a uni- or multivariate series",  # noqa: E501
         "python_version": None,
         "python_dependencies": "polars",
         "python_type": "polars.DataFrame",
@@ -911,6 +917,7 @@ class SeriesGluontsList(ScitypeSeries):
         "name": "gluonts_ListDataset_series",  # any string
         "name_python": "series_gluonts_listdataset",  # lower_snake_case
         "name_aliases": [],
+        "description": "gluonts ListDataset representation of a uni- or multivariate series",  # noqa: E501
         "python_version": None,
         "python_dependencies": "gluonts",
         "python_type": "list",
@@ -1055,6 +1062,7 @@ class SeriesGluontsPandas(ScitypeSeries):
         "name": "gluonts_PandasDataset_series",  # any string
         "name_python": "series_gluonts_pandasdataset",  # lower_snake_case
         "name_aliases": [],
+        "description": "gluonts PandasDataset representation of a uni- or multivariate series",  # noqa: E501
         "python_version": None,
         "python_dependencies": "gluonts",
         "python_type": "gluonts.PandasDataset",
@@ -1132,7 +1140,7 @@ class SeriesGluontsPandas(ScitypeSeries):
         if _req("has_nans", return_metadata):
             metadata["has_nans"] = df.isna().any().any()
 
-        if _req("dtypekind_dfip", return_metadata):
+        if _req(["feature_kind", "dtypekind_dfip"], return_metadata):
             index_cols_count = len(df.columns)
 
             # slicing off additional index columns
diff --git a/sktime/datatypes/_series/_convert.py b/sktime/datatypes/_series/_convert.py
index ee1e50efc..2794e95c7 100644
--- a/sktime/datatypes/_series/_convert.py
+++ b/sktime/datatypes/_series/_convert.py
@@ -38,9 +38,20 @@ import pandas as pd
 ##############################################################
 from sktime.datatypes._convert_utils._coerce import _coerce_df_dtypes
 from sktime.datatypes._convert_utils._convert import _extend_conversions
-from sktime.datatypes._series._registry import MTYPE_LIST_SERIES
 from sktime.utils.dependencies import _check_soft_dependencies
 
+# this needs to be refactored with the convert module
+MTYPE_LIST_SERIES = [
+    "pd.Series",
+    "pd.DataFrame",
+    "np.ndarray",
+    "xr.DataArray",
+    "dask_series",
+    "pl.DataFrame",
+    "gluonts_ListDataset_series",
+    "gluonts_PandasDataset_series",
+]
+
 convert_dict = dict()
 
 
diff --git a/sktime/datatypes/_series/_registry.py b/sktime/datatypes/_series/_registry.py
deleted file mode 100644
index a0d888410..000000000
--- a/sktime/datatypes/_series/_registry.py
+++ /dev/null
@@ -1,54 +0,0 @@
-"""Registry of mtypes for Series scitype.
-
-See datatypes._registry for API.
-"""
-
-__all__ = [
-    "MTYPE_REGISTER_SERIES",
-    "MTYPE_LIST_SERIES",
-    "MTYPE_SOFT_DEPS_SERIES",
-]
-
-
-MTYPE_REGISTER_SERIES = [
-    ("pd.Series", "Series", "pd.Series representation of a univariate series"),
-    (
-        "pd.DataFrame",
-        "Series",
-        "pd.DataFrame representation of a uni- or multivariate series",
-    ),
-    (
-        "np.ndarray",
-        "Series",
-        "2D numpy.ndarray with rows=samples, cols=variables, index=integers",
-    ),
-    (
-        "xr.DataArray",
-        "Series",
-        "xr.DataArray representation of a uni- or multivariate series",
-    ),
-    (
-        "dask_series",
-        "Series",
-        "xdas representation of a uni- or multivariate series",
-    ),
-    (
-        "pl.DataFrame",
-        "Series",
-        "pl.DataFrame representation of a uni- or multivariate series",
-    ),
-    (
-        "gluonts_ListDataset_series",
-        "Series",
-        "gluonTS representation of univariate and multivariate series",
-    ),
-]
-
-MTYPE_SOFT_DEPS_SERIES = {
-    "xr.DataArray": "xarray",
-    "dask_series": "dask",
-    "pl.DataFrame": "polars",
-    "gluonts_ListDataset_series": "gluonts",
-}
-
-MTYPE_LIST_SERIES = [x[0] for x in MTYPE_REGISTER_SERIES]
diff --git a/sktime/datatypes/_table/__init__.py b/sktime/datatypes/_table/__init__.py
index dbdfd021c..d06e68a57 100644
--- a/sktime/datatypes/_table/__init__.py
+++ b/sktime/datatypes/_table/__init__.py
@@ -1,10 +1,5 @@
 """Module exports: Series type checkers, converters and mtype inference."""
 
 from sktime.datatypes._table._convert import convert_dict as convert_dict_Table
-from sktime.datatypes._table._registry import MTYPE_LIST_TABLE, MTYPE_REGISTER_TABLE
 
-__all__ = [
-    "convert_dict_Table",
-    "MTYPE_LIST_TABLE",
-    "MTYPE_REGISTER_TABLE",
-]
+__all__ = ["convert_dict_Table"]
diff --git a/sktime/datatypes/_table/_check.py b/sktime/datatypes/_table/_check.py
index a9c959cae..6464c6c72 100644
--- a/sktime/datatypes/_table/_check.py
+++ b/sktime/datatypes/_table/_check.py
@@ -102,6 +102,7 @@ class TablePdDataFrame(ScitypeTable):
         "name": "pd_DataFrame_Table",  # any string
         "name_python": "table_pd_df",  # lower_snake_case
         "name_aliases": [],
+        "description": "pandas.DataFrame representation of a data table",
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "pandas.DataFrame",
@@ -223,6 +224,7 @@ class TablePdSeries(ScitypeTable):
         "name": "pd_Series_Table",  # any string
         "name_python": "table_pd_series",  # lower_snake_case
         "name_aliases": [],
+        "description": "pandas.Series representation of a data table",
         "python_version": None,
         "python_dependencies": "pandas",
         "python_type": "pandas.Series",
@@ -350,6 +352,7 @@ class TableNp1D(ScitypeTable):
         "name": "numpy1D",  # any string
         "name_python": "table_numpy1d",  # lower_snake_case
         "name_aliases": [],
+        "description": "1D np.narray representation of a univariate data table",
         "python_version": None,
         "python_dependencies": "numpy",
         "python_type": "numpy.ndarray",
@@ -475,6 +478,7 @@ class TableNp2D(ScitypeTable):
         "name": "numpy2D",  # any string
         "name_python": "table_numpy2d",  # lower_snake_case
         "name_aliases": [],
+        "description": "2D np.narray representation of a multivariate data table",
         "python_version": None,
         "python_dependencies": "numpy",
         "python_type": "numpy.ndarray",
@@ -599,6 +603,7 @@ class TableListOfDict(ScitypeTable):
         "name": "list_of_dict",  # any string
         "name_python": "table_list_of_dict",  # lower_snake_case
         "name_aliases": [],
+        "description": "list of dictionaries with primitive entries",
         "python_version": None,
         "python_dependencies": "numpy",
         "python_type": "list",
@@ -744,6 +749,7 @@ class TablePolarsEager(ScitypeTable):
         "name": "polars_eager_table",  # any string
         "name_python": "table_polars_eager",  # lower_snake_case
         "name_aliases": [],
+        "description": "eager polars.DataFrame representation of a data table",
         "python_version": None,
         "python_dependencies": ["polars", "pyarrow"],
         "python_type": "polars.DataFrame",
@@ -810,6 +816,7 @@ class TablePolarsLazy(ScitypeTable):
         "name": "polars_lazy_table",  # any string
         "name_python": "table_polars_lazy",  # lower_snake_case
         "name_aliases": [],
+        "description": "lazy polars.DataFrame representation of a data table",
         "python_version": None,
         "python_dependencies": ["polars", "pyarrow"],
         "python_type": "polars.LazyFrame",
diff --git a/sktime/datatypes/_table/_convert.py b/sktime/datatypes/_table/_convert.py
index 8e078d4a7..abf6c633c 100644
--- a/sktime/datatypes/_table/_convert.py
+++ b/sktime/datatypes/_table/_convert.py
@@ -34,9 +34,19 @@ import numpy as np
 import pandas as pd
 
 from sktime.datatypes._convert_utils._convert import _extend_conversions
-from sktime.datatypes._table._registry import MTYPE_LIST_TABLE
 from sktime.utils.dependencies import _check_soft_dependencies
 
+# this needs to be refactored with the convert module
+MTYPE_LIST_TABLE = [
+    "pd_DataFrame_Table",
+    "numpy1D",
+    "numpy2D",
+    "pd_Series_Table",
+    "list_of_dict",
+    "polars_eager_table",
+    "polars_lazy_table",
+]
+
 ##############################################################
 # methods to convert one machine type to another machine type
 ##############################################################
diff --git a/sktime/datatypes/_table/_registry.py b/sktime/datatypes/_table/_registry.py
deleted file mode 100644
index f7f7974cf..000000000
--- a/sktime/datatypes/_table/_registry.py
+++ /dev/null
@@ -1,22 +0,0 @@
-"""Registry of mtypes for Table scitype.
-
-See datatypes._registry for API.
-"""
-
-__all__ = [
-    "MTYPE_REGISTER_TABLE",
-    "MTYPE_LIST_TABLE",
-]
-
-
-MTYPE_REGISTER_TABLE = [
-    ("pd_DataFrame_Table", "Table", "pd.DataFrame representation of a data table"),
-    ("numpy1D", "Table", "1D np.narray representation of a univariate data table"),
-    ("numpy2D", "Table", "2D np.narray representation of a multivariate data table"),
-    ("pd_Series_Table", "Table", "pd.Series representation of a univariate data table"),
-    ("list_of_dict", "Table", "list of dictionaries with primitive entries"),
-    ("polars_eager_table", "Table", "polars.DataFrame representation of a data table"),
-    ("polars_lazy_table", "Table", "polars.LazyFrame representation of a data table"),
-]
-
-MTYPE_LIST_TABLE = [x[0] for x in MTYPE_REGISTER_TABLE]


Test patch:
diff --git a/sktime/datatypes/tests/test_lookup.py b/sktime/datatypes/tests/test_lookup.py
index bc4120011..7f2b34c04 100644
--- a/sktime/datatypes/tests/test_lookup.py
+++ b/sktime/datatypes/tests/test_lookup.py
@@ -2,20 +2,28 @@
 
 __author__ = ["fkiraly"]
 
-import pytest
-
 from sktime.datatypes._registry import (
-    MTYPE_REGISTER,
     MTYPE_SOFT_DEPS,
+    generate_mtype_register,
     mtype_to_scitype,
     scitype_to_mtype,
 )
 from sktime.utils.dependencies import _check_soft_dependencies
 
-MTYPE_SCITYPE_PAIRS = [(k[0], k[1]) for k in MTYPE_REGISTER]
+
+def pytest_generate_tests(metafunc):
+    register = generate_mtype_register()
+    if "mtype" in metafunc.fixturenames and "scitype" in metafunc.fixturenames:
+        mtypes_scitypes = [(k[0], k[1]) for k in register]
+        metafunc.parametrize("mtype, scitype", mtypes_scitypes)
+    elif "mtype" in metafunc.fixturenames:
+        mtypes = [k[0] for k in register]
+        metafunc.parametrize("mtype", mtypes)
+    elif "scitype" in metafunc.fixturenames:
+        scitypes = [k[1] for k in register]
+        metafunc.parametrize("scitype", scitypes)
 
 
-@pytest.mark.parametrize("mtype, scitype", MTYPE_SCITYPE_PAIRS)
 def test_mtype_to_scitype(mtype, scitype):
     """Tests that mtype_to_scitype yields the correct output for a string.
 
@@ -50,6 +58,7 @@ def test_mtype_to_scitype_list():
     AssertionError mtype_to_scitype does not convert mtype to scitype
     Exception if any is raised by mtype_to_scitype
     """
+    MTYPE_REGISTER = generate_mtype_register()
     mtype_list = [k[0] for k in MTYPE_REGISTER]
     expected_scitype_list = [k[1] for k in MTYPE_REGISTER]
     result = mtype_to_scitype(mtype_list)
@@ -59,7 +68,6 @@ def test_mtype_to_scitype_list():
     assert result == expected_scitype_list, msg
 
 
-@pytest.mark.parametrize("mtype, scitype", MTYPE_SCITYPE_PAIRS)
 def test_scitype_to_mtype(mtype, scitype):
     """Tests that scitype_to_mtype yields the correct output for a string.
 
diff --git a/sktime/tests/_config.py b/sktime/tests/_config.py
index b1ca27442..3790bd551 100644
--- a/sktime/tests/_config.py
+++ b/sktime/tests/_config.py
@@ -72,6 +72,7 @@ EXCLUDE_ESTIMATORS = [
     # multiple timeouts and sporadic failures reported related to VARMAX
     # 2997, 3176, 7985
     "VARMAX",
+    "SCINetForecaster",  # known bug #7871
 ]