diff --git a/docs/contributing/LOCAL_DEVELOPMENT.md b/docs/contributing/LOCAL_DEVELOPMENT.md index b2a5cd581d..f93ec56e96 100644 --- a/docs/contributing/LOCAL_DEVELOPMENT.md +++ b/docs/contributing/LOCAL_DEVELOPMENT.md @@ -35,18 +35,17 @@ access. ## Backend -The backend is contained within the `./invokeai/backend` folder structure. To -get started however please install the development dependencies. +The backend is contained within the `./invokeai/backend` and `./invokeai/app` directories. +To get started please install the development dependencies. From the root of the repository run the following command. Note the use of `"`. ```zsh -pip install ".[test]" +pip install ".[dev,test]" ``` -This in an optional group of packages which is defined within the -`pyproject.toml` and will be required for testing the changes you make the the -code. +These are optional groups of packages which are defined within the `pyproject.toml` +and will be required for testing the changes you make to the code. ### Running Tests @@ -76,6 +75,20 @@ pytest --cov; open ./coverage/html/index.html ![html-detail](../assets/contributing/html-detail.png) +### Reloading Changes + +Experimenting with changes to the Python source code is a drag if you have to re-start the server — +and re-load those multi-gigabyte models — +after every change. + +For a faster development workflow, add the `--dev_reload` flag when starting the server. +The server will watch for changes to all the Python files in the `invokeai` directory and apply those changes to the +running server on the fly. + +This will allow you to avoid restarting the server (and reloading models) in most cases, but there are some caveats; see +the [jurigged documentation](https://github.com/breuleux/jurigged#caveats) for details. + + ## Front End diff --git a/invokeai/app/api_app.py b/invokeai/app/api_app.py index b34000dc04..902af0c02c 100644 --- a/invokeai/app/api_app.py +++ b/invokeai/app/api_app.py @@ -1,11 +1,11 @@ # Copyright (c) 2022-2023 Kyle Schouviller (https://github.com/kyle0654) and the InvokeAI Team import asyncio -from inspect import signature - import logging -import uvicorn import socket +from inspect import signature +from pathlib import Path +import uvicorn from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html @@ -13,7 +13,6 @@ from fastapi.openapi.utils import get_openapi from fastapi.staticfiles import StaticFiles from fastapi_events.handlers.local import local_handler from fastapi_events.middleware import EventHandlerASGIMiddleware -from pathlib import Path from pydantic.schema import schema from .services.config import InvokeAIAppConfig @@ -30,9 +29,12 @@ from .api.sockets import SocketIO from .invocations.baseinvocation import BaseInvocation, _InputField, _OutputField, UIConfigBase import torch + +# noinspection PyUnresolvedReferences import invokeai.backend.util.hotfixes # noqa: F401 (monkeypatching on import) if torch.backends.mps.is_available(): + # noinspection PyUnresolvedReferences import invokeai.backend.util.mps_fixes # noqa: F401 (monkeypatching on import) @@ -40,7 +42,6 @@ app_config = InvokeAIAppConfig.get_config() app_config.parse_args() logger = InvokeAILogger.getLogger(config=app_config) - # fix for windows mimetypes registry entries being borked # see https://github.com/invoke-ai/InvokeAI/discussions/3684#discussioncomment-6391352 mimetypes.add_type("application/javascript", ".js") @@ -208,6 +209,17 @@ def invoke_api(): check_invokeai_root(app_config) # note, may exit with an exception if root not set up + if app_config.dev_reload: + try: + import jurigged + except ImportError as e: + logger.error( + 'Can\'t start `--dev_reload` because jurigged is not found; `pip install -e ".[dev]"` to include development dependencies.', + exc_info=e, + ) + else: + jurigged.watch(logger=InvokeAILogger.getLogger(name="jurigged").info) + port = find_port(app_config.port) if port != app_config.port: logger.warn(f"Port {app_config.port} in use, using port {port}") diff --git a/invokeai/app/services/config/invokeai_config.py b/invokeai/app/services/config/invokeai_config.py index 728fe188b5..1a2c22c89a 100644 --- a/invokeai/app/services/config/invokeai_config.py +++ b/invokeai/app/services/config/invokeai_config.py @@ -169,11 +169,13 @@ two configs are kept in separate sections of the config file: """ from __future__ import annotations + import os -from omegaconf import OmegaConf, DictConfig from pathlib import Path +from typing import ClassVar, Dict, List, Literal, Union, get_type_hints, Optional + +from omegaconf import OmegaConf, DictConfig from pydantic import Field, parse_obj_as -from typing import ClassVar, Dict, List, Literal, Union, Optional, get_type_hints from .base import InvokeAISettings @@ -233,6 +235,8 @@ class InvokeAIAppConfig(InvokeAISettings): log_format : Literal['plain', 'color', 'syslog', 'legacy'] = Field(default="color", description='Log format. Use "plain" for text-only, "color" for colorized output, "legacy" for 2.3-style logging and "syslog" for syslog-style', category="Logging") log_level : Literal["debug", "info", "warning", "error", "critical"] = Field(default="info", description="Emit logging messages at this level or higher", category="Logging") + dev_reload : bool = Field(default=False, description="Automatically reload when Python sources are changed.", category="Development") + version : bool = Field(default=False, description="Show InvokeAI version and exit", category="Other") # CACHE diff --git a/pyproject.toml b/pyproject.toml index 02e53f066a..9aef66a35f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,6 +93,7 @@ dependencies = [ "mkdocs-redirects==1.2.0", ] "dev" = [ + "jurigged", "pudb", ] "test" = [