From d32e4ba58b59c65d81db553998883dd5fd3501f1 Mon Sep 17 00:00:00 2001 From: yiekheng Date: Sat, 2 May 2026 17:37:13 +0800 Subject: [PATCH] feat(api): add create_app factory for gunicorn entrypoint --- app/cm_api.py | 11 +++++++++++ tests/test_bot_cli.py | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/app/cm_api.py b/app/cm_api.py index bc2eb44..565cd1f 100644 --- a/app/cm_api.py +++ b/app/cm_api.py @@ -199,6 +199,17 @@ class CM_API: return thread +def create_app(): + """WSGI factory used by gunicorn (`app.cm_api:create_app()`). + + Returns the Flask app object so gunicorn can serve it. The + surrounding CM_API class still owns route registration and DB + connection management — this just hands gunicorn the underlying + Flask instance. + """ + return CM_API().app + + if __name__ == '__main__': api = CM_API() api.run(port = 3000) diff --git a/tests/test_bot_cli.py b/tests/test_bot_cli.py index da99b73..baa8d5c 100644 --- a/tests/test_bot_cli.py +++ b/tests/test_bot_cli.py @@ -289,5 +289,24 @@ class CmdInteractiveTests(unittest.TestCase): self.assertIn("CM Bot CLI", out.getvalue()) +class CreateAppFactoryTests(unittest.TestCase): + """The gunicorn entrypoint loads `app.cm_api:create_app()`. The factory + must exist as a module-level callable that returns the Flask app + object — not the CM_API wrapper class.""" + + def test_create_app_returns_flask_instance(self): + from flask import Flask + from app.cm_api import create_app + + wsgi = create_app() + self.assertIsInstance(wsgi, Flask) + + def test_create_app_registers_acc_route(self): + from app.cm_api import create_app + wsgi = create_app() + rules = {r.rule for r in wsgi.url_map.iter_rules()} + self.assertIn("/acc/", rules) + + if __name__ == "__main__": unittest.main()