Repository: cogent3/cogent3
Pull request #1593 (2023-10-04 00:49:19)

New function for discovering cogent3 type hints


Patch:
diff --git a/src/cogent3/app/typing.py b/src/cogent3/app/typing.py
index 035a0c725..ce2faabaa 100644
--- a/src/cogent3/app/typing.py
+++ b/src/cogent3/app/typing.py
@@ -3,11 +3,14 @@
 from __future__ import annotations
 
 import inspect
+import re
 
 from typing import ForwardRef, Iterable, TypeVar, Union
 
 from typing_extensions import get_args, get_origin
 
+from cogent3.util import warning as c3warn
+
 
 AlignedSeqsType = TypeVar("AlignedSeqsType", "Alignment", "ArrayAlignment")
 UnalignedSeqsType = TypeVar("UnalignedSeqsType", bound="SequenceCollection")
@@ -44,6 +47,18 @@ ResultType = Union[
 # todo when move to python 3.8 define protocols for IdentifierType and SerialisableType
 IdentifierType = TypeVar("IdentifierType")
 
+
+def _is_type(text):
+    p = re.compile("[A-Z][a-z]+")
+    matches = list(p.finditer(text))
+    if len(matches) <= 1 or matches[0].start() != 0:
+        return False
+
+    return matches[-1].group() == "Type"
+
+
+_all_types = {n: t for n, t in locals().items() if _is_type(n)}
+
 # the following constants are deprecated
 ALIGNED_TYPE = "aligned"
 IDENTIFIER_TYPE = "identifier"
@@ -103,6 +118,9 @@ def get_constraint_names(*hints) -> set[str, ...]:
     return all_hints
 
 
+@c3warn.deprecated_callable(
+    "2023.12", reason="migrating to proper types", is_discontinued=True
+)
 def hints_from_strings(*strings: Iterable[str]) -> list:
     """returns list of type hints corresponding to string values"""
     types = []
@@ -137,3 +155,29 @@ def type_tree(hint, depth=0) -> tuple:
         levels = (levels,)
 
     return depth, (level_type, levels)
+
+
+def defined_types():
+    """returns a table of the type hints and the cogent3 classes they represent
+
+    Notes
+    -----
+    These (or standard Python) types are required to annotate argument and
+    return values from cogent3 apps. They define the compatability of apps.
+    """
+    from cogent3.util.table import Table
+
+    rows = [[n, ", ".join(get_constraint_names(t))] for n, t in _all_types.items()]
+    title = "To use a type hint, from cogent3.app import typing"
+    legend = (
+        "An app which uses one of these hints is compatible with the indicated types."
+    )
+    table = Table(
+        header=["type hint", "includes"],
+        data=rows,
+        title=title,
+        legend=legend,
+        index_name="type hint",
+    )
+    table.set_repr_policy(show_shape=False)
+    return table


Test patch:
diff --git a/tests/test_app/test_typing.py b/tests/test_app/test_typing.py
index ee6879dee..c07c89987 100644
--- a/tests/test_app/test_typing.py
+++ b/tests/test_app/test_typing.py
@@ -11,8 +11,8 @@ from cogent3.app.typing import (
     SerialisableType,
     TabularType,
     UnalignedSeqsType,
+    defined_types,
     get_constraint_names,
-    hints_from_strings,
     type_tree,
 )
 
@@ -68,17 +68,6 @@ def test_get_constraint_names_mixed_serilisable_identifiertype():
     assert got == {"SerialisableType", "IdentifierType", "Alignment", "ArrayAlignment"}
 
 
-def test_hints_from_strings_invalid():
-    """raise an exception if unknown string"""
-    with pytest.raises(ValueError):
-        hints_from_strings("abcde")
-
-
-def test_hints_from_strings():
-    got = hints_from_strings("serialisable", "aligned")
-    assert got == [SerialisableType, AlignedSeqsType]
-
-
 def test_hints_resolved_from_str():
     got = get_constraint_names("DnaSequence")
     assert got == {"DnaSequence"}
@@ -131,3 +120,10 @@ def test_typing_tree_depth(hint, expect):
 def test_type_tree(hint, expect):
     _, t = type_tree(hint)
     assert t == expect, (t, expect)
+
+
+def test_defined_types():
+    types = defined_types()
+    # we are checking a single value which we know has 3 entries
+    # also indexing by the type name
+    assert len(types["TabularType"][0, "includes"].split(",")) == 3