flask-sqlalchemy
flask-sqlalchemy copied to clipboard
Unable to connect to SQLite database when initialised through app factory in a different package
Flask-SQLAlchemy is unable to connect to the database file if it is initialised through an app factory in a different package. It is able to connect fine if the app factory is in the entrypoint file, but if the app is imported from a package then with app.app_context(): db.create_all() returns the error:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unable to open database file
The following is the full stack trace:
Traceback (most recent call last):
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3280, in _wrap_pool_connect
return fn()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 310, in connect
return _ConnectionFairy._checkout(self)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 868, in _checkout
fairy = _ConnectionRecord.checkout(pool)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 476, in checkout
rec = pool._do_get()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/impl.py", line 256, in _do_get
return self._create_connection()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 256, in _create_connection
return _ConnectionRecord(self)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 371, in __init__
self.__connect()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 665, in __connect
with util.safe_reraise():
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
compat.raise_(
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 661, in __connect
self.dbapi_connection = connection = pool._invoke_creator(self)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/create.py", line 590, in connect
return dialect.connect(*cargs, **cparams)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 597, in connect
return self.dbapi.connect(*cargs, **cparams)
sqlite3.OperationalError: unable to open database file
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/athshean/Git/flask-app/flask/main.py", line 7, in <module>
app = create_app()
File "/home/athshean/Git/flask-app/flask/app/__init__.py", line 20, in create_app
with app.app_context(): db.create_all()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/flask_sqlalchemy/__init__.py", line 1094, in create_all
self._execute_for_all_tables(app, bind, 'create_all')
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/flask_sqlalchemy/__init__.py", line 1086, in _execute_for_all_tables
op(bind=self.get_engine(app, bind), **extra)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/sql/schema.py", line 4888, in create_all
bind._run_ddl_visitor(
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3146, in _run_ddl_visitor
with self.begin() as conn:
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3062, in begin
conn = self.connect(close_with_result=close_with_result)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3234, in connect
return self._connection_cls(self, close_with_result=close_with_result)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 96, in __init__
else engine.raw_connection()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3313, in raw_connection
return self._wrap_pool_connect(self.pool.connect, _connection)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3283, in _wrap_pool_connect
Connection._handle_dbapi_exception_noconnection(
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 2117, in _handle_dbapi_exception_noconnection
util.raise_(
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/base.py", line 3280, in _wrap_pool_connect
return fn()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 310, in connect
return _ConnectionFairy._checkout(self)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 868, in _checkout
fairy = _ConnectionRecord.checkout(pool)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 476, in checkout
rec = pool._do_get()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/impl.py", line 256, in _do_get
return self._create_connection()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 256, in _create_connection
return _ConnectionRecord(self)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 371, in __init__
self.__connect()
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 665, in __connect
with util.safe_reraise():
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py", line 70, in __exit__
compat.raise_(
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/util/compat.py", line 208, in raise_
raise exception
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/pool/base.py", line 661, in __connect
self.dbapi_connection = connection = pool._invoke_creator(self)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/create.py", line 590, in connect
return dialect.connect(*cargs, **cparams)
File "/home/athshean/Git/flask-app/flask/env/lib/python3.10/site-packages/sqlalchemy/engine/default.py", line 597, in connect
return self.dbapi.connect(*cargs, **cparams)
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unable to open database file
To reproduce:
"""main.py"""
from app import create_app
app = create_app()
if __name__=='__main__':
app.run()
"""app/__init__.py"""
from .config import Config
from .db import db
from flask import Flask
def create_app():
app = Flask(__name__)
app.config.from_object(Config())
db.init_app(app)
with app.app_context(): db.create_all()
return app
"""app/config.py"""
import os
from dotenv import load_dotenv
load_dotenv()
from pathlib import Path
class Config(object):
APP_HOST = '0.0.0.0'
DATA = os.getenv('DATA')
SQLALCHEMY_DATABASE_URI = f'sqlite:///{Path(DATA)}/database.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False
"""app/db.py"""
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Expected result: The db.create_all() command should execute as normal.
Environment:
- Python version: 3.10
- Flask-SQLAlchemy version: 2.5.1
- SQLAlchemy version:1.4.37
What's DATA set to? Maybe a relative path?
Hi,
I can reproduce this issue too.
for ex:
Doesn't work with init_app()
from flask import Flask from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() app = Flask(name) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://' db.init_app(app) print(db) <SQLAlchemy engine=None>
It works when instantiated with constructor
from flask import Flask from flask_sqlalchemy import SQLAlchemy
app = Flask(name) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://' db = SQLAlchemy(app) print(db) <SQLAlchemy engine=mysql+pymysql://>
In the current version, a relative path is relative to the Flask application root. When version 3 is released, it will be relative to the instance path. A relative path in a connection string has three slashes. If you need to specify an absolute path, it should start with four slashes. Beyond that, this is something you'll need to debug in your code, it's not something that Flask-SQLAlchemy is affecting.