Repository: LorenFrankLab/spyglass (language: python)

Issue:
SSLError when connecting to database using Python 3.10
**Describe the bug**
When I try to connect to the database using a Python 3.10 environment, I get the following SSLError:
```
OperationalError: (2003, "Can't connect to MySQL server on 'lmf-db.cin.ucsf.edu' ([SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997))")
```
This appears to be a low-level error related to stricter TLS requirements in Python 3.10. The issue has been reported here: https://github.com/datajoint/datajoint-python/issues/1007

**To Reproduce**
```python
import spyglass.common as sgc
```

Does anyone else get this as well?

I see that in `environment.yml` we limit spyglass to <3.10, but in `pyproject.toml`, we do not. If someone else can reproduce this, then perhaps we should.



Discussion / hints:
@rly I can reproduce this error. I say we should limit python to 3.10 in pyproject.toml and hope that datajoint addresses this soon enough. 
I assume no one has an objection; so I will proceed to make a PR to address this ticket. It is very simple. If there is strong objection, the PR can be ignored.

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c3fbe4de..84d6d2c11 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,9 @@ dj.FreeTable(dj.conn(), "common_session.session_group").drop()
     - Remove stored hashes from pytests #1152
     - Remove mambaforge from tests #1153
     - Remove debug statement #1164
+- Allow python < 3.13 #1169
+- Remove numpy version restriction #1169
+- Add testing for python versions 3.9, 3.10, 3.11, 3.12 #1169
 
 ### Pipelines
 
diff --git a/environment.yml b/environment.yml
index 7fa1b51ea..a5229b8a8 100644
--- a/environment.yml
+++ b/environment.yml
@@ -23,13 +23,13 @@ dependencies:
   # - libgcc # dlc-only
   - matplotlib
   - non_local_detector
-  - numpy<1.24
+  - numpy
   - pip
   - position_tools
   - pybind11  # req by mountainsort4 -> isosplit5
   - pydotplus
   - pyfftw<=0.12.0  # ghostipy req. install from conda-forge for Mac ARM
-  - python>=3.9,<3.10
+  - python>=3.9,<3.13
   - pytorch<1.12.0
   - ripple_detection
   - seaborn
diff --git a/environment_dlc.yml b/environment_dlc.yml
index 9870a0424..156bed793 100644
--- a/environment_dlc.yml
+++ b/environment_dlc.yml
@@ -23,13 +23,13 @@ dependencies:
   - libgcc   # dlc-only
   - matplotlib
   - non_local_detector
-  - numpy<1.24
+  - numpy
   - pip>=20.2.*
   - position_tools
   - pybind11  # req by mountainsort4 -> isosplit5
   - pydotplus>=2.0.*
   - pyfftw<=0.12.0  # ghostipy req. install from conda-forge for Mac ARM
-  - python>=3.9,<3.10
+  - python>=3.9,<3.13
   - pytorch<1.12.0
   - ripple_detection
   - seaborn
diff --git a/pyproject.toml b/pyproject.toml
index ed3a570c8..0bd9164cb 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
 name = "spyglass-neuro"
 description = "Neuroscience data analysis framework for reproducible research"
 readme = "README.md"
