Repository: aeon-toolkit/aeon
Pull request #1342 (2024-03-25 20:18:03)

[ENH] remove conversion in get_cutoff
the get_cutoff function has an argument check_input (default False) and convert_input (default True). These parameters are never set when this function is called. 

if passed a pd.Index, _get_cutoff_from_index is called instead.

```python
if convert_input:
         obj = convert_to(obj, GET_CUTOFF_SUPPORTED_TYPES)
```
where GET_CUTOFF_SUPPORTED_TYPES is all valid input types. Any estimator would have failed if passed an invalid type, and conversion cannot work if passed, for example, a string.

Also adapted convert_series to work with lists of types in anticipation of remaining convert_to and added tests for convert series 


aeon-actions-bot[bot]: 
## Thank you for contributing to `aeon`

I have added the following labels to this PR based on the title: **[ $\\color{#FEF1BE}{\\textsf{enhancement}}$ ]**.


The [Checks](https://github.com/aeon-toolkit/aeon/pull/1342/checks) tab will show the status of our automated tests. You can click on individual test runs in the tab or "Details" in the panel below to see more information if there is a failure.

If our `pre-commit` code quality check fails, any trivial fixes will automatically be pushed to your PR unless it is a draft.

Don't hesitate to ask questions on the `aeon` [Slack](
https://join.slack.com/t/aeon-toolkit/shared_invite/zt-22vwvut29-HDpCu~7VBUozyfL_8j3dLA) channel if you have any.
    

Patch:
diff --git a/aeon/datatypes/_vec_df.py b/aeon/datatypes/_vec_df.py
index 1249bd66..7a2c7571 100644
--- a/aeon/datatypes/_vec_df.py
+++ b/aeon/datatypes/_vec_df.py
@@ -13,7 +13,7 @@ from aeon.utils.multiindex import flatten_multiindex
 
 
 class _VectorizedDF:
-    """Wrapper for easy vectorization/iteration over instances.
+    """Wrapper for easy iteration over instances.
 
     VectorizedDF is an iterable that returns pandas.DataFrame
         in aeon Series or Panel format.
diff --git a/aeon/utils/conversion/_convert_series.py b/aeon/utils/conversion/_convert_series.py
index 6f2abe24..be6db5bb 100644
--- a/aeon/utils/conversion/_convert_series.py
+++ b/aeon/utils/conversion/_convert_series.py
@@ -12,6 +12,58 @@ import numpy as np
 import pandas as pd
 
 
+def _resolve_input_type(y):
+    """Resolve the input type of y.
+
+    Parameters
+    ----------
+    y : np.ndarray, pd.Series, pd.DataFrame
+        Time series to be converted.
+
+    Returns
+    -------
+    str
+        String identifier of the input type.
+    """
+    if isinstance(y, pd.Series):
+        return "pd.Series"
+    if isinstance(y, pd.DataFrame):
+        return "pd.DataFrame"
+    if isinstance(y, np.ndarray):
+        return "np.ndarray"
+    raise ValueError(f"Unknown input type: {type(y)}")
+
+
+def _resolve_output_type(output_type):
+    """Resolve the output type of y.
+
+    Parameters
+    ----------
+    output_type : str or list of str
+        The type to convert y to. If a list of string, either the type of y is in the
+        list, in which case y is returned, or conversion is attempted on the first
+        entry in the list of a valid output_type ["np.ndarray", "pd.Series",
+        "pd.DataFrame"].
+
+    Returns
+    -------
+    str
+        String identifier of the output type.
+    """
+    valid_types = ["np.ndarray", "pd.Series", "pd.DataFrame"]
+    # Check if output_type is a list
+    if isinstance(output_type, list):
+        # Iterate over the list and find the first valid type
+        for typ in output_type:
+            if typ in valid_types:
+                return typ
+        # If none in the list are valid, raise an error
+        raise ValueError("None of the types in the list are valid output types")
+    if isinstance(output_type, str) and output_type in valid_types:
+        return output_type
+    raise ValueError(f"Unknown output type {output_type}")
+
+
 def convert_series(y, output_type):
     """Convert series y to the specified output_type.
 
@@ -20,46 +72,44 @@ def convert_series(y, output_type):
     Parameters
     ----------
     y : np.ndarray, pd.Series, pd.DataFrame
-        Time series to be converted
-    output_type : string
-        The type to convert y to
+        Time series to be converted.
+    output_type : string or list of string
+        The type to convert y to. If a list of string, either the type of y is in the
+        list, in which case y is returned, or conversion is attempted on the first
+        entry in the list of a valid output_type ["np.ndarray", "pd.Series",
+        "pd.DataFrame"].
 
     Returns
     -------
     converted version of y
     """
-    if output_type == "np.ndarray":
-        if isinstance(y, (pd.Series, pd.DataFrame)):
-            return y.to_numpy()
-        elif isinstance(y, np.ndarray):
+    input_type = _resolve_input_type(y)
+    # If input type in the list, return it
+    if isinstance(output_type, list):
+        if input_type in output_type:
             return y
-        else:
-            raise ValueError(f"Cannot convert: {type(y)} to np.ndarray")
-    elif output_type == "pd.Series":
-        if isinstance(y, pd.Series):
+    elif isinstance(output_type, str):
+        if input_type == output_type:
             return y
-        elif isinstance(y, pd.DataFrame):
-            if y.shape[1] > 1:
-                raise ValueError(
-                    "DataFrame more than one column, cannot convert to Series"
-                )
-            y = y.iloc[:, 0]
-            return y
-        elif isinstance(y, np.ndarray):
-            y = y.squeeze()
-            if y.ndim == 1:
-                # Convert 1D numpy array to pandas Series
-                return pd.Series(y)
-            else:
-                raise ValueError(
-                    "Cannot convert array with more than one dimension to a pd.Series"
-                )
-    elif output_type == "pd.DataFrame":
-        if isinstance(y, pd.DataFrame):
-            return y
-        elif isinstance(y, pd.Series):
+    else:
+        raise ValueError("Unknown output type must be list or string")
+    output_type = _resolve_output_type(output_type)
+    if input_type == output_type:
+        return y
+    if output_type == "np.ndarray":
+        return y.to_numpy()
+    if output_type == "pd.Series":
+        y = y.squeeze()
+        if y.ndim > 1:
+            raise ValueError(
+                "DataFrame of more than one row or column, cannot convert to "
+                "pd.Series"
+            )
+        return pd.Series(y)
+    if output_type == "pd.DataFrame":
+        if input_type == "pd.Series":
             return y.to_frame()
-        elif isinstance(y, np.ndarray):
+        elif input_type == "np.ndarray":
             return pd.DataFrame(y)
         else:
             raise ValueError(
diff --git a/aeon/utils/index_functions.py b/aeon/utils/index_functions.py
index 0c09fdf1..867727c3 100644
--- a/aeon/utils/index_functions.py
+++ b/aeon/utils/index_functions.py
@@ -4,6 +4,7 @@ import numpy as np
 import pandas as pd
 
 from aeon.datatypes import convert_to
+from aeon.datatypes._vec_df import _VectorizedDF
 from aeon.utils.validation import (
     is_collection,
     is_hierarchical,
@@ -96,20 +97,6 @@ def get_index_for_series(obj, cutoff=0):
     return pd.RangeIndex(cutoff, cutoff + obj.shape[0])
 
 
-GET_CUTOFF_SUPPORTED_TYPES = [
-    "pd.DataFrame",
-    "pd.Series",
-    "np.ndarray",
-    "pd-multiindex",
-    "numpy3D",
-    "nested_univ",
-    "df-list",
-    "pd_multiindex_hier",
-    "np.ndarray",
-    "numpy3D",
-]
-
-
 def _get_cutoff_from_index(idx, return_index=False, reverse_order=False):
     """Get cutoff = latest time point of pandas index.
 
@@ -180,10 +167,8 @@ def get_cutoff(
     cutoff=0,
     return_index=False,
     reverse_order=False,
-    check_input=False,
-    convert_input=True,
 ):
-    """Get cutoff = latest time point of time series or time series panel.
+    """Get the latest time point of time series or collection of time series.
 
     Assumptions on obj are not checked, these should be validated separately.
     Function may return unexpected results without prior validation.
@@ -191,34 +176,28 @@ def get_cutoff(
     Parameters
     ----------
     obj : aeon compatible time series data container or pandas.Index
-        if aeon time series, must be of Series, Panel, or Hierarchical scitype
-        all mtypes are supported via conversion to internally supported types
-        to avoid conversions, pass data in one of GET_CUTOFF_SUPPORTED_TYPES
-        if pandas.Index, it is assumed that last level is time-like or integer,
-        e.g., as in the pd.DataFrame, pd-multiindex, or pd_multiindex_hier mtypes
-    cutoff : int, optional, default=0
-        current cutoff, used to offset index if obj is np.ndarray
-    return_index : bool, optional, default=False
-        whether a pd.Index object should be returned (True)
-            or a pandas compatible index element (False)
+        if aeon time series, must be of Series, Collection, or Hierarchical abstract
+        type. if ``pandas.Index``, it is assumed that last level is time-like or integer
+        e.g., as in the pd.DataFrame, pd-multiindex, or pd_multiindex_hier internal
+        types.
+    cutoff : int, default=0
+        Current cutoff, used to offset index if obj is np.ndarray
+    return_index : bool, default=False
+        Whether a pd.Index object should be returned (True) or a pandas compatible
+        index element (False).
         note: return_index=True may set freq attribute of time types to None
-            return_index=False will typically preserve freq attribute
-    reverse_order : bool, optional, default=False
-        if False, returns largest time index. If True, returns smallest time index
-    check_input : bool, optional, default=False
-        whether to check input for validity, i.e., is it one of the scitypes
-    convert_input : bool, optional, default=True
-        whether to convert the input (True), or skip conversion (False)
-        if skipped, function assumes that inputs are one of GET_CUTOFF_SUPPORTED_TYPES
+            return_index=False will typically preserve freq attribute.
+    reverse_order : bool, default=False
+        if False, returns largest time index. If True, returns smallest time index.
 
     Returns
     -------
     cutoff_index : pandas compatible index element (if return_index=False)
-        pd.Index of length 1 (if return_index=True)
+        pd.Index of length 1 (if return_index=True).
 
     Raises
     ------
-    ValueError, TypeError, if check_input or convert_input are True
+    ValueError, TypeError, if check_input or convert_input are True.
     """
     # deal with VectorizedDF
     if hasattr(obj, "X"):
@@ -228,13 +207,8 @@ def get_cutoff(
         return _get_cutoff_from_index(
             idx=obj, return_index=return_index, reverse_order=reverse_order
         )
-
-    if check_input:
-        if not (is_hierarchical(obj) or is_collection(obj) or is_single_series(obj)):
-            raise ValueError("obj must be of Series, Panel, or Hierarchical scitype")
-
-    if convert_input:
-        obj = convert_to(obj, GET_CUTOFF_SUPPORTED_TYPES)
+    if not (is_hierarchical(obj) or is_collection(obj) or is_single_series(obj)):
+        raise ValueError("obj must be of Series, Panel, or Hierarchical abstract type")
 
     if cutoff is None:
         cutoff = 0
@@ -343,9 +317,6 @@ def update_data(X, X_new=None):
         numpy based containers will always be interpreted as having new row index
         if one of X, X_new is None, returns the other; if both are None, returns None
     """
-    from aeon.datatypes._convert import convert_to
-    from aeon.datatypes._vec_df import _VectorizedDF
-
     # if X or X_new is vectorized, unwrap it first
     if isinstance(X, _VectorizedDF):
         X = X.X
@@ -478,7 +449,7 @@ def get_window(obj, window_length=None, lag=None):
         return convert_to(obj_subset, obj_in_mtype)
 
     raise ValueError(
-        "bug in get_window, unreachable condition, ifs should be exhaustive"
+        "passed get_window an object that is not of type np.ndarray or pd.DataFrame"
     )
 
 
diff --git a/build_tools/generate_developer_tables.py b/build_tools/generate_developer_tables.py
index 16892073..afe39cf0 100644
--- a/build_tools/generate_developer_tables.py
+++ b/build_tools/generate_developer_tables.py
@@ -131,22 +131,21 @@ def key(profile):
 def generate_table(contributors):
     """Generate the html table from the list of contributors."""
     lines = [
-        ".. raw :: html\n",
-        "    <!-- Generated by generate_developer_table.py -->",
-        '    <div class="aeon-teams-container">',
+        "<!-- Generated by generate_developer_table.py -->",
+        "<div class='aeon-teams-container'>",
     ]
     for contributor in contributors:
-        lines.append("    <div>")
+        lines.append("<div>")
         lines.append(
-            "    <a href='%s'><img src='%s' class='avatar' /></a> <br />"
+            "<a href='%s'><img src='%s' class='avatar' /></a> <br />"
             % (contributor["html_url"], contributor["avatar_url"])
         )
         lines.append(
-            "    <p><a href='%s'>%s</a></p>"
+            "<p><a href='%s'>%s</a></p>"
             % (contributor["html_url"], contributor["name"])
         )
-        lines.append("    </div>")
-    lines.append("    </div>")
+        lines.append("</div>")
+    lines.append("</div>")
     return "\n".join(lines) + "\n"
 
 
@@ -165,38 +164,38 @@ if __name__ == "__main__":
     ) = get_contributors(auth)
 
     with open(
-        REPO_FOLDER / "docs" / "about" / "code_of_conduct_workgroup.rst",
+        REPO_FOLDER / "docs" / "about" / "code_of_conduct_workgroup.md",
         "w+",
         encoding="utf-8",
     ) as rst_file:
         rst_file.write(generate_table(cocw))
 
     with open(
-        REPO_FOLDER / "docs" / "about" / "communications_workgroup.rst",
+        REPO_FOLDER / "docs" / "about" / "communications_workgroup.md",
         "w+",
         encoding="utf-8",
     ) as rst_file:
         rst_file.write(generate_table(cw))
 
     with open(
-        REPO_FOLDER / "docs" / "about" / "core_developers.rst", "w+", encoding="utf-8"
+        REPO_FOLDER / "docs" / "about" / "core_developers.md", "w+", encoding="utf-8"
     ) as rst_file:
         rst_file.write(generate_table(cd))
 
     with open(
-        REPO_FOLDER / "docs" / "about" / "finance_workgroup.rst", "w+", encoding="utf-8"
+        REPO_FOLDER / "docs" / "about" / "finance_workgroup.md", "w+", encoding="utf-8"
     ) as rst_file:
         rst_file.write(generate_table(fw))
 
     with open(
-        REPO_FOLDER / "docs" / "about" / "infrastructure_workgroup.rst",
+        REPO_FOLDER / "docs" / "about" / "infrastructure_workgroup.md",
         "w+",
         encoding="utf-8",
     ) as rst_file:
         rst_file.write(generate_table(iw))
 
     with open(
-        REPO_FOLDER / "docs" / "about" / "release_management_workgroup.rst",
+        REPO_FOLDER / "docs" / "about" / "release_management_workgroup.md",
         "w+",
         encoding="utf-8",
     ) as rst_file:
diff --git a/docs/about.md b/docs/about.md
index ed579894..6e9c39f0 100644
--- a/docs/about.md
+++ b/docs/about.md
@@ -10,24 +10,21 @@ A list of all contributors can be found [here](contributors.md).
 The code of conduct workgroup maintains the code of conduct and handles any
 issues related that arise.
 
-```{eval-rst}
-.. include:: about/code_of_conduct_workgroup.rst
+```{include} about/code_of_conduct_workgroup.md
 ```
 
 ### Communications Workgroup
 
 The communications workgroup manages the project's communication channels.
 
-```{eval-rst}
-.. include:: about/communications_workgroup.rst
+```{include} about/communications_workgroup.md
 ```
 
 ### Finance Workgroup
 
 The finance workgroup is responsible for managing the project's finances.
 
-```{eval-rst}
-.. include:: about/finance_workgroup.rst
+```{include} about/finance_workgroup.md
 ```
 
 ### Infrastructure Workgroup
@@ -35,63 +32,29 @@ The finance workgroup is responsible for managing the project's finances.
 The infrastructure workgroup is responsible for managing the project's infrastructure
 and CI.
 
-```{eval-rst}
-.. include:: about/infrastructure_workgroup.rst
+```{include} about/infrastructure_workgroup.md
 ```
 
 ### Release Management Workgroup
 
 The release management workgroup is responsible for managing the project's releases.
 
-```{eval-rst}
-.. include:: about/release_management_workgroup.rst
+```{include} about/release_management_workgroup.md
 ```
 
 ### Core Developers
 
 The core developers push forward `aeon`'s development and maintain the package.
 
-```{eval-rst}
-.. include:: about/core_developers.rst
+```{include} about/core_developers.md
 ```
 
-#### Pre-fork Core Developers
-
-The following listed contributors were part of the sktime core developer team at some
-point prior to the split of the project.
-
-<details><summary>sktime v0.16.0 core developers</summary>
-<p>
-
-- {user}`abostrom`
-- {user}`ayushmaanseth`
-- {user}`goastler`
-- {user}`hyang1996`
-- {user}`james-large`
-- {user}`jasonlines`
-- {user}`matteogales`
-- {user}`prockenschaub`
-- {user}`sajaysurya`
-- {user}`fkiraly`
-- {user}`mloning`
-- {user}`miraep8`
-- {user}`rnkuhns`
-- {user}`achieveordie`
-- {user}`khrapovs`
-- {user}`SveaMeyer13`
-- {user}`lovkush-a`
-- {user}`freddyaboulton`
-- {user}`danbartl`
-- {user}`big-o`
-
-</p>
-</details>
-
 ## History
 
-`aeon` was started in January 2023 as a fork of the
-[sktime project](https://pypi.org/project/sktime/0.16.0/) by 8 core developers using
-v0.16.0 as a base.
+`aeon` was started in January 2023 as a fork of the `sktime` project by 8 core
+developers using [v0.16.0](https://github.com/aeon-toolkit/aeon/releases/tag/sktime-v0.16.0)
+as a base. In following year, the project grew to include an additional 4 core
+developers and was accepted as a NumFOCUS affiliated project in December 2023.
 
 ## Artwork
 
@@ -119,14 +82,57 @@ The project developers would like to thank the following funders.
   - ![https://epsrc.ukri.org](images/funder_logos/ukri-epsrc-logo.png)
 ```
 
-#### Pre-fork funding
+## Infrastructure
+
+We would also like to thank [GitHub Actions](https://github.com/features/actions)
+and [ReadtheDocs](https://readthedocs.org) for the free compute time on their servers
+and documentation hosting.
+
+## Affiliation
+
+`aeon` is an affiliated project of [NumFOCUS](https://numfocus.org/).
+
+![https://numfocus.org/](images/other_logos/numfocus-logo.png){w=300px}
 
-As a fork of the sktime project, `aeon` has benefited from funding given to sktime prior
-to the projects split. We would like to thank the funders from before the split.
+
+## Pre-fork Acknowledgements
+
+<details><summary>sktime v0.16.0 core developers</summary>
+<p>
+
+The following listed contributors were part of the `sktime` core developer team at some
+point prior to the split of the project.
+
+- {user}`abostrom`
+- {user}`ayushmaanseth`
+- {user}`goastler`
+- {user}`hyang1996`
+- {user}`james-large`
+- {user}`jasonlines`
+- {user}`matteogales`
+- {user}`prockenschaub`
+- {user}`sajaysurya`
+- {user}`fkiraly`
+- {user}`mloning`
+- {user}`miraep8`
+- {user}`rnkuhns`
+- {user}`achieveordie`
+- {user}`khrapovs`
+- {user}`SveaMeyer13`
+- {user}`lovkush-a`
+- {user}`freddyaboulton`
+- {user}`danbartl`
+- {user}`big-o`
+
+</p>
+</details>
 
 <details><summary>sktime v0.16.0 funders</summary>
 <p>
 
+As a fork of the `sktime` project, `aeon` has benefited from funding given to `sktime`
+prior to the projects split. We would like to thank the funders from before the split.
+
 ```{list-table}
 :widths: 50 50
 :header-rows: 1
@@ -141,14 +147,14 @@ to the projects split. We would like to thank the funders from before the split.
   - ![https://opensource.mercedes-benz.com](images/funder_logos/mercedes-benz-logo.png)
 ```
 
-##### Sprints
+__Sprints__
 
 The 2019 joint sktime/MLJ development sprint was kindly hosted by
 [UCL](https://www.ucl.ac.uk) and [The Alan Turing Institute](https://turing.ac.uk).
 Some participants could attend thanks to the initial funding of the
 [The Alan Turing Institute](https://turing.ac.uk).
 
-##### Internships
+__Internships__
 
 [Google Summer of Code (GSoC)](https://summerofcode.withgoogle.com),
 [Major League Hacking](https://mlh.io) and [Outreachy](https://www.outreachy.org)
@@ -188,16 +194,3 @@ Outreachy.
 
 </p>
 </details>
-
-
-## Infrastructure
-
-We would also like to thank [GitHub Actions](https://github.com/features/actions)
-and [ReadtheDocs](https://readthedocs.org) for the free compute time on their servers
-and documentation hosting.
-
-## Affiliation
-
-`aeon` is an affiliated project of [NumFOCUS](https://numfocus.org/).
-
-![https://numfocus.org/](images/other_logos/numfocus-logo.png){w=200px}
diff --git a/docs/about/code_of_conduct_workgroup.md b/docs/about/code_of_conduct_workgroup.md
new file mode 100644
index 00000000..b7f46f9a
--- /dev/null
+++ b/docs/about/code_of_conduct_workgroup.md
@@ -0,0 +1,23 @@
+<!-- Generated by generate_developer_table.py -->
+<div class='aeon-teams-container'>
+<div>
+<a href='https://github.com/KatieBuc'><img src='https://avatars.githubusercontent.com/u/34525024?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/KatieBuc'>Katie Buchhorn</a></p>
+</div>
+<div>
+<a href='https://github.com/hadifawaz1999'><img src='https://avatars.githubusercontent.com/u/54309336?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/hadifawaz1999'>Ali El Hadi ISMAIL FAWAZ</a></p>
+</div>
+<div>
+<a href='https://github.com/GuzalBulatova'><img src='https://avatars.githubusercontent.com/u/73598322?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/GuzalBulatova'>Guzal</a></p>
+</div>
+<div>
+<a href='https://github.com/patrickzib'><img src='https://avatars.githubusercontent.com/u/7783034?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/patrickzib'>Patrick Schäfer</a></p>
+</div>
+<div>
+<a href='https://github.com/ltsaprounis'><img src='https://avatars.githubusercontent.com/u/64217214?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/ltsaprounis'>Leonidas Tsaprounis</a></p>
+</div>
+</div>
diff --git a/docs/about/code_of_conduct_workgroup.rst b/docs/about/code_of_conduct_workgroup.rst
deleted file mode 100644
index 9f3b54bd..00000000
--- a/docs/about/code_of_conduct_workgroup.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-.. raw :: html
-
-    <!-- Generated by generate_developer_table.py -->
-    <div class="aeon-teams-container">
-    <div>
-    <a href='https://github.com/KatieBuc'><img src='https://avatars.githubusercontent.com/u/34525024?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/KatieBuc'>Katie Buchhorn</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/hadifawaz1999'><img src='https://avatars.githubusercontent.com/u/54309336?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/hadifawaz1999'>Ali El Hadi ISMAIL FAWAZ</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/GuzalBulatova'><img src='https://avatars.githubusercontent.com/u/73598322?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/GuzalBulatova'>Guzal</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/patrickzib'><img src='https://avatars.githubusercontent.com/u/7783034?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/patrickzib'>Patrick Schäfer</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/ltsaprounis'><img src='https://avatars.githubusercontent.com/u/64217214?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/ltsaprounis'>Leonidas Tsaprounis</a></p>
-    </div>
-    </div>
diff --git a/docs/about/communications_workgroup.md b/docs/about/communications_workgroup.md
new file mode 100644
index 00000000..6fcb2aac
--- /dev/null
+++ b/docs/about/communications_workgroup.md
@@ -0,0 +1,11 @@
+<!-- Generated by generate_developer_table.py -->
+<div class='aeon-teams-container'>
+<div>
+<a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
+</div>
+<div>
+<a href='https://github.com/baraline'><img src='https://avatars.githubusercontent.com/u/10759117?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/baraline'>Antoine Guillaume</a></p>
+</div>
+</div>
diff --git a/docs/about/communications_workgroup.rst b/docs/about/communications_workgroup.rst
deleted file mode 100644
index 0d7b8990..00000000
--- a/docs/about/communications_workgroup.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-.. raw :: html
-
-    <!-- Generated by generate_developer_table.py -->
-    <div class="aeon-teams-container">
-    <div>
-    <a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/baraline'><img src='https://avatars.githubusercontent.com/u/10759117?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/baraline'>Antoine Guillaume</a></p>
-    </div>
-    </div>
diff --git a/docs/about/core_developers.md b/docs/about/core_developers.md
new file mode 100644
index 00000000..9ece34c0
--- /dev/null
+++ b/docs/about/core_developers.md
@@ -0,0 +1,51 @@
+<!-- Generated by generate_developer_table.py -->
+<div class='aeon-teams-container'>
+<div>
+<a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
+</div>
+<div>
+<a href='https://github.com/chrisholder'><img src='https://avatars.githubusercontent.com/u/4674372?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/chrisholder'>chrisholder</a></p>
+</div>
+<div>
+<a href='https://github.com/hadifawaz1999'><img src='https://avatars.githubusercontent.com/u/54309336?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/hadifawaz1999'>Ali El Hadi ISMAIL FAWAZ</a></p>
+</div>
+<div>
+<a href='https://github.com/baraline'><img src='https://avatars.githubusercontent.com/u/10759117?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/baraline'>Antoine Guillaume</a></p>
+</div>
+<div>
+<a href='https://github.com/GuzalBulatova'><img src='https://avatars.githubusercontent.com/u/73598322?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/GuzalBulatova'>Guzal</a></p>
+</div>
+<div>
+<a href='https://github.com/lmmentel'><img src='https://avatars.githubusercontent.com/u/8989838?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/lmmentel'>Lukasz Mentel</a></p>
+</div>
+<div>
+<a href='https://github.com/MatthewMiddlehurst'><img src='https://avatars.githubusercontent.com/u/25731235?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/MatthewMiddlehurst'>Matthew Middlehurst</a></p>
+</div>
+<div>
+<a href='https://github.com/dguijo'><img src='https://avatars.githubusercontent.com/u/47889499?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/dguijo'>David Guijo Rubio</a></p>
+</div>
+<div>
+<a href='https://github.com/CodeLionX'><img src='https://avatars.githubusercontent.com/u/10573700?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/CodeLionX'>Sebastian Schmidl</a></p>
+</div>
+<div>
+<a href='https://github.com/patrickzib'><img src='https://avatars.githubusercontent.com/u/7783034?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/patrickzib'>Patrick Schäfer</a></p>
+</div>
+<div>
+<a href='https://github.com/ltsaprounis'><img src='https://avatars.githubusercontent.com/u/64217214?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/ltsaprounis'>Leonidas Tsaprounis</a></p>
+</div>
+<div>
+<a href='https://github.com/aiwalter'><img src='https://avatars.githubusercontent.com/u/29627036?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/aiwalter'>Martin Walter</a></p>
+</div>
+</div>
diff --git a/docs/about/core_developers.rst b/docs/about/core_developers.rst
deleted file mode 100644
index 925c08ec..00000000
--- a/docs/about/core_developers.rst
+++ /dev/null
@@ -1,49 +0,0 @@
-.. raw :: html
-
-    <!-- Generated by generate_developer_table.py -->
-    <div class="aeon-teams-container">
-    <div>
-    <a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/chrisholder'><img src='https://avatars.githubusercontent.com/u/4674372?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/chrisholder'>chrisholder</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/hadifawaz1999'><img src='https://avatars.githubusercontent.com/u/54309336?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/hadifawaz1999'>Ali El Hadi ISMAIL FAWAZ</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/baraline'><img src='https://avatars.githubusercontent.com/u/10759117?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/baraline'>Antoine Guillaume</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/GuzalBulatova'><img src='https://avatars.githubusercontent.com/u/73598322?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/GuzalBulatova'>Guzal</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/lmmentel'><img src='https://avatars.githubusercontent.com/u/8989838?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/lmmentel'>Lukasz Mentel</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/MatthewMiddlehurst'><img src='https://avatars.githubusercontent.com/u/25731235?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/MatthewMiddlehurst'>Matthew Middlehurst</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/dguijo'><img src='https://avatars.githubusercontent.com/u/47889499?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/dguijo'>David Guijo Rubio</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/patrickzib'><img src='https://avatars.githubusercontent.com/u/7783034?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/patrickzib'>Patrick Schäfer</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/ltsaprounis'><img src='https://avatars.githubusercontent.com/u/64217214?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/ltsaprounis'>Leonidas Tsaprounis</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/aiwalter'><img src='https://avatars.githubusercontent.com/u/29627036?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/aiwalter'>Martin Walter</a></p>
-    </div>
-    </div>
diff --git a/docs/about/finance_workgroup.md b/docs/about/finance_workgroup.md
new file mode 100644
index 00000000..ca621b8a
--- /dev/null
+++ b/docs/about/finance_workgroup.md
@@ -0,0 +1,11 @@
+<!-- Generated by generate_developer_table.py -->
+<div class='aeon-teams-container'>
+<div>
+<a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
+</div>
+<div>
+<a href='https://github.com/dguijo'><img src='https://avatars.githubusercontent.com/u/47889499?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/dguijo'>David Guijo Rubio</a></p>
+</div>
+</div>
diff --git a/docs/about/finance_workgroup.rst b/docs/about/finance_workgroup.rst
deleted file mode 100644
index f6612c22..00000000
--- a/docs/about/finance_workgroup.rst
+++ /dev/null
@@ -1,13 +0,0 @@
-.. raw :: html
-
-    <!-- Generated by generate_developer_table.py -->
-    <div class="aeon-teams-container">
-    <div>
-    <a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/dguijo'><img src='https://avatars.githubusercontent.com/u/47889499?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/dguijo'>David Guijo Rubio</a></p>
-    </div>
-    </div>
diff --git a/docs/about/infrastructure_workgroup.md b/docs/about/infrastructure_workgroup.md
new file mode 100644
index 00000000..5be9f21d
--- /dev/null
+++ b/docs/about/infrastructure_workgroup.md
@@ -0,0 +1,19 @@
+<!-- Generated by generate_developer_table.py -->
+<div class='aeon-teams-container'>
+<div>
+<a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
+</div>
+<div>
+<a href='https://github.com/MatthewMiddlehurst'><img src='https://avatars.githubusercontent.com/u/25731235?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/MatthewMiddlehurst'>Matthew Middlehurst</a></p>
+</div>
+<div>
+<a href='https://github.com/ltsaprounis'><img src='https://avatars.githubusercontent.com/u/64217214?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/ltsaprounis'>Leonidas Tsaprounis</a></p>
+</div>
+<div>
+<a href='https://github.com/aiwalter'><img src='https://avatars.githubusercontent.com/u/29627036?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/aiwalter'>Martin Walter</a></p>
+</div>
+</div>
diff --git a/docs/about/infrastructure_workgroup.rst b/docs/about/infrastructure_workgroup.rst
deleted file mode 100644
index cc6c56f9..00000000
--- a/docs/about/infrastructure_workgroup.rst
+++ /dev/null
@@ -1,21 +0,0 @@
-.. raw :: html
-
-    <!-- Generated by generate_developer_table.py -->
-    <div class="aeon-teams-container">
-    <div>
-    <a href='https://github.com/TonyBagnall'><img src='https://avatars.githubusercontent.com/u/9594042?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/TonyBagnall'>Tony Bagnall</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/MatthewMiddlehurst'><img src='https://avatars.githubusercontent.com/u/25731235?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/MatthewMiddlehurst'>Matthew Middlehurst</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/ltsaprounis'><img src='https://avatars.githubusercontent.com/u/64217214?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/ltsaprounis'>Leonidas Tsaprounis</a></p>
-    </div>
-    <div>
-    <a href='https://github.com/aiwalter'><img src='https://avatars.githubusercontent.com/u/29627036?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/aiwalter'>Martin Walter</a></p>
-    </div>
-    </div>
diff --git a/docs/about/release_management_workgroup.md b/docs/about/release_management_workgroup.md
new file mode 100644
index 00000000..926009ee
--- /dev/null
+++ b/docs/about/release_management_workgroup.md
@@ -0,0 +1,7 @@
+<!-- Generated by generate_developer_table.py -->
+<div class='aeon-teams-container'>
+<div>
+<a href='https://github.com/MatthewMiddlehurst'><img src='https://avatars.githubusercontent.com/u/25731235?v=4' class='avatar' /></a> <br />
+<p><a href='https://github.com/MatthewMiddlehurst'>Matthew Middlehurst</a></p>
+</div>
+</div>
diff --git a/docs/about/release_management_workgroup.rst b/docs/about/release_management_workgroup.rst
deleted file mode 100644
index e09d7b5e..00000000
--- a/docs/about/release_management_workgroup.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-.. raw :: html
-
-    <!-- Generated by generate_developer_table.py -->
-    <div class="aeon-teams-container">
-    <div>
-    <a href='https://github.com/MatthewMiddlehurst'><img src='https://avatars.githubusercontent.com/u/25731235?v=4' class='avatar' /></a> <br />
-    <p><a href='https://github.com/MatthewMiddlehurst'>Matthew Middlehurst</a></p>
-    </div>
-    </div>


Test patch:
diff --git a/aeon/utils/conversion/tests/test_convert_series.py b/aeon/utils/conversion/tests/test_convert_series.py
new file mode 100644
index 00000000..a950f5b7
--- /dev/null
+++ b/aeon/utils/conversion/tests/test_convert_series.py
@@ -0,0 +1,108 @@
+"""Tests for convert series."""
+
+import numpy as np
+import pandas as pd
+import pytest
+
+from aeon.utils.conversion import convert_series
+from aeon.utils.conversion._convert_series import (
+    _resolve_input_type,
+    _resolve_output_type,
+)
+
+TO_TYPE = ["np.ndarray", "pd.Series", "pd.DataFrame"]
+uni = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
+uni2 = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]])
+UNIVARIATE = [uni, pd.Series(uni), pd.DataFrame(uni)]
+UNIVARIATE2 = [uni2, pd.DataFrame(uni2), uni2.T, pd.DataFrame(uni2.T)]
+multi = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]])
+MULTIVARIATE = [multi, pd.DataFrame(multi)]
+
+
+@pytest.mark.parametrize("data", UNIVARIATE)
+@pytest.mark.parametrize("to_type", TO_TYPE)
+def test_convert_univariate_series(data, to_type):
+    """Test convert series with single univariate input of each type."""
+    x = convert_series(data, to_type)
+    assert isinstance(x, eval(to_type))
+
+
+@pytest.mark.parametrize("data", UNIVARIATE2)
+@pytest.mark.parametrize("to_type", TO_TYPE)
+def test_convert_univariate_as_multivariate(data, to_type):
+    """Test convert a univariate series stored in 2D data structure."""
+    x = convert_series(data, to_type)
+    assert isinstance(x, eval(to_type))
+
+
+@pytest.mark.parametrize("data", MULTIVARIATE)
+@pytest.mark.parametrize("to_type", TO_TYPE)
+def test_convert_multivariate_series(data, to_type):
+    """Test convert series with single input of each type."""
+    if to_type == "pd.Series":
+        with pytest.raises(ValueError, match="cannot convert to pd.Series"):
+            convert_series(data, to_type)
+        return
+    x = convert_series(data, to_type)
+    assert isinstance(x, eval(to_type))
+
+
+def test_convert_series_wrong_type():
+    """Test convert series with wrong input type."""
+    with pytest.raises(ValueError, match="Unknown input type"):
+        convert_series("string", "np.ndarray")
+    with pytest.raises(ValueError, match="Unknown input type"):
+        convert_series([1, 2, 3], "np.ndarray")
+    with pytest.raises(ValueError, match="Unknown output type"):
+        convert_series(np.array([[[1, 2, 3]]]), "numpy3D")
+    with pytest.raises(ValueError, match="Unknown output type"):
+        convert_series(np.ndarray([1, 2, 3]), "np-list")
+    with pytest.raises(ValueError, match="Unknown output type"):
+        convert_series(np.ndarray([1, 2, 3]), "pd_multiindex_hier")
+
+
+def test__resolve_input_type():
+    """Test _input_type function."""
+    for i in range(len(UNIVARIATE)):
+        assert _resolve_input_type(UNIVARIATE[i]) == TO_TYPE[i]
+    with pytest.raises(ValueError, match="Unknown input type"):
+        _resolve_input_type("string")
+
+
+def test__resolve_output_type():
+    """Test resolve output type."""
+    for i in range(len(TO_TYPE)):
+        assert _resolve_output_type(TO_TYPE[i]) == TO_TYPE[i]
+    with pytest.raises(ValueError, match="Unknown output type"):
+        _resolve_output_type("string")
+    test = ["np.ndarray", "pd.Series", "pd.DataFrame"]
+    assert _resolve_output_type(test) == "np.ndarray"
+    test = ["FOO", "pd.Series", "pd.DataFrame"]
+    assert _resolve_output_type(test) == "pd.Series"
+    test = ["FOO", "BAR", "pd.DataFrame"]
+    assert _resolve_output_type(test) == "pd.DataFrame"
+    test = ["FOO", "BAR", "ARSENAL"]
+    with pytest.raises(ValueError, match="Unknown input type"):
+        _resolve_input_type(test)
+
+
+def test_convert_series_lists():
+    """Test series conversion with list type inputs."""
+    # Test returns self if in list
+    for i in range(len(UNIVARIATE)):
+        test = ["np.ndarray", "pd.Series", "pd.DataFrame"]
+        x = convert_series(UNIVARIATE[i], test)
+        assert type(x) is type(UNIVARIATE[i])
+        # Test with invalid names at start
+        test.insert(0, "FOO")
+        x = convert_series(UNIVARIATE[i], test)
+        assert type(x) is type(UNIVARIATE[i])
+        # Test when type not present
+        test = ["np.ndarray", "pd.Series", "pd.DataFrame"]
+        test.remove(TO_TYPE[i])
+        x = convert_series(UNIVARIATE[i], test)
+        assert x.__class__.__name__ == test[0].split(".")[1]
+        # Test with invalid names at start
+        test.insert(0, "FOO")
+        x = convert_series(UNIVARIATE[i], test)
+        assert x.__class__.__name__ == test[1].split(".")[1]
diff --git a/aeon/utils/tests/test_index_functions.py b/aeon/utils/tests/test_index_functions.py
index 7431f9ca..4caf3a3d 100644
--- a/aeon/utils/tests/test_index_functions.py
+++ b/aeon/utils/tests/test_index_functions.py
@@ -84,11 +84,10 @@ def test_get_time_index(datatype):
         assert (idx == exp_idx).all()
 
 
-@pytest.mark.parametrize("convert_input", [True, False])
 @pytest.mark.parametrize("reverse_order", [True, False])
 @pytest.mark.parametrize("return_index", [True, False])
 @pytest.mark.parametrize("datatype", EXAMPLE_DATA.keys())
-def test_get_cutoff(datatype, return_index, reverse_order, convert_input):
+def test_get_cutoff(datatype, return_index, reverse_order):
     """Tests that get_cutoff has correct output.
 
     Parameters
@@ -96,7 +95,6 @@ def test_get_cutoff(datatype, return_index, reverse_order, convert_input):
     datatype : str - datatype of input
     return_index : bool - whether index (True) or index element is returned (False)
     reverse_order : bool - whether first (True) or last index (False) is retrieved
-    convert_input : bool - whether input is converted (True) or passed through (False)
 
     Raises
     ------
@@ -110,7 +108,6 @@ def test_get_cutoff(datatype, return_index, reverse_order, convert_input):
         data,
         return_index=return_index,
         reverse_order=reverse_order,
-        convert_input=convert_input,
     )
 
     if return_index:
@@ -217,7 +214,7 @@ def test_get_cutoff_wrong_input(bad_inputs):
     Exception (from pytest) if the error is not raised as expected
     """
     with pytest.raises(Exception, match="must be of Series, Panel, or Hierarchical"):
-        get_cutoff(bad_inputs, check_input=True)
+        get_cutoff(bad_inputs)
 
 
 @pytest.mark.parametrize("window_length, lag", [(2, 0), (None, 0), (4, 1)])