Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] unpin flask >= 3.0.0 #89

Open
utnapischtim opened this issue Sep 26, 2024 · 0 comments
Open

[Proposal] unpin flask >= 3.0.0 #89

utnapischtim opened this issue Sep 26, 2024 · 0 comments
Assignees
Labels
Proposal: Pending Proposal for new RFC, pending triage

Comments

@utnapischtim
Copy link

utnapischtim commented Sep 26, 2024

Motivation

remove a lot of deprecation warnings

Summary

migrate to flask>=3.0.0

open discussion points

pytest-invenio

  • Problem
    • the way how pytest-invenio.fixtures creates a db fixture doesn't work anymore. the reason is that flask-sqlalchemy has changed how the get_bind method returns the binding. this means that this has no effect this leads to the problem that in sqlalchemy.Session the should_commit is always true and this means that the transaction will be commited here which is then a problem, because the session.rollback couldn't rollback what is already stored in the database.
    • the new way doesn't work either because it needs this commit because otherwise the transaction parent here of the session.rollback will also be rolledback which removes to much! and the reason why this change doesn't work is because the flask-sqlalchemy.session has no _transaction property.

itsdangerous.jws

https://github.com/lepture/flask-oauthlib

  • Problem:
    • the library is a dependency which is deprecated and should not used anymore
    • but the library has to be updated otherwise we can't migrate to flask>=3.0.0
  • Solution:
    • clone the library to inveniosoftware
    • and fix the open problems (NOTE: done the work locally to make it work locally, but not created any commits or PR without decision how to solve the problem)
  • alternative solution:

unpin various dependencies

  • Problem:
    • to upgrade Flask some other package have to be upgraded too
  • Solution:
    • unpin the packages
    • flask, werkzeug, itsdangerous, wtforms, oauthlib, request-oauthlib, webargs, flask-sqlalchemy, sqlalchemy, sqlalchemy-continuum, sqlalchemy-utils, alembic, flask-alembic
  • alternative solution:
    • don't migrate to flask>=3.0.0

