Skip to content

Application Layer

Application orchestration components: main window, app services, and bootstrap flow.


EzQt_App

EzQt_App

EzQt_App(theme_file_name: str | None = None, **kwargs: Any)

Bases: QMainWindow

Main EzQt_App application.

This class represents the main application window with all its components (menu, pages, settings, etc.).

Initialize the EzQt_App application.

PARAMETER DESCRIPTION
theme_file_name

Deprecated — no longer used. All .qss files placed under bin/themes/ are now loaded automatically. Passing a value emits a deprecation warning.

TYPE: str | None DEFAULT: None

**kwargs

Backward compatibility for legacy arguments (e.g., themeFileName).

TYPE: Any DEFAULT: {}

Source code in src/ezqt_app/app.py
def __init__(
    self,
    theme_file_name: str | None = None,
    **kwargs: Any,
) -> None:
    """
    Initialize the EzQt_App application.

    Args:
        theme_file_name: Deprecated — no longer used.  All ``.qss`` files
            placed under ``bin/themes/`` are now loaded automatically.
            Passing a value emits a deprecation warning.
        **kwargs: Backward compatibility for legacy arguments (e.g., themeFileName).
    """
    QMainWindow.__init__(self)
    self._has_menu: bool = True
    self._has_settings_panel: bool = True
    self._ui_initialized: bool = False

    # Deprecation: theme_file_name is no longer used
    if theme_file_name is not None:
        warn_tech(
            code="app.deprecated_arg.theme_file_name",
            message=(
                "Argument 'theme_file_name' is deprecated and has no effect. "
                "Place your .qss files in bin/themes/ — they are loaded automatically."
            ),
        )

    # Handle backward compatibility
    if "themeFileName" in kwargs:
        warn_tech(
            code="app.legacy_arg",
            message="Argument 'themeFileName' is deprecated. Use 'theme_file_name' instead.",
        )
        kwargs.pop("themeFileName")

    # Load resources and settings
    AppService.load_fonts_resources()
    AppService.load_app_settings()

    self._config_service = get_config_service()

no_menu

no_menu() -> EzQt_App

Disable the left menu for this application instance.

RETURNS DESCRIPTION
EzQt_App

Self instance for chaining.

TYPE: EzQt_App

Source code in src/ezqt_app/app.py
def no_menu(self) -> EzQt_App:
    """
    Disable the left menu for this application instance.

    Returns:
        EzQt_App: Self instance for chaining.
    """
    self._has_menu = False
    return self

no_settings_panel

no_settings_panel() -> EzQt_App

Disable the settings slide-in panel for this application instance.

RETURNS DESCRIPTION
EzQt_App

Self instance for chaining.

TYPE: EzQt_App

Source code in src/ezqt_app/app.py
def no_settings_panel(self) -> EzQt_App:
    """
    Disable the settings slide-in panel for this application instance.

    Returns:
        EzQt_App: Self instance for chaining.
    """
    self._has_settings_panel = False
    return self

build

build() -> EzQt_App

Explicitly build the UI layout.

Automatically called on first show() if not called.

RETURNS DESCRIPTION
EzQt_App

Self instance for chaining.

TYPE: EzQt_App

Source code in src/ezqt_app/app.py
def build(self) -> EzQt_App:
    """
    Explicitly build the UI layout.

    Automatically called on first show() if not called.

    Returns:
        EzQt_App: Self instance for chaining.
    """
    if not self._ui_initialized:
        self._build_ui()
    return self

showEvent

showEvent(event: QShowEvent) -> None

Ensure UI is built before showing the window.

PARAMETER DESCRIPTION
event

The QShowEvent instance.

TYPE: QShowEvent

Source code in src/ezqt_app/app.py
def showEvent(self, event: QShowEvent) -> None:
    """
    Ensure UI is built before showing the window.

    Args:
        event: The QShowEvent instance.
    """
    if not self._ui_initialized:
        self._build_ui()
    super().showEvent(event)

set_app_theme

set_app_theme() -> None

Update and apply the application theme based on current settings.

The theme was already persisted and applied to SettingsService by _on_theme_selector_changed before this slot fires. We only need to trigger a full UI refresh here.

Source code in src/ezqt_app/app.py
def set_app_theme(self) -> None:
    """Update and apply the application theme based on current settings.

    The theme was already persisted and applied to ``SettingsService`` by
    ``_on_theme_selector_changed`` before this slot fires.  We only need to
    trigger a full UI refresh here.
    """
    self.build()
    self.update_ui()

update_ui

update_ui() -> None

Force a full UI refresh including themes, icons, and styles.

Source code in src/ezqt_app/app.py
def update_ui(self) -> None:
    """Force a full UI refresh including themes, icons, and styles."""
    self.build()
    ThemeService.apply_theme(self._as_window())
    ez_app = EzApplication.instance()
    if isinstance(ez_app, EzApplication):
        ez_app.themeChanged.emit()
    self.ui.header_container.update_all_theme_icons()
    self.ui.menu_container.update_all_theme_icons()
    self.ui.settings_panel.update_all_theme_icons()

    QApplication.processEvents()
    app_instance = QApplication.instance()
    if isinstance(app_instance, QApplication):
        for widget in app_instance.allWidgets():
            widget.style().unpolish(widget)
            widget.style().polish(widget)

refresh_theme

refresh_theme() -> EzQt_App

Re-apply the theme stylesheet and polish all widgets.

Call this after adding custom widgets to the application to ensure that QSS rules (especially #objectName selectors) are correctly evaluated against the newly added widgets. Also refreshes all ThemeIcon instances so that icons added after build() (e.g. via add_menu()) are correctly coloured for the current theme.

RETURNS DESCRIPTION
self

Allows method chaining.

TYPE: EzQt_App

Example::

window = EzQt_App().build()
window.show()
add_things_to_my_app(window, Icons)
window.refresh_theme()
Source code in src/ezqt_app/app.py
def refresh_theme(self) -> EzQt_App:
    """Re-apply the theme stylesheet and polish all widgets.

    Call this after adding custom widgets to the application to ensure
    that QSS rules (especially ``#objectName`` selectors) are correctly
    evaluated against the newly added widgets.  Also refreshes all
    ``ThemeIcon`` instances so that icons added after ``build()`` (e.g.
    via ``add_menu()``) are correctly coloured for the current theme.

    Returns:
        self: Allows method chaining.

    Example::

        window = EzQt_App().build()
        window.show()
        add_things_to_my_app(window, Icons)
        window.refresh_theme()
    """
    ThemeService.apply_theme(self._as_window())
    self.ui.header_container.update_all_theme_icons()
    self.ui.menu_container.update_all_theme_icons()
    self.ui.settings_panel.update_all_theme_icons()
    app_instance = QApplication.instance()
    if isinstance(app_instance, QApplication):
        for widget in app_instance.allWidgets():
            widget.style().unpolish(widget)
            widget.style().polish(widget)
    return self

set_app_icon

set_app_icon(icon: str | QPixmap, y_shrink: int = 0, y_offset: int = 0) -> None

Set the application logo in the header.

PARAMETER DESCRIPTION
icon

Path to icon or QPixmap object.

TYPE: str | QPixmap

y_shrink

Vertical shrink factor.

TYPE: int DEFAULT: 0

y_offset

Vertical offset adjustment.

TYPE: int DEFAULT: 0

Source code in src/ezqt_app/app.py
def set_app_icon(
    self, icon: str | QPixmap, y_shrink: int = 0, y_offset: int = 0
) -> None:
    """
    Set the application logo in the header.

    Args:
        icon: Path to icon or QPixmap object.
        y_shrink: Vertical shrink factor.
        y_offset: Vertical offset adjustment.
    """
    self.build()
    return self.ui.header_container.set_app_logo(
        logo=icon, y_shrink=y_shrink, y_offset=y_offset
    )

add_menu

add_menu(name: str, icon: str) -> QWidget

Add a new menu item and corresponding page.

PARAMETER DESCRIPTION
name

Label for the menu and page.

TYPE: str

icon

Icon name or path.

TYPE: str

RETURNS DESCRIPTION
QWidget

The created page widget.

TYPE: QWidget

Source code in src/ezqt_app/app.py
def add_menu(self, name: str, icon: str) -> QWidget:
    """
    Add a new menu item and corresponding page.

    Args:
        name: Label for the menu and page.
        icon: Icon name or path.

    Returns:
        QWidget: The created page widget.
    """
    self.build()
    page = self.ui.pages_container.add_page(name)
    menu = self.ui.menu_container.add_menu(name, icon)
    menu.setProperty("page", page)
    if len(self.ui.menu_container.menus) == 1:
        menu.setProperty("class", "active")
    menu.clicked.connect(lambda: self.ui.pages_container.set_current_widget(page))
    menu.clicked.connect(self.switch_menu)

    return page

switch_menu

switch_menu() -> None

Update active state of menu buttons based on sender.

Source code in src/ezqt_app/app.py
def switch_menu(self) -> None:
    """Update active state of menu buttons based on sender."""
    sender = self.sender()
    if not sender:
        return
    senderName = sender.objectName()

    for btnName, _ in self.ui.menu_container.menus.items():
        if senderName == f"menu_{btnName}":
            MenuService.deselect_menu(self._as_window(), senderName)
            MenuService.select_menu(self._as_window(), senderName)

resizeEvent

resizeEvent(_event: QResizeEvent) -> None

Handle window resize events to update UI components.

PARAMETER DESCRIPTION
_event

The QResizeEvent instance (unused).

TYPE: QResizeEvent

Source code in src/ezqt_app/app.py
def resizeEvent(self, _event: QResizeEvent) -> None:
    """
    Handle window resize events to update UI components.

    Args:
        _event: The QResizeEvent instance (unused).
    """
    if self._ui_initialized:
        UiDefinitionsService.resize_grips(self._as_window())

mousePressEvent

mousePressEvent(event: QMouseEvent) -> None

Handle mouse press events for window dragging and diagnostics.

PARAMETER DESCRIPTION
event

The QMouseEvent instance.

TYPE: QMouseEvent

Source code in src/ezqt_app/app.py
def mousePressEvent(self, event: QMouseEvent) -> None:
    """
    Handle mouse press events for window dragging and diagnostics.

    Args:
        event: The QMouseEvent instance.
    """
    if not self._ui_initialized:
        return
    self.dragPos = event.globalPosition().toPoint()
    if IS_DEV:
        child_widget = self.childAt(event.position().toPoint())
        if child_widget:
            child_name = child_widget.objectName()
            get_printer().verbose_msg(f"Mouse click on widget: {child_name}")
        elif event.buttons() == Qt.MouseButton.LeftButton:
            get_printer().verbose_msg("Mouse click: LEFT CLICK")
        elif event.buttons() == Qt.MouseButton.RightButton:
            get_printer().verbose_msg("Mouse click: RIGHT CLICK")

set_credits

set_credits(credits: Any) -> None

Set credit text in the bottom bar.

PARAMETER DESCRIPTION
credits

Text or object to display as credits.

TYPE: Any

Source code in src/ezqt_app/app.py
def set_credits(self, credits: Any) -> None:
    """
    Set credit text in the bottom bar.

    Args:
        credits: Text or object to display as credits.
    """
    if hasattr(self.ui, "bottom_bar") and self.ui.bottom_bar:
        self.ui.bottom_bar.set_credits(credits)

set_version

set_version(version: str) -> None

Set version text in the bottom bar.

PARAMETER DESCRIPTION
version

Version string to display.

TYPE: str

Source code in src/ezqt_app/app.py
def set_version(self, version: str) -> None:
    """
    Set version text in the bottom bar.

    Args:
        version: Version string to display.
    """
    if hasattr(self.ui, "bottom_bar") and self.ui.bottom_bar:
        self.ui.bottom_bar.set_version(version)

get_translation_stats

get_translation_stats() -> dict[str, Any]

Retrieve current translation statistics.

RETURNS DESCRIPTION
dict

Statistics about translated and missing strings.

TYPE: dict[str, Any]

Source code in src/ezqt_app/app.py
def get_translation_stats(self) -> dict[str, Any]:
    """
    Retrieve current translation statistics.

    Returns:
        dict: Statistics about translated and missing strings.
    """
    from .services.translation import get_translation_stats

    return get_translation_stats()

enable_auto_translation

enable_auto_translation(enabled: bool = True) -> None

Enable or disable automatic translation collection.

PARAMETER DESCRIPTION
enabled

Whether to enable auto-translation.

TYPE: bool DEFAULT: True

Source code in src/ezqt_app/app.py
def enable_auto_translation(self, enabled: bool = True) -> None:
    """
    Enable or disable automatic translation collection.

    Args:
        enabled: Whether to enable auto-translation.
    """
    from .services.translation import enable_auto_translation

    enable_auto_translation(enabled)

clear_translation_cache

clear_translation_cache() -> None

Clear the automatic translation cache.

Source code in src/ezqt_app/app.py
def clear_translation_cache(self) -> None:
    """Clear the automatic translation cache."""
    from .services.translation import clear_auto_translation_cache

    clear_auto_translation_cache()

collect_strings_for_translation

collect_strings_for_translation(widget: QWidget | None = None, recursive: bool = True) -> dict[str, Any]

Scan widgets for translatable strings and add them to the collector.

PARAMETER DESCRIPTION
widget

Root widget to start scanning from (default: self).

TYPE: QWidget | None DEFAULT: None

recursive

Whether to scan child widgets recursively.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
dict

Summary of the collection process.

TYPE: dict[str, Any]

Source code in src/ezqt_app/app.py
def collect_strings_for_translation(
    self, widget: QWidget | None = None, recursive: bool = True
) -> dict[str, Any]:
    """
    Scan widgets for translatable strings and add them to the collector.

    Args:
        widget: Root widget to start scanning from (default: self).
        recursive: Whether to scan child widgets recursively.

    Returns:
        dict: Summary of the collection process.
    """
    from .services.translation import collect_and_compare_strings

    if widget is None:
        widget = self
    return collect_and_compare_strings(widget, recursive)

get_new_strings

get_new_strings() -> set[str]

Get all newly discovered strings since last save.

RETURNS DESCRIPTION
set[str]

set[str]: Set of new translatable strings.

Source code in src/ezqt_app/app.py
def get_new_strings(self) -> set[str]:
    """
    Get all newly discovered strings since last save.

    Returns:
        set[str]: Set of new translatable strings.
    """
    from .services.translation import get_new_strings

    return get_new_strings()

get_string_collector_stats

get_string_collector_stats() -> dict[str, Any]

Get statistics from the string collector.

RETURNS DESCRIPTION
dict

Collector statistics.

TYPE: dict[str, Any]

Source code in src/ezqt_app/app.py
def get_string_collector_stats(self) -> dict[str, Any]:
    """
    Get statistics from the string collector.

    Returns:
        dict: Collector statistics.
    """
    from .services.translation import get_string_collector_stats

    return get_string_collector_stats()

setAppTheme

setAppTheme() -> None

Deprecated alias for set_app_theme. .. deprecated:: 1.0.0

Source code in src/ezqt_app/app.py
def setAppTheme(self) -> None:
    """
    Deprecated alias for set_app_theme.
    .. deprecated:: 1.0.0
    """
    warn_tech(
        code="app.legacy_method",
        message="Method 'setAppTheme' is deprecated. Use 'set_app_theme' instead.",
    )
    self.set_app_theme()

updateUI

updateUI() -> None

Deprecated alias for update_ui. .. deprecated:: 1.0.0

Source code in src/ezqt_app/app.py
def updateUI(self) -> None:
    """
    Deprecated alias for update_ui.
    .. deprecated:: 1.0.0
    """
    warn_tech(
        code="app.legacy_method",
        message="Method 'updateUI' is deprecated. Use 'update_ui' instead.",
    )
    self.update_ui()

setAppIcon

setAppIcon(logo: str | QPixmap, y_shrink: int = 0, y_offset: int = 0) -> None

Deprecated alias for set_app_icon. .. deprecated:: 1.0.0

Source code in src/ezqt_app/app.py
def setAppIcon(
    self, logo: str | QPixmap, y_shrink: int = 0, y_offset: int = 0
) -> None:
    """
    Deprecated alias for set_app_icon.
    .. deprecated:: 1.0.0
    """
    warn_tech(
        code="app.legacy_method",
        message="Method 'setAppIcon' is deprecated. Use 'set_app_icon' instead.",
    )
    self.set_app_icon(logo, y_shrink, y_offset)

addMenu

addMenu(name: str, icon: str) -> QWidget

Deprecated alias for add_menu. .. deprecated:: 1.0.0

Source code in src/ezqt_app/app.py
def addMenu(self, name: str, icon: str) -> QWidget:
    """
    Deprecated alias for add_menu.
    .. deprecated:: 1.0.0
    """
    warn_tech(
        code="app.legacy_method",
        message="Method 'addMenu' is deprecated. Use 'add_menu' instead.",
    )
    return self.add_menu(name, icon)

switchMenu

switchMenu() -> None

Deprecated alias for switch_menu. .. deprecated:: 1.0.0

Source code in src/ezqt_app/app.py
def switchMenu(self) -> None:
    """
    Deprecated alias for switch_menu.
    .. deprecated:: 1.0.0
    """
    warn_tech(
        code="app.legacy_method",
        message="Method 'switchMenu' is deprecated. Use 'switch_menu' instead.",
    )
    self.switch_menu()

AppService

AppService

Central orchestration service for application lifecycle.

Aggregates config, asset, resource and settings operations into a single cohesive snake_case API used by widgets, CLI and bootstrap.

check_assets_requirements staticmethod

check_assets_requirements(base_path: Path | None = None, bin_path: Path | None = None, overwrite_policy: str = 'ask') -> None

Generate asset binaries, QRC and RC files at APP_PATH.

PARAMETER DESCRIPTION
base_path

Optional base path for assets.

TYPE: Path | None DEFAULT: None

bin_path

Optional binary path.

TYPE: Path | None DEFAULT: None

overwrite_policy

Policy for overwriting existing files (default: "ask").

TYPE: str DEFAULT: 'ask'

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def check_assets_requirements(
    base_path: Path | None = None,
    bin_path: Path | None = None,
    overwrite_policy: str = "ask",
) -> None:
    """
    Generate asset binaries, QRC and RC files at APP_PATH.

    Args:
        base_path: Optional base path for assets.
        bin_path: Optional binary path.
        overwrite_policy: Policy for overwriting existing files (default: "ask").
    """
    AssetsService.check_assets_requirements(
        base_path=base_path,
        bin_path=bin_path,
        overwrite_policy=overwrite_policy,
    )

make_required_files staticmethod

make_required_files(mk_theme: bool = True, mk_config: bool = True, mk_translations: bool = True, base_path: Path | None = None, bin_path: Path | None = None, overwrite_policy: str = 'ask') -> None

Copy YAML, QSS theme and translation files into project directories.

PARAMETER DESCRIPTION
mk_theme

When True also copies the QSS theme file.

TYPE: bool DEFAULT: True

mk_config

When True copies configuration files.

TYPE: bool DEFAULT: True

mk_translations

When True copies translation files.

TYPE: bool DEFAULT: True

base_path

Optional base path.

TYPE: Path | None DEFAULT: None

bin_path

Optional binary path.

TYPE: Path | None DEFAULT: None

overwrite_policy

Policy for overwriting (default: "ask").

TYPE: str DEFAULT: 'ask'

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def make_required_files(
    mk_theme: bool = True,
    mk_config: bool = True,
    mk_translations: bool = True,
    base_path: Path | None = None,
    bin_path: Path | None = None,
    overwrite_policy: str = "ask",
) -> None:
    """
    Copy YAML, QSS theme and translation files into project directories.

    Args:
        mk_theme: When True also copies the QSS theme file.
        mk_config: When True copies configuration files.
        mk_translations: When True copies translation files.
        base_path: Optional base path.
        bin_path: Optional binary path.
        overwrite_policy: Policy for overwriting (default: "ask").
    """
    AssetsService.make_required_files(
        mk_theme=mk_theme,
        mk_config=mk_config,
        mk_translations=mk_translations,
        base_path=base_path,
        bin_path=bin_path,
        overwrite_policy=overwrite_policy,
    )

set_project_root staticmethod

set_project_root(project_root: Path) -> None

Set the project root directory used by the config service.

PARAMETER DESCRIPTION
project_root

The Path to the project root.

TYPE: Path

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def set_project_root(project_root: Path) -> None:
    """
    Set the project root directory used by the config service.

    Args:
        project_root: The Path to the project root.
    """
    get_config_service().set_project_root(project_root)

load_config staticmethod

load_config(config_name: str) -> dict[str, Any]

Load a named configuration from its YAML file.

PARAMETER DESCRIPTION
config_name

Logical name of the configuration (e.g. "app").

TYPE: str

RETURNS DESCRIPTION
dict

The loaded configuration data.

TYPE: dict[str, Any]

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def load_config(config_name: str) -> dict[str, Any]:
    """
    Load a named configuration from its YAML file.

    Args:
        config_name: Logical name of the configuration (e.g. "app").

    Returns:
        dict: The loaded configuration data.
    """
    return get_config_service().load_config(config_name)

get_config_value staticmethod

get_config_value(config_name: str, key_path: str, default: Any = None) -> Any

Get a value from a named configuration using dot-separated path.

PARAMETER DESCRIPTION
config_name

Logical name of the configuration.

TYPE: str

key_path

Dot-separated key path, e.g. "app.name".

TYPE: str

default

Value returned when the path is absent.

TYPE: Any DEFAULT: None

RETURNS DESCRIPTION
Any

The configuration value or default.

TYPE: Any

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def get_config_value(config_name: str, key_path: str, default: Any = None) -> Any:
    """
    Get a value from a named configuration using dot-separated path.

    Args:
        config_name: Logical name of the configuration.
        key_path: Dot-separated key path, e.g. "app.name".
        default: Value returned when the path is absent.

    Returns:
        Any: The configuration value or default.
    """
    return get_config_service().get_config_value(config_name, key_path, default)

save_config staticmethod

save_config(config_name: str, data: dict[str, Any]) -> None

Persist a named configuration to its YAML file.

PARAMETER DESCRIPTION
config_name

Logical name of the configuration.

TYPE: str

data

Full configuration dict to write.

TYPE: dict[str, Any]

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def save_config(config_name: str, data: dict[str, Any]) -> None:
    """
    Persist a named configuration to its YAML file.

    Args:
        config_name: Logical name of the configuration.
        data: Full configuration dict to write.
    """
    get_config_service().save_config(config_name, data)

write_yaml_config staticmethod

write_yaml_config(keys: list[str], val: Any) -> None

Write a single value into a YAML config using a key list immediately.

PARAMETER DESCRIPTION
keys

List where keys[0] is config name and keys[1:] is the path.

TYPE: list[str]

val

Value to assign at the leaf key.

TYPE: Any

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def write_yaml_config(keys: list[str], val: Any) -> None:
    """
    Write a single value into a YAML config using a key list immediately.

    Args:
        keys: List where keys[0] is config name and keys[1:] is the path.
        val: Value to assign at the leaf key.
    """
    if not keys:
        return

    config_name = keys[0]
    config_service = get_config_service()
    config = config_service.load_config(config_name)

    current = config
    for key in keys[1:-1]:
        if key not in current:
            current[key] = {}
        current = current[key]

    current[keys[-1]] = val
    config_service.save_config(config_name, config)

stage_config_value staticmethod

stage_config_value(keys: list[str], val: Any) -> None

Mutate a config value in the shared cache and mark it dirty for flush.

PARAMETER DESCRIPTION
keys

List where keys[0] is config name and keys[1:] is the path.

TYPE: list[str]

val

Value to assign at the leaf key.

TYPE: Any

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def stage_config_value(keys: list[str], val: Any) -> None:
    """
    Mutate a config value in the shared cache and mark it dirty for flush.

    Args:
        keys: List where keys[0] is config name and keys[1:] is the path.
        val: Value to assign at the leaf key.
    """
    if not keys:
        return

    global _quit_signal_connected  # noqa: PLW0603

    config_name = keys[0]
    config_service = get_config_service()

    config: dict[str, Any] = config_service.load_config(config_name)
    current: dict[str, Any] = config
    for key in keys[1:-1]:
        if key not in current or not isinstance(current[key], dict):
            current[key] = {}
        current = current[key]

    current[keys[-1]] = val
    _dirty.add(config_name)

    if not _quit_signal_connected:
        from PySide6.QtCore import QCoreApplication

        app = QCoreApplication.instance()
        if app is not None:
            app.aboutToQuit.connect(AppService.flush_all)
            _quit_signal_connected = True

flush_all staticmethod

flush_all() -> None

Write all dirty configs to disk and clear the dirty set.

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def flush_all() -> None:
    """Write all dirty configs to disk and clear the dirty set."""
    if not _dirty:
        return

    config_service = get_config_service()
    for config_name in list(_dirty):
        config_data = config_service.load_config(config_name)
        config_service.save_config(config_name, config_data)

    _dirty.clear()

copy_package_configs_to_project staticmethod

copy_package_configs_to_project() -> None

Copy package default configs into the child project directory.

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def copy_package_configs_to_project() -> None:
    """Copy package default configs into the child project directory."""
    get_config_service().copy_package_configs_to_project()

get_package_resource staticmethod

get_package_resource(resource_path: str) -> Path

Return a Path to an installed package resource.

PARAMETER DESCRIPTION
resource_path

Relative path inside the package.

TYPE: str

RETURNS DESCRIPTION
Path

Absolute path to the resource.

TYPE: Path

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def get_package_resource(resource_path: str) -> Path:
    """
    Return a Path to an installed package resource.

    Args:
        resource_path: Relative path inside the package.

    Returns:
        Path: Absolute path to the resource.
    """
    return get_package_resource(resource_path)

get_package_resource_content staticmethod

get_package_resource_content(resource_path: str) -> str

Return the text content of an installed package resource.

PARAMETER DESCRIPTION
resource_path

Relative path inside the package.

TYPE: str

RETURNS DESCRIPTION
str

Content of the resource.

TYPE: str

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def get_package_resource_content(resource_path: str) -> str:
    """
    Return the text content of an installed package resource.

    Args:
        resource_path: Relative path inside the package.

    Returns:
        str: Content of the resource.
    """
    return get_package_resource_content(resource_path)

load_fonts_resources staticmethod

load_fonts_resources(app: bool = False) -> None

Load .ttf font files into Qt's font database.

PARAMETER DESCRIPTION
app

Whether to also load fonts from the bin/fonts/ directory.

TYPE: bool DEFAULT: False

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def load_fonts_resources(app: bool = False) -> None:
    """
    Load .ttf font files into Qt's font database.

    Args:
        app: Whether to also load fonts from the bin/fonts/ directory.
    """
    ResourceService.load_fonts_resources(app)

load_app_settings staticmethod

load_app_settings() -> dict[str, Any]

Load app settings from YAML and apply to SettingsService.

RETURNS DESCRIPTION
dict

Loaded settings.

TYPE: dict[str, Any]

Source code in src/ezqt_app/services/application/app_service.py
@staticmethod
def load_app_settings() -> dict[str, Any]:
    """
    Load app settings from YAML and apply to SettingsService.

    Returns:
        dict: Loaded settings.
    """
    return SettingsLoader.load_app_settings()

InitService

InitService

InitService()

Coordinates initialization with a single options object.

Source code in src/ezqt_app/services/bootstrap/init_service.py
def __init__(self) -> None:
    self._initialized = False

run

run(options: InitOptions | None = None) -> InitResult

Run initialization sequence with normalized options.

Source code in src/ezqt_app/services/bootstrap/init_service.py
def run(self, options: InitOptions | None = None) -> InitResult:
    """Run initialization sequence with normalized options."""
    resolved = (options or InitOptions()).resolve()

    if self._initialized:
        err = InitAlreadyInitializedError(
            code="bootstrap.already_initialized",
            message="Initialization already completed",
            context={
                "project_root": (
                    str(resolved.project_root) if resolved.project_root else None
                ),
                "bin_path": str(resolved.bin_path) if resolved.bin_path else None,
            },
        )
        return InitResult(
            success=True,
            message="Already initialized",
            error=ResultError(
                code=err.code, message=err.message, context=err.context
            ),
        )

    try:
        sequence = InitializationSequence(resolved)
        summary = sequence.execute(verbose=resolved.verbose)
    except Exception as e:
        return InitResult(
            success=False,
            message="Initialization failed before sequence completion",
            error=ResultError(
                code="bootstrap.unexpected_error",
                message=str(e),
                context={
                    "project_root": (
                        str(resolved.project_root)
                        if resolved.project_root
                        else None
                    ),
                    "bin_path": (
                        str(resolved.bin_path) if resolved.bin_path else None
                    ),
                },
            ),
        )

    # CLI-only optional step: generate main.py from package template.
    if summary.success and resolved.generate_main and resolved.project_root:
        maker = FileService(
            base_path=Path(resolved.project_root),
            bin_path=resolved.bin_path,
            verbose=resolved.verbose,
            overwrite_policy=resolved.overwrite_policy.value,
        )
        maker.make_main_from_template()

    if summary.success:
        self._initialized = True

    return summary

is_initialized

is_initialized() -> bool

Return True if initialization has completed successfully.

Source code in src/ezqt_app/services/bootstrap/init_service.py
def is_initialized(self) -> bool:
    """Return ``True`` if initialization has completed successfully."""
    return self._initialized

reset

reset() -> None

Reset initialization state.

Source code in src/ezqt_app/services/bootstrap/init_service.py
def reset(self) -> None:
    """Reset initialization state."""
    self._initialized = False

InitOptions

InitOptions dataclass

InitOptions(project_root: Path | None = None, bin_path: Path | None = None, mk_theme: bool = True, mk_config: bool = True, mk_translations: bool = True, build_resources: bool = True, generate_main: bool = False, verbose: bool = True, overwrite_policy: OverwritePolicy = ASK)

Options driving initialization behavior across API and CLI.

ATTRIBUTE DESCRIPTION
project_root

Absolute path to the project root directory. When None, defaults to Path.cwd() at resolve time.

TYPE: Path | None

bin_path

Directory where generated assets (resources_rc.py, app_icons.py, app_images.py, themes) are written. When None, defaults to <project_root>/bin. A relative value is resolved against project_root; an absolute value is used as-is.

TYPE: Path | None

mk_theme

Generate QSS theme files under bin_path/themes/.

TYPE: bool

mk_config

Generate the config/ YAML files.

TYPE: bool

mk_translations

Generate the translations/ TS source files.

TYPE: bool

build_resources

Compile the QRC file with pyside6-rcc and write resources_rc.py, app_icons.py, and app_images.py into bin_path. Raises ResourceCompilationError if pyside6-rcc is not found on PATH.

TYPE: bool

generate_main

Write a main.py entrypoint in the project root.

TYPE: bool

verbose

Print step-by-step progress to stdout.

TYPE: bool

overwrite_policy

Controls behavior when generated files already exist. See :class:OverwritePolicy.

TYPE: OverwritePolicy

resolve

resolve() -> InitOptions

Return a copy with normalized paths and defaults resolved.

Source code in src/ezqt_app/services/bootstrap/contracts/options.py
def resolve(self) -> InitOptions:
    """Return a copy with normalized paths and defaults resolved."""
    root = self.project_root or Path.cwd()
    if self.bin_path is None:
        bin_path = root / "bin"
    elif not self.bin_path.is_absolute():
        bin_path = (root / self.bin_path).resolve()
    else:
        bin_path = self.bin_path

    return InitOptions(
        project_root=root,
        bin_path=bin_path,
        mk_theme=self.mk_theme,
        mk_config=self.mk_config,
        mk_translations=self.mk_translations,
        build_resources=self.build_resources,
        generate_main=self.generate_main,
        verbose=self.verbose,
        overwrite_policy=self.overwrite_policy,
    )

InitializationSequence

InitializationSequence

InitializationSequence(options: InitOptions | None = None)

Orchestrates the ordered initialization steps for EzQt_App.

Each step is registered with a name, description, callable and a required flag. If a required step fails the sequence stops immediately; non-required steps are allowed to fail silently.

Source code in src/ezqt_app/services/bootstrap/sequence.py
def __init__(self, options: InitOptions | None = None) -> None:
    self.options = (options or InitOptions()).resolve()
    self.steps: list[InitStep] = []
    self.current_step: InitStep | None = None
    self.printer = get_printer(self.options.verbose)

    # Register the resolved bin path early so all runtime services
    # (themes, fonts, config, translations) use the correct directory.
    if self.options.bin_path is not None:
        from ...utils.runtime_paths import set_bin_path

        set_bin_path(self.options.bin_path)

    self._setup_steps()

add_step

add_step(name: str, description: str, function: Callable[[], None], required: bool = True) -> None

Append a new step to the sequence.

Source code in src/ezqt_app/services/bootstrap/sequence.py
def add_step(
    self,
    name: str,
    description: str,
    function: Callable[[], None],
    required: bool = True,
) -> None:
    """Append a new step to the sequence."""
    self.steps.append(
        InitStep(
            name=name, description=description, function=function, required=required
        )
    )

execute

execute(verbose: bool = True) -> InitResult

Run all registered steps in order.

Returns

InitResult Typed aggregate result with step-level execution details.

Source code in src/ezqt_app/services/bootstrap/sequence.py
def execute(self, verbose: bool = True) -> InitResult:
    """Run all registered steps in order.

    Returns
    -------
    InitResult
        Typed aggregate result with step-level execution details.
    """
    import time

    if verbose:
        self.printer.custom_print(
            "~ [Initializer] Starting EzQt_App Initialization Sequence",
            color="MAGENTA",
        )
        self.printer.raw_print("...")

    start_time = time.time()
    successful_steps = 0
    failed_steps = 0
    skipped_steps = 0
    first_error: Exception | None = None
    first_failed_step: str | None = None

    for step in self.steps:
        self.current_step = step
        step_start = time.time()
        step.status = StepStatus.RUNNING

        try:
            step.function()
            step.status = StepStatus.SUCCESS
            step.duration = time.time() - step_start
            successful_steps += 1
        except Exception as e:
            step.status = StepStatus.FAILED
            step.error_message = str(e)
            step.duration = time.time() - step_start
            failed_steps += 1
            if first_error is None:
                first_error = e
                first_failed_step = step.name

            if verbose:
                self.printer.error(
                    f"[Initializer] Step failed ({step.duration:.2f}s): {e}"
                )

            if step.required:
                if verbose:
                    self.printer.error(
                        f"[Initializer] Initialization failed at required step: {step.name}"
                    )
                break

    total_time = time.time() - start_time
    summary = InitResult(
        success=(failed_steps == 0),
        total_steps=len(self.steps),
        successful=successful_steps,
        failed=failed_steps,
        skipped=skipped_steps,
        total_time=total_time,
        steps=[
            InitStepResult(
                name=step.name,
                description=step.description,
                required=step.required,
                status=step.status.value,
                error_message=step.error_message,
                duration=step.duration,
            )
            for step in self.steps
        ],
    )

    if first_error is not None and first_failed_step is not None:
        if isinstance(first_error, EzQtError):
            summary.error = ResultError(
                code=first_error.code,
                message=first_error.message,
                context=first_error.context,
            )
        else:
            summary.error = ResultError(
                code=self._error_code_for_step(first_failed_step),
                message=str(first_error),
                context={
                    "step": first_failed_step,
                    "error_type": type(first_error).__name__,
                },
            )

    if verbose:
        self._print_summary(summary)

    return summary

StartupConfig

StartupConfig

StartupConfig()

Manages system-level startup configuration.

Handles encoding, locale, environment variables and project root detection. Idempotent: subsequent calls to :meth:configure are no-ops once the instance is configured.

Source code in src/ezqt_app/services/bootstrap/startup_config.py
def __init__(self) -> None:
    self._configured = False

configure

configure(project_root: Path | None = None) -> None

Run all startup configuration steps (idempotent).

Source code in src/ezqt_app/services/bootstrap/startup_config.py
def configure(self, project_root: Path | None = None) -> None:
    """Run all startup configuration steps (idempotent)."""
    if self._configured:
        return

    self._configure_encoding()
    self._configure_environment()
    self._configure_locale()
    self._configure_system()
    self._configure_project_root(project_root)

    self._configured = True