From 596025a435de2b7d847493cac34a94a05c809c0a Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Mon, 11 Mar 2024 14:20:57 -0400 Subject: [PATCH 1/6] Allow lists of basemodel objects in omegaconf --- invokeai/app/services/config/config_base.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/invokeai/app/services/config/config_base.py b/invokeai/app/services/config/config_base.py index 20dac149374..d11d98901b0 100644 --- a/invokeai/app/services/config/config_base.py +++ b/invokeai/app/services/config/config_base.py @@ -15,6 +15,7 @@ import sys from argparse import ArgumentParser from pathlib import Path +from pydantic import BaseModel from typing import Any, ClassVar, Dict, List, Literal, Optional, Union, get_args, get_origin, get_type_hints from omegaconf import DictConfig, ListConfig, OmegaConf @@ -62,6 +63,18 @@ def to_yaml(self) -> str: assert isinstance(category, str) if category not in field_dict[type]: field_dict[type][category] = {} + if isinstance(value, BaseModel): + dump = value.model_dump(exclude_defaults=True, exclude_unset=True, exclude_none=True) + field_dict[type][category][name] = dump + continue + if isinstance(value, list): + val_list: List[Dict[str, Any]] = [] + for list_val in value: + if isinstance(list_val, BaseModel): + dump = list_val.model_dump(exclude_defaults=True, exclude_unset=True, exclude_none=True) + val_list.append(dump) + field_dict[type][category][name] = val_list + continue # keep paths as strings to make it easier to read field_dict[type][category][name] = str(value) if isinstance(value, Path) else value conf = OmegaConf.create(field_dict) From 71a4998afe0e006e08f52a711fd561150afa8c88 Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Mon, 11 Mar 2024 14:36:56 -0400 Subject: [PATCH 2/6] Skip list logic if the list only contains primitives --- invokeai/app/services/config/config_base.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/invokeai/app/services/config/config_base.py b/invokeai/app/services/config/config_base.py index d11d98901b0..b03d446babf 100644 --- a/invokeai/app/services/config/config_base.py +++ b/invokeai/app/services/config/config_base.py @@ -18,7 +18,7 @@ from pydantic import BaseModel from typing import Any, ClassVar, Dict, List, Literal, Optional, Union, get_args, get_origin, get_type_hints -from omegaconf import DictConfig, ListConfig, OmegaConf +from omegaconf import DictConfig, ListConfig, OmegaConf, DictKeyType from pydantic_settings import BaseSettings, SettingsConfigDict from invokeai.app.services.config.config_common import PagingArgumentParser, int_or_float_or_str @@ -68,13 +68,17 @@ def to_yaml(self) -> str: field_dict[type][category][name] = dump continue if isinstance(value, list): - val_list: List[Dict[str, Any]] = [] - for list_val in value: - if isinstance(list_val, BaseModel): - dump = list_val.model_dump(exclude_defaults=True, exclude_unset=True, exclude_none=True) - val_list.append(dump) - field_dict[type][category][name] = val_list - continue + if not value or len(value) == 0: + continue + primitive = isinstance(value[0], get_args(DictKeyType)) + if not primitive: + val_list: List[Dict[str, Any]] = [] + for list_val in value: + if isinstance(list_val, BaseModel): + dump = list_val.model_dump(exclude_defaults=True, exclude_unset=True, exclude_none=True) + val_list.append(dump) + field_dict[type][category][name] = val_list + continue # keep paths as strings to make it easier to read field_dict[type][category][name] = str(value) if isinstance(value, Path) else value conf = OmegaConf.create(field_dict) From 9f93d245cb0b2853957549a9c33c1c7954493c6f Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Mon, 11 Mar 2024 14:38:52 -0400 Subject: [PATCH 3/6] Run ruff --- invokeai/app/services/config/config_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/invokeai/app/services/config/config_base.py b/invokeai/app/services/config/config_base.py index b03d446babf..d7c8d40e2d2 100644 --- a/invokeai/app/services/config/config_base.py +++ b/invokeai/app/services/config/config_base.py @@ -15,10 +15,10 @@ import sys from argparse import ArgumentParser from pathlib import Path -from pydantic import BaseModel from typing import Any, ClassVar, Dict, List, Literal, Optional, Union, get_args, get_origin, get_type_hints -from omegaconf import DictConfig, ListConfig, OmegaConf, DictKeyType +from omegaconf import DictConfig, DictKeyType, ListConfig, OmegaConf +from pydantic import BaseModel from pydantic_settings import BaseSettings, SettingsConfigDict from invokeai.app.services.config.config_common import PagingArgumentParser, int_or_float_or_str From 0c6511383e4e6e84343cab36d442c9bca8be250d Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Mon, 11 Mar 2024 15:01:41 -0400 Subject: [PATCH 4/6] Gracefully error without deleting invokeai.yaml --- invokeai/backend/install/invokeai_configure.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index 53cca64a1a5..a00808ab8f8 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -17,7 +17,7 @@ from argparse import Namespace from enum import Enum from pathlib import Path -from shutil import get_terminal_size +from shutil import get_terminal_size, copy, move, rmtree from typing import Any, Optional, Set, Tuple, Type, get_args, get_type_hints from urllib import request @@ -929,6 +929,10 @@ def main() -> None: errors = set() FORCE_FULL_PRECISION = opt.full_precision # FIXME global + new_init_file = config.root_path / "invokeai.yaml" + backup_init_file = new_init_file.with_suffix(".bak") + if new_init_file.exists(): + copy(new_init_file, new_init_file.with_suffix(".bak")) try: # if we do a root migration/upgrade, then we are keeping previous @@ -943,7 +947,6 @@ def main() -> None: install_helper = InstallHelper(config, logger) models_to_download = default_user_selections(opt, install_helper) - new_init_file = config.root_path / "invokeai.yaml" if opt.yes_to_all: write_default_options(opt, new_init_file) @@ -975,8 +978,17 @@ def main() -> None: input("Press any key to continue...") except WindowTooSmallException as e: logger.error(str(e)) + if backup_init_file.exists(): + move(backup_init_file, new_init_file) except KeyboardInterrupt: print("\nGoodbye! Come back soon.") + if backup_init_file.exists(): + move(backup_init_file, new_init_file) + except Exception: + print("An error occurred during installation.") + if backup_init_file.exists(): + move(backup_init_file, new_init_file) + print(traceback.format_exc(), file=sys.stderr) # ------------------------------------- From 8bcfae4692b0f21b89a009b763c1d9d00c886296 Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Mon, 11 Mar 2024 15:02:17 -0400 Subject: [PATCH 5/6] Remove redundant with_suffix call --- invokeai/backend/install/invokeai_configure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index a00808ab8f8..3afca4f60b8 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -932,7 +932,7 @@ def main() -> None: new_init_file = config.root_path / "invokeai.yaml" backup_init_file = new_init_file.with_suffix(".bak") if new_init_file.exists(): - copy(new_init_file, new_init_file.with_suffix(".bak")) + copy(new_init_file, backup_init_file) try: # if we do a root migration/upgrade, then we are keeping previous From 3bc04f3c3e19b78c9a7beedab85c3458d95e5763 Mon Sep 17 00:00:00 2001 From: Brandon Rising Date: Mon, 11 Mar 2024 15:02:45 -0400 Subject: [PATCH 6/6] Run ruff --- invokeai/backend/install/invokeai_configure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/invokeai/backend/install/invokeai_configure.py b/invokeai/backend/install/invokeai_configure.py index 3afca4f60b8..736c7fc5f75 100755 --- a/invokeai/backend/install/invokeai_configure.py +++ b/invokeai/backend/install/invokeai_configure.py @@ -17,7 +17,7 @@ from argparse import Namespace from enum import Enum from pathlib import Path -from shutil import get_terminal_size, copy, move, rmtree +from shutil import copy, get_terminal_size, move from typing import Any, Optional, Set, Tuple, Type, get_args, get_type_hints from urllib import request