versioned table set to True instead of False invenio-banners

  • Problem:
    • remove SAWarnings like:
      SAWarning: On mapper Mapper[RDMFileRecordMetadataVersion(rdm_records_files_version)], primary key column 'rdm_records_files_version.transaction_id' is being combined with distinct primary key column 'rdm_records_files_version.transaction_id' in attribute 'transaction_id'. Use explicit properties to give each column its own mapped attribute name. (This warning originated from the configure_mappers() process, which was invoked automatically in response to a user-initiated operation.)
      return cls.query_class(
  • Solution:
    • set versioned to True in invenio-banners see commit
  • alternative solutions:
    • stay with SAWarnings
    • find out that the warnings are hiding some other problem
    • find out the real problem (probably time consuming)
  • !!!Solved!!!:

invenio-banners not clear how test could ever worked

invenio-banners stored datetime format

invenio-db

  • Problem:
    • check every commit if it introduces problems
  • Note:
    • tests are green with the invenio-base PR

invenio-vocabularies

PR's

open

inveniosoftware/flask-iiif#102
inveniosoftware/flask-kvsession#8
inveniosoftware/flask-menu#89
inveniosoftware/flask-security-fork#63

inveniosoftware/invenio-access#208
inveniosoftware/invenio-app-rdm#2856
inveniosoftware/invenio-banners#35
inveniosoftware/invenio-base#182
inveniosoftware/invenio-db#174
inveniosoftware/invenio-files-rest#311
inveniosoftware/invenio-github#174
inveniosoftware/invenio-oauth2server#265
inveniosoftware/invenio-oauthclient#336
inveniosoftware/invenio-rest#139

sqlalchemy compatibility PR's which are not included above

inveniosoftware/invenio-records-resources#597
inveniosoftware/invenio-records#326
inveniosoftware/invenio-pidstore#158

already finished and released packages

waiting for release

some more detailed information of the PR's

inveniosoftware/invenio-base#182

since itsdangerous >= 2.1.0 has removed the jws functionality i copy pasted the code into invenio-base to use it as it is. i have removed the deprecation warning from the code. further i added a copyright notice to reference where the code comes from. the open question is: is this enough? the itsdangerous is licensed under BSD-3-Clause license

the license unproblematic way would be to reimplement it with the suggested Authlib but that would take more time

NOTE: i pinned watchdog to ==2.3.1. the newest version has a problem with reloading on http requests which i didn't understand

inveniosoftware/invenio-banners#35

inveniosoftware/invenio-db#174

go through all commits of this PR

unpin deps

forward compatibility with flask,werkzeug >= 3.0.0.

invenio-admin

sqlalchemy changed api

waiting for release

invenio-rdm-records

external libraries which seem out of support

https://github.com/pallets-eco/flask-caching

  • https://github.com/lepture/flask-oauthlib
    • on the github page it states itself that lepture/oauthlib should be used instead, but it doesn't seem a drop in replacement
    • changes: remove upper pin for oauthlib and requests-oauthlib (dependency resolution not possible)
    • use urllib.parse imports instead of the werkzeug.url ones. this would make the invenio_oauth2server._compat obsolet (at least the part with the werkzeug.url overwrites)

SAWarnings which appear if inveniosoftware/invenio-banners@02a2f85 is kept the old way. to be explicit __versioned__ = {"versioning": False} produces following SAWarnings

  • SAWarning: On mapper Mapper[RDMFileRecordMetadataVersion(rdm_records_files_version)], primary key column 'rdm_records_files_version.transaction_id' is being combined with distinct primary key column 'rdm_records_files_version.transaction_id' in attribute 'transaction_id'. Use explicit properties to give each column its own mapped attribute name. (This warning originated from the configure_mappers() process, which was invoked automatically in response to a user-initiated operation.)
    return cls.query_class(

  • SAWarning: relationship 'RDMMediaFileRecordMetadataVersion.transaction' will copy column transaction.id to column rdm_records_media_files_version.transaction_id, which conflicts with relationship(s): 'RDMMediaFileRecordMetadataVersion.transaction' (copies transaction.id to rdm_records_media_files_version.transaction_id). If this is not the intention, consider if these relationships should be linked with back_populates, or if viewonly=True should be applied to one or more if they are read-only. For the less common case that foreign key constraints are partially overlapping, the orm.foreign() annotation can be used to isolate the columns that should be written towards. To silence this warning, add the parameter 'overlaps="transaction"' to the 'RDMMediaFileRecordMetadataVersion.transaction' relationship. (Background on this warning at: https://sqlalche.me/e/20/qzyx) (This warning originated from the configure_mappers() process, which was invoked automatically in response to a user-initiated operation.)
    return cls.query_class(

  • SAWarning: relationship 'PageListVersion.transaction' will copy column transaction.id to column pages_pagelist_version.transaction_id, which conflicts with relationship(s): 'PageListVersion.transaction' (copies transaction.id to pages_pagelist_version.transaction_id). If this is not the intention, consider if these relationships should be linked with back_populates, or if viewonly=True should be applied to one or more if they are read-only. For the less common case that foreign key constraints are partially overlapping, the orm.foreign() annotation can be used to isolate the columns that should be written towards. To silence this warning, add the parameter 'overlaps="transaction"' to the 'PageListVersion.transaction' relationship. (Background on this warning at: https://sqlalche.me/e/20/qzyx) (This warning originated from the configure_mappers() process, which was invoked automatically in response to a user-initiated operation.)
    return cls.query_class(

  • SAWarning: On mapper Mapper[PageModelVersion(pages_page_version)], primary key column 'pages_page_version.transaction_id' is being combined with distinct primary key column 'pages_page_version.transaction_id' in attribute 'transaction_id'. Use explicit properties to give each column its own mapped attribute name. (This warning originated from the configure_mappers() process, which was invoked automatically in response to a user-initiated operation.)
    return cls.query_class(

  • flask_sqlalchemy/model.py:144: SAWarning: This declarative base already contains a class with the same class name and module name as sqlalchemy_continuum.model_builder.RDMRecordMetadataVersion, and will be replaced in the string-lookup table. (multiple of those with different *Version tables)
    super().init(name, bases, d, **kwargs)

additional fixed deprecation warnings after sqlalchemy migration

biggest problem and showstopper. it is solved!

ERROR tests/resources/test_resources.py::test_update_non_existing_banner - sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "uq_accounts_role_name"

or better said the problem with transaction.rollback() not working as expected. it seems that there are some autoflushes somewhere in the code. it seems that session.begin_nested() flushes whats added to the transaction to have a clean savepoint. which is not good because then the transaction.rollback() in the db fixture can't do what it is supposed to do!

i tested with a custom session object:


    connection = database.engine.connect()
    transaction = connection.begin()
    options = dict(
        bind=connection,
        binds={},
        class_=FlaskSqlalchemySession,
        # class_=NoFlushSession,
        query_cls=database.Query,
        join_transaction_mode="control_fully",
        expire_on_commit=False,
        autocommit=False,
        autoflush=False,
        **db_session_options,
    )
    Session = sessionmaker(db=database, **options)
    session = Session(
        bind=connection,
        join_transaction_mode="control_fully",
        expire_on_commit=False,
        autocommit=False,
        autoflush=False,
    )
    old_session = database.session
    database.session = session
    yield database
    session.close()
    transaction.rollback()
    connection.close()
    database.session = old_session

it does not what you think. it doesn't revert the transaction. it seems that the changes commited are written to the database and therefore can't be rollback.

ATTENTION: it seems i fixed that problem with inveniosoftware/pytest-invenio@6f04238 and applied in inveniosoftware/invenio-banners@8da0d89 . ok, since the tests are green now on invenio-banners this change works also with the old pytest-invenio fixture code

@utnapischtim utnapischtim added the Proposal: Pending Proposal for new RFC, pending triage label Sep 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Proposal: Pending Proposal for new RFC, pending triage
Projects
None yet
Development

No branches or pull requests

5 participants