-requires-python = ">=3.9,<3.10"
+requires-python = ">=3.9,<3.13"
 license = { file = "LICENSE" }
 authors = [
     { name = "Loren Frank", email = "loren.frank@ucsf.edu" },
@@ -46,11 +46,11 @@ dependencies = [
     "matplotlib",
     "ndx_franklab_novela>=0.1.0",
     "non_local_detector",
-    "numpy<1.24",
+    "numpy",
     "opencv-python",
-    "panel>=1.4.0", # panel #6325 resolved
+    "panel>=1.4.0",                  # panel #6325 resolved
     "position_tools>=0.1.0",
-    "pubnub<6.4.0",            # TODO: remove this when sortingview is updated
+    "pubnub<6.4.0",                  # TODO: remove this when sortingview is updated
     "pydotplus",
     "pynwb>=2.2.0,<3",
     "ripple_detection",
@@ -62,21 +62,21 @@ dependencies = [
 
 [project.optional-dependencies]
 dlc = [
-  "ffmpeg",
-  "deeplabcut[tf]",          # removing dlc pin removes need to pin tf/numba
+    "ffmpeg",
+    "deeplabcut[tf]", # removing dlc pin removes need to pin tf/numba
 ]
 test = [
-    "click",                 # for CLI subpackage only
-    "docker",                # for tests in a container
+    "click",                  # for CLI subpackage only
+    "docker",                 # for tests in a container
     "ghostipy",
-    "kachery",               # database access
+    "kachery",                # database access
     "kachery-client",
     "kachery-cloud>=0.4.0",
     "opencv-python-headless", # for headless testing of Qt
-    "pre-commit",            # linting
-    "pytest",                # unit testing
-    "pytest-cov",            # code coverage
-    "pytest-xvfb",           # for headless testing of Qt
+    "pre-commit",             # linting
+    "pytest",                 # unit testing
+    "pytest-cov",             # code coverage
+    "pytest-xvfb",            # for headless testing of Qt
 ]
 docs = [
     "hatch",                 # Get version from env
@@ -134,7 +134,7 @@ addopts = [
     # "--no-dlc",      # don't run DLC tests
     "--show-capture=no",
     "--pdbcls=IPython.terminal.debugger:TerminalPdb", # use ipython debugger
-    "--doctest-modules", # run doctests in all modules
+    "--doctest-modules",                              # run doctests in all modules
     "--cov=spyglass",
     "--cov-report=term-missing",
     "--no-cov-on-fail",
@@ -143,9 +143,9 @@ testpaths = ["tests"]
 log_level = "INFO"
 env = [
     "QT_QPA_PLATFORM = offscreen", # QT fails headless without this
-    "DISPLAY = :0", # QT fails headless without this
-    "TF_ENABLE_ONEDNN_OPTS = 0", # TF disable approx calcs
-    "TF_CPP_MIN_LOG_LEVEL = 2", # Disable TF warnings
+    "DISPLAY = :0",                # QT fails headless without this
+    "TF_ENABLE_ONEDNN_OPTS = 0",   # TF disable approx calcs
+    "TF_CPP_MIN_LOG_LEVEL = 2",    # Disable TF warnings
 ]
 
 [tool.coverage.run]
@@ -175,4 +175,4 @@ omit = [ # which submodules have no tests
 line-length = 80
 
 [tool.ruff.lint]
-ignore = ["F401" , "E402", "E501"]
+ignore = ["F401", "E402", "E501"]


Test patch:
diff --git a/.github/workflows/test-package-build.yml b/.github/workflows/test-package-build.yml
index 3513bb664..e07017a31 100644
--- a/.github/workflows/test-package-build.yml
+++ b/.github/workflows/test-package-build.yml
@@ -29,7 +29,6 @@ jobs:
           python-version: 3.9
       - run: |
           pip install --upgrade build twine
-          pip install importlib_metadata==7.2.1 # twine #977
       - name: Build sdist and wheel
         run: python -m build
       - run: twine check dist/*
@@ -50,6 +49,7 @@ jobs:
     needs: [build]
     strategy:
       matrix:
+        python-version: ['3.9', '3.10', '3.11', '3.12']
         package: ['wheel', 'sdist', 'archive']
     steps:
       - name: Download sdist and wheel artifacts
@@ -66,11 +66,13 @@ jobs:
           path: archive/
       - uses: actions/setup-python@v5
         with:
-          python-version: 3.9
+          python-version: ${{ matrix.python-version }}
       - name: Display Python version
         run: python -c "import sys; print(sys.version)"
-      - name: Update pip
-        run: pip install --upgrade pip
+      - name: Install build dependencies
+        run: |
+          pip install --upgrade setuptools wheel
+          pip install --upgrade pip
       - name: Install wheel
         if: matrix.package == 'wheel'
         run: pip install dist/*.whl