diff --git a/CHANGES.rst b/CHANGES.rst index 996fe3f3..724c5848 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,9 @@ +Version 3.1.2 +------------- + +- Fix issue with calling ``repr()`` on ``SQLAlchemy`` instance with no default engine. :issue:`1295` + + Version 3.1.1 ------------- diff --git a/src/flask_sqlalchemy/extension.py b/src/flask_sqlalchemy/extension.py index 43e1b9a4..3429e059 100644 --- a/src/flask_sqlalchemy/extension.py +++ b/src/flask_sqlalchemy/extension.py @@ -281,12 +281,14 @@ def __repr__(self) -> str: if not has_app_context(): return f"<{type(self).__name__}>" - message = f"{type(self).__name__} {self.engine.url}" + num_default_engines = 1 if self.engines.get(None) else 0 + engine_str = self.engine.url if num_default_engines else "(No default engine)" - if len(self.engines) > 1: - message = f"{message} +{len(self.engines) - 1}" + num_other_engines = len(self.engines) - num_default_engines + if num_other_engines >= 1: + engine_str = f"{engine_str} +{num_other_engines} engines" - return f"<{message}>" + return f"<{type(self).__name__} {engine_str}>" def init_app(self, app: Flask) -> None: """Initialize a Flask application for use with this extension instance. This diff --git a/tests/test_extension_repr.py b/tests/test_extension_repr.py new file mode 100644 index 00000000..cfa94c75 --- /dev/null +++ b/tests/test_extension_repr.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from flask import Flask + +from flask_sqlalchemy import SQLAlchemy + + +def test_repr_no_context() -> None: + db = SQLAlchemy() + app = Flask(__name__) + app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://" + + db.init_app(app) + assert repr(db) == "" + + +def test_repr_default() -> None: + db = SQLAlchemy() + app = Flask(__name__) + app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://" + + db.init_app(app) + with app.app_context(): + assert repr(db) == "" + + +def test_repr_default_plustwo() -> None: + db = SQLAlchemy() + app = Flask(__name__) + app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://" + app.config["SQLALCHEMY_BINDS"] = { + "a": "sqlite:///:memory:", + "b": "sqlite:///test.db", + } + + db.init_app(app) + with app.app_context(): + assert repr(db) == "" + + +def test_repr_nodefault() -> None: + db = SQLAlchemy() + app = Flask(__name__) + app.config["SQLALCHEMY_BINDS"] = {"x": "sqlite:///:memory:"} + + db.init_app(app) + with app.app_context(): + assert repr(db) == "" + + +def test_repr_nodefault_plustwo() -> None: + db = SQLAlchemy() + app = Flask(__name__) + app.config["SQLALCHEMY_BINDS"] = { + "a": "sqlite:///:memory:", + "b": "sqlite:///test.db", + } + + db.init_app(app) + with app.app_context(): + assert repr(db) == ""