diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8285071e..f041bfd9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8, 3.9, "3.10", "3.11"] + python-version: ["3.10", "3.11"] steps: - uses: actions/checkout@master - name: Setup Python ${{ matrix.python-version }} diff --git a/nbexchange/app.py b/nbexchange/app.py index 2996d0bf..3f162851 100644 --- a/nbexchange/app.py +++ b/nbexchange/app.py @@ -141,6 +141,7 @@ def init_logging(self): See sqlalchemy.create_engine for details. """ ).tag(config=True) + upgrade_db = Bool( False, help="""Upgrade the database automatically on start. diff --git a/nbexchange/dbutil.py b/nbexchange/dbutil.py index 69e29632..a4980941 100644 --- a/nbexchange/dbutil.py +++ b/nbexchange/dbutil.py @@ -217,7 +217,7 @@ def register_ping_connection(engine): From SQLAlchemy docs on pessimistic disconnect handling: - https://docs.sqlalchemy.org/en/rel_1_1/core/pooling.html#disconnect-handling-pessimistic + https://docs.sqlalchemy.org/en/20/core/pooling.html#custom-legacy-pessimistic-ping """ @event.listens_for(engine, "engine_connect") @@ -236,7 +236,7 @@ def ping_connection(connection, branch): # run a SELECT 1. use a core select() so that # the SELECT of a scalar value without a table is # appropriately formatted for the backend - connection.scalar(select([1])) + connection.scalar(select(1)) except exc.DBAPIError as err: # catch SQLAlchemy's DBAPIError, which is a wrapper # for the DBAPI's exception. It includes a .connection_invalidated @@ -249,7 +249,7 @@ def ping_connection(connection, branch): # itself and establish a new connection. The disconnect detection # here also causes the whole connection pool to be invalidated # so that all stale connections are discarded. - connection.scalar(select([1])) + connection.scalar(select(1)) else: raise finally: @@ -349,13 +349,15 @@ def setup_db(url="sqlite:///:memory:", reset=False, log=None, **kwargs): # is ever created. kwargs.setdefault("poolclass", StaticPool) - engine = create_engine(url, **kwargs) + # From sqlalchemy 2.0, testing pools is now built in + engine = create_engine(url, pool_pre_ping=True, **kwargs) if url.startswith("sqlite"): register_foreign_keys(engine) - # enable pessimistic disconnect handling - register_ping_connection(engine) + # not needed: https://docs.sqlalchemy.org/en/20/core/pooling.html#disconnect-handling-pessimistic + # # enable pessimistic disconnect handling + # register_ping_connection(engine) if reset: Base.metadata.drop_all(engine) diff --git a/nbexchange/models/__init__.py b/nbexchange/models/__init__.py index 2aa0c216..c62b37a7 100644 --- a/nbexchange/models/__init__.py +++ b/nbexchange/models/__init__.py @@ -5,7 +5,8 @@ must be imported below the declaration for `Alembic` autogenerate to work. """ -from sqlalchemy.ext.declarative import declarative_base +# import sqlalchemy.orm as orm +from sqlalchemy.orm import declarative_base Base = declarative_base() diff --git a/nbexchange/tests/test_smoketest.py b/nbexchange/tests/test_smoketest.py deleted file mode 100644 index da16c7f7..00000000 --- a/nbexchange/tests/test_smoketest.py +++ /dev/null @@ -1,6 +0,0 @@ -import socket - - -def test_smoketest_nbexchange(container): - sock = socket.socket() - sock.connect(("127.0.0.1", container.ports["9000/tcp"][0])) diff --git a/pyproject.toml b/pyproject.toml index d1189a43..2180da8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,15 +31,17 @@ classifiers = [ "Intended Audience :: Education", ] +# nbgrader 0.8.4 requires sqlalchemy 2, which breaks Jupyterhub # pyjwt limited due to djangorestframework-jwt dependencies +# sqlalchemy spec is whatever nbgrader uses dependencies = [ "alembic>=1.6.5", "jupyterhub>=1.4.1", - "nbgrader==0.8.2", # From pypi dated March 28th 2023 + "nbgrader==0.8.3", "psycopg2-binary>=2.8.6", "pyjwt<2", "sentry-sdk==1.14.0", - "sqlalchemy>=1.4.3", + "sqlalchemy>=1.4,<3", "tornado==6.1", "tornado-prometheus==0.1.1", ]