Repository: Textualize/textual
File: src/textual/app.py (Python)

Code before:
        ]
        self.css_path = css_paths

        self._registry: WeakSet[DOMNode] = WeakSet()

        # Sensitivity on X is double the sensitivity on Y to account for
        # cells being twice as tall as wide
        self.scroll_sensitivity_x: float = 4.0
        """Number of columns to scroll in the X direction with wheel or trackpad."""
        self.scroll_sensitivity_y: float = 2.0
        """Number of lines to scroll in the Y direction with wheel or trackpad."""

        self._installed_screens: dict[str, Screen | Callable[[], Screen]] = {}
        for var_name, dct in (("SCREENS", self.SCREENS), ("MODES", self.MODES)):
            for screen_name, v in dct.items():
                if (
                    isinstance(v, Screen)
                    or (not callable(v))
                    and (not isinstance(v, str))
                ):
                    raise TypeError(
                        f"{var_name} should contain a Screen type or callable, not an instance"
                        f" (got instance of {type(v).__name__} for {screen_name!r})"
                    )
        self._installed_screens.update(**self.SCREENS)
        self.modes: dict[str, str | Callable[[], Screen]] = self.MODES.copy()
        """Contains the working-copy of the `MODES` for each instance."""

        self._compose_stacks: list[list[Widget]] = []
        self._composed: list[list[Widget]] = []
        self._recompose_required = False

        self.devtools: DevtoolsClient | None = None
        self._devtools_redirector: StdoutRedirector | None = None
        if "devtools" in self.features:
            try:
                from textual_dev.client import DevtoolsClient
                from textual_dev.redirect_output import StdoutRedirector
            except ImportError:
                # Dev dependencies not installed
                pass
            else:
                self.devtools = DevtoolsClient(constants.DEVTOOLS_HOST)
                self._devtools_redirector = StdoutRedirector(self.devtools)

        self._loop: asyncio.AbstractEventLoop | None = None
        self._return_value: ReturnType | None = None
        """Internal attribute used to set the return value for the app."""
        self._return_code: int | None = None
        """Internal attribute used to set the return code for the app."""
        self._exit = False

Review comment (suggestion):
I think `modes` should be private. It probably isn't of much use for the dev, so `self._modes` is probably better.

If we want it to be public later, we could add a property.

Code after:
        self._registry: WeakSet[DOMNode] = WeakSet()

        # Sensitivity on X is double the sensitivity on Y to account for
        # cells being twice as tall as wide
        self.scroll_sensitivity_x: float = 4.0
        """Number of columns to scroll in the X direction with wheel or trackpad."""
        self.scroll_sensitivity_y: float = 2.0
        """Number of lines to scroll in the Y direction with wheel or trackpad."""

        self._installed_screens: dict[str, Screen | Callable[[], Screen]] = {}
        self._installed_screens.update(**self.SCREENS)
        self._modes: dict[str, str | Callable[[], Screen]] = self.MODES.copy()
        """Contains the working-copy of the `MODES` for each instance."""

        self._compose_stacks: list[list[Widget]] = []
        self._composed: list[list[Widget]] = []
        self._recompose_required = False

        self.devtools: DevtoolsClient | None = None
        self._devtools_redirector: StdoutRedirector | None = None
        if "devtools" in self.features:
            try:
                from textual_dev.client import DevtoolsClient
                from textual_dev.redirect_output import StdoutRedirector
            except ImportError:
                # Dev dependencies not installed
                pass
            else:
                self.devtools = DevtoolsClient(constants.DEVTOOLS_HOST)
                self._devtools_redirector = StdoutRedirector(self.devtools)

        self._loop: asyncio.AbstractEventLoop | None = None
        self._return_value: ReturnType | None = None
        """Internal attribute used to set the return value for the app."""
        self._return_code: int | None = None
        """Internal attribute used to set the return code for the app."""
        self._exit = False
        self._disable_tooltips = False
        self._disable_notifications = False

        self.css_monitor = (
            FileMonitor(self.css_path, self._on_css_change)
            if watch_css or self.debug
            else None
        )
        self._screenshot: str | None = None
        self._dom_ready = False
        self._batch_count = 0
        self._notifications = Notifications()

        self._capture_print: WeakKeyDictionary[MessageTarget, tuple[bool, bool]] = (