32

I've been learning the flask web application framework and feel quite comfortable with it. I've previously built a simple to do app that worked perfectly. I was working on the same project, but trying to implement it using TDD. I've encountered an error with the database that I've never seen before and don't know how to fix.

When I examine my code, I cant see any issue. It also looks identical to the code of the working project, so I really don't know what I am doing wrong.

Here is the errors:

(env) PS C:\coding-projects\task-master-tdd> flask shell
Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:43:08) [MSC v.1926 32 bit (Intel)] on win32
App: project [development]
Instance: C:\coding-projects\task-master-tdd\instance
>>> from project import db
>>> db
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 1060, in __repr__
    self.engine.url if self.app or current_app else None
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 943, in engine
    return self.get_engine()
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 962, in get_engine
    return connector.get_engine()
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 555, in get_engine
    options = self.get_options(sa_url, echo)
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 570, in get_options
    self._sa.apply_driver_hacks(self._app, sa_url, options)
  File "c:\coding-projects\task-master-tdd\env\lib\site-packages\flask_sqlalchemy\__init__.py", line 914, in apply_driver_hacks
    sa_url.database = os.path.join(app.root_path, sa_url.database)
AttributeError: can't set attribute
>>>

my config.py file:

import os

# load the environment variables from the .env file
from dotenv import load_dotenv
load_dotenv()

# Determine the folder of the top-level directory of this project
BASEDIR = os.path.abspath(os.path.dirname(__file__))


class Config:
    FLASK_ENV = 'development'
    TESTING = False
    DEBUG = False
    SECRET_KEY = os.getenv('SECRET_KEY', default='A very terrible secret key.')
    SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL',
                                        default=f"sqlite:///{os.path.join(BASEDIR, 'instance', 'app.db')}")
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL',
                                        default=f"sqlite:///{os.path.join(BASEDIR, 'instance', 'test.db')}")

class ProductionConfig(Config):
    FLASK_ENV = 'production'

my user model:

from project import db, login_manager
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash

class User(db.Model, UserMixin):
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String, unique=True)
    hashed_password = db.Column(db.String)

    def __init__(self, username, password):
        self.username = username
        self.hashed_password = generate_password_hash(password)

    def is_password_valid(self, password):
        return check_password_hash(self.hashed_password, password)

    def __repr__(self):
        return '<User {}>'.format(self.id)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))
Ilja Everilä
  • 50,538
  • 7
  • 126
  • 127
Ange Uwase
  • 561
  • 4
  • 10
  • I've been working on a project for the past couple days and just encountered this same exact error, even though I haven't modified anything important/relevant. Strangely enough, I'm now encountering the same issue when I create a fresh, totally separate test project which throws me for a bit of a loop. – npburns224 Mar 16 '21 at 08:02
  • 1
    I suddenly have the same problem without changing anything related. Maybe a library dependency was changed? – alexander Mar 16 '21 at 08:39

6 Answers6

44

Edit

If you're experiencing this, upgrading Flask-SQLAlchemy to >= 2.5 should resolve the issue per https://github.com/pallets/flask-sqlalchemy/issues/910#issuecomment-802098285.

Pinning SQLAlchemy to ~1.3 should no longer be necessary.


I ran into this issue a little earlier, but think I've figured out what's going on.

SQLAlchemy is automatically installed as a dependency for Flask-SQLAlchemy and its latest release (1.4.0) introduces the following breaking change:

The URL object is now an immutable named tuple. To modify a URL object, use the URL.set() method to produce a new URL object.

I was able to fix this issue by simply installing the previous version of SQL Alchemy (1.3.23).

SuperShoot
  • 9,880
  • 2
  • 38
  • 55
npburns224
  • 632
  • 7
  • 11
  • 4
    Relevant github issue tracking fixes: https://github.com/pallets/flask-sqlalchemy/issues/910 – SuperShoot Mar 17 '21 at 01:28
  • you save my day – huynq9 Apr 25 '21 at 07:16
  • upgrading Flask-SQLAlchemy to >= 2.5 was the solution. And also adding '''SQLALCHEMY_DATABASE_URI = 'sqlite:///site2.db' #instead of os.environ.get('SQLALCHEMY_DATABASE_URI')''' in the config.py file. What a nightmare! – Corina Roca Dec 16 '21 at 16:13
  • I had version 2.4.4. and it worked fine with the "main" application but not when I was trying to execute (smoke) tests in a docker container => caused that error. Kept whacking may head to wall until found this and tried updating the version. Can't believe how this error manifested only at docker container where it is also annoyingly difficult to debug. > ( – Ville Myrskyneva Jul 14 '22 at 11:18
10

Double check that this issue affects you by running

pip freeze

You should find that the current version of sqlalchemy is 1.4.0. I found the quickest solution for now is to manually revert to a previous version of sqlalchemy:

pip install SQLAlchemy==1.3.23

If you've just reverted to the previous version and it works then now is a great time to pin your versions:

pip freeze > requirements.txt
sterne
  • 645
  • 1
  • 6
  • 15
4

Confirming npburns224's / SuperShoot's answer: Upgrading Flask-SQLAlchemy (and thus its dependency SQLAlchemy) to the latest version did the trick for me.

pip install --upgrade flask-sqlalchemy

I am now running Flask-SQLAlchemy 2.5.1 and SQLAlchemy 1.4.3 successfully.

1

I was able to fix this by pinning my sql-alchemy version to less than 1.4.0. Similar examples are listed above. Below are the steps that I did to solve this until a patch happens.

Freeze your packages

pip freeze > requirements.txt

Update your SQLAlchemy in your requirements.txt

SQLAlchemy<1.4.0

Reinstall the packages

pip install -r requirements.txt

For more information on how to do this refer to the pip documentation: https://pip.pypa.io/en/stable/

gleek
  • 101
  • 1
  • 2
  • Downgrade SQLAlchemy to 1.13.23 should be fine, and upgrade Flask-SQLAlchemy to 2.5.1 will solve the problem as well. – Daliang LYU Mar 22 '21 at 08:30
  • Yes, @DaliangLYU is correct `flask-sqlalchemy` has an update that fixes this issue. https://github.com/pallets/flask-sqlalchemy/releases for more information. – gleek Mar 23 '21 at 21:22
0

Just faced the exact same error. Turns out, I had the wrong Flask-SQLAlchemy library installed. I installed it using conda instead of pip, and conda installed the proper one for my operating system and environment.

conda install Flask-SQLAlchemy
-3

I solved this problem by overriding apply_driver_hacks in the SQLAlchemy class. In this new method I removed this line: sa_url.database = os.path.join(app.root_path, sa_url.database). I copied the rest of the method.

class MySQLAlchemy(SQLAlchemy):
    def apply_driver_hacks(self, app, sa_url, options):
        ...

The method can be found here. The fix I described should only be a temporary one. The problem might be fixed in newer versions of flask-sqlalchemy.

alexander
  • 519
  • 6
  • 17