flask-sqlalchemy icon indicating copy to clipboard operation
flask-sqlalchemy copied to clipboard

Unable to connect to SQLite database when initialised through app factory in a different package

Open athshean opened this issue 3 years ago • 2 comments

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

athshean avatar Jun 11 '22 16:06 athshean

What's DATA set to? Maybe a relative path?

ThiefMaster avatar Jun 11 '22 16:06 ThiefMaster

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://>

Sudhakargen avatar Aug 04 '22 08:08 Sudhakargen

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.

davidism avatar Sep 18 '22 17:09 davidism