Files
natureinpots_community/app/__init__.py
2025-06-04 23:24:16 -05:00

108 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# app/__init__.py
import os
import json
import glob
import importlib.util
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_wtf.csrf import CSRFProtect
from dotenv import load_dotenv
load_dotenv()
# ----------------------------------------------------------------
# 1) Initialize core extensions
# ----------------------------------------------------------------
db = SQLAlchemy()
migrate = Migrate()
login_manager = LoginManager()
csrf = CSRFProtect()
def create_app():
app = Flask(__name__)
app.config.from_object('app.config.Config')
# Initialize extensions with app
csrf.init_app(app)
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
login_manager.login_view = 'auth.login'
# ----------------------------------------------------------------
# 2) Register error handlers
# ----------------------------------------------------------------
from .errors import bp as errors_bp
app.register_blueprint(errors_bp)
# ----------------------------------------------------------------
# 3) Auto-load each plugins models.py so that SQLAlchemy metadata
# knows about every table (Plant, PlantOwnershipLog, PlantUpdate, etc.)
# ----------------------------------------------------------------
plugin_model_paths = glob.glob(os.path.join(os.path.dirname(__file__), '..', 'plugins', '*', 'models.py'))
for path in plugin_model_paths:
module_name = path.replace("/", ".").replace(".py", "")
try:
spec = importlib.util.spec_from_file_location(module_name, path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
print(f"✅ (Startup) Loaded: {module_name}")
except Exception as e:
print(f"❌ (Startup) Failed to load {module_name}: {e}")
# ----------------------------------------------------------------
# 4) Auto-discover & register each plugins routes.py and CLI
# ----------------------------------------------------------------
plugin_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'plugins'))
for plugin in os.listdir(plugin_path):
if plugin.endswith('.noload'):
print(f"[⏭] Skipping plugin '{plugin}' (marked as .noload)")
continue
plugin_dir = os.path.join(plugin_path, plugin)
if not os.path.isdir(plugin_dir):
continue
# --- (a) Register routes blueprint if present ---
route_file = os.path.join(plugin_dir, 'routes.py')
if os.path.isfile(route_file):
try:
spec = importlib.util.spec_from_file_location(f"plugins.{plugin}.routes", route_file)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
if hasattr(mod, 'bp'):
app.register_blueprint(mod.bp, strict_slashes=False)
print(f"✔️ Registered routes for plugin '{plugin}'")
except Exception as e:
print(f"❌ Failed to load routes from plugin '{plugin}': {e}")
# --- (b) Register CLI & entry point if present ---
init_file = os.path.join(plugin_dir, '__init__.py')
plugin_json = os.path.join(plugin_dir, 'plugin.json')
if os.path.isfile(init_file):
try:
cli_module = importlib.import_module(f"plugins.{plugin}")
if hasattr(cli_module, 'register_cli'):
cli_module.register_cli(app)
print(f"✔️ Registered CLI for plugin '{plugin}'")
if os.path.isfile(plugin_json):
with open(plugin_json, 'r') as f:
meta = json.load(f)
entry = meta.get('entry_point')
if entry and hasattr(cli_module, entry):
getattr(cli_module, entry)(app)
print(f"✔️ Ran entry point '{entry}' for plugin '{plugin}'")
except Exception as e:
print(f"❌ Failed to load CLI for plugin '{plugin}': {e}")
@app.context_processor
def inject_current_year():
from datetime import datetime
return {'current_year': datetime.now().year}
return app