Repository: aeon-toolkit/aeon
Pull request #1190 (2024-02-16 17:16:51)

[ENH] Replace check_is_scitype with is_single_series and is_collection
#### Reference Issues/PRs

refactors check_is_scitype using four methods, is_single_series, is_collection, is_tabular and is_hierarchical. In many places, check_is_scitype was used entirely for this functionality. In other places, the returned meta_data is also used. 

Currently, only the checking functionality has been replaced, the meta_data requires a further rework. Note that is_tabular  is only used in the testing of base class, not sure of its future. There is some commented out code left here for the next PR


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

I did not find any labels to add based on the title. Please add the [ENH], [MNT], [BUG], [DOC], [REF], [DEP] and/or [GOV] tags to your pull requests titles. For now you can add the labels manually.
This PR changes too many different packages (>3) for automatic addition of labels, please manually add package labels if relevant.

The [Checks](https://github.com/aeon-toolkit/aeon/pull/1190/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.
    
review-notebook-app[bot]: Check out this pull request on&nbsp; <a href="https://app.reviewnb.com/aeon-toolkit/aeon/pull/1190"><img align="absmiddle"  alt="ReviewNB" height="28" class="BotMessageButtonImage" src="https://raw.githubusercontent.com/ReviewNB/support/master/images/button_reviewnb.png"/></a> 

 See visual diffs & provide feedback on Jupyter Notebooks. 

---

 <i>Powered by <a href='https://www.reviewnb.com/?utm_source=gh'>ReviewNB</a></i>

Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 34be435c..1cbcf299 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -2342,6 +2342,16 @@
         "doc",
         "research"
       ]
+    },
+    {
+      "login": "AnonymousCodes911",
+    "name": "Utkarsh Kumar",
+    "avatar_url": "https://avatars.githubusercontent.com/u/67187480?v=4",
+    "profile": "https://github.com/AnonymousCodes911",
+    "contributions": [
+      "code",
+      "doc"
+    ]
     }
   ],
   "commitType": "docs"
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2df7d253..8bf6c05b 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -58,13 +58,13 @@ repos:
     rev: 1.7.1
     hooks:
       - id: nbqa-isort
-        additional_dependencies: [ isort==5.10.1 ]
+        additional_dependencies: [ isort==5.13.2 ]
         args: [ "--nbqa-dont-skip-bad-cells", "--profile=black", "--multi-line=3" ]
       - id: nbqa-black
-        additional_dependencies: [ black==22.10.0 ]
+        additional_dependencies: [ black==24.2.0 ]
         args: [ "--nbqa-dont-skip-bad-cells" ]
       - id: nbqa-flake8
-        additional_dependencies: [ flake8==5.0.4 ]
+        additional_dependencies: [ flake8==7.0.0 ]
         args: [ "--nbqa-dont-skip-bad-cells", "--extend-ignore=E402,E203", "--max-line-length=88" ]
 
   - repo: https://github.com/pycqa/pydocstyle
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index bbc06e88..80546c7e 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -1,7 +1,7 @@
 # Contributors
 
 <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
-[![All Contributors](https://img.shields.io/badge/all_contributors-227-orange.svg)](#contributors)
+[![All Contributors](https://img.shields.io/badge/all_contributors-228-orange.svg)](#contributors)
 <!-- ALL-CONTRIBUTORS-BADGE:END -->
 
 This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
@@ -244,6 +244,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="12.5%"><a href="http://www.timeseriesclassification.com"><img src="https://avatars1.githubusercontent.com/u/9594042?v=4?s=80" width="80px;" alt="Tony Bagnall"/><br /><sub><b>Tony Bagnall</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=TonyBagnall" title="Code">💻</a> <a href="#business-TonyBagnall" title="Business development">💼</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=TonyBagnall" title="Documentation">📖</a> <a href="#design-TonyBagnall" title="Design">🎨</a> <a href="#eventOrganizing-TonyBagnall" title="Event Organizing">📋</a> <a href="#fundingFinding-TonyBagnall" title="Funding Finding">🔍</a> <a href="#ideas-TonyBagnall" title="Ideas, Planning, & Feedback">🤔</a> <a href="#projectManagement-TonyBagnall" title="Project Management">📆</a> <a href="#question-TonyBagnall" title="Answering Questions">💬</a> <a href="https://github.com/aeon-toolkit/aeon/pulls?q=is%3Apr+reviewed-by%3ATonyBagnall" title="Reviewed Pull Requests">👀</a> <a href="#talk-TonyBagnall" title="Talks">📢</a> <a href="#data-TonyBagnall" title="Data">🔣</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="12.5%"><a href="https://github.com/AnonymousCodes911"><img src="https://avatars.githubusercontent.com/u/67187480?v=4?s=80" width="80px;" alt="Utkarsh Kumar"/><br /><sub><b>Utkarsh Kumar</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=AnonymousCodes911" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=AnonymousCodes911" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/utsavcoding"><img src="https://avatars3.githubusercontent.com/u/55446385?v=4?s=80" width="80px;" alt="Utsav Kumar Tiwari"/><br /><sub><b>Utsav Kumar Tiwari</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=utsavcoding" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=utsavcoding" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/Vedant222"><img src="https://avatars.githubusercontent.com/u/70121054?v=4?s=80" width="80px;" alt="Vedant"/><br /><sub><b>Vedant</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=Vedant222" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/victordremov"><img src="https://avatars.githubusercontent.com/u/32140716?s=80" width="80px;" alt="Viktor Dremov"/><br /><sub><b>Viktor Dremov</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=victordremov" title="Code">💻</a></td>
@@ -251,9 +252,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/VyomkeshVyas"><img src="https://avatars.githubusercontent.com/u/110027694?v=4?s=80" width="80px;" alt="Vyomkesh Vyas"/><br /><sub><b>Vyomkesh Vyas</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=VyomkeshVyas" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=VyomkeshVyas" title="Documentation">📖</a> <a href="#example-VyomkeshVyas" title="Examples">💡</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=VyomkeshVyas" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://www.linkedin.com/in/templierw/"><img src="https://github.com/templierw.png?s=80" width="80px;" alt="William Templier"/><br /><sub><b>William Templier</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=templierw" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/wwzeng1"><img src="https://avatars.githubusercontent.com/u/44910023?v=4?s=80" width="80px;" alt="William Zeng"/><br /><sub><b>William Zeng</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Awwzeng1" title="Bug reports">🐛</a></td>
-      <td align="center" valign="top" width="12.5%"><a href="https://github.com/magittan"><img src="https://avatars0.githubusercontent.com/u/14024202?v=4?s=80" width="80px;" alt="William Zheng"/><br /><sub><b>William Zheng</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=magittan" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=magittan" title="Tests">⚠️</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="12.5%"><a href="https://github.com/magittan"><img src="https://avatars0.githubusercontent.com/u/14024202?v=4?s=80" width="80px;" alt="William Zheng"/><br /><sub><b>William Zheng</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=magittan" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=magittan" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/yairbeer"><img src="https://avatars.githubusercontent.com/yairbeer?s=80" width="80px;" alt="Yair Beer"/><br /><sub><b>Yair Beer</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=yairbeer" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/yashlamba"><img src="https://avatars.githubusercontent.com/u/44164398?v=4?s=80" width="80px;" alt="Yash Lamba"/><br /><sub><b>Yash Lamba</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=yashlamba" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/xuyxu"><img src="https://avatars2.githubusercontent.com/u/22359569?v=4?s=80" width="80px;" alt="Yi-Xuan Xu"/><br /><sub><b>Yi-Xuan Xu</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=xuyxu" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=xuyxu" title="Tests">⚠️</a> <a href="#maintenance-xuyxu" title="Maintenance">🚧</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=xuyxu" title="Documentation">📖</a></td>
@@ -261,9 +262,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/aa25desh"><img src="https://avatars1.githubusercontent.com/u/29518290?v=4?s=80" width="80px;" alt="aa25desh"/><br /><sub><b>aa25desh</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=aa25desh" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Aaa25desh" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/abandus"><img src="https://avatars2.githubusercontent.com/u/46486474?v=4?s=80" width="80px;" alt="abandus"/><br /><sub><b>abandus</b></sub></a><br /><a href="#ideas-abandus" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=abandus" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/adoherty21"><img src="https://avatars.githubusercontent.com/u/52799751?s=400&v=4?s=80" width="80px;" alt="adoherty21"/><br /><sub><b>adoherty21</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Aadoherty21" title="Bug reports">🐛</a></td>
-      <td align="center" valign="top" width="12.5%"><a href="https://github.com/bethrice44"><img src="https://avatars.githubusercontent.com/u/11226988?v=4?s=80" width="80px;" alt="bethrice44"/><br /><sub><b>bethrice44</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Abethrice44" title="Bug reports">🐛</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=bethrice44" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/pulls?q=is%3Apr+reviewed-by%3Abethrice44" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=bethrice44" title="Tests">⚠️</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="12.5%"><a href="https://github.com/bethrice44"><img src="https://avatars.githubusercontent.com/u/11226988?v=4?s=80" width="80px;" alt="bethrice44"/><br /><sub><b>bethrice44</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Abethrice44" title="Bug reports">🐛</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=bethrice44" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/pulls?q=is%3Apr+reviewed-by%3Abethrice44" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=bethrice44" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/big-o"><img src="https://avatars1.githubusercontent.com/u/1134151?v=4?s=80" width="80px;" alt="big-o"/><br /><sub><b>big-o</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=big-o" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=big-o" title="Tests">⚠️</a> <a href="#design-big-o" title="Design">🎨</a> <a href="#ideas-big-o" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/aeon-toolkit/aeon/pulls?q=is%3Apr+reviewed-by%3Abig-o" title="Reviewed Pull Requests">👀</a> <a href="#tutorial-big-o" title="Tutorials">✅</a> <a href="#mentoring-big-o" title="Mentoring">🧑‍🏫</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/bobbys-dev"><img src="https://avatars.githubusercontent.com/bobbys-dev?s=80" width="80px;" alt="bobbys"/><br /><sub><b>bobbys</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=bobbys-dev" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/brettkoonce"><img src="https://avatars2.githubusercontent.com/u/11281814?v=4?s=80" width="80px;" alt="brett koonce"/><br /><sub><b>brett koonce</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=brettkoonce" title="Documentation">📖</a></td>
@@ -271,9 +272,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/chizzi25"><img src="https://avatars3.githubusercontent.com/u/67911243?v=4?s=80" width="80px;" alt="chizzi25"/><br /><sub><b>chizzi25</b></sub></a><br /><a href="#blog-chizzi25" title="Blogposts">📝</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/chrisholder"><img src="https://avatars.githubusercontent.com/u/4674372?v=4?s=80" width="80px;" alt="chrisholder"/><br /><sub><b>chrisholder</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=chrisholder" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=chrisholder" title="Tests">⚠️</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=chrisholder" title="Documentation">📖</a> <a href="#design-chrisholder" title="Design">🎨</a> <a href="#example-chrisholder" title="Examples">💡</a> <a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Achrisholder" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/danbartl"><img src="https://avatars.githubusercontent.com/u/19947407?v=4?s=80" width="80px;" alt="danbartl"/><br /><sub><b>danbartl</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Adanbartl" title="Bug reports">🐛</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=danbartl" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/pulls?q=is%3Apr+reviewed-by%3Adanbartl" title="Reviewed Pull Requests">👀</a> <a href="#talk-danbartl" title="Talks">📢</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=danbartl" title="Tests">⚠️</a> <a href="#tutorial-danbartl" title="Tutorials">✅</a> <a href="#video-danbartl" title="Videos">📹</a></td>
-      <td align="center" valign="top" width="12.5%"><a href="https://github.com/hamzahiqb"><img src="https://avatars3.githubusercontent.com/u/10302415?v=4?s=80" width="80px;" alt="hamzahiqb"/><br /><sub><b>hamzahiqb</b></sub></a><br /><a href="#infra-hamzahiqb" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="12.5%"><a href="https://github.com/hamzahiqb"><img src="https://avatars3.githubusercontent.com/u/10302415?v=4?s=80" width="80px;" alt="hamzahiqb"/><br /><sub><b>hamzahiqb</b></sub></a><br /><a href="#infra-hamzahiqb" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/hiqbal2"><img src="https://avatars3.githubusercontent.com/u/10302415?v=4?s=80" width="80px;" alt="hiqbal2"/><br /><sub><b>hiqbal2</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=hiqbal2" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/jesellier"><img src="https://avatars0.githubusercontent.com/u/51952076?v=4?s=80" width="80px;" alt="jesellier"/><br /><sub><b>jesellier</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=jesellier" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/jschemm"><img src="https://avatars.githubusercontent.com/u/81151346?v=4?s=80" width="80px;" alt="jschemm"/><br /><sub><b>jschemm</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=jschemm" title="Code">💻</a></td>
@@ -281,9 +282,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/kkoziara"><img src="https://avatars1.githubusercontent.com/u/4346849?v=4?s=80" width="80px;" alt="kkoziara"/><br /><sub><b>kkoziara</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=kkoziara" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Akkoziara" title="Bug reports">🐛</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/matteogales"><img src="https://avatars0.githubusercontent.com/u/9269326?v=4?s=80" width="80px;" alt="matteogales"/><br /><sub><b>matteogales</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=matteogales" title="Code">💻</a> <a href="#design-matteogales" title="Design">🎨</a> <a href="#ideas-matteogales" title="Ideas, Planning, & Feedback">🤔</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/oleskiewicz"><img src="https://avatars1.githubusercontent.com/u/5682158?v=4?s=80" width="80px;" alt="oleskiewicz"/><br /><sub><b>oleskiewicz</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=oleskiewicz" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=oleskiewicz" title="Documentation">📖</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=oleskiewicz" title="Tests">⚠️</a></td>
-      <td align="center" valign="top" width="12.5%"><a href="https://github.com/pabworks"><img src="https://avatars.githubusercontent.com/u/32725127?v=4?s=80" width="80px;" alt="pabworks"/><br /><sub><b>pabworks</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=pabworks" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=pabworks" title="Tests">⚠️</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="12.5%"><a href="https://github.com/pabworks"><img src="https://avatars.githubusercontent.com/u/32725127?v=4?s=80" width="80px;" alt="pabworks"/><br /><sub><b>pabworks</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=pabworks" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=pabworks" title="Tests">⚠️</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/xloem"><img src="https://avatars.githubusercontent.com/u/279585?v=4?s=80" width="80px;" alt="patiently pending world peace"/><br /><sub><b>patiently pending world peace</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=xloem" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/raishubham1"><img src="https://avatars3.githubusercontent.com/u/29356417?v=4?s=80" width="80px;" alt="raishubham1"/><br /><sub><b>raishubham1</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=raishubham1" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/simone-pignotti"><img src="https://avatars1.githubusercontent.com/u/44410066?v=4?s=80" width="80px;" alt="simone-pignotti"/><br /><sub><b>simone-pignotti</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=simone-pignotti" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/issues?q=author%3Asimone-pignotti" title="Bug reports">🐛</a></td>
@@ -291,9 +292,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/sri1419"><img src="https://avatars2.githubusercontent.com/u/65078278?v=4?s=80" width="80px;" alt="sri1419"/><br /><sub><b>sri1419</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=sri1419" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/tensorflow-as-tf"><img src="https://avatars.githubusercontent.com/u/51345718?v=4?s=80" width="80px;" alt="tensorflow-as-tf"/><br /><sub><b>tensorflow-as-tf</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=tensorflow-as-tf" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/vedazeren"><img src="https://avatars3.githubusercontent.com/u/63582874?v=4?s=80" width="80px;" alt="vedazeren"/><br /><sub><b>vedazeren</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=vedazeren" title="Code">💻</a> <a href="https://github.com/aeon-toolkit/aeon/commits?author=vedazeren" title="Tests">⚠️</a></td>
-      <td align="center" valign="top" width="12.5%"><a href="https://github.com/vincent-nich12"><img src="https://avatars3.githubusercontent.com/u/36476633?v=4?s=80" width="80px;" alt="vincent-nich12"/><br /><sub><b>vincent-nich12</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=vincent-nich12" title="Code">💻</a></td>
     </tr>
     <tr>
+      <td align="center" valign="top" width="12.5%"><a href="https://github.com/vincent-nich12"><img src="https://avatars3.githubusercontent.com/u/36476633?v=4?s=80" width="80px;" alt="vincent-nich12"/><br /><sub><b>vincent-nich12</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=vincent-nich12" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/vollmersj"><img src="https://avatars2.githubusercontent.com/u/12613127?v=4?s=80" width="80px;" alt="vollmersj"/><br /><sub><b>vollmersj</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=vollmersj" title="Documentation">📖</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/xiaobenbenecho"><img src="https://avatars.githubusercontent.com/u/17461849?v=4?s=80" width="80px;" alt="xiaobenbenecho"/><br /><sub><b>xiaobenbenecho</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=xiaobenbenecho" title="Code">💻</a></td>
       <td align="center" valign="top" width="12.5%"><a href="https://github.com/xiaopu222"><img src="https://avatars.githubusercontent.com/u/118000577?v=4?s=80" width="80px;" alt="xiaopu222"/><br /><sub><b>xiaopu222</b></sub></a><br /><a href="https://github.com/aeon-toolkit/aeon/commits?author=xiaopu222" title="Documentation">📖</a></td>
diff --git a/aeon/classification/deep_learning/_cnn.py b/aeon/classification/deep_learning/_cnn.py
index 4db6900e..10563255 100644
--- a/aeon/classification/deep_learning/_cnn.py
+++ b/aeon/classification/deep_learning/_cnn.py
@@ -216,10 +216,11 @@ class CNNClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
+
 
         Returns
         -------
diff --git a/aeon/classification/deep_learning/_encoder.py b/aeon/classification/deep_learning/_encoder.py
index 2c77b70f..76daaf9a 100644
--- a/aeon/classification/deep_learning/_encoder.py
+++ b/aeon/classification/deep_learning/_encoder.py
@@ -199,10 +199,10 @@ class EncoderClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/classification/deep_learning/_fcn.py b/aeon/classification/deep_learning/_fcn.py
index f7255b4e..582d6f4f 100644
--- a/aeon/classification/deep_learning/_fcn.py
+++ b/aeon/classification/deep_learning/_fcn.py
@@ -212,10 +212,10 @@ class FCNClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/classification/deep_learning/_inception_time.py b/aeon/classification/deep_learning/_inception_time.py
index 0b9e9a8c..420ce177 100644
--- a/aeon/classification/deep_learning/_inception_time.py
+++ b/aeon/classification/deep_learning/_inception_time.py
@@ -233,10 +233,10 @@ class InceptionTimeClassifier(BaseClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (c), n_timepoints (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
@@ -612,11 +612,13 @@ class IndividualInceptionClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : array-like of shape = (n_instances, n_channels, n_timepoints)
-            The training input samples. If a 2D array-like is passed,
-            n_channels is assumed to be 1.
-        y : array-like, shape = (n_instances)
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of,
+            shape (n_instances, n_channels, n_timepoints).
+            If a 2D array-like is passed, n_channels is assumed to be 1.
+        y : np.ndarray
+            The training data class labels of shape (n_instances,).
+
 
         Returns
         -------
diff --git a/aeon/classification/deep_learning/_lite_time.py b/aeon/classification/deep_learning/_lite_time.py
index 09c05724..048eb420 100644
--- a/aeon/classification/deep_learning/_lite_time.py
+++ b/aeon/classification/deep_learning/_lite_time.py
@@ -161,10 +161,10 @@ class LITETimeClassifier(BaseClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (c), n_timepoints (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
@@ -456,11 +456,12 @@ class IndividualLITEClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : array-like of shape = (n_instances, n_channels, n_timepoints)
-            The training input samples. If a 2D array-like is passed,
-            n_channels is assumed to be 1.
-        y : array-like, shape = (n_instances)
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of,
+            shape (n_instances, n_channels, n_timepoints).
+            If a 2D array-like is passed, n_channels is assumed to be 1.
+        y : np.ndarray
+            The training data class labels of shape (n_instances,).
 
         Returns
         -------
diff --git a/aeon/classification/deep_learning/_mlp.py b/aeon/classification/deep_learning/_mlp.py
index 26bbfe93..241b0fc5 100644
--- a/aeon/classification/deep_learning/_mlp.py
+++ b/aeon/classification/deep_learning/_mlp.py
@@ -173,10 +173,10 @@ class MLPClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/classification/deep_learning/_resnet.py b/aeon/classification/deep_learning/_resnet.py
index fff1190f..639adbda 100644
--- a/aeon/classification/deep_learning/_resnet.py
+++ b/aeon/classification/deep_learning/_resnet.py
@@ -223,10 +223,10 @@ class ResNetClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/classification/deep_learning/_tapnet.py b/aeon/classification/deep_learning/_tapnet.py
index 90978573..28acc4f7 100644
--- a/aeon/classification/deep_learning/_tapnet.py
+++ b/aeon/classification/deep_learning/_tapnet.py
@@ -209,10 +209,10 @@ class TapNetClassifier(BaseDeepClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances(n), n_channels(d), series_length(m))
-            Input training samples
-        y : np.ndarray of shape n
-            Input training class labels
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/classification/distance_based/_shape_dtw.py b/aeon/classification/distance_based/_shape_dtw.py
index 50867979..b37ca244 100644
--- a/aeon/classification/distance_based/_shape_dtw.py
+++ b/aeon/classification/distance_based/_shape_dtw.py
@@ -115,11 +115,10 @@ class ShapeDTW(BaseClassifier):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_cases, n_channels, n_timepoints)
-            or list of [n_cases] np.ndarray shape (n_channels, n_timepoints_i)
-            The training input samples.
-        y : array-like, shape = (n_cases)
-            The class labels.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints)
+        y : np.ndarray
+            The training data class labels of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/forecasting/base/_base.py b/aeon/forecasting/base/_base.py
index 6c9cf071..f0a338af 100644
--- a/aeon/forecasting/base/_base.py
+++ b/aeon/forecasting/base/_base.py
@@ -55,6 +55,7 @@ from aeon.datatypes import (
 from aeon.forecasting.base._fh import ForecastingHorizon
 from aeon.utils.datetime import _shift
 from aeon.utils.index_functions import get_cutoff, update_data
+from aeon.utils.validation import is_collection, is_hierarchical, is_single_series
 from aeon.utils.validation._dependencies import _check_estimator_deps
 from aeon.utils.validation.forecasting import check_alpha, check_cv, check_fh, check_X
 from aeon.utils.validation.series import check_equal_time_index
@@ -1328,26 +1329,32 @@ class BaseForecaster(BaseEstimator):
         for abs in ALLOWED_ABSTRACT_TYPES:
             types = set(scitype_to_mtype(abs))
             types = list(types.difference(FORBIDDEN_TYPES))
-            mtypes_msg = f'"For {abs} type: {types}. '
 
         # checking y
         if y is not None:
-            y_valid, _, y_metadata = check_is_scitype(
+            if is_hierarchical(y):
+                y_type = "Hierarchical"
+            elif is_collection(y):
+                y_type = "Panel"
+            elif is_single_series(y):
+                y_type = "Series"
+            else:
+                raise TypeError(
+                    "y must be in an aeon compatible format, "
+                    "of abstract type Series, Panel or Hierarchical, for instance a "
+                    "pandas.DataFrame with aeon compatible time indices, or with "
+                    "MultiIndex and last(-1) level an aeon compatible time index. For "
+                    "further details see  examples/forecasting, or examples/datasets"
+                    "If you think y is already in an aeon supported input format, "
+                    "run aeon.datatypes.check_raise(y, mtype) to diagnose the error, "
+                    "where mtype is the string of the type specification you want for "
+                    "y. Possible mtype specification strings are as follows. "
+                )
+            # TODO: Still need to extract the correct "scitype and "mtype" of y,
+            #  is_univariate and _check_missing without check_is_scitype
+            _, _, y_metadata = check_is_scitype(
                 y, scitype=ALLOWED_ABSTRACT_TYPES, return_metadata=True, var_name="y"
             )
-            msg = (
-                "y must be in an aeon compatible format, "
-                "of abstract type Series, Panel or Hierarchical, "
-                "for instance a pandas.DataFrame with aeon compatible time indices, "
-                "or with MultiIndex and last(-1) level an aeon compatible time index."
-                "For further details see  examples/forecasting, or examples/datasets"
-                "If you think y is already in an aeon supported input format, "
-                "run aeon.datatypes.check_raise(y, mtype) to diagnose the error, "
-                "where mtype is the string of the type specification you want for y. "
-                "Possible mtype specification strings are as follows. "
-            )
-            if not y_valid:
-                raise TypeError(msg + mtypes_msg)
 
             y_type = y_metadata["scitype"]
             self._y_mtype_last_seen = y_metadata["mtype"]
@@ -1376,24 +1383,31 @@ class BaseForecaster(BaseEstimator):
 
         # checking X
         if X is not None:
-            X_valid, _, X_metadata = check_is_scitype(
+            # checking y
+            if X is not None:
+                if is_hierarchical(X):
+                    X_type = "Hierarchical"
+                elif is_collection(X):
+                    X_type = "Panel"
+                elif is_single_series(X):
+                    X_type = "Series"
+                else:
+                    raise TypeError(
+                        "y must be in an aeon compatible format, "
+                        "of abstract type Series, Panel or Hierarchical, for instance a"
+                        "pandas.DataFrame with aeon compatible time indices, or with "
+                        "MultiIndex and last(-1) level an aeon compatible time index."
+                        "For further details see  examples/forecasting, or "
+                        "examples/datasets. If you think y is already in an aeon "
+                        "supported input format, run aeon.datatypes.check_raise(y, "
+                        "mtype) to diagnose the error, where mtype is the string of "
+                        "the type specification you want for y. "
+                        "Possible mtype specification strings are as follows. "
+                    )
+            # TODO: Still need to extract the "scitype" of y without check_is_scitype
+            _, _, X_metadata = check_is_scitype(
                 X, scitype=ALLOWED_ABSTRACT_TYPES, return_metadata=True, var_name="X"
             )
-
-            msg = (
-                "X must be either None, or in an aeon compatible format, "
-                "of abstract type Series, Panel or Hierarchical, "
-                "for instance a pandas.DataFrame with aeon compatible time indices, "
-                "or with MultiIndex and last(-1) level an aeon compatible time index."
-                "For further details see  examples/forecasting, or examples/datasets."
-                "If you think X is already in an aeon supported input format, "
-                "run aeon.datatypes.check_raise(X, mtype) to diagnose the error, "
-                "where mtype is the string of the type specification you want for X. "
-                "Possible mtype specification strings are as follows. "
-            )
-            if not X_valid:
-                raise TypeError(msg + mtypes_msg)
-
             X_type = X_metadata["scitype"]
             X_requires_vectorization = X_type not in X_inner_abstract_type
             requires_vectorization = requires_vectorization or X_requires_vectorization
diff --git a/aeon/forecasting/model_evaluation/_functions.py b/aeon/forecasting/model_evaluation/_functions.py
index af8d5480..81b90e96 100644
--- a/aeon/forecasting/model_evaluation/_functions.py
+++ b/aeon/forecasting/model_evaluation/_functions.py
@@ -10,9 +10,10 @@ from typing import List, Optional, Union
 import numpy as np
 import pandas as pd
 
-from aeon.datatypes import check_is_scitype, convert_to
+from aeon.datatypes import convert_to
 from aeon.exceptions import FitFailedWarning
 from aeon.forecasting.base import ForecastingHorizon
+from aeon.utils.validation import is_collection, is_hierarchical, is_single_series
 from aeon.utils.validation._dependencies import _check_soft_dependencies
 from aeon.utils.validation.forecasting import check_cv, check_scoring
 
@@ -330,12 +331,9 @@ def evaluate(
     else:
         scoring = check_scoring(scoring)
 
-    ALLOWED_SCITYPES = ["Series", "Panel", "Hierarchical"]
-
-    y_valid, _, _ = check_is_scitype(y, scitype=ALLOWED_SCITYPES, return_metadata=True)
-    if not y_valid:
+    if not (is_single_series(y) or is_hierarchical(y) or is_collection(y)):
         raise TypeError(
-            f"Expected y dtype {ALLOWED_SCITYPES!r}. Got {type(y)} instead."
+            f"Expected a series, collection or hierarchy. Got {type(y)} instead."
         )
 
     y = convert_to(y, to_type=PANDAS_MTYPES)
@@ -350,12 +348,9 @@ def evaluate(
         pass
 
     if X is not None:
-        X_valid, _, _ = check_is_scitype(
-            X, scitype=ALLOWED_SCITYPES, return_metadata=True
-        )
-        if not X_valid:
+        if not (is_single_series(X) or is_hierarchical(X) or is_collection(X)):
             raise TypeError(
-                f"Expected X dtype {ALLOWED_SCITYPES!r}. Got {type(X)} instead."
+                f"Expected a series, collection or hierarchy. Got {type(y)} instead."
             )
         X = convert_to(X, to_type=PANDAS_MTYPES)
     score_name = (
diff --git a/aeon/forecasting/model_selection/_split.py b/aeon/forecasting/model_selection/_split.py
index e11f4408..e9b12ffd 100644
--- a/aeon/forecasting/model_selection/_split.py
+++ b/aeon/forecasting/model_selection/_split.py
@@ -28,8 +28,11 @@ from aeon.utils.validation import (
     array_is_datetime64,
     array_is_int,
     check_window_length,
+    is_collection,
     is_datetime,
+    is_hierarchical,
     is_int,
+    is_single_series,
     is_timedelta,
     is_timedelta_or_date_offset,
 )
@@ -455,9 +458,9 @@ class BaseSplitter(BaseObject):
 
         Yields
         ------
-        train : time series of same aeon mtype as `y`
+        train : time series of same aeon type as `y`
             training series in the split
-        test : time series of same aeon mtype as `y`
+        test : time series of same aeon type as `y`
             test series in the split
         """
         y, y_orig_mtype = self._check_y(y)
@@ -484,13 +487,13 @@ class BaseSplitter(BaseObject):
         y_index : y, if y was pd.Index; otherwise _check_y(y).index
         """
         if not isinstance(y, pd.Index):
-            y, _ = self._check_y(y, allow_index=True)
+            y, _ = self._check_y(y)
             y_index = y.index
         else:
             y_index = y
         return y_index
 
-    def _check_y(self, y, allow_index=False):
+    def _check_y(self, y):
         """Check and coerce y to a pandas based mtype.
 
         Parameters
@@ -509,52 +512,24 @@ class BaseSplitter(BaseObject):
         ------
         TypeError if y is not one of the permissible mtypes
         """
-        if allow_index and isinstance(y, pd.Index):
-            return y, "pd.Index"
-
-        ALLOWED_SCITYPES = ["Series", "Panel", "Hierarchical"]
-        ALLOWED_MTYPES = [
-            "pd.Series",
-            "pd.DataFrame",
-            "np.ndarray",
-            "nested_univ",
-            "numpy3D",
-            # "numpy2D",
-            "pd-multiindex",
-            # "pd-wide",
-            # "pd-long",
-            "df-list",
-            "pd_multiindex_hier",
-        ]
-        y_valid, _, y_metadata = check_is_scitype(
-            y, scitype=ALLOWED_SCITYPES, return_metadata=True, var_name="y"
-        )
-        if allow_index:
-            msg = (
-                "y must be a pandas.Index, or a time series in an aeon compatible "
-                "format, of scitype Series, Panel or Hierarchical, "
-                "for instance a pandas.DataFrame with aeon compatible time indices, "
-                "or with MultiIndex and last(-1) level an aeon compatible time index."
-                f" Allowed compatible mtype format specifications are: {ALLOWED_MTYPES}"
-                "For further details see  examples/forecasting, or examples/datasets"
-                "If you think y is already in an aeon supported input format, "
-                "run aeon.datatypes.check_raise(y, mtype) to diagnose the error, "
-                "where mtype is the string of the type specification you want for y. "
-            )
-        else:
-            msg = (
+        if not (is_hierarchical(y) or is_collection(y) or is_single_series(y)):
+            raise TypeError(
                 "y must be in an aeon compatible format, "
                 "of scitype Series, Panel or Hierarchical, "
                 "for instance a pandas.DataFrame with aeon compatible time indices, "
                 "or with MultiIndex and last(-1) level an aeon compatible time index."
-                f" Allowed compatible mtype format specifications are: {ALLOWED_MTYPES}"
                 "See  examples/forecasting, or examples/datasets, "
                 "If you think y is already in an aeon supported input format, "
                 "run aeon.datatypes.check_raise(y, mtype) to diagnose the error, "
                 "where mtype is the string of the type specification you want for y. "
             )
-        if not y_valid:
-            raise TypeError(msg)
+        # TODO: Still need to extract the "mtype" of y without check_is_scitype
+        _, _, y_metadata = check_is_scitype(
+            y,
+            scitype=["Hierarchical", "Panel", "Series"],
+            return_metadata=True,
+            var_name="y",
+        )
 
         y_inner = convert_to(y, to_type=PANDAS_MTYPES)
 
diff --git a/aeon/regression/deep_learning/_cnn.py b/aeon/regression/deep_learning/_cnn.py
index af7fbacf..d483b48c 100644
--- a/aeon/regression/deep_learning/_cnn.py
+++ b/aeon/regression/deep_learning/_cnn.py
@@ -221,10 +221,10 @@ class CNNRegressor(BaseDeepRegressor):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data target values.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints).
+        y : np.ndarray
+            The training data target values of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/regression/deep_learning/_fcn.py b/aeon/regression/deep_learning/_fcn.py
index fb3505f7..67b1254b 100644
--- a/aeon/regression/deep_learning/_fcn.py
+++ b/aeon/regression/deep_learning/_fcn.py
@@ -211,10 +211,10 @@ class FCNRegressor(BaseDeepRegressor):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data target values.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints).
+        y : np.ndarray
+            The training data target values of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/regression/deep_learning/_inception_time.py b/aeon/regression/deep_learning/_inception_time.py
index 538ca13a..5c763d09 100644
--- a/aeon/regression/deep_learning/_inception_time.py
+++ b/aeon/regression/deep_learning/_inception_time.py
@@ -237,10 +237,10 @@ class InceptionTimeRegressor(BaseRegressor):
 
         Parameters
         ----------
-        X : np.ndarray of shape (n_instances, n_channels, series_length)
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data target values.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints).
+        y : np.ndarray
+            The training data target values of shape (n_cases,).
 
         Returns
         -------
@@ -588,11 +588,12 @@ class IndividualInceptionRegressor(BaseDeepRegressor):
 
         Parameters
         ----------
-        X : np.ndarray of shape (n_instances, n_channels, series_length)
-            The training input samples. If a 2D array-like is passed,
-            n_channels is assumed to be 1.
-        y : np.ndarray of shape (n_instances)
-            The training data target values.
+        X : np.ndarray
+            The training input samples of,
+            shape (n_instances, n_channels, n_timepoints).
+            If a 2D array-like is passed, n_channels is assumed to be 1.
+        y : np.ndarray
+            The training data target values of shape (n_instances,).
 
         Returns
         -------
diff --git a/aeon/regression/deep_learning/_resnet.py b/aeon/regression/deep_learning/_resnet.py
index 22d0d5d3..8455c159 100644
--- a/aeon/regression/deep_learning/_resnet.py
+++ b/aeon/regression/deep_learning/_resnet.py
@@ -232,10 +232,10 @@ class ResNetRegressor(BaseDeepRegressor):
 
         Parameters
         ----------
-        X : np.ndarray of shape = (n_instances (n), n_channels (d), series_length (m))
-            The training input samples.
-        y : np.ndarray of shape n
-            The training data target values.
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints).
+        y : np.ndarray
+            The training data target values of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/regression/deep_learning/_tapnet.py b/aeon/regression/deep_learning/_tapnet.py
index f746b26b..8ff83538 100644
--- a/aeon/regression/deep_learning/_tapnet.py
+++ b/aeon/regression/deep_learning/_tapnet.py
@@ -200,10 +200,10 @@ class TapNetRegressor(BaseDeepRegressor):
 
         Parameters
         ----------
-        X   : np.ndarray of shape = (n_instances(n), n_channels(d), series_length(m))
-            Input training samples
-        y   : np.ndarray of shape n
-            Input training responses
+        X : np.ndarray
+            The training input samples of shape (n_cases, n_channels, n_timepoints).
+        y : np.ndarray
+            The training data target values of shape (n_cases,).
 
         Returns
         -------
diff --git a/aeon/transformations/base.py b/aeon/transformations/base.py
index 1b3f1895..d122f9bf 100644
--- a/aeon/transformations/base.py
+++ b/aeon/transformations/base.py
@@ -58,7 +58,12 @@ from aeon.utils.sklearn import (
     is_sklearn_regressor,
     is_sklearn_transformer,
 )
-from aeon.utils.validation import is_univariate_series
+from aeon.utils.validation import (
+    is_collection,
+    is_hierarchical,
+    is_single_series,
+    is_univariate_series,
+)
 from aeon.utils.validation._dependencies import _check_estimator_deps
 
 # single/multiple primitives
@@ -805,27 +810,19 @@ class BaseTransformer(BaseEstimator):
 
         ALLOWED_SCITYPES = ["Series", "Panel", "Hierarchical"]
         ALLOWED_MTYPES = self.ALLOWED_INPUT_TYPES
-
+        if not (is_hierarchical(X) or is_collection(X) or is_single_series(X)):
+            raise TypeError(
+                "must be in an aeon compatible format for storing series, hierarchical "
+                "series or collections of series."
+            )
         # checking X
-        X_valid, msg, X_metadata = check_is_scitype(
+        _, _, X_metadata = check_is_scitype(
             X,
             scitype=ALLOWED_SCITYPES,
             return_metadata=True,
             var_name="X",
         )
 
-        msg_invalid_input = (
-            f"must be in an aeon compatible format for storing series, hierarchical "
-            f"series or collections of series. For example, a "
-            f"pandas.DataFrame with aeon compatible time indices for a single series, "
-            f"or a 3D numpy shape (n_cases, n_channels, n_timepoints) for a "
-            f"collection. Allowed compatible formats are described as {ALLOWED_MTYPES}."
-        )
-        if not X_valid:
-            for mtype, err in msg.items():
-                msg_invalid_input += f" [{mtype}: {err}] "
-            raise TypeError("X " + msg_invalid_input)
-
         X_scitype = X_metadata["scitype"]
         X_mtype = X_metadata["mtype"]
         # remember these for potential back-conversion (in transform etc)
@@ -833,7 +830,7 @@ class BaseTransformer(BaseEstimator):
         metadata["_X_input_scitype"] = X_scitype
 
         if X_mtype not in ALLOWED_MTYPES:
-            raise TypeError("X " + msg_invalid_input)
+            raise TypeError("X an invalid internal type")
 
         if X_scitype in X_inner_scitype:
             case = "case 1: scitype supported"
@@ -862,15 +859,13 @@ class BaseTransformer(BaseEstimator):
                 y_possible_scitypes = "Panel"
             elif X_scitype == "Hierarchical":
                 y_possible_scitypes = ["Panel", "Hierarchical"]
-
-            y_valid, _, y_metadata = check_is_scitype(
+            if not (is_hierarchical(y) or is_collection(y) or is_single_series(y)):
+                raise TypeError("Error, y is not a valid type for X type.")
+            # TODO: Still need to extract the "scitype" of y without check_is_scitype
+            _, _, y_metadata = check_is_scitype(
                 y, scitype=y_possible_scitypes, return_metadata=True, var_name="y"
             )
-            if not y_valid:
-                raise TypeError("y " + msg_invalid_input)
-
             y_scitype = y_metadata["scitype"]
-
         else:
             # y_scitype is used below - set to None if y is None
             y_scitype = None
diff --git a/aeon/utils/index_functions.py b/aeon/utils/index_functions.py
index 42fc423f..ee8de2da 100644
--- a/aeon/utils/index_functions.py
+++ b/aeon/utils/index_functions.py
@@ -3,6 +3,9 @@
 import numpy as np
 import pandas as pd
 
+from aeon.datatypes import check_is_scitype, convert_to
+from aeon.utils.validation import is_collection, is_hierarchical, is_single_series
+
 
 def _get_index(x):
     if hasattr(x, "index"):
@@ -211,10 +214,7 @@ def get_cutoff(
     Raises
     ------
     ValueError, TypeError, if check_input or convert_input are True
-        exceptions from check or conversion failure, in check_is_scitype, convert_to
     """
-    from aeon.datatypes import check_is_scitype, convert_to
-
     # deal with VectorizedDF
     if hasattr(obj, "X"):
         obj = obj.X
@@ -225,8 +225,7 @@ def get_cutoff(
         )
 
     if check_input:
-        valid = check_is_scitype(obj, scitype=["Series", "Panel", "Hierarchical"])
-        if not valid:
+        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:
@@ -413,16 +412,15 @@ def get_window(obj, window_length=None, lag=None):
         (cutoff - window_length - lag, cutoff - lag)
         None if obj was None
     """
-    from aeon.datatypes import check_is_scitype, convert_to
-
     if obj is None or (window_length is None and lag is None):
         return obj
-
-    valid, _, metadata = check_is_scitype(
-        obj, scitype=["Series", "Panel", "Hierarchical"], return_metadata=True
-    )
+    valid = is_hierarchical(obj) or is_collection(obj) or is_single_series(obj)
     if not valid:
         raise ValueError("obj must be of Series, Panel, or Hierarchical scitype")
+    # TODO: Still need to extract the "mtype" without check_is_scitype
+    _, _, metadata = check_is_scitype(
+        obj, scitype=["Series", "Panel", "Hierarchical"], return_metadata=True
+    )
     obj_in_mtype = metadata["mtype"]
 
     obj = convert_to(obj, GET_WINDOW_SUPPORTED_MTYPES)
@@ -509,16 +507,16 @@ def get_slice(obj, start=None, end=None):
     obj sub-set sliced for `start` (inclusive) and `end` (exclusive) indices
         None if obj was None
     """
-    from aeon.datatypes import check_is_scitype, convert_to
-
     if (start is None and end is None) or obj is None:
         return obj
 
-    valid, _, metadata = check_is_scitype(
-        obj, scitype=["Series", "Panel", "Hierarchical"], return_metadata=True
-    )
+    valid = is_hierarchical(obj) or is_collection(obj) or is_single_series(obj)
     if not valid:
         raise ValueError("obj must be of Series, Panel, or Hierarchical scitype")
+    # TODO: Still need to extract the "mtype" without check_is_scitype
+    _, _, metadata = check_is_scitype(
+        obj, scitype=["Series", "Panel", "Hierarchical"], return_metadata=True
+    )
     obj_in_mtype = metadata["mtype"]
 
     obj = convert_to(obj, GET_WINDOW_SUPPORTED_MTYPES)
diff --git a/aeon/utils/registry/__init__.py b/aeon/utils/registry/__init__.py
new file mode 100644
index 00000000..dce5672e
--- /dev/null
+++ b/aeon/utils/registry/__init__.py
@@ -0,0 +1,1 @@
+"""Registry."""
diff --git a/aeon/utils/registry/_data_types.py b/aeon/utils/registry/_data_types.py
new file mode 100644
index 00000000..dc080d64
--- /dev/null
+++ b/aeon/utils/registry/_data_types.py
@@ -0,0 +1,11 @@
+COLLECTIONS_DATA_TYPES = [
+    "numpy3D",  # 3D np.ndarray of format (n_cases, n_channels, n_timepoints)
+    "np-list",  # python list of 2D numpy array of length [n_cases],
+    # each of shape (n_channels, n_timepoints_i)
+    "df-list",  # python list of 2D pd.DataFrames of length [n_cases], each a of
+    # shape (n_timepoints_i, n_channels)
+    "numpy2D",  # 2D np.ndarray of shape (n_cases, n_timepoints)
+    "pd-wide",  # 2D pd.DataFrame of shape (n_cases, n_timepoints)
+    "nested_univ",  # pd.DataFrame (n_cases, n_channels) with each cell a pd.Series,
+    "pd-multiindex",  # pd.DataFrame with multi-index,
+]
diff --git a/aeon/utils/validation/__init__.py b/aeon/utils/validation/__init__.py
index d87828ad..194119c3 100644
--- a/aeon/utils/validation/__init__.py
+++ b/aeon/utils/validation/__init__.py
@@ -19,6 +19,10 @@ __all__ = [
     "is_pred_interval_proba",
     "is_pred_quantiles_proba",
     "is_pdmultiindex_hierarchical",
+    "is_single_series",
+    "is_collection",
+    "is_tabular",
+    "is_hierarchical",
 ]
 
 import os
@@ -32,14 +36,18 @@ from aeon.utils.validation.collection import (
     get_n_cases,
     get_type,
     has_missing,
+    is_collection,
     is_equal_length,
     is_nested_univ_dataframe,
+    is_tabular,
     is_univariate,
 )
 from aeon.utils.validation.series import (
+    is_hierarchical,
     is_pdmultiindex_hierarchical,
     is_pred_interval_proba,
     is_pred_quantiles_proba,
+    is_single_series,
     is_univariate_series,
 )
 
@@ -54,6 +62,12 @@ NON_FLOAT_WINDOW_LENGTH_TYPES = Union[
 ]
 
 
+def is_valid_type(y) -> bool:
+    if is_hierarchical(y) or is_collection(y) or is_single_series(y):
+        return True
+    return False
+
+
 def is_array(x) -> bool:
     """Check if x is either a list or np.ndarray."""
     return isinstance(x, (list, np.ndarray))
diff --git a/aeon/utils/validation/collection.py b/aeon/utils/validation/collection.py
index 51d1ecd0..897bbacd 100644
--- a/aeon/utils/validation/collection.py
+++ b/aeon/utils/validation/collection.py
@@ -4,12 +4,22 @@ import numpy as np
 import pandas as pd
 
 
+def is_tabular(X):
+    """Check X is a 2D table."""
+    if isinstance(X, np.ndarray):
+        if X.ndim != 2:
+            return False
+        return True
+    if isinstance(X, pd.DataFrame):
+        return _is_pd_wide(X)
+
+
 def is_collection(X):
     """Check X is a valid collection data structure."""
     try:
         get_type(X)
         return True
-    except TypeError:
+    except (TypeError, ValueError):
         return False
 
 
diff --git a/aeon/utils/validation/series.py b/aeon/utils/validation/series.py
index 2c00da6b..f47e1edb 100644
--- a/aeon/utils/validation/series.py
+++ b/aeon/utils/validation/series.py
@@ -6,6 +6,8 @@ __all__ = [
     "check_time_index",
     "check_equal_time_index",
     "check_consistent_index_type",
+    "is_hierarchical",
+    "is_single_series",
 ]
 
 from typing import Union
@@ -23,6 +25,77 @@ assert set(RELATIVE_INDEX_TYPES).issubset(VALID_INDEX_TYPES)
 assert set(ABSOLUTE_INDEX_TYPES).issubset(VALID_INDEX_TYPES)
 
 
+def is_single_series(y):
+    """Check if input is a single time series.
+
+    Minimal checks that do not check the index characteristics. To check index and
+    throw an error if not correct, use `check_series` instead.
+
+    Parameters
+    ----------
+    y : Any object
+
+    Returns
+    -------
+    bool
+        True if y is one of VALID_DATA_TYPES a valid shape with unique columns.
+    """
+    if isinstance(y, pd.Series):
+        return True
+    if isinstance(y, pd.DataFrame):
+        if "object" in y.dtypes.values:
+            return False
+        return True
+    if isinstance(y, np.ndarray):
+        if y.ndim > 2:
+            return False
+        return True
+    return False
+
+
+def is_hierarchical(y):
+    """Check to see if y is in a hierarchical dataframe.
+
+     Hierarchical is defined as a pd.DataFrame having 3 or more indices.
+
+    Parameters
+    ----------
+    y : Any object
+
+    Returns
+    -------
+    bool
+        True if y is a pd.DataFrame with three or more indices.
+    """
+    if isinstance(y, pd.DataFrame):
+        if y.index.nlevels >= 3:
+            return True
+    return False
+
+
+def _check_pd_dataframe(y):
+    # check that columns are unique
+    if not y.columns.is_unique:
+        raise ValueError(
+            f"Series in a pd.DataFrame must have unique column indices " f"{y.columns}"
+        )
+    # check whether the time index is of valid type
+    if not is_in_valid_index_types(y.index):
+        raise ValueError(
+            f"{type(y.index)} is not supported for series, use "
+            f"one of {VALID_INDEX_TYPES} or integer index instead."
+        )
+    # check that no dtype is object
+    if "object" in y.dtypes.values:
+        raise ValueError("y should not have column of 'object' dtype")
+    # Check time index is ordered in time
+    if not y.index.is_monotonic_increasing:
+        raise ValueError(
+            f"The (time) index of a series must be sorted monotonically increasing, "
+            f"but found: {y.index}"
+        )
+
+
 def is_univariate_series(y):
     """Check if series is univariate.
 
diff --git a/docs/contributing.md b/docs/contributing.md
index 7e176dce..13ddc649 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -55,7 +55,7 @@ bot to do this for you. A list of relevant tags can be found [here](https://allc
 
 For further information on contributing to `aeon`, please see the following pages.
 
-::::{grid} 1 2 2 2
+::::{grid} 1 2 3 3
 :gutter: 3
 
 :::{grid-item-card}
@@ -107,7 +107,7 @@ Mentoring and Projects
 
 ^^^
 
-`aeon` projects and mentoring oppertunities.
+`aeon` projects and mentoring opportunities.
 
 +++
 
diff --git a/docs/developer_guide.md b/docs/developer_guide.md
index 759ef7a6..cd6cfda9 100644
--- a/docs/developer_guide.md
+++ b/docs/developer_guide.md
@@ -1,35 +1,237 @@
 # Developer Guide
 
-Welcome to the `aeon` developer guide. This guide is intended for new developers who
-want to start contributing code to `aeon` and current developers who want to learn
-about specific topics for code and non-code developments.
+Welcome to the `aeon` developer guide. This guide is intended for new developers and
+current developers who want to learn about specific topics for code and non-code
+developments.
 
-The following is a quick checklist for new developers. At any point during the process,
-feel free to post questions on Slack or ask [core developers](./about.md#core-developers)
+For a step-by-step guide for setting up a development version of `aeon`
+and creating a pull request, see the [contributing guide](contributing.md). At any point
+during the process, feel free to post questions on Slack or ask [core developers](./about.md#core-developers)
 for help.
 
-- Fork the repository and install a [development version](developer_guide/dev_installation.md)
-of `aeon`.
-- Get familiar with the [git workflow](developer_guide/git_workflow.rst).
-- Set up [Continuous Integration (CI)](developer_guide/continuous_integration.rst)
-testing locally and learn how to check the status on pull requests.
-- Read up on the `aeon` [coding standards](developer_guide/coding_standards.rst) and
-pre-commit setup.
-
-`aeon` follows the `scikit-learn` API whenever possible. If you’re new to
-`scikit-learn`, take a look at their [getting-started guide](https://scikit-learn.org/stable/getting_started.html).
+`aeon` aims to follow the `scikit-learn` API and conventions whenever possible. If
+you’re new to `scikit-learn`, take a look at their [getting-started guide](https://scikit-learn.org/stable/getting_started.html).
 If you’re already familiar with `scikit-learn`, you may still learn something new from
 their [developer's guide](https://scikit-learn.org/stable/developers/index.html).
 
-## Specific Topics
+::::{grid} 1 2 3 3
+:gutter: 3
+
+:::{grid-item-card}
+:text-align: center
+
+Adding Estimators
+
+^^^
+
+A guide to creating new `aeon` estimators.
+
++++
+
+```{button-ref} developer_guide/add_estimators
+:color: primary
+:click-parent:
+:expand:
+
+Adding Estimators
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+AEP's
+
+^^^
+
+Writing `aeon` Enhancement Proposals (AEP).
+
++++
+
+```{button-ref} developer_guide/aep
+:color: primary
+:click-parent:
+:expand:
+
+AEP's
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+Coding Standards
+
+^^^
+
+Coding standards for the `aeon` code base.
+
++++
+
+```{button-ref} developer_guide/coding_standards
+:color: primary
+:click-parent:
+:expand:
+
+Coding Standards
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+CI/CD
+
+^^^
+
+A description of the `aeon` CI/CD pipeline.
+
++++
+
+```{button-ref} developer_guide/continuous_integration
+:color: primary
+:click-parent:
+:expand:
+
+CI/CD
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+Dependencies
+
+^^^
+
+A guide to the types of `aeon` dependencies.
+
++++
+
+```{button-ref} developer_guide/dependencies
+:color: primary
+:click-parent:
+:expand:
+
+Dependencies
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+Deprecation
+
+^^^
+
+Deprecation policy for `aeon`.
+
++++
+
+```{button-ref} developer_guide/deprecation
+:color: primary
+:click-parent:
+:expand:
+
+Deprecation
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+Developer Installation
+
+^^^
+
+A guide to installing `aeon` for development.
+
++++
+
+```{button-ref} developer_guide/dev_installation
+:color: primary
+:click-parent:
+:expand:
+
+Developer Installation
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+Documentation
+
+^^^
+
+A guide to writing `aeon` documentation and docstrings.
+
++++
+
+```{button-ref} developer_guide/documentation
+:color: primary
+:click-parent:
+:expand:
+
+Documentation
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+Release
+
+^^^
+
+The `aeon` release process.
+
++++
+
+```{button-ref} developer_guide/release
+:color: primary
+:click-parent:
+:expand:
+
+Release
+```
+
+:::
+
+:::{grid-item-card}
+:text-align: center
+
+Testing
+
+^^^
+
+The `aeon` testing framework.
+
++++
+
+```{button-ref} developer_guide/testing
+:color: primary
+:click-parent:
+:expand:
+
+Testing
+```
+
+:::
 
-Below we list further reading and guidance for specific topics in the development of
-`aeon`.
+::::
 
 ```{toctree}
-:maxdepth: 1
+:hidden:
 
-developer_guide/add_dataset.md
 developer_guide/add_estimators.md
 developer_guide/aep.md
 developer_guide/coding_standards.md
@@ -38,7 +240,6 @@ developer_guide/dependencies.md
 developer_guide/deprecation.md
 developer_guide/dev_installation.md
 developer_guide/documentation.md
-developer_guide/git_workflow.md
 developer_guide/release.md
 developer_guide/testing_framework.md
 ```
diff --git a/docs/developer_guide/add_dataset.md b/docs/developer_guide/add_dataset.md
deleted file mode 100644
index 7fabc0ab..00000000
--- a/docs/developer_guide/add_dataset.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Adding a New Dataset
-
-To add a new dataset into `aeon` internal dataset repository, please proceed with the following steps:
-
-1. From the root of your `aeon` local repository, create a `<dataset-name>` folder:
-
-```{code-block} powershell
-mkdir ./datasets/data/<dataset-name>
-```
-2. In the above directory, add your dataset file `<dataset-name>.<EXT>`, where
-`<EXT>` is the file extension:
-
-   * The list of supported file formats is available in the `aeon/MANIFEST.in` file (*e.g.*, `.csv`, `.txt`).
-   * If your file format ``<EXT>`` does not figure in the list, simply add it in the `aeon/MANIFEST.in` file:
-
-```{code-block} powershell
-"aeon/MANIFEST.in"
-...
-recursive-include aeon/datasets *.csv ... *.<EXT>
-...
-```
-3. In ``aeon/datasets/_single_problem_loaders.py``, declare a `load_<dataset-name>(...)` function. Feel free to use any other declared functions as templates for either classification or regression datasets.
-
-4. In ``aeon/datasets/__init__.py``, append `"load_<dataset-name>"` to the list `__all__`.
-
-5. In ``aeon/datasets/setup.py``, append `"<dataset-name>"` to the tuple `included_datasets`.
diff --git a/docs/developer_guide/add_estimators.md b/docs/developer_guide/add_estimators.md
index 23489206..adc84fb7 100644
--- a/docs/developer_guide/add_estimators.md
+++ b/docs/developer_guide/add_estimators.md
@@ -1,4 +1,4 @@
-# Implementing estimators
+# Implementing Estimators
 
 This page describes how to implement `aeon` compatible estimators, and how to ensure and test compatibility. There are additional steps for estimators that are contributed to `aeon` directly.
 
@@ -6,56 +6,93 @@ This page describes how to implement `aeon` compatible estimators, and how to en
 
 The high-level steps to implement `aeon` compatible estimators are as follows:
 
-1. identify the type of the estimator: forecaster, classifier, etc
-2. copy the extension template for that kind of estimator to its intended location
-3. complete the extension template
-4. run the `aeon` test suite and/or the `check_estimator` utility (see [here](https://www.aeon-toolkit.org/en/latest/developer_guide/add_estimators.html#using-the-check-estimator-utility))
-5. if the test suite highlights bugs or issues, fix them and go to 4
+1. Identify the type of the estimator: [forecaster](/examples/forecasting/forecasting.ipynb), [classifier](/examples/classification/classification.ipynb), etc.
+2. Copy the [extension template](https://github.com/aeon-toolkit/aeon/tree/main/extension_templates) for that kind of estimator to its intended location and rename it
+3. Fill out the extension template
+4. Run the `aeon` test suite and/or the `check_estimator` utility (see [here](https://www.aeon-toolkit.org/en/latest/developer_guide/add_estimators.html#using-the-check-estimator-utility))
+5. If the test suite highlights bugs or issues, fix them and return to 4
 
-### What is my learning task?
+### `aeon` learning tasks and base classes
 
-`aeon` is structured along modules encompassing specific learning tasks, e.g., forecasting, classification, regression or segmentation, with a class structure to reflect that. See the [base class overview](https://www.aeon-toolkit.org/en/stable/examples/base/base_classes.html) for more on the code structure.
+`aeon` is structured along modules encompassing specific learning tasks, e.g.,
+forecasting, classification, regression or segmentation, with a class structure to
+reflect that. See the [base class overview](/examples/base/base_classes.ipynb)
+for more on the code structure.
 
-We tag each estimator with a type associated with the relevant base classifier. For example, the type of an estimator that extends BaseForecaster is "forecaster" and the type of an estimator that solves the time series classification task is "classifier".
+We tag each estimator with a type associated with the relevant base classifier. For
+example, the type of an estimator that extends `BaseForecaster` is "forecaster" and
+the type of an estimator that solves the time series classification task and
+extends `BaseClassifier` is "classifier".
 
-Estimators for a given task are located in the respective module. The estimator types also map onto the different extension templates found in the [extension_templates](https://github.com/aeon-toolkit/aeon/tree/main/extension_templates) directory of `aeon`.
+Estimators for a given task are located in the respective module, i.e. classifiers will
+be found in `classification`. The estimator types also map onto the different extension
+templates found in the [extension_templates](https://github.com/aeon-toolkit/aeon/tree/main/extension_templates) directory of `aeon`.
 
-Base classes contain operations common to all algorithms of that type concerning checking and conversion of input data, and checking that tags match the data. For each module, the template gives a step by step guide on how to extend the base classes. For example, `BaseClassifier` defines the `fit` and `predict` base class methods that handle data checking and conversion. All classifiers extend `BaseClassifier` and implement the private methods `_fit` and `_predict` which contain the core logic of the algorithm.
+Base classes contain operations common to all algorithms of that type concerning
+checking and conversion of input data, and checking that tags match the data. For each
+module, the template gives a step by step guide on how to extend the base classes. For
+example, `BaseClassifier` defines the `fit` and `predict` base class methods that
+handle data checking and conversion. All classifiers extend `BaseClassifier` and
+implement the private methods `_fit` and `_predict` which contain the core logic of
+the algorithm.
 
-### What are `aeon` extension templates?
+### `aeon` extension templates
 
-Extension templates are convenient "fill-in" templates for implementers of new estimators. Classes contain `tags` that describe the algorithm and the type of data it can handle.
+Extension templates are convenient "fill-in" templates for implementers of new
+estimators. Classes contain `tags` that describe the algorithm and the type of data
+it can handle.
 
-### How to use `aeon` extension templates
-
-To use the `aeon` extension templates, copy them to the intended location of the estimator. Inside the extension templates, necessary actions are marked with `todo`. The typical workflow goes through the extension template by searching for `todo`, and carrying out the action described next to the `todo`.
+To use the `aeon` extension templates, copy them to the intended location of the
+estimator. Inside the extension templates, necessary actions are marked with
+`todo`. The typical workflow goes through the extension template by searching for
+`todo`, and carrying out the action described next to the `todo`.
 
 Extension templates typically have the following `todo`:
 
-* choosing name and parameters for the estimator
-* filling in the `__init__`: writing parameters to `self`, calling `super`'s `__init__`
-* filling in docstrings of the module and the estimator. This is recommended as early as parameters have been settled on, it tends to be useful as a specification to follow in implementation.
-* filling in the tags for the estimator. Some tags are "capabilities", i.e., what the estimator can do, e.g., dealing with nans. Other tags determine the format of inputs seen in the "inner" methods `_fit`, etc, these tags are usually called `X_inner_type` or similar.
-* Filling in the inherited abstract methods, e.g., `_fit` and `_predict`. The docstrings and  comments in the extension template should be followed here. The docstrings also describe the guarantees on the inputs to the "inner" methods, which are typically stronger than the guarantees on inputs to the public methods, and determined by values of tags that have been set. For instance, setting the tag `y_inner_type` to `pd.DataFrame` for a forecaster guarantees that the `y` seen by `_fit` will be a `pandas.DataFrame`, complying with additional data container specifications in `aeon` (e.g., index types).
-* filling in testing parameters in `get_test_params`. The selection of parameters should cover major estimator internal case distinctions to achieve good coverage.
+- choosing name and parameters for the estimator
+- filling in the `__init__`: writing parameters to `self`, calling `super`'s `__init__`
+- filling in docstrings of the module and the estimator. This is recommended as early
+as parameters have been settled on, it tends to be useful as a specification to follow
+in implementation
+- filling in the tags for the estimator. Some tags are "capabilities", i.e., what the
+estimator can do, e.g., dealing with NaN values. Other tags determine the format of
+inputs seen in the "inner" methods `_fit`, etc, these tags are usually called
+`X_inner_type` or similar
+- Filling in the inherited abstract methods, e.g., `_fit` and `_predict`. The
+docstrings and comments in the extension template should be followed here. The
+docstrings also describe the guarantees on the inputs to the "inner" methods, which
+are typically stronger than the guarantees on inputs to the public methods, and
+determined by values of tags that have been set. For instance, setting the tag
+`y_inner_type` to `pd.DataFrame` for a forecaster guarantees that the `y` seen by
+`_fit` will be a `pandas.DataFrame`, complying with additional data container
+specifications in `aeon` (e.g., index types)
+- filling in testing parameters in `get_test_params`. The selection of parameters
+should cover major estimator internal case distinctions to achieve good coverage
 
 Some common caveats, also described in extension template text:
 
-* `__init__` parameters should be written to `self` and never be changed
-* special case of this: estimator components, i.e., parameters that are estimators, should generally be cloned (via `sklearn.clone`), and method should be called only on the clones
-* methods should generally avoid side effects on arguments
-* non-state changing methods should not write to `self` in general
-* typically, implementing `get_params` and `set_params` is not needed, since `aeon`'s `BaseEstimator` inherits from `sklearn`'s. Custom `get_params`, `set_params` are typically needed only for complex cases only heterogeneous composites, e.g., pipelines with parameters that are nested structures containing estimators.
-
+- `__init__` parameters should be written to `self` and never be changed
+  - special case of this: estimator components, i.e., parameters that are estimators,
+  should generally be cloned (i.e. via `sklearn.clone`), and method should be called
+  only on the clones
+- methods should generally avoid side effects on arguments
+- non-state changing methods (i.e. `predict` and `transform` should not write to
+`self` in general
+- typically, implementing `get_params` and `set_params` is not needed, since `aeon`'s
+`BaseEstimator` inherits from `sklearn`'s. Custom `get_params`, `set_params` are
+typically needed only for complex cases only heterogeneous composites, e.g., pipelines
+with parameters that are nested structures containing estimators
 
 ### Using the `check_estimator` utility
 
-Usually, the simplest way to test complaince with `aeon` is via the `check_estimator` methods in the `utils.estimator_checks` module.
+Usually, the simplest way to test complaince with `aeon` is via the `check_estimator`
+methods in the `utils.estimator_checks` module.
 
 When invoked, this will collect tests in `aeon` relevant for the estimator type and
 run them on the estimator.
 
-This can be used for manual debugging in a notebook environment. Example of running the full test suite for `NaiveForecaster`:
+This can be used for manual debugging in a notebook environment. Example of running the
+full test suite for `NaiveForecaster`:
 
 ```{code-block} powershell
 from aeon.utils.estimator_checks import check_estimator
@@ -63,11 +100,22 @@ from aeon.forecasting.naive import NaiveForecaster
 check_estimator(NaiveForecaster)
 ```
 
-The `check_estimator` utility will return, by default, a `dict`, indexed by test/fixture combination strings, that is, a test name and the fixture combination string in squared brackets. Example: `'test_repr[NaiveForecaster-2]'`, where `test_repr` is the test name, and `NaiveForecaster-2` the fixture combination string.
+The `check_estimator` utility will return, by default, a `dict`, indexed by
+test/fixture combination strings, that is, a test name and the fixture combination
+string in squared brackets. Example: `'test_repr[NaiveForecaster-2]'`, where
+`test_repr` is the test name, and `NaiveForecaster-2` the fixture combination string.
 
-Values of the return `dict` are either the string `"PASSED"`, if the test succeeds, or the exception that the test would raise at failure. `check_estimator` does not raise exceptions by default, the default is returning them as dictionary values. To raise the exceptions instead, e.g., for debugging, use the argument `raise_exceptions=True`, which will raise the exceptions instead of returning them as dictionary values. In that case, there will be at most one exception raised, namely the first exception encountered in the test execution order.
+Values of the return `dict` are either the string `"PASSED"`, if the test succeeds,
+or the exception that the test would raise at failure. `check_estimator` does not raise
+exceptions by default, the default is returning them as dictionary values. To raise the
+exceptions instead, e.g., for debugging, use the argument `raise_exceptions=True`, which
+will raise the exceptions instead of returning them as dictionary values. In that case,
+there will be at most one exception raised, namely the first exception encountered in
+the test execution order.
 
-To run or exclude certain tests, use the `tests_to_run` or `tests_to_exclude` arguments. Values provided should be names of tests (str), or a list of names of tests. Note that test names exclude the part in squared brackets.
+To run or exclude certain tests, use the `tests_to_run` or `tests_to_exclude` arguments.
+Values provided should be names of tests (str), or a list of names of tests. Note that
+test names exclude the part in squared brackets.
 
 Example, running the test `test_constructor` with all fixtures:
 
@@ -77,7 +125,10 @@ check_estimator(NaiveForecaster, tests_to_run="test_constructor")
 outputs
 `{'test_constructor[NaiveForecaster]': 'PASSED'}`
 
-To run or exclude certain test-fixture-combinations, use the `fixtures_to_run` or `fixtures_to_exclude` arguments. Values provided should be names of test-fixture-combination strings (str), or a list of such. Valid strings are precisely the dictionary keys when using `check_estimator` with default parameters.
+To run or exclude certain test-fixture-combinations, use the `fixtures_to_run` or
+`fixtures_to_exclude` arguments. Values provided should be names of
+test-fixture-combination strings (str), or a list of such. Valid strings are precisely
+the dictionary keys when using `check_estimator` with default parameters.
 
 Example, running the test-fixture-combination `"test_repr[NaiveForecaster-2]"`:
 
@@ -90,32 +141,50 @@ A useful workflow for using `check_estimator` to debug an estimator is as follow
 
 1. Run `check_estimator(MyEstimator)` to find failing tests
 2. Subset to failing tests or fixtures using `fixtures_to_run` or `tests_to_run`
-3. If the failure is not obvious, set `raise_exceptions=True` to raise the exception and inspecet the traceback.
-4. If the failure is still not clear, use advanced debuggers on the line of code with `check_estimator`.
+3. If the failure is not obvious, set `raise_exceptions=True` to raise the exception and inspecet the traceback
+4. If the failure is still not clear, use advanced debuggers on the line of code with `check_estimator`
 
 ### Running the test suite in a repository clone
 
-If the target location of the estimator is within `aeon`, then the `aeon` test suite can be run instead. The `aeon` test suite (and CI/CD) is `pytest` based, `pytest` will automatically collect all estimators of a certain type and tests applying for a given estimator.
-
-Generic interface compliance tests are contained in the classes `TestAllEstimators`, `TestAllForecasters`, and so on. `pytest` test-fixture-strings for an estimator `EstimatorName` will always contain `EstimatorName` as a substring, and are identical with the test-fixture-strings returned by `check_estimator`.
+If the target location of the estimator is within `aeon`, then the `aeon` test suite
+can be run instead. The `aeon` test suite (and CI/CD) is `pytest` based, `pytest` will
+automatically collect all estimators of a certain type and tests applying for a given
+estimator.
 
-To run tests only for a given estimator from the console, the command `pytest -k "EstimatorName"` can be used. This will typically have the same effect as using `check_estimator(EstimatorName)`, only via direct `pytest` call. When using Visual Studio Code or pycharm, tests can also be sub-setted using GUI filter functionality - for this, refer to the respective IDE documentation on test integration.
+Generic interface compliance tests are contained in the classes `TestAllEstimators`,
+`TestAllForecasters`, and so on. `pytest` test-fixture-strings for an estimator
+`EstimatorName` will always contain `EstimatorName` as a substring, and are identical
+with the test-fixture-strings returned by `check_estimator`.
 
-To identify codebase locations of tests applying to a specific estimator, a quick approach is searching the codebase for test strings produced by `check_estimator`, preceded by `def` (for function/method definition).
+To run tests only for a given estimator from the console, the command
+`pytest -k "EstimatorName"` can be used. This will typically have the same effect as
+using `check_estimator(EstimatorName)`, only via direct `pytest` call. When using
+Visual Studio Code or pycharm, tests can also be sub-setted using GUI filter
+functionality - for this, refer to the respective IDE documentation on test integration.
 
+To identify codebase locations of tests applying to a specific estimator, a quick
+approach is searching the codebase for test strings produced by `check_estimator`,
+preceded by `def` (for function/method definition).
 
-## Adding an `aeon` compatible estimator to `aeon`
+## Adding an estimator to `aeon`
 
 When adding an `aeon` compatible estimator to `aeon` itself, a number of
 additional things need to be done:
 
-* ensure that code also meets `aeon's` developer documentation standards.
-* add the estimator to the `aeon` API reference. This is done by adding a reference to the estimator in the correct `rst` file inside `docs/api_reference`.
-* authors of the estimator should add themselves to `CODEOWNERS`, as owners of the contributed estimator.
-* if the estimator relies on soft dependencies, or adds new soft dependencies, the steps in the [`dependencies developer guide`](https://github.com/aeon-toolkit/aeon/blob/main/docs/developer_guide/dependencies.md) should be followed
-* ensure that the estimator passes the entire local test suite of `aeon`, with the estimator in its target location. To run tests only for the estimator, the command `pytest -k "EstimatorName"` can be used (or vs code GUI filterfunctionality)
-* ensure that test parameters in `get_test_params` are chosen such that runtime of estimator specific tests remains in the seconds order on `aeon` remote CI/CD
-
-When contributing to `aeon`, core developers will give helpful pointers on the above in their PR reviews.
-
-It is recommended to open a draft PR to get feedback early.
+- Ensure that code also meets `aeon's` developer documentation standards
+- Add the estimator to the `aeon` API reference. This is done by adding a reference to
+the estimator in the correct `rst` file inside `docs/api_reference`
+- Authors of the estimator should add themselves to `CODEOWNERS`, as owners of the
+contributed estimator
+- If the estimator relies on soft dependencies, or adds new soft dependencies, the
+steps in the [dependencies developer guide](developer_guide/dependencies.md)
+should be followed
+- Ensure that the estimator passes the entire local test suite of `aeon`, with the
+estimator in its target location. To run tests only for the estimator, the command
+`pytest -k "EstimatorName"` can be used (or vs code GUI filter functionality)
+- Ensure that test parameters in `get_test_params` are chosen such that runtime of
+estimator specific tests remains in the seconds order on `aeon` remote CI/CD
+
+When contributing to `aeon`, core developers will give helpful pointers on the above in
+their PR reviews. It is recommended to open a draft PR and ask developers for their
+opinions to get feedback early.
diff --git a/docs/developer_guide/aep.md b/docs/developer_guide/aep.md
index be32c057..82aa9881 100644
--- a/docs/developer_guide/aep.md
+++ b/docs/developer_guide/aep.md
@@ -1,4 +1,4 @@
-# Enhancement Proposals
+# `aeon` Enhancement Proposals
 
 ## Description
 
diff --git a/docs/developer_guide/coding_standards.md b/docs/developer_guide/coding_standards.md
index 131cdeb5..725a24a4 100644
--- a/docs/developer_guide/coding_standards.md
+++ b/docs/developer_guide/coding_standards.md
@@ -1,72 +1,77 @@
-# Coding standards
+# Coding Standards
 
-## Coding style
+The `aeon` codebase adheres to a number of coding standards. While these can feel
+restrictive at times, they are important for keeping the codebase readable and
+maintainable in a collaborative environment.
 
-We follow:
+This page provides an overview of the `aeon` coding standards, with the most important
+being:
 
-* the [PEP8](https://www.python.org/dev/peps/pep-0008/) coding guidelines. A good example can be found [here](https://gist.github.com/nateGeorge/5455d2c57fb33c1ae04706f2dc4fee01)
-
-* code formatting according to `black`, `flake8`, `isort`, `numpydoc`
+- The [PEP8](https://www.python.org/dev/peps/pep-0008/) coding guidelines. A good
+example can be found [here](https://gist.github.com/nateGeorge/5455d2c57fb33c1ae04706f2dc4fee01)
+- Code formatting according to [black](https://black.readthedocs.io/) and [flake8](https://flake8.pycqa.org/en/)
+- Documentation formatting using the [numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html)
+style
 
 ### Code formatting and linting
 
-We adhere to the following code formatting standards:
-
-* [`black`](https://black.readthedocs.io/en/stable/) with default settings
-
-* [`flake8`](https://flake8.pycqa.org/en/latest/) with a `max_line_length=88` and
-  some exceptions as per `setup.cfg`
-
-* [`isort`](https://isort.readthedocs.io/en/latest/) with default settings
-
-* [`numpydoc`](https://numpydoc.readthedocs.io/en/latest/format.html) to enforce numpy [docstring standard](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard>) , along with aeon specific conventions described in our [`developer_guide`'s](https://github.com/aeon-toolkit/aeon/tree/main/docs/developer_guide).
-
-This is enforced through our CI/CD workflows via [`pre-commit`](https://pre-commit.com/)
-
-The full pre-commit configuration can be found in [`.pre-commit-config.yaml`](https://github.com/aeon-toolkit/aeon/blob/main/.pre-commit-config.yaml). Additional configurations can be found in [`pyproject.toml`](https://github.com/aeon-toolkit/aeon/blob/main/pyproject.toml).
+Our coding standards are enforced through our CI/CD workflows via [pre-commit](https://pre-commit.com/).
+We adhere to the code formatting standards using the following `pre-commit` hooks:
+
+- [black](https://black.readthedocs.io/en/stable/) with default settings
+- [flake8](https://flake8.pycqa.org/en/latest/) with a `max_line_length=88` and the
+`flake8-bugbear` and `flake8-print` plugins
+- [isort](https://isort.readthedocs.io/en/latest/) to sort file imports
+- [nbQA](https://github.com/nbQA-dev/nbQA) to lint and format Jupyter notebooks using
+the above hooks
+- [ruff](https://docs.astral.sh/ruff/)'s [pydocstyle](https://docs.astral.sh/ruff/rules/#pydocstyle-d)
+module to enforce the [numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard>)
+documentation style
+- [pyupgrade](https://github.com/asottile/pyupgrade) to upgrade Python syntax to modern
+standards
+- Some standard [pre-commit hooks](https://pre-commit.com/hooks.html) for general code
+quality
+
+The full `pre-commit` configuration can be found in [.pre-commit-config.yaml](https://github.com/aeon-toolkit/aeon/blob/main/.pre-commit-config.yaml).
+Additional configurations for some hooks can be found in the [pyproject.toml](https://github.com/aeon-toolkit/aeon/blob/main/pyproject.toml).
 
 ### `aeon` specific code formatting conventions
 
-- Check out our [`glossary`](https://www.aeon-toolkit.org/en/stable/glossary.html).
-- Use underscores to separate words in non-class names: `n_instances` rather than `ninstances`.
-- exceptionally, capital letters `X`, `Y`, `Z`, are permissible as variable names or part of variable names such as `X_train` if referring to data sets, in accordance with the PEP8 convention that such variable names are permissible if in prior use in an area (here, this is the `scikit-learn` adjacenet ecosystem)
-- Avoid multiple statements on one line. Prefer a line return after a control flow statement (`if`/`for`).
-- Use absolute imports for references inside aeon.
-- Don’t use `import *` in the source code. It is considered harmful by the official Python recommendations. It makes the code harder to read as the origin of symbols is no longer explicitly referenced, but most important, it prevents using a static analysis tool like pyflakes to automatically find bugs.
-
-### Setting up local code quality checks
+- Check out our [glossary](glossary.md) for
+preferred terminology
+- Use underscores to separate words in non-class names i.e.`n_instances` rather than
+`ninstances`.
+- Exceptionally, capital letters `X`, `Y`, `Z`, are permissible as variable names or
+part of variable names such as `X_train` if referring to data sets.
+- Use absolute imports for references inside `aeon`.
+- Don’t use `import *` in the source code. It is considered harmful by the official
+Python recommendations.
 
-There are two options to set up local code quality checks:
+### Using `pre-commit`
 
-* using `pre-commit` for automated code formatting
-* setting up `black`, `flake8`, `isort` and/or `numpydoc` manually in a local dev IDE
+To set up pre-commit, follow these steps in a Python environment with the `aeon`
+`dev` dependencies installed.
 
-#### Using pre-commit
+Type the below in your Python environment, and in the root of your local repository
+clone:
 
-To set up pre-commit, follow these steps in a python environment with the `aeon` `dev` dependencies installed.
-
-Type the below in your python environment, and in the root of your local repository clone:
-
-1. If not already done, ensure `aeon` with `dev` dependencies is installed, this includes `pre-commit`:
+1. If not already done, ensure `aeon` with `dev` dependencies is installed, this
+includes `pre-commit`:
 
 ```{code-block} powershell
 pip install -e .[dev]
 ```
+
 2. Set up pre-commit:
 
 ```{code-block} powershell
 pre-commit install
 ```
-Once installed, pre-commit will automatically run all `aeon` code quality checks on the files you changed whenever you make a new commit.
-
-If you want to exclude some line of code from being checked, you can add a `#noqa` (no quality assurance) comment at the end of that line.
-
-#### Integrating with your local developer IDE
-
-Local developer IDEs will usually integrate with common code quality checks, but need setting them up in IDE specific ways.
-
-For Visual Studio Code, `black`, `flake8`, `isort` and/or `numpydoc` will need to be activated individually in the preferences (e.g., search for `black` and check the box). The packages `black` etc will need to be installed in the python environment used by the IDE, this can be achieved by an install of `aeon` with `dev` dependencies.
 
-Visual Studio Code preferences also allow setting of parameters such as `max_line_length=88` for `flake8`.
+Once installed, pre-commit will automatically run all `aeon` code quality checks on
+the files you changed whenever you make a new commit.
 
-In Visual Studio Code, we also recommend to add `"editor.ruler": 88` to your local `settings.json` to display the max line length.
+If you want to exclude some line of code from being checked, you can add a `# noqa`
+(no quality assurance) comment at the end of that line. This should only be used
+sparingly and with good reason. It is best to limit this to specific checks, i.e.
+`# noqa: T201` for `print` statements.
diff --git a/docs/developer_guide/continuous_integration.md b/docs/developer_guide/continuous_integration.md
index e25b930b..6e9798e0 100644
--- a/docs/developer_guide/continuous_integration.md
+++ b/docs/developer_guide/continuous_integration.md
@@ -2,15 +2,14 @@
 
 We use continuous integration services on GitHub to automatically check
 if new pull requests do not break anything and meet code quality
-standards such as a common [`coding standards`](https://github.com/aeon-toolkit/aeon/blob/main/docs/developer_guide/coding_standards.md).
+standards such as a common [coding standards](developer_guide/coding_standards.md).
 Before setting up Continuous Integration, be sure that you have set
-up your developer environment, and installed a
-[development version](https://www.aeon-toolkit.org/en/stable/installation.html)
+up your developer environment, and installed a [development version](developer_guide/dev_installation.md)
 of aeon.
 
 ## Code quality checks
 
-We use [`pre-commit`](https://pre-commit.com) for code quality checks (a process we also refer to as "linting" checks).
+We use [pre-commit](https://pre-commit.com) for code quality checks (a process we also refer to as "linting" checks).
 
 We recommend that you also set this up locally as it will ensure that you never run into code quality errors when you make your first PR!
 These checks run automatically before you make a new commit.
@@ -22,11 +21,11 @@ pre-commit install
 
 `pre-commit` should now automatically run anything you make a commit! Please let us know if you encounter any issues getting this setup.
 
-For a detailed guide on code quality and linting for developers, see [`coding_standards`](https://github.com/aeon-toolkit/aeon/blob/main/docs/developer_guide/coding_standards.md).
+For a detailed guide on code quality and linting for developers, see [coding_standards](developer_guide/coding_standards.md).
 
 ## Unit testing
 
-We use [`pytest`](https://docs.pytest.org/en/latest/) for unit testing.
+We use [pytest](https://docs.pytest.org/en/latest/) for unit testing.
 
 To check if your code passes all tests locally, you need to install the development version of `aeon` and all extra dependencies.
 
@@ -40,7 +39,7 @@ pip install -e .[dev]
    of aeon which will include the changes you make.
 
    For trouble shooting on different operating systems, please see our detailed
-   [installation instructions](https://www.aeon-toolkit.org/en/latest/installation.html).
+   [installation instructions](installation.md).
 
 2. To run all unit tests, run:
 
@@ -50,15 +49,15 @@ pytest ./aeon
 
 ## Test coverage
 
-We use [`coverage`](https://coverage.readthedocs.io/), the [`pytest-cov`](https://github.com/pytest-dev/pytest-cov) plugin, and [`codecov`](https://codecov.io) for test coverage.
+We use [coverage](https://coverage.readthedocs.io/), the [pytest-cov](https://github.com/pytest-dev/pytest-cov) plugin, and [codecov](https://codecov.io) for test coverage.
 
 ## Infrastructure
 
 This section gives an overview of the infrastructure and continuous
 integration services we use.
 
-| Platform       | Operation                                                                  | Configuration                                                                                                                                              |
-| -------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| GitHub Actions | Build/test/distribute on Linux, MacOS and Windows, run code quality checks | [`.github/workflows/`](https://github.com/aeon-toolkit/aeon/tree/main/.github/workflows)                                                                   |
-| Read the Docs  | Build/deploy documentation                                                 | [`.readthedocs.yml`](https://github.com/aeon-toolkit/aeon/blob/main/.readthedocs.yml)                                                                      |
-| Codecov        | Test coverage                                                              | [`.codecov.yml`](https://github.com/aeon-toolkit/aeon/blob/main/.codecov.yml), [`.coveragerc`](https://github.com/aeon-toolkit/aeon/blob/main/.coveragerc) |
+| Platform       | Operation                                                                  | Configuration                                                                                                                                          |
+| -------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| GitHub Actions | Build/test/distribute on Linux, MacOS and Windows, run code quality checks | [.github/workflows/](https://github.com/aeon-toolkit/aeon/tree/main/.github/workflows)                                                                 |
+| Read the Docs  | Build/deploy documentation                                                 | [.readthedocs.yml](https://github.com/aeon-toolkit/aeon/blob/main/.readthedocs.yml)                                                                    |
+| Codecov        | Test coverage                                                              | [.codecov.yml](https://github.com/aeon-toolkit/aeon/blob/main/.codecov.yml), [.coveragerc](https://github.com/aeon-toolkit/aeon/blob/main/.coveragerc) |
diff --git a/docs/developer_guide/git_workflow.md b/docs/developer_guide/git_workflow.md
deleted file mode 100644
index 17ebccda..00000000
--- a/docs/developer_guide/git_workflow.md
+++ /dev/null
@@ -1,71 +0,0 @@
-# Git and GitHub workflow
-
-The preferred workflow for contributing to aeon's repository is to fork the main repository on GitHub, clone, and develop on a new branch.
-
-1. Fork the [project repository](https://github.com/aeon-toolkit/aeon) by clicking on the 'Fork' button near the top right of the page. This creates a copy of the code under your GitHub user account. For more details on how to fork a repository, see [this guide](https://help.github.com/articles/fork-a-repo/).
-
-2. [Clone](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository) your fork of the `aeon` repo from your GitHub account to your local disk:
-
-    ```powershell
-    git clone git@github.com:<username>/aeon.git
-    cd aeon
-    ```
-
-    where `<username>` is your GitHub username.
-
-3. Configure and link the remote for your fork to the upstream repository:
-
-    ```powershell
-    git remote -v
-    git remote add upstream https://github.com/aeon-toolkit/aeon.git
-    ```
-
-4. Verify the new upstream repository you've specified for your fork:
-
-    ```powershell
-    git remote -v
-    > origin    https://github.com/<username>/aeon.git (fetch)
-    > origin    https://github.com/<username>/aeon.git (push)
-    > upstream  https://github.com/aeon-toolkit/aeon.git (fetch)
-    > upstream  https://github.com/aeon-toolkit/aeon.git (push)
-    ```
-
-5. [Sync](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork) the `main` branch of your fork with the upstream repository:
-
-    ```powershell
-    git fetch upstream
-    git checkout main
-    git merge upstream/main
-    ```
-
-6. Create a new `feature` branch from the `main` branch to hold your changes:
-
-    ```powershell
-    git checkout main
-    git checkout -b <feature-branch>
-    ```
-
-    Always use a `feature` branch. It's good practice to never work on the `main` branch. Name the `feature` branch after your contribution.
-
-7. Develop your contribution on your feature branch. Add changed files using `git add` and then `git commit` files to record your changes in Git:
-
-    ```powershell
-    git add <modified_files>
-    git commit
-    ```
-
-8. When finished, push the changes to your GitHub account with:
-
-    ```powershell
-    git push --set-upstream origin my-feature-branch
-    ```
-
-9. Follow [these instructions](https://help.github.com/articles/creating-a-pull-request-from-a-fork) to create a pull request from your fork. If your work is still work in progress, open a draft pull request.
-
-    We recommend opening a pull request early, so that other contributors become aware of your work and can give you feedback early on.
-
-10. To add more changes, simply repeat steps 7 - 8. Pull requests are updated automatically if you push new changes to the same branch.
-
-> **Note:**
->
-> If the above is unclear, look up the [Git documentation](https://git-scm.com/documentation). If you get stuck, chat with us on [Slack](https://join.slack.com/t/aeon-toolkit/shared_invite/zt-22vwvut29-HDpCu~7VBUozyfL_8j3dLA).
diff --git a/docs/developer_guide/release.md b/docs/developer_guide/release.md
index ffd51687..ac56a417 100644
--- a/docs/developer_guide/release.md
+++ b/docs/developer_guide/release.md
@@ -35,7 +35,7 @@ The release process is as follows, on high-level:
   notes in the changelog, following the pattern of current GitHub release notes. The
   full GitHub commit log between releases can also be included.
 
-## ``pypi`` release and release validation
+## `pypi` release and release validation
 
 Creation of the GitHub release trigger the `pypi` release workflow.
 
@@ -50,6 +50,13 @@ Creation of the GitHub release trigger the `pypi` release workflow.
   does not succeed or wheels have not been uploaded, action to diagnose and remedy must
   be taken.
 
+## `conda-forge` release and release validation
+
+7. **Merge the ``conda-forge`` release PR.**
+  After some time a PR will be automatically created in the [aeon conda-forge feedstock](https://github.com/conda-forge/aeon-feedstock).
+  Follow the instructions in the PR to merge it, making sure to update any dependencies
+  that have changed and dependency version bounds.
+
 ## Release notes
 
 Generally, [release notes](https://www.aeon-toolkit.org/en/latest/changelog.html) should follow the general pattern of previous release notes, with sections:
diff --git a/examples/classification/distance_based.ipynb b/examples/classification/distance_based.ipynb
index e98b32d3..6e9b244a 100644
--- a/examples/classification/distance_based.ipynb
+++ b/examples/classification/distance_based.ipynb
@@ -83,7 +83,7 @@
     "## Distance based classifiers\n",
     "The data was derived from twelve monthly electrical power demand time series from Italy and first used in the paper \"Intelligent Icons: Integrating Lite-Weight Data Mining and Visualization into GUI Operating Systems\". The classification task is to distinguish days from Oct to March (inclusive) from April to September.\n",
     "\n",
-    "The dataset consists of 1096 rows in total. Each row represents a day of Italys electric power consumption. All days have a label either 1 or 2. 67 rows are used for training and the rest are for testing. "
+    "The dataset consists of 1096 rows in total. Each row represents a day of Italys electric power consumption. All days have a label either 1 or 2. 67 rows are used for training and the rest are for testing."
    ]
   },
   {


Test patch:
diff --git a/aeon/testing/utils/_cicd_numba_caching.py b/aeon/testing/utils/_cicd_numba_caching.py
index 40dd1830..4aad4b49 100644
--- a/aeon/testing/utils/_cicd_numba_caching.py
+++ b/aeon/testing/utils/_cicd_numba_caching.py
@@ -88,3 +88,24 @@ def custom_load_index(self):
 
 original_load_index = numba.core.caching.IndexDataCacheFile._load_index
 numba.core.caching.IndexDataCacheFile._load_index = custom_load_index
+
+
+# Force all numba functions to be cached
+original_jit = numba.core.decorators._jit
+
+
+def custom_njit(*args, **kwargs):
+    """Force jit to cache.
+
+    This is used for libraries like stumpy that doesn't cache by default. This
+    function will force all functions running to be cache'd
+    """
+    target = kwargs["targetoptions"]
+    # This target can't be cached
+    if "no_cpython_wrapper" not in target:
+        kwargs["cache"] = True
+    return original_jit(*args, **kwargs)
+
+
+# Overwrite the jit function with the custom version
+numba.core.decorators._jit = custom_njit
diff --git a/aeon/transformations/tests/test_base.py b/aeon/transformations/tests/test_base.py
index f0df223e..8aebd5c6 100644
--- a/aeon/transformations/tests/test_base.py
+++ b/aeon/transformations/tests/test_base.py
@@ -17,7 +17,7 @@ import numpy as np
 import pandas as pd
 from numpy.testing import assert_array_equal
 
-from aeon.datatypes import check_is_scitype, mtype_to_scitype
+from aeon.datatypes import mtype_to_scitype
 from aeon.testing.utils.data_gen import get_examples, make_series
 from aeon.testing.utils.scenarios_transformers import (
     TransformerFitTransformHierarchicalMultivariate,
@@ -30,6 +30,12 @@ from aeon.testing.utils.scenarios_transformers import (
 from aeon.transformations.base import BaseTransformer
 from aeon.transformations.boxcox import BoxCoxTransformer
 from aeon.transformations.compose import FitInTransform
+from aeon.utils.validation import (
+    is_collection,
+    is_hierarchical,
+    is_single_series,
+    is_tabular,
+)
 
 
 def inner_X_types(est):
@@ -81,11 +87,12 @@ def test_series_in_series_out_not_supported_but_panel():
     scenario = TransformerFitTransformSeriesUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
 
-    valid, _, _ = check_is_scitype(Xt, scitype="Series", return_metadata=True)
-    assert valid, "fit.transform does not return a Series when given a Series"
+    assert is_single_series(Xt), (
+        "fit.transform does not return a Series when given a " "Series"
+    )
 
 
-def test_panel_in_panel_out_supported():
+def test_collection_in_collection_out_supported():
     """Test that fit/transform runs and returns the correct output type.
 
     Setting: transformer has tags
@@ -105,8 +112,9 @@ def test_panel_in_panel_out_supported():
     assert est.get_tag("output_data_type") == "Series"
     scenario = TransformerFitTransformPanelUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Panel", return_metadata=True)
-    assert valid, "fit.transform does not return a Panel when given a Panel"
+    assert is_collection(Xt), (
+        "fit.transform does not return a collection when given " "a collection"
+    )
 
 
 class _DummyTwo(BaseTransformer):
@@ -142,11 +150,12 @@ def test_series_in_series_out_supported():
     assert est.get_tag("output_data_type") == "Series"
     scenario = TransformerFitTransformSeriesUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Series", return_metadata=True)
-    assert valid, "fit.transform does not return a Series when given a Series"
+    assert is_single_series(
+        Xt
+    ), "fit.transform does not return a Series when given a Series"
 
 
-def test_panel_in_panel_out_not_supported_but_series():
+def test_collection_in_collection_out_not_supported_but_series():
     """Test that fit/transform runs and returns the correct output type.
 
     Setting: transformer has tags
@@ -168,11 +177,12 @@ def test_panel_in_panel_out_not_supported_but_series():
     assert est.get_tag("output_data_type") == "Series"
     scenario = TransformerFitTransformPanelUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Panel", return_metadata=True)
-    assert valid, "fit.transform does not return a Panel when given a Panel"
+    assert is_collection(Xt), (
+        "fit.transform does not return a collection when given " "a collection"
+    )
 
 
-def test_vectorization_multivariate_no_row_vectorization_empty_fit():
+def test_broadcast_multivariate_no_row_broadcast_empty_fit():
     """Test that multivariate vectorization of univariate transformers works.
 
     This test should trigger column (variable) vectorization, but not row vectorization.
@@ -197,8 +207,9 @@ def test_vectorization_multivariate_no_row_vectorization_empty_fit():
     assert est.get_tag("univariate-only")
     scenario = TransformerFitTransformSeriesMultivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Series", return_metadata=True)
-    assert valid, "fit.transform does not return a Series when given a Series"
+    assert is_single_series(
+        Xt
+    ), "fit.transform does not return a series when given a series"
     # length of Xt should be number of hierarchy levels times number of time points
     assert len(Xt) == len(scenario.args["fit"]["X"])
     assert len(Xt.columns) == len(scenario.args["fit"]["X"].columns)
@@ -226,8 +237,9 @@ def test_hierarchical_in_hierarchical_out_not_supported_but_series():
     assert est.get_tag("output_data_type") == "Series"
     scenario = TransformerFitTransformHierarchicalUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Hierarchical", return_metadata=True)
-    assert valid, "fit.transform does not return a Hierarchical when given Hierarchical"
+    assert is_hierarchical(Xt), (
+        "fit.transform does not return a Hierarchical when " "given Hierarchical"
+    )
     # length of Xt should be number of hierarchy levels times number of time points
     assert len(Xt) == 2 * 4 * 12
 
@@ -258,8 +270,9 @@ def test_vectorization_multivariate_and_hierarchical():
     assert est.get_tag("univariate-only")
     scenario = TransformerFitTransformHierarchicalMultivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Hierarchical", return_metadata=True)
-    assert valid, "fit.transform does not return a Hierarchical when given Hierarchical"
+    assert is_hierarchical(Xt), (
+        "fit.transform does not return a Hierarchical when " "given Hierarchical"
+    )
     # length of Xt should be number of hierarchy levels times number of time points
     assert len(Xt) == len(scenario.args["fit"]["X"])
     assert len(Xt.columns) == len(scenario.args["fit"]["X"].columns)
@@ -291,8 +304,9 @@ def test_vectorization_multivariate_and_hierarchical_empty_fit():
     assert est.get_tag("univariate-only")
     scenario = TransformerFitTransformHierarchicalMultivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Hierarchical", return_metadata=True)
-    assert valid, "fit.transform does not return a Hierarchical when given Hierarchical"
+    assert is_hierarchical(Xt), (
+        "fit.transform does not return a Hierarchical when " "given Hierarchical"
+    )
     # length of Xt should be number of hierarchy levels times number of time points
     assert len(Xt) == len(scenario.args["fit"]["X"])
     assert len(Xt.columns) == len(scenario.args["fit"]["X"].columns)
@@ -330,8 +344,9 @@ def test_series_in_series_out_supported_fit_in_transform():
     assert est.get_class_tag("output_data_type") == "Series"
     scenario = TransformerFitTransformSeriesUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Series", return_metadata=True)
-    assert valid, "fit.transform does not return a Series when given a Series"
+    assert is_single_series(
+        Xt
+    ), "fit.transform does not return a series when given a series"
 
 
 def test_hierarchical_in_hierarchical_out_not_supported_but_series_fit_in_transform():
@@ -356,8 +371,9 @@ def test_hierarchical_in_hierarchical_out_not_supported_but_series_fit_in_transf
     assert est.get_tag("output_data_type") == "Series"
     scenario = TransformerFitTransformHierarchicalUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Hierarchical", return_metadata=True)
-    assert valid, "fit.transform does not return a Hierarchical when given Hierarchical"
+    assert is_hierarchical(Xt), (
+        "fit.transform does not return a Hierarchical when " "given Hierarchical"
+    )
     # length of Xt should be number of hierarchy levels times number of time points
     assert len(Xt) == 2 * 4 * 12
 
@@ -395,8 +411,7 @@ def test_series_in_primitives_out_supported_fit_in_transform():
     assert est.get_tag("output_data_type") == "Primitives"
     scenario = TransformerFitTransformSeriesUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Table", return_metadata=True)
-    assert valid, "fit.transform does not return a Table when given a Series"
+    assert is_tabular(Xt), "fit.transform does not return a Table when given a Series"
     # length of Xt should be one, for a single series passed
     assert len(Xt) == 1
 
@@ -423,8 +438,7 @@ def test_panel_in_primitives_out_not_supported_fit_in_transform():
     assert est.get_tag("output_data_type") == "Primitives"
     scenario = TransformerFitTransformPanelUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Table", return_metadata=True)
-    assert valid, "fit.transform does not return a Table when given a Panel"
+    assert is_tabular(Xt), "fit.transform does not return a Table when given a Panel"
     # length of Xt should be seven = number of samples in the scenario
     assert len(Xt) == 7
 
@@ -489,8 +503,7 @@ def test_series_in_primitives_out_not_supported_fit_in_transform():
     assert est.get_tag("output_data_type") == "Primitives"
     scenario = TransformerFitTransformSeriesUnivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Table", return_metadata=True)
-    assert valid, "fit.transform does not return a Table when given a Series"
+    assert is_tabular(Xt), "fit.transform does not return a Table when given a Series"
     # length of Xt should be one, for a single series passed
     assert len(Xt) == 1
 
@@ -530,8 +543,7 @@ def test_panel_in_primitives_out_supported_with_y_in_fit_but_not_transform():
     assert est.get_tag("output_data_type") == "Primitives"
     scenario = TransformerFitTransformPanelUnivariateWithClassYOnlyFit()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Table", return_metadata=True)
-    assert valid, "fit.transform does not return a Table when given a Panel"
+    assert is_tabular(Xt), "fit.transform does not return a Table when given a Panel"
     # length of Xt should be seven = number of samples in the scenario
     assert len(Xt) == 7
 
@@ -560,8 +572,9 @@ def test_vectorization_multivariate_no_row_vectorization():
     assert est.get_tag("univariate-only")
     scenario = TransformerFitTransformSeriesMultivariate()
     Xt = scenario.run(est, method_sequence=["fit", "transform"])
-    valid, _, _ = check_is_scitype(Xt, scitype="Series", return_metadata=True)
-    assert valid, "fit.transform does not return a Series when given a Series"
+    assert is_single_series(
+        Xt
+    ), "fit.transform does not return a Series when given a Series"
     # length of Xt should be number of hierarchy levels times number of time points
     assert len(Xt) == len(scenario.args["fit"]["X"])
     assert len(Xt.columns) == len(scenario.args["fit"]["X"].columns)
diff --git a/docs/developer_guide/testing.md b/docs/developer_guide/testing.md
new file mode 100644
index 00000000..2875358c
--- /dev/null
+++ b/docs/developer_guide/testing.md
@@ -0,0 +1,20 @@
+# Testing framework
+
+`aeon` uses `pytest` for testing interface compliance of estimators, and correctness of
+code. This page gives an overview of the test frames, and introductions on how to add
+tests, or how to extend the testing framework.
+
+## Test module architecture
+
+`aeon` testing happens on three layers, roughly corresponding to the inheritance layers
+of estimators.
+
+* **package level**: testing interface compliance with the `BaseObject` and
+`BaseEstimator` specifications, in `tests/test_all_estimators.py`
+* **module level**: testing interface compliance of concrete estimators with their base
+class, for instance `classification/tests/test_all_classifiers.py`
+* **low level**: testing individual functionality of estimators or other code, in
+individual files in `tests` folders.
+
+The `aeon` testing framework is under redesign. If you have questions, please ask
+a developer or in Slack.
diff --git a/docs/developer_guide/testing_framework.md b/docs/developer_guide/testing_framework.md
deleted file mode 100644
index 79dee4d4..00000000
--- a/docs/developer_guide/testing_framework.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Testing framework
-
-`aeon` uses `pytest` for testing interface compliance of estimators, and correctness of code. This page gives an overview over the tests, and introductions on how to add tests, or how to extend the testing framework.
-
-## Test module architecture
-
-`aeon` testing happens on three layers, roughly corresponding to the inheritance layers of estimators.
-
-* **package level**: testing interface compliance with the `BaseObject` and `BaseEstimator` specifications, in `tests/test_all_estimators.py`
-
-* **module level**: testing interface compliance of concrete estimators with their base class, for instance `classification/tests/test_all_classifiers.py`
-
-* **low level**: testing individual functionality of estimators or other code, in individual files in `tests` folders.
-
-The `aeon` testing framework is under redesign. For information on the current state of the testing framework, please
-refer to the docstring documentation of the `testing` module.