refactor imports

This commit is contained in:
Vladimir Mandic
2026-02-19 15:28:24 +01:00
parent 216558185b
commit f78f0eb4a5
32 changed files with 78 additions and 72 deletions
+1
View File
@@ -61,6 +61,7 @@ TBD
- refactor: entire logging into separate `modules/logger`
- refactor: replace `timestamp` based startup checks with state caching
- refactor: split monolithic `shared` module and introduce `ui_definitions`
- refactor: modularize all imports and avoid re-imports
- use `threading` for deferable operatios
- use `threading` for io-independent parallel operations
- remove requirements: `clip`, `open-clip`
+2 -2
View File
@@ -12,10 +12,10 @@
"platform": "linux",
"requirements": "48d1c48d0709cdb9cad3c0da88b582783f02f0ecaf3499c4a81d9e1a1e453c40",
"extensions": {
"stable-diffusion-webui-rembg": "f3e21bb70e5f8a665b066c5d0ece99bfcff272f3",
"stable-diffusion-webui-rembg": "cfceed7243ce97cf8fd64a43df0291448c22a9dd",
"sd-extension-chainner": "2a7005fbcf8985644b66121365fa7228a65f34b0",
"sd-extension-system-info": "1a35ac4d73ce1f55527f7a95fc61b0915795c21b",
"sdnext-kanvas": "79cae1944646e57cfbfb126a971a04e44e45d776",
"sdnext-modernui": "fc7cf10dcc3f17377b6a18c4cd0dbd2be5480f0b"
}
}
}
+2 -2
View File
@@ -5,6 +5,7 @@ import os
import sys
import time
import shlex
import threading
import subprocess
import installer
from modules.logger import log
@@ -209,6 +210,7 @@ def start_server(immediate=True, server=None):
server = importlib.util.module_from_spec(module_spec)
log.debug(f'Starting module: {server}')
module_spec.loader.exec_module(server)
threading.Thread(target=installer.run_deferred_tasks, daemon=True).start()
uvicorn = None
if args.test:
log.info("Test only")
@@ -292,8 +294,6 @@ def main():
args = installer.parse_args(parser)
log.info(f'Installer time: {init_summary()}')
get_custom_args()
import threading
threading.Thread(target=installer.run_deferred_tasks, daemon=True).start()
uv, instance = start_server(immediate=True, server=None)
if installer.restart_required:
+1
View File
@@ -0,0 +1 @@
# SD.Next modules package
+15 -24
View File
@@ -36,6 +36,12 @@ if not hasattr(BaseModel, "__config__"):
BaseModel.__config__ = DummyConfig
class PydanticConfig:
arbitrary_types_allowed = True
orm_mode = True
allow_population_by_field_name = True
def underscore(name: str) -> str: # Convert CamelCase or PascalCase string to underscore_case (snake_case).
# use instead of inflection.underscore
s1 = re.sub('([a-z0-9])([A-Z])', r'\1_\2', name)
@@ -92,11 +98,7 @@ class PydanticModelGenerator:
if PYDANTIC_V2:
config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True, populate_by_name=True)
else:
class Config:
arbitrary_types_allowed = True
orm_mode = True
allow_population_by_field_name = True
config = Config
config = PydanticConfig
DynamicModel = create_model(self._model_name, __config__=config, **model_fields)
return DynamicModel
@@ -405,14 +407,10 @@ for key, metadata in shared.opts.data_labels.items():
fields.update({key: (Optional[optType], Field())})
if PYDANTIC_V2:
config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True, populate_by_name=True)
pydantic_config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True, populate_by_name=True)
else:
class Config:
arbitrary_types_allowed = True
orm_mode = True
allow_population_by_field_name = True
config = Config
OptionsModel = create_model("Options", __config__=config, **fields)
pydantic_config = PydanticConfig
OptionsModel = create_model("Options", __config__=pydantic_config, **fields)
flags = {}
_options = vars(shared.parser)['_option_string_actions']
@@ -425,14 +423,10 @@ for key in _options:
flags.update({flag.dest: (_type, Field(default=flag.default, description=flag.help))})
if PYDANTIC_V2:
config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True, populate_by_name=True)
pydantic_config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True, populate_by_name=True)
else:
class Config:
arbitrary_types_allowed = True
orm_mode = True
allow_population_by_field_name = True
config = Config
FlagsModel = create_model("Flags", __config__=config, **flags)
pydantic_config = PydanticConfig
FlagsModel = create_model("Flags", __config__=pydantic_config, **flags)
class ResEmbeddings(BaseModel):
loaded: list = Field(default=None, title="loaded", description="List of loaded embeddings")
@@ -499,12 +493,9 @@ def create_model_from_signature(func: Callable, model_name: str, base_model: typ
if PYDANTIC_V2:
config = ConfigDict(arbitrary_types_allowed=True, from_attributes=True, populate_by_name=True, extra='allow' if varkw else 'ignore')
else:
class Config:
arbitrary_types_allowed = True
orm_mode = True
allow_population_by_field_name = True
class CustomConfig(PydanticConfig):
extra = 'allow' if varkw else 'ignore'
config = Config
config = CustomConfig
model = create_model(
model_name,
+6 -2
View File
@@ -4,10 +4,14 @@ from typing import Any
from fastapi import Request, Depends
from fastapi.exceptions import HTTPException
from fastapi.responses import FileResponse
import installer
from modules import shared
from modules.logger import log
from modules.api import models, helpers
def _get_version():
return installer.get_version()
def post_shutdown():
log.info('Shutdown request received')
@@ -43,7 +47,7 @@ def get_js(request: Request):
def get_motd():
import requests
motd = ''
ver = shared.get_version()
ver = _get_version()
if ver.get('updated', None) is not None:
motd = f"version <b>{ver['commit']} {ver['updated']}</b> <span style='color: var(--primary-500)'>{ver['url'].split('/')[-1]}</span><br>" # pylint: disable=use-maxsplit-arg
if shared.opts.motd:
@@ -60,7 +64,7 @@ def get_motd():
return motd
def get_version():
return shared.get_version()
return _get_version()
def get_platform():
from installer import get_platform as installer_get_platform
+2 -1
View File
@@ -4,6 +4,7 @@ import rich.progress as p
from PIL import Image
from modules import shared, errors, paths
from modules.logger import log, console
from modules.json_helpers import writefile
pbar = None
@@ -33,7 +34,7 @@ def download_civit_meta(model_path: str, model_id):
if r.status_code == 200:
try:
data = r.json()
shared.writefile(data, filename=fn, mode='w', silent=True)
writefile(data, filename=fn, mode='w', silent=True)
log.info(f'CivitAI download: id={model_id} url={url} file="{fn}"')
return r.status_code, len(data), '' # code/size/note
except Exception as e:
+10 -10
View File
@@ -12,7 +12,7 @@ from modules.control.units import lite # Kohya ControlLLLite
from modules.control.units import t2iadapter # TencentARC T2I-Adapter
from modules.control.units import reference # ControlNet-Reference
from modules.control.processor import preprocess_image
from modules import devices, shared, errors, processing, images, video, sd_models, sd_vae, scripts_manager, masking
from modules import devices, shared, errors, processing, sd_models, sd_vae, scripts_manager, masking
from modules.logger import log
from modules.processing_class import StableDiffusionProcessingControl
from modules.ui_common import infotext_to_html
@@ -495,16 +495,16 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
log.warning('Control: separate init video not support for video input')
input_type = 1
try:
video = cv2.VideoCapture(inputs)
if not video.isOpened():
cap = cv2.VideoCapture(inputs)
if not cap.isOpened():
if is_generator:
yield terminate(f'Video open failed: path={inputs}')
return [], '', '', 'Error: video open failed'
frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(video.get(cv2.CAP_PROP_FPS))
w, h = int(video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
codec = util.decode_fourcc(video.get(cv2.CAP_PROP_FOURCC))
status, frame = video.read()
frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(cap.get(cv2.CAP_PROP_FPS))
w, h = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
codec = util.decode_fourcc(cap.get(cv2.CAP_PROP_FOURCC))
status, frame = cap.read()
if status:
shared.state.frame_count = 1 + frames // (video_skip_frames + 1)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
@@ -662,8 +662,8 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
else:
status = False
if video is not None:
video.release()
if cap is not None:
cap.release()
debug_log(f'Control: pipeline units={len(active_model)} process={len(active_process)} outputs={len(output_images)}')
except Exception as e:
+2 -2
View File
@@ -1,9 +1,9 @@
from typing import Union
import itertools
import os
from collections import UserDict
from dataclasses import dataclass, field
from typing import Union
from collections.abc import Callable, Iterator
from dataclasses import dataclass, field
from modules.logger import log
+1 -1
View File
@@ -1,7 +1,7 @@
import hashlib
import os.path
from rich import progress, errors
from installer import console
from modules.logger import console
from modules.logger import log
from modules.json_helpers import readfile, writefile
from modules.paths import data_path
+2 -1
View File
@@ -7,6 +7,7 @@ import piexif.helper
from PIL import Image, PngImagePlugin
from modules import shared, script_callbacks, errors, paths
from modules.logger import log
from modules.json_helpers import writefile
from modules.image.grid import check_grid_size
from modules.image.namegen import FilenameGenerator
from modules.image.watermark import set_watermark
@@ -114,7 +115,7 @@ def atomically_save_image():
idx = len(entries)
entry = { 'id': idx, 'filename': filename, 'time': datetime.datetime.now().isoformat(), 'info': exifinfo }
entries.append(entry)
shared.writefile(entries, fn, mode='w', silent=True)
writefile(entries, fn, mode='w', silent=True)
log.info(f'Save: json="{fn}" records={len(entries)}')
shared.state.outputs(filename)
shared.state.end(jobid)
+2 -2
View File
@@ -5,16 +5,16 @@ from modules.image.namegen import FilenameGenerator
from modules.image.grid import image_grid, check_grid_size, get_grid_size, draw_grid_annotations, draw_prompt_matrix, combine_grid
__all__ = [
'FilenameGenerator',
'check_grid_size',
'combine_grid',
'draw_grid_annotations',
'draw_prompt_matrix',
'get_grid_size',
'image_data',
'image_grid',
'combine_grid',
'read_info_from_image',
'resize_image',
'sanitize_filename_part',
'save_image',
'FilenameGenerator',
]
+1 -1
View File
@@ -1,7 +1,7 @@
import os
import enum
from collections import namedtuple
from modules import hashes, shared, sd_models, sd_checkpoint
from modules import hashes, shared, sd_checkpoint
NetworkWeights = namedtuple('NetworkWeights', ['network_key', 'sd_key', 'w', 'sd_module'])
+1 -1
View File
@@ -5,7 +5,7 @@ import safetensors.torch
import torch
import modules.memstats
import modules.devices as devices
from installer import console
from modules.logger import console
from modules.logger import log
from modules.sd_models import read_state_dict
from modules.merging import merge_methods
+2 -1
View File
@@ -9,6 +9,7 @@ import huggingface_hub as hf
from installer import install
from modules.logger import log, console
from modules import shared, errors, files_cache
from modules.json_helpers import writefile
from modules.upscaler import Upscaler
from modules import paths
@@ -108,7 +109,7 @@ def download_diffusers_model(hub_id: str, cache_dir: str = None, download_config
with open(os.path.join(download_dir, "hidden"), "w", encoding="utf-8") as f: # mark prior as hidden
f.write("True")
if pipeline_dir is not None:
shared.writefile(model_info_dict, os.path.join(pipeline_dir, "model_info.json"))
writefile(model_info_dict, os.path.join(pipeline_dir, "model_info.json"))
shared.state.end(jobid)
return pipeline_dir
+1 -1
View File
@@ -4,7 +4,7 @@ from PIL import Image
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn, TimeElapsedColumn
import modules.postprocess.esrgan_model_arch as arch
from modules import images, devices, shared
from modules.images.grid import split_grid
from modules.image.grid import split_grid
from modules.logger import log, console
from modules.upscaler import Upscaler, UpscalerData, compile_upscaler
+3 -2
View File
@@ -6,9 +6,10 @@ from copy import copy
import numpy as np
import gradio as gr
from PIL import Image, ImageDraw
from modules import shared, processing, devices, processing_class, ui_common, ui_components, ui_symbols, images, extra_networks, sd_models
from modules import shared, processing, devices, processing_class, ui_common, ui_components, ui_symbols, extra_networks, sd_models
from modules.logger import log
from modules.detailer import Detailer
from modules.image.grid import get_font
predefined = [ # <https://huggingface.co/vladmandic/yolo-detailers/tree/main>
@@ -244,7 +245,7 @@ class YoloRestorer(Detailer):
image = Image.fromarray(image)
image = image.convert('RGBA')
size = min(image.width, image.height) // 32
font = images.get_font(size)
font = get_font(size)
color = (0, 190, 190)
log.debug(f'Detailer: draw={items}')
for i, item in enumerate(items):
+3 -2
View File
@@ -1,8 +1,9 @@
import os
from installer import git_commit
from modules import shared, sd_samplers_common, sd_vae, generation_parameters_copypaste
from modules import shared, sd_samplers_common, sd_vae
from modules.logger import log
from modules.processing_class import StableDiffusionProcessing
from modules.infotext import quote
args = {} # maintain history
@@ -194,7 +195,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts=None, all_seeds=No
if len(v) == 0 or v == '0x0':
del args[k]
debug(f'Infotext: args={args}')
params_text = ", ".join([k if k == v else f'{k}: {generation_parameters_copypaste.quote(v)}' for k, v in args.items()])
params_text = ", ".join([k if k == v else f'{k}: {quote(v)}' for k, v in args.items()])
if hasattr(p, 'original_prompt'):
args['Original prompt'] = p.original_prompt
+4 -4
View File
@@ -55,15 +55,15 @@ if sys.platform == "win32":
_cuda_getCurrentRawStream = torch._C._cuda_getCurrentRawStream # pylint: disable=protected-access
def torch__C__cuda_getCurrentRawStream(device):
from modules import zluda
return zluda.core.to_hip_stream(_cuda_getCurrentRawStream(device))
from modules import zluda_installer
return zluda_installer.core.to_hip_stream(_cuda_getCurrentRawStream(device))
def get_default_agent() -> Agent | None:
if shared.devices.has_rocm():
return devices.get_hip_agent()
else:
from modules import zluda
return zluda.default_agent
from modules import zluda_installer
return zluda_installer.default_agent
def apply_triton_patches():
agent = get_default_agent()
+2 -1
View File
@@ -8,6 +8,7 @@ import collections
from PIL import Image
from modules import shared, paths, modelloader, hashes, sd_hijack_accelerate
from modules.logger import log
from modules.json_helpers import writefile
checkpoints_list = {}
@@ -426,6 +427,6 @@ def write_metadata():
if sd_metadata_pending == 0:
log.debug(f'Model metadata: file="{sd_metadata_file}" no changes')
return
shared.writefile(sd_metadata, sd_metadata_file)
writefile(sd_metadata, sd_metadata_file)
log.info(f'Model metadata saved: file="{sd_metadata_file}" items={sd_metadata_pending} time={sd_metadata_timer:.2f}')
sd_metadata_pending = 0
+2 -1
View File
@@ -13,6 +13,7 @@ import huggingface_hub as hf
from modules.logger import log
from modules import timer, paths, shared, shared_items, modelloader, devices, script_callbacks, sd_vae, sd_unet, errors, sd_models_compile, sd_detect, model_quant, sd_hijack_te, sd_hijack_accelerate, sd_hijack_safetensors, attention
from modules.memstats import memory_stats
from modules.shared_helpers import walk_files
from modules.modeldata import model_data
from modules.sd_checkpoint import CheckpointInfo, select_checkpoint, list_models, checkpoint_titles, get_closest_checkpoint_match, update_model_hashes, write_metadata, checkpoints_list # pylint: disable=unused-import
from modules.sd_offload import get_module_names, disable_offload, set_diffuser_offload, apply_balanced_offload, set_accelerate # pylint: disable=unused-import
@@ -507,7 +508,7 @@ def load_diffuser_force(detected_model_type, checkpoint_info, diffusers_load_con
def load_diffuser_folder(model_type, pipeline, checkpoint_info, diffusers_load_config, op='model'):
sd_model = None
files = shared.walk_files(checkpoint_info.path, ['.safetensors', '.bin', '.ckpt'])
files = walk_files(checkpoint_info.path, ['.safetensors', '.bin', '.ckpt'])
if 'variant' not in diffusers_load_config and any('diffusion_pytorch_model.fp16' in f for f in files): # deal with diffusers lack of variant fallback when loading
diffusers_load_config['variant'] = 'fp16'
+1 -1
View File
@@ -271,7 +271,7 @@ class State:
def do_set_current_image(self):
if (self.current_latent is None) or self.disable_preview or (self.preview_job == self.job_no):
return False
from modules import shared, sd_samplers, sd_samplers_common
from modules import shared
from modules.sd_samplers_common import samples_to_image_grid, sample_to_image
self.preview_job = self.job_no
try:
+2 -1
View File
@@ -4,6 +4,7 @@ import gradio as gr
import modules.shared
import modules.extensions
from modules.logger import log
from modules.json_helpers import writefile
gradio_theme = gr.themes.Base()
@@ -29,7 +30,7 @@ def refresh_themes(no_update=False):
r = modules.shared.req('https://huggingface.co/datasets/freddyaboulton/gradio-theme-subdomains/resolve/main/subdomains.json')
if r.status_code == 200:
res = r.json()
modules.shared.writefile(res, themes_file)
writefile(res, themes_file)
else:
log.error('Error refreshing UI themes')
except Exception:
+2 -1
View File
@@ -6,6 +6,7 @@ from modules import errors, shared, progress, generation_parameters_copypaste, c
from modules import ui_common, ui_sections, ui_guidance
from modules import ui_control_helpers as helpers
from modules.logger import log
from modules.memstats import ram_stats
import installer
@@ -39,7 +40,7 @@ def return_stats(t: float = None):
gpu += f"| GPU {peak} MB"
gpu += f" {used}%" if used > 0 else ''
gpu += f" | retries {retries} oom {ooms}" if retries > 0 or ooms > 0 else ''
ram = shared.ram_stats()
ram = ram_stats()
if ram['used'] > 0:
cpu += f"| RAM {ram['used']} GB"
cpu += f" {round(100.0 * ram['used'] / ram['total'])}%" if ram['total'] > 0 else ''
+1 -1
View File
@@ -44,7 +44,7 @@ def list_extensions():
global extensions_list # pylint: disable=global-statement
extensions_list = shared.readfile(extensions_data_file, silent=True, as_type="list")
if len(extensions_list) == 0:
log.info("Extension list: No information found. Refresh required.")
log.info("Extension list: No information found - refresh required")
found = []
for ext in extensions.extensions:
ext.read_info()
+1 -1
View File
@@ -123,7 +123,7 @@ class UiLoadsave:
return readfile(self.filename, as_type="dict")
def write_to_file(self, current_ui_settings):
from modules.shared import writefile
from modules.json_helpers import writefile
writefile(current_ui_settings, self.filename)
def dump_defaults(self):
+1 -1
View File
@@ -1,7 +1,7 @@
import torch
import gradio as gr
import diffusers
from modules import scripts_manager, processing, shared, images, video, sd_models, devices
from modules import scripts_manager, processing, shared, video, sd_models, devices
from modules.logger import log
+1 -1
View File
@@ -4,7 +4,7 @@ from PIL import Image, ImageDraw
from modules import images, devices, scripts_manager
from modules.processing import get_processed, process_images
from modules.shared import opts, state, log
from modules.images.grid import split_grid
from modules.image.grid import split_grid
class Script(scripts_manager.Script):
+1 -1
View File
@@ -5,7 +5,7 @@ from modules import processing, shared, images, devices, scripts_manager
from modules.processing import get_processed
from modules.shared import opts, state, log
from modules.image.util import flatten
from modules.images.grid import split_grid
from modules.image.grid import split_grid
class Script(scripts_manager.Script):
+1 -1
View File
@@ -7,7 +7,7 @@ TODO text2video items:
"""
import gradio as gr
from modules import scripts_manager, processing, shared, images, video, sd_models, modelloader
from modules import scripts_manager, processing, shared, video, sd_models, modelloader
from modules.logger import log
+1 -1
View File
@@ -1,7 +1,7 @@
import time
from copy import copy
from PIL import Image
from modues.images.grid import GridAnnotation
from modules.image.grid import GridAnnotation
from modules import shared, images, processing
from modules.logger import log
from modules.image.util import draw_text