From f65de3af69b69fe232e6cb84b039a3bcd5ab13d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Konieczny?= Date: Thu, 9 Jun 2022 15:03:56 +0200 Subject: [PATCH] Fix null version bug in existing data (#24) --- chrononaut/__init__.py | 4 ++-- docs/conf.py | 18 +++++++++--------- requirements.txt | 4 ++-- setup.py | 3 ++- tests/files/seed_null_version.sql | 3 +++ tests/test_versioning.py | 20 ++++++++++++++++++++ 6 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 tests/files/seed_null_version.sql diff --git a/chrononaut/__init__.py b/chrononaut/__init__.py index a59e729..d3e180d 100644 --- a/chrononaut/__init__.py +++ b/chrononaut/__init__.py @@ -46,7 +46,7 @@ def before_flush(session, flush_context, instances): for obj in session.dirty: if hasattr(obj, "__versioned__") and is_modified(obj): # Objects cannot be updated in the `after_flush` step hence bumping the version here - obj.version = obj.version + 1 + obj.version = obj.version + 1 if obj.version is not None else 1 if hasattr(obj, "__chrononaut_record_change_info__"): append_recorded_changes(obj, session) @@ -56,7 +56,7 @@ def before_flush(session, flush_context, instances): ): raise ChrononautException("Cannot commit version removal") elif hasattr(obj, "__versioned__"): - obj.version = obj.version + 1 + obj.version = obj.version + 1 if obj.version is not None else 1 create_version(obj, session, deleted=True) @event.listens_for(session, "after_flush") diff --git a/docs/conf.py b/docs/conf.py index 4a5048a..623954d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,18 +46,18 @@ master_doc = "index" # General information about the project. -project = u"Chrononaut" -copyright = u"2018, Reference Genomics, Inc." -author = u"Reference Genomics, Inc." +project = "Chrononaut" +copyright = "2018, Reference Genomics, Inc." +author = "Reference Genomics, Inc." # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u"0.2.3" +version = "0.2.3" # The full version, including alpha/beta/rc tags. -release = u"0.2.3" +release = "0.2.3" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -145,8 +145,8 @@ ( master_doc, "Chrononaut.tex", - u"Chrononaut Documentation", - u"Reference Genomics, Inc.", + "Chrononaut Documentation", + "Reference Genomics, Inc.", "manual", ) ] @@ -156,7 +156,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "chrononaut", u"Chrononaut Documentation", [author], 1)] +man_pages = [(master_doc, "chrononaut", "Chrononaut Documentation", [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -168,7 +168,7 @@ ( master_doc, "Chrononaut", - u"Chrononaut Documentation", + "Chrononaut Documentation", author, "Chrononaut", "One line description of project.", diff --git a/requirements.txt b/requirements.txt index f1f8d45..860a25e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # Requirements -Flask==1.1.2 +Flask==2.1.0 Flask-SQLAlchemy==2.5.1 SQLAlchemy==1.4.25 psycopg2-binary>=2.8.1 @@ -9,9 +9,9 @@ python-dateutil # Testing & documentation requirements (note these must be installable across all Tox environment) pytest>=3.0.7 -codecov pytest-cov==2.4.0 Flask-Security-Fork==2.0.1 +Werkzeug==2.0.0 sphinx==1.5.5 sphinx-autobuild==0.6.0 Flask-Sphinx-Themes==1.0.1 diff --git a/setup.py b/setup.py index f6a811e..cc4aa2f 100755 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ version=__version__, # noqa packages=find_packages(exclude=["*test*"]), install_requires=[ - "Flask>=1.1.2", + "Flask>=2.1.0", "Flask-SQLAlchemy>=2.5.1", "SQLAlchemy>=1.4.0", "psycopg2>=2.7.1", @@ -34,6 +34,7 @@ author="Nick Greenfield", author_email="opensource@onecodex.com", long_description=__doc__, + long_description_content_type="text/markdown", license="MIT License", keywords="Chrononaut", url="https://github.com/onecodex/chrononaut", diff --git a/tests/files/seed_null_version.sql b/tests/files/seed_null_version.sql new file mode 100644 index 0000000..048b3f0 --- /dev/null +++ b/tests/files/seed_null_version.sql @@ -0,0 +1,3 @@ +INSERT INTO todos (id, title, text, todo_type, priority, version, created_at) +VALUES + (13, 'Todo #10', 'Text', 'basic', 'mid', NULL, '2016-06-11 20:10:00.134125-01'); diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 3b90977..6980095 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -1,5 +1,6 @@ from chrononaut.flask_versioning import serialize_datetime, UTC from datetime import datetime +from sqlalchemy import text import pytest import chrononaut @@ -339,3 +340,22 @@ def test_version_fetching_and_diffing(db, session): set(todo.diff(time_0).keys()) == {"text"} set(todo.diff(time_0, include_hidden=True).keys()) == {"text", "done"} assert todo.diff(time_0, include_hidden=True)["done"] == (None, True) + + +def test_null_version(db, session): + """NULL version may be encountered when adding `Versioned` mixin to existing table.""" + sql = text(open("tests/files/seed_null_version.sql", "r").read()) + session.execute(sql) + session.commit() + + todo = db.Todo.query.get(13) + assert todo.versions() == [] + + # Update the Task + todo.title = "Task 0.1" + session.commit() + + # Check old versions + prior_todos = todo.versions() + assert len(prior_todos) == 1 + assert prior_todos[0].version == 1