Source code for duck.setup

"""
Module for setting up Duck space and configure all necessary components to ensure the application is ready for operation.
"""

import os
import sys
import asyncio
import platform
import threading

from typing import List

from duck.exceptions.all import SettingsError
from duck.routes import register_blueprints, register_urlpatterns
from duck.logging import logger
from duck.settings import SETTINGS
from duck.settings.loaded import SettingsLoaded
from duck.html.components.core.system import LivelyComponentSystem
from duck.env import is_testing_environment


[docs] def makedirs(): """ Initial function for Duck application directories creation. """ # TEMPLATE_DIRS setup tdirs = str(SETTINGS["TEMPLATE_DIRS"]) if isinstance(tdirs, (list)): for tdir in tdirs: os.makedirs(tdir, exist_ok=True) # STATIC_ROOT setup sroot = SETTINGS["STATIC_ROOT"] if os.path.isfile(sroot): raise SettingsError( "STATIC_ROOT in settings.py should be a directory not a file") if sroot and not os.path.isdir(sroot): os.makedirs(sroot, exist_ok=True) # SESSION_DIR setup sdir = SETTINGS["SESSION_DIR"] if os.path.isfile(sdir): raise SettingsError( "SESSION_DIR in settings.py should be a directory not a file") if sdir and not os.path.isdir(sdir): os.makedirs(sdir, exist_ok=True) # STATIC_ROOT setup sroot = SETTINGS["STATIC_ROOT"] if os.path.isfile(sroot): raise SettingsError( "STATIC_ROOT in settings.py should be a directory not a file") if sroot and not os.path.isdir(sroot): os.makedirs(sroot, exist_ok=True) # MEDIA_ROOT setup mroot = SETTINGS["MEDIA_ROOT"] if os.path.isfile(mroot): raise SettingsError( "MEDIA_ROOT in settings.py should be a directory not a file") if mroot and not os.path.isdir(mroot): os.makedirs(mroot, exist_ok=True) # FILE_UPLOAD_DIR setup fdir = SETTINGS["FILE_UPLOAD_DIR"] if os.path.isfile(fdir): raise SettingsError( "FILE_UPLOAD_DIR in settings.py should be a directory not a file") if fdir and not os.path.isdir(fdir): os.makedirs(fdir, exist_ok=True) # LOGGING_DIR setup ldir = SETTINGS["LOGGING_DIR"] if os.path.isfile(ldir): raise SettingsError( "LOGGING_DIR in settings.py should be a directory not a file") if ldir and not os.path.isdir(ldir): os.makedirs(ldir, exist_ok=True)
[docs] def set_asyncio_loop(): """ Configure the event loop policy based on SETTINGS["ASYNC_LOOP"]. Supports: - "asyncio": Default Python event loop (no changes made) - "uvloop": High-performance event loop (requires uvloop installed) Raises: SettingsError: If the specified ASYNC_LOOP value is unsupported. """ supported_loops = {"asyncio", "uvloop"} loop_choice = SETTINGS.get("ASYNC_LOOP", "asyncio") # Only configure the loop if async handling is enabled or HTTP/2 is used if SETTINGS.get("ASYNC_HANDLING") or SETTINGS.get("SUPPORT_HTTP_2"): if loop_choice not in supported_loops: raise SettingsError( f"Invalid ASYNC_LOOP setting: '{loop_choice}'. " f"Supported options are: {sorted(supported_loops)}." ) if loop_choice == "uvloop": current_platform = platform.system() or "" if current_platform.lower() == "windows": # There are some community/experimental efforts for Windows but they are # not reliable across all uvloop releases. Provide a clear message. raise SettingsError( "uvloop is generally not supported on Windows in official releases. " "Set ASYNC_LOOP to 'asyncio' or run on a Unix-like OS (Linux, macOS)." ) try: import uvloop except ImportError as e: raise SettingsError("uvloop is not installed, but ASYNC_LOOP is set to 'uvloop'.") from e asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
[docs] def setup(make_app_dirs: bool = True, use_threads_for_heavy_work: bool = True): """ Setup the Duck application. Initialize and configure all necessary components to ensure the application is ready for operation. Args: make_app_dirs (bool): Whether to create application directories which might be useful to the project. Notes: - This configures and registers all routes either simple or ones created """ # Improve the setup it's taking approx >= 2s from duck.backend.django.setup import prepare_django, DjangoSetupWarning base_dir = str(SETTINGS['BASE_DIR']) # Set asyncio event loop for ASYNC_HANDLING or HTTP/2 set_asyncio_loop() # Create base application (directories if make_app_dirs: # Only make app dirs if not in testing environment if not is_testing_environment(): if use_threads_for_heavy_work: threading.Thread(target=makedirs).start() # app dirs creation else: makedirs() # Try preparing Django backend try: prepare_django(True) except Exception as e: logger.warn(f"Django setup failed: {e}", DjangoSetupWarning) if SETTINGS['DEBUG']: logger.log_exception(e) # Register some urlpatterns register_urlpatterns(SettingsLoaded.URLPATTERNS) register_blueprints(SettingsLoaded.BLUEPRINTS) # Register Lively component system urlpattern if LivelyComponentSystem.is_active(): lively_urlpatterns = LivelyComponentSystem.get_urlpatterns() register_urlpatterns(lively_urlpatterns) # register lively component system urlpatterns. if base_dir not in sys.path: # Add project directory to path sys.path.insert(-1, base_dir)