From b39224047b1a287143930aa4b88f1c9f13bb23d7 Mon Sep 17 00:00:00 2001 From: Artur Sadurski <asadurski@users.noreply.github.com> Date: Fri, 16 Jul 2021 11:14:49 +0200 Subject: [PATCH 1/4] restrict SQLAlchemy to versions before 1.4 Fixes "Can't operate on closed transaction inside context manager." error on file save. The code uses old-style connections. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d055913..00b017d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ Jinja2>=2.7.3 Mako>=1.0.0 MarkupSafe>=0.23 Pygments>=2.0.1 -SQLAlchemy>=1.0.5 +SQLAlchemy>=1.0.5,<1.4 alembic>=0.7.6 backports.ssl-match-hostname>=3.4.0.2 certifi>=14.05.14 From 6e4f8182c2d4ef97e86daea9b234e4b1664d8c46 Mon Sep 17 00:00:00 2001 From: artur <a.sadurski@gmail.com> Date: Tue, 26 Mar 2024 19:18:21 +0100 Subject: [PATCH 2/4] IPython compatibility patch --- pgcontents/utils/ipycompat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgcontents/utils/ipycompat.py b/pgcontents/utils/ipycompat.py index 7e59d90..f480629 100644 --- a/pgcontents/utils/ipycompat.py +++ b/pgcontents/utils/ipycompat.py @@ -3,7 +3,7 @@ """ import IPython -SUPPORTED_VERSIONS = {3, 4, 5} +SUPPORTED_VERSIONS = {3, 4, 5, 6, 7, 8} IPY_MAJOR = IPython.version_info[0] if IPY_MAJOR not in SUPPORTED_VERSIONS: raise ImportError("IPython version %d is not supported." % IPY_MAJOR) From a89903573a2a06f1cb208606b05df66264bbadf5 Mon Sep 17 00:00:00 2001 From: artur <a.sadurski@gmail.com> Date: Tue, 9 Jul 2024 18:03:57 +0200 Subject: [PATCH 3/4] pin SQLAlchemy version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 00b017d..6288799 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ Jinja2>=2.7.3 Mako>=1.0.0 MarkupSafe>=0.23 Pygments>=2.0.1 -SQLAlchemy>=1.0.5,<1.4 +SQLAlchemy==1.4.52 alembic>=0.7.6 backports.ssl-match-hostname>=3.4.0.2 certifi>=14.05.14 From 3319a95a7571e6e70fe3c47b41a27f10ac8e4c86 Mon Sep 17 00:00:00 2001 From: artur <a.sadurski@gmail.com> Date: Thu, 18 Jul 2024 12:21:59 +0200 Subject: [PATCH 4/4] upgrade sessions code to SQLAlchemy 1.4 style --- pgcontents/pgmanager.py | 11 ++++++---- pgcontents/query.py | 45 +++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/pgcontents/pgmanager.py b/pgcontents/pgmanager.py index c4eea1f..ed27bdb 100644 --- a/pgcontents/pgmanager.py +++ b/pgcontents/pgmanager.py @@ -17,6 +17,8 @@ """ from __future__ import unicode_literals from itertools import chain + +from sqlalchemy.orm import Session from tornado import web from .api_utils import ( @@ -331,13 +333,14 @@ def save(self, model, path): if model['type'] not in ('file', 'directory', 'notebook'): self.do_400("Unhandled contents type: %s" % model['type']) try: - with self.engine.begin() as db: + session = Session(self.engine) + with session.begin(): if model['type'] == 'notebook': - validation_message = self._save_notebook(db, model, path) + validation_message = self._save_notebook(session, model, path) elif model['type'] == 'file': - validation_message = self._save_file(db, model, path) + validation_message = self._save_file(session, model, path) else: - validation_message = self._save_directory(db, path) + validation_message = self._save_directory(session, path) except (web.HTTPError, PathOutsideRoot): raise except FileTooLarge: diff --git a/pgcontents/query.py b/pgcontents/query.py index 0140d81..bc1437f 100644 --- a/pgcontents/query.py +++ b/pgcontents/query.py @@ -298,6 +298,7 @@ def _file_default_fields(): files.c.name, files.c.created_at, files.c.parent_name, + files.c.user_id, ] @@ -472,32 +473,32 @@ def save_file(db, user_id, path, content, max_size_bytes): """ check_content(content, max_size_bytes) directory, name = split_api_filepath(path) - with db.begin_nested() as savepoint: - try: + savepoint = db.begin_nested() + try: + res = db.execute( + files.insert().values( + name=name, + user_id=user_id, + parent_name=directory, + content=content, + ) + ) + except IntegrityError as error: + # The file already exists, so overwrite its content with the newer + # version. + if is_unique_violation(error): + savepoint.rollback() res = db.execute( - files.insert().values( - name=name, - user_id=user_id, - parent_name=directory, + files.update().where( + _file_where(user_id, path), + ).values( content=content, + created_at=func.now(), ) ) - except IntegrityError as error: - # The file already exists, so overwrite its content with the newer - # version. - if is_unique_violation(error): - savepoint.rollback() - res = db.execute( - files.update().where( - _file_where(user_id, path), - ).values( - content=content, - created_at=func.now(), - ) - ) - else: - # Unknown error. Reraise - raise + else: + # Unknown error. Reraise + raise return res