Merge pull request #4486 from awsr/py310-merge

Typing updates to options and fix `Extension` type inference
This commit is contained in:
Vladimir Mandic
2025-12-21 13:42:18 +01:00
committed by GitHub
6 changed files with 37 additions and 20 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
from __future__ import annotations
import os
from datetime import datetime
import git
@@ -5,7 +6,7 @@ from modules import shared, errors
from modules.paths import extensions_dir, extensions_builtin_dir
extensions = []
extensions: list[Extension] = []
if not os.path.exists(extensions_dir):
os.makedirs(extensions_dir)
+19 -9
View File
@@ -1,8 +1,18 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
from installer import log
def options_section(section_identifier, options_dict):
if TYPE_CHECKING:
from collections.abc import Callable
from gradio.components import Component
from modules.shared_legacy import LegacyOption
from modules.ui_components import DropdownEditable
def options_section(section_identifier: tuple[str, str], options_dict: dict[str, OptionInfo | LegacyOption]):
"""Set the `section` value for all OptionInfo/LegacyOption items"""
for v in options_dict.values():
v.section = section_identifier
return options_dict
@@ -11,14 +21,14 @@ def options_section(section_identifier, options_dict):
class OptionInfo:
def __init__(
self,
default=None,
default: Any | None = None,
label="",
component=None,
component_args=None,
onchange=None,
section=None,
refresh=None,
folder=None,
component: type[Component] | type[DropdownEditable] | None = None,
component_args: dict | Callable[..., dict] | None = None,
onchange: Callable | None = None,
section: tuple[str, ...] | None = None,
refresh: Callable | None = None,
folder=False,
submit=None,
comment_before='',
comment_after='',
@@ -40,7 +50,7 @@ class OptionInfo:
self.exclude = ['sd_model_checkpoint', 'sd_model_refiner', 'sd_vae', 'sd_unet', 'sd_text_encoder']
self.dynamic = callable(component_args)
args = {} if self.dynamic else (component_args or {}) # executing callable here is too expensive
self.visible = args.get('visible', True) and len(self.label) > 2
self.visible = args.get('visible', True) and len(self.label) > 2 # type: ignore - Type checking only sees the value of self.dynamic, not the `callable` check
def needs_reload_ui(self):
return self
+10 -5
View File
@@ -1,3 +1,4 @@
from __future__ import annotations
import os
import json
import threading
@@ -6,10 +7,12 @@ from modules import cmd_args, errors
from modules.json_helpers import readfile, writefile
from modules.shared_legacy import LegacyOption
from installer import log
if TYPE_CHECKING:
from modules.options import OptionInfo
if TYPE_CHECKING:
from collections.abc import Callable
from modules.options import OptionInfo
cmd_opts = cmd_args.parse_args()
compatibility_opts = ['clip_skip', 'uni_pc_lower_order_final', 'uni_pc_order']
@@ -21,7 +24,9 @@ class Options():
typemap = {int: float}
debug = os.environ.get('SD_CONFIG_DEBUG', None) is not None
def __init__(self, options_templates:dict={}, restricted_opts:dict={}):
def __init__(self, options_templates: dict[str, OptionInfo | LegacyOption] = {}, restricted_opts: set[str] | None = None):
if restricted_opts is None:
restricted_opts = set()
self.data_labels = options_templates
self.restricted_opts = restricted_opts
self.data = {k: v.default for k, v in self.data_labels.items()}
@@ -168,7 +173,7 @@ class Options():
self.data['quicksettings_list'] = [i.strip() for i in self.data.get('quicksettings').split(',')]
unknown_settings = []
for k, v in self.data.items():
info: OptionInfo = self.data_labels.get(k, None)
info: OptionInfo | None = self.data_labels.get(k, None)
if info is not None:
if not info.validate(k, v):
self.data[k] = info.default
@@ -180,7 +185,7 @@ class Options():
if len(unknown_settings) > 0:
log.warning(f"Setting validation: unknown={unknown_settings}")
def onchange(self, key, func, call=True):
def onchange(self, key, func: Callable, call=True):
item = self.data_labels.get(key)
item.onchange = func
if call:
+3 -2
View File
@@ -27,7 +27,8 @@ from installer import log, print_dict, console, get_version # pylint: disable=un
if TYPE_CHECKING:
# Behavior modified by __future__.annotations
from diffusers import DiffusionPipeline
from ui_extra_networks import ExtraNetworksPage
from modules.shared_legacy import LegacyOption
from modules.ui_extra_networks import ExtraNetworksPage
class Backend(Enum):
@@ -51,7 +52,7 @@ face_restorers = []
yolo = None
tab_names = []
extra_networks: list[ExtraNetworksPage] = []
options_templates = {}
options_templates: dict[str, OptionInfo | LegacyOption] = {}
hypernetworks = {}
settings_components = {}
restricted_opts = {
+2 -2
View File
@@ -29,8 +29,8 @@ sort_ordering = {
}
def get_installed(ext) -> extensions.Extension:
installed: extensions.Extension = [e for e in extensions.extensions if (e.remote or '').startswith(ext['url'].replace('.git', ''))]
def get_installed(ext):
installed = [e for e in extensions.extensions if (e.remote or '').startswith(ext['url'].replace('.git', ''))]
return installed[0] if len(installed) > 0 else None
+1 -1
View File
@@ -84,7 +84,7 @@ def create_setting_component(key, is_quicksettings=False):
with gr.Row():
res = comp(label=info.label, value=fun(), elem_id=elem_id, **args)
ui_common.create_refresh_button(res, info.refresh, info.component_args, f"settings_{key}_refresh")
elif info.folder is not None:
elif info.folder:
with gr.Row():
res = comp(label=info.label, value=fun(), elem_id=elem_id, elem_classes="folder-selector", **args)
else: