Files
wizarr/app/__init__.py
Matthieu B 73c29458fe fix: resolve all test failures, linting errors, and type errors
- Fix 55 test failures caused by missing request contexts and incorrect
  session_transaction() usage across 8 test files
- Fix ruff import sorting errors and unused imports
- Fix 122 type errors: rename method override parameters to match base
  classes, add None guards for fetchone()/datetime, widen dict type
  annotations, add type: ignore for SQLAlchemy stub limitations
- Add [tool.ty.rules] config to suppress unsupported-base warnings
- Fix _ variable shadowing gettext in wizard routes
- Add noqa: ARG002 for unused method arguments required by base class
2026-03-29 16:20:23 +02:00

193 lines
6.6 KiB
Python
Raw Permalink 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.
import os
from flask import Flask
from .config import DevelopmentConfig
from .error_handlers import register_error_handlers
from .extensions import init_extensions
from .logging_config import configure_logging
from .middleware import require_onboarding
def create_app(config_object=DevelopmentConfig):
"""Create and configure Flask application with clean startup sequence."""
from .logging_helpers import AppLogger, should_show_startup
# Initialize logger and determine if we should show startup
show_startup = should_show_startup()
logger = AppLogger("wizarr.app")
if show_startup:
logger.welcome(os.getenv("APP_VERSION", "dev"))
logger.start_sequence(total_steps=10)
# Step 1: Configure logging
if show_startup:
logger.step("Configuring logging system", "📝")
configure_logging()
# Step 2: Create Flask application
if show_startup:
logger.step("Creating Flask application", "🌐")
app = Flask(__name__)
app.config.from_object(config_object)
# Step 3: Initialize extensions
if show_startup:
logger.step("Initializing extensions", "🔧")
init_extensions(app)
# Step 4: Register blueprints
if show_startup:
logger.step("Registering blueprints", "🛡️")
from .blueprints import all_blueprints
for bp in all_blueprints:
app.register_blueprint(bp)
# Initialise activity monitoring (blueprint already registered above)
from app.activity import init_app as init_activity
init_activity(app)
# Register activity scheduler tasks if the scheduler is available
try:
from .extensions import scheduler as activity_scheduler
if (
activity_scheduler
and hasattr(activity_scheduler, "scheduler")
and activity_scheduler.scheduler
):
from app.tasks.activity import register_activity_tasks
register_activity_tasks(app, activity_scheduler)
except Exception as exc:
app.logger.warning(f"Failed to register activity tasks: {exc}")
# Step 5: Setup context processors and filters
if show_startup:
logger.step("Configuring request processing", "⚙️")
from .context_processors import inject_plus_features, inject_server_name
app.context_processor(inject_server_name)
app.context_processor(inject_plus_features)
register_error_handlers(app)
# Register custom Jinja filters
from .jinja_filters import register_filters
register_filters(app)
app.before_request(require_onboarding)
# Step 6: Initialize wizard steps
if show_startup:
logger.step("Setting up wizard steps", "🪄")
with app.app_context():
try:
from .services.wizard_seed import import_default_wizard_steps
import_default_wizard_steps()
if show_startup:
logger.success("Wizard steps imported")
except Exception as exc:
# Non-fatal log and continue startup to avoid blocking the app
logger.warning(f"Wizard step bootstrap failed: {exc}")
# Step 7: Run wizard migrations
if show_startup:
logger.step("Running wizard migrations", "🔄")
try:
from .services.wizard_migration import run_wizard_migrations
migration_success = run_wizard_migrations()
if show_startup:
if migration_success:
logger.success("Wizard migrations completed")
else:
logger.warning("Wizard step migrations had issues")
except Exception as exc:
# Non-fatal log and continue startup to avoid blocking the app
logger.warning(f"Wizard step migration failed: {exc}")
# Step 8: Scan libraries for all media servers
# Skip during migrations to avoid database locking issues
skip_library_scan = os.getenv("FLASK_SKIP_SCHEDULER") == "true"
if not skip_library_scan:
if show_startup:
logger.step("Scanning media server libraries", "📚")
try:
from .services.library_scanner import scan_all_server_libraries
total_scanned, _ = scan_all_server_libraries(show_logs=show_startup)
if show_startup:
if total_scanned > 0:
logger.success(f"Scanned {total_scanned} libraries")
else:
logger.info("No media servers configured")
except Exception as exc:
# Non-fatal log and continue startup to avoid blocking the app
if show_startup:
logger.warning(f"Library scanning failed: {exc}")
elif show_startup:
logger.step("Scanning media server libraries", "📚")
logger.info("Skipped during migrations")
# Step 9: Initialize Plus features if enabled
if show_startup:
logger.step("Checking for Plus features", "")
# Check if plus features should be enabled
plus_enabled = os.getenv("WIZARR_PLUS_ENABLED", "false").lower() in (
"true",
"1",
"yes",
)
if plus_enabled:
try:
import plus
plus.enable_plus_features() # type: ignore
with app.app_context():
plus.initialize_plus_features(app) # type: ignore
if show_startup:
logger.success("Plus features enabled")
except ImportError:
if show_startup:
logger.warning("Plus features requested but plus module not found")
except Exception as exc:
if show_startup:
logger.warning(f"Plus features initialization failed: {exc}")
elif show_startup:
logger.info("Plus features disabled")
# Step 10: Show scheduler status and complete startup
if show_startup:
logger.step("Finalizing application setup", "")
# Show scheduler status right in the main startup sequence
from .extensions import scheduler
if scheduler and hasattr(scheduler, "scheduler") and scheduler.scheduler:
if scheduler.running:
dev_mode = os.getenv("WIZARR_ENABLE_SCHEDULER", "false").lower() in (
"true",
"1",
"yes",
)
logger.scheduler_status(enabled=True, dev_mode=dev_mode)
else:
logger.info("Scheduler initialized but not running")
else:
logger.info("Scheduler disabled")
# Complete startup sequence
logger.complete()
return app