Repository: sktime/sktime

Issue:
[BUG] all_tags returns empty list with estimator type
**Describe the bug**
`all_tags` returns empty list when passing estimator type. I suspect it was just copied over from `all_estimators` and can just be removed for now. Otherwise the docstring needs to be updated too. 

**To Reproduce**
```python
from sktime.registry import all_tags
all_tags(estimator_types="forecaster")
```

**Expected behavior**
Get list of tags applicable for given estimator type.




Discussion:

Resolving patch:
diff --git a/sktime/registry/_lookup.py b/sktime/registry/_lookup.py
--- a/sktime/registry/_lookup.py
+++ b/sktime/registry/_lookup.py
@@ -14,6 +14,7 @@
 
 import inspect
 import pkgutil
+from copy import deepcopy
 from importlib import import_module
 from operator import itemgetter
 from pathlib import Path
@@ -282,11 +283,31 @@ def all_tags(
                 ("list", list_of_string) - any individual string and sub-list is valid
         d : string - plain English description of the tag
     """
+
+    def is_tag_for_type(tag, estimator_types):
+        tag_types = tag[1]
+        if isinstance(tag_types, str):
+            tag_types = [tag_types]
+        elif not isinstance(tag_types, list):
+            raise ValueError(
+                "Error in ESTIMATOR_TAG_REGISTER, "
+                "2nd entries of register tuples must be list or list of str"
+            )
+        if isinstance(estimator_types, str):
+            estimator_types = [estimator_types]
+
+        tag_types = set(tag_types)
+        estimator_types = set(estimator_types)
+        is_valid_tag_for_type = len(tag_types.intersection(estimator_types)) > 0
+
+        return is_valid_tag_for_type
+
     all_tags = ESTIMATOR_TAG_REGISTER
 
     if estimator_types is not None:
-        estimator_types = _check_estimator_types(estimator_types)
-        all_tags = [tag for tag in all_tags if tag[1] in estimator_types]
+        # checking, but not using the return since that is classes, not strings
+        _check_estimator_types(estimator_types)
+        all_tags = [tag for tag in all_tags if is_tag_for_type(tag, estimator_types)]
 
     all_tags = sorted(all_tags, key=itemgetter(0))
 
@@ -299,6 +320,9 @@ def all_tags(
 
 
 def _check_estimator_types(estimator_types):
+    """Return list of classes corresponding to type strings."""
+    estimator_types = deepcopy(estimator_types)
+
     if not isinstance(estimator_types, list):
         estimator_types = [estimator_types]  # make iterable
 
diff --git a/sktime/registry/_tags.py b/sktime/registry/_tags.py
--- a/sktime/registry/_tags.py
+++ b/sktime/registry/_tags.py
@@ -112,7 +112,7 @@
     ),
     (
         "symmetric",
-        ["transformer-pairwise-tabular", "transformer-pairwise-panel"],
+        ["transformer-pairwise", "transformer-pairwise-panel"],
         "bool",
         "is the transformer symmetric, i.e., t(x,y)=t(y,x) always?",
     ),


Test patch:
diff --git a/sktime/registry/tests/__init__.py b/sktime/registry/tests/__init__.py
new file mode 100644
--- /dev/null
+++ b/sktime/registry/tests/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+"""Registry tests."""
diff --git a/sktime/registry/tests/test_lookup.py b/sktime/registry/tests/test_lookup.py
new file mode 100644
--- /dev/null
+++ b/sktime/registry/tests/test_lookup.py
@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+# copyright: sktime developers, BSD-3-Clause License (see LICENSE file)
+"""Testing of registry lookup functionality."""
+
+__author__ = ["fkiraly"]
+
+import pytest
+
+from sktime.base import BaseEstimator
+from sktime.registry import all_estimators, all_tags
+from sktime.registry._base_classes import (
+    BASE_CLASS_LOOKUP,
+    BASE_CLASS_SCITYPE_LIST,
+    TRANSFORMER_MIXIN_SCITYPE_LIST,
+)
+
+VALID_SCITYPES_SET = set(
+    BASE_CLASS_SCITYPE_LIST + TRANSFORMER_MIXIN_SCITYPE_LIST + ["estimator"]
+)
+
+# some scitypes have no associated tags yet
+SCITYPES_WITHOUT_TAGS = ["series-annotator", "clusterer"]
+
+# shorthands for easy reading
+b = BASE_CLASS_SCITYPE_LIST
+n = len(b)
+
+# selected examples of "search for two types at once to avoid quadratic scaling"
+double_estimator_scitypes = [[b[i], b[(i + 3) % n]] for i in range(n)]
+# fixtures search by individual scitypes, "None", and some pairs
+estimator_scitype_fixture = [None] + BASE_CLASS_SCITYPE_LIST + double_estimator_scitypes
+
+
+def _to_list(obj):
+    """Put obj in list if it is not a list."""
+    if not isinstance(obj, list):
+        return [obj]
+    else:
+        return obj
+
+
+def _get_type_tuple(estimator_scitype):
+    """Convert scitype string(s) into tuple of classes for isinstance check.
+
+    Parameters
+    ----------
+    estimator_scitypes: None, string, or list of string
+
+    Returns
+    -------
+    estimator_classes : tuple of sktime base classes,
+        corresponding to scitype strings in estimator_scitypes
+    """
+    if estimator_scitype is not None:
+
+        estimator_classes = tuple(
+            BASE_CLASS_LOOKUP[scitype] for scitype in _to_list(estimator_scitype)
+        )
+    else:
+        estimator_classes = (BaseEstimator,)
+
+    return estimator_classes
+
+
+@pytest.mark.parametrize("return_names", [True, False])
+@pytest.mark.parametrize("estimator_scitype", estimator_scitype_fixture)
+def test_all_estimators_by_scitype(estimator_scitype, return_names):
+    """Check that all_estimators return argument has correct type."""
+    estimators = all_estimators(
+        estimator_types=estimator_scitype,
+        return_names=return_names,
+    )
+
+    estimator_classes = _get_type_tuple(estimator_scitype)
+
+    assert isinstance(estimators, list)
+    # there should be at least one estimator returned
+    assert len(estimators) > 0
+
+    # checks return type specification (see docstring)
+    if return_names:
+        for estimator in estimators:
+            assert isinstance(estimator, tuple) and len(estimator) == 2
+            assert isinstance(estimator[0], str)
+            assert issubclass(estimator[1], estimator_classes)
+            assert estimator[0] == estimator[1].__name__
+    else:
+        for estimator in estimators:
+            assert issubclass(estimator, estimator_classes)
+
+
+@pytest.mark.parametrize("estimator_scitype", estimator_scitype_fixture)
+def test_all_tags(estimator_scitype):
+    """Check that all_tags return argument has correct type."""
+    tags = all_tags(estimator_types=estimator_scitype)
+    assert isinstance(tags, list)
+
+    # there should be at least one tag returned
+    # exception: scitypes which we know don't have tags associated
+    if estimator_scitype not in SCITYPES_WITHOUT_TAGS:
+        assert len(tags) > 0
+
+    # checks return type specification (see docstring)
+    for tag in tags:
+        assert isinstance(tag, tuple)
+        assert isinstance(tag[0], str)
+        assert VALID_SCITYPES_SET.issuperset(_to_list(tag[1]))
+        assert isinstance(tag[2], (str, tuple))
+        if isinstance(tag[2], tuple):
+            assert len(tag[2]) == 2
+            assert isinstance(tag[2][0], str)
+            assert isinstance(tag[2][1], list)
+        assert isinstance(tag[3], str)