From 35aa8c64227fb424a9379a480c7948e8039bbba0 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 2 Jun 2026 17:06:18 +0200 Subject: [PATCH] fix openpose and add test-compile Signed-off-by: Vladimir Mandic --- CHANGELOG.md | 1 + .../leres/pix2pix/options/base_options.py | 4 +- .../proc/segment_anything/utils/onnx.py | 2 +- .../models/base_models/midas_repo/hubconf.py | 6 +- .../midas_repo/midas/model_loader.py | 8 +- .../zoedepth/models/zoedepth/zoedepth_v1.py | 12 +- .../models/zoedepth_nk/zoedepth_nk_v1.py | 14 +- modules/control/units/xs_model.py | 16 +- package.json | 3 +- scripts/layerdiffuse/layerdiffuse_model.py | 5 +- scripts/mixture_tiling.py | 9 +- test/test-compile.py | 184 ++++++++++++++++++ 12 files changed, 215 insertions(+), 49 deletions(-) create mode 100644 test/test-compile.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c4045bf22..cd9b42b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,6 +115,7 @@ Plus continued work on modernization of codebase: UI is now fully TypeScript bas - `taesd` preview constant size with reduced layers - `output path` use correct base folder for initial folders - `ltx` prompt embeds move to device, thanks @ryanmeador + - `openpose` processor ## Update for 2026-05-13 diff --git a/modules/control/proc/leres/pix2pix/options/base_options.py b/modules/control/proc/leres/pix2pix/options/base_options.py index 63acea872..2a3a25dd4 100644 --- a/modules/control/proc/leres/pix2pix/options/base_options.py +++ b/modules/control/proc/leres/pix2pix/options/base_options.py @@ -1,8 +1,8 @@ import argparse import os -from proc.leres.pix2pix.util import util +from ..util import util # import torch -from proc.leres.pix2pix import models +from .. import models # import pix2pix.data import numpy as np diff --git a/modules/control/proc/segment_anything/utils/onnx.py b/modules/control/proc/segment_anything/utils/onnx.py index 4eaf0b89b..103867faf 100644 --- a/modules/control/proc/segment_anything/utils/onnx.py +++ b/modules/control/proc/segment_anything/utils/onnx.py @@ -10,7 +10,7 @@ from torch.nn import functional as F from typing import Tuple -from proc.segment_anything.modeling import Sam +from ..modeling import Sam from .amg import calculate_stability_score diff --git a/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/hubconf.py b/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/hubconf.py index 43291563d..e6f593e2d 100644 --- a/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/hubconf.py +++ b/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/hubconf.py @@ -2,9 +2,9 @@ dependencies = ["torch"] import torch -from midas.dpt_depth import DPTDepthModel -from midas.midas_net import MidasNet -from midas.midas_net_custom import MidasNet_small +from .midas.dpt_depth import DPTDepthModel +from .midas.midas_net import MidasNet +from .midas.midas_net_custom import MidasNet_small def DPT_BEiT_L_512(pretrained=True, **kwargs): """ # This docstring shows up in hub.help() diff --git a/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/midas/model_loader.py b/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/midas/model_loader.py index f2607d722..ea7dcbe05 100644 --- a/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/midas/model_loader.py +++ b/modules/control/proc/zoe/zoedepth/models/base_models/midas_repo/midas/model_loader.py @@ -1,10 +1,10 @@ import cv2 import torch -from midas.dpt_depth import DPTDepthModel -from midas.midas_net import MidasNet -from midas.midas_net_custom import MidasNet_small -from midas.transforms import Resize, NormalizeImage, PrepareForNet +from .dpt_depth import DPTDepthModel +from .midas_net import MidasNet +from .midas_net_custom import MidasNet_small +from .transforms import Resize, NormalizeImage, PrepareForNet from torchvision.transforms import Compose diff --git a/modules/control/proc/zoe/zoedepth/models/zoedepth/zoedepth_v1.py b/modules/control/proc/zoe/zoedepth/models/zoedepth/zoedepth_v1.py index b10afa59f..385eaf873 100644 --- a/modules/control/proc/zoe/zoedepth/models/zoedepth/zoedepth_v1.py +++ b/modules/control/proc/zoe/zoedepth/models/zoedepth/zoedepth_v1.py @@ -26,12 +26,12 @@ import itertools import torch import torch.nn as nn -from proc.zoe.zoedepth.models.depth_model import DepthModel -from proc.zoe.zoedepth.models.base_models.midas import MidasCore -from proc.zoe.zoedepth.models.layers.attractor import AttractorLayer, AttractorLayerUnnormed -from proc.zoe.zoedepth.models.layers.dist_layers import ConditionalLogBinomial -from proc.zoe.zoedepth.models.layers.localbins_layers import Projector, SeedBinRegressor, SeedBinRegressorUnnormed -from proc.zoe.zoedepth.models.model_io import load_state_from_resource +from ..depth_model import DepthModel +from ...base_models.midas import MidasCore +from ...layers.attractor import AttractorLayer, AttractorLayerUnnormed +from ...layers.dist_layers import ConditionalLogBinomial +from ...layers.localbins_layers import Projector, SeedBinRegressor, SeedBinRegressorUnnormed +from ...model_io import load_state_from_resource class ZoeDepth(DepthModel): diff --git a/modules/control/proc/zoe/zoedepth/models/zoedepth_nk/zoedepth_nk_v1.py b/modules/control/proc/zoe/zoedepth/models/zoedepth_nk/zoedepth_nk_v1.py index 52f427add..91e3ca72a 100644 --- a/modules/control/proc/zoe/zoedepth/models/zoedepth_nk/zoedepth_nk_v1.py +++ b/modules/control/proc/zoe/zoedepth/models/zoedepth_nk/zoedepth_nk_v1.py @@ -27,13 +27,13 @@ import itertools import torch import torch.nn as nn -from proc.zoe.zoedepth.models.depth_model import DepthModel -from proc.zoe.zoedepth.models.base_models.midas import MidasCore -from proc.zoe.zoedepth.models.layers.attractor import AttractorLayer, AttractorLayerUnnormed -from proc.zoe.zoedepth.models.layers.dist_layers import ConditionalLogBinomial -from proc.zoe.zoedepth.models.layers.localbins_layers import Projector, SeedBinRegressor, SeedBinRegressorUnnormed -from proc.zoe.zoedepth.models.layers.patch_transformer import PatchTransformerEncoder -from proc.zoe.zoedepth.models.model_io import load_state_from_resource +from ..depth_model import DepthModel +from ...base_models.midas import MidasCore +from ...layers.attractor import AttractorLayer, AttractorLayerUnnormed +from ...layers.dist_layers import ConditionalLogBinomial +from ...layers.localbins_layers import Projector, SeedBinRegressor, SeedBinRegressorUnnormed +from ...layers.patch_transformer import PatchTransformerEncoder +from ...model_io import load_state_from_resource class ZoeDepthNK(DepthModel): def __init__(self, core, bin_conf, bin_centers_type="softplus", bin_embedding_dim=128, diff --git a/modules/control/units/xs_model.py b/modules/control/units/xs_model.py index 9040d24a7..f21803d87 100644 --- a/modules/control/units/xs_model.py +++ b/modules/control/units/xs_model.py @@ -26,20 +26,8 @@ from diffusers.models.attention_processor import AttentionProcessor from diffusers.models.autoencoders import AutoencoderKL from diffusers.models.lora import LoRACompatibleConv from diffusers.models.modeling_utils import ModelMixin - -try: - from diffusers.models.unet_2d_blocks import CrossAttnDownBlock2D, CrossAttnUpBlock2D, DownBlock2D, Downsample2D, ResnetBlock2D, Transformer2DModel, UpBlock2D, Upsample2D # pylint: disable=no-name-in-module -except Exception: - pass -try: - from diffusers.models.unets.unet_2d_blocks import CrossAttnDownBlock2D, CrossAttnUpBlock2D, DownBlock2D, Downsample2D, ResnetBlock2D, Transformer2DModel, UpBlock2D, Upsample2D -except Exception: - pass - -try: - from diffusers.models.unet_2d_condition import UNet2DConditionModel -except Exception: - from diffusers.models.unets.unet_2d_condition import UNet2DConditionModel +from diffusers.models.unets.unet_2d_blocks import CrossAttnDownBlock2D, CrossAttnUpBlock2D, DownBlock2D, Downsample2D, ResnetBlock2D, Transformer2DModel, UpBlock2D, Upsample2D +from diffusers.models.unets.unet_2d_condition import UNet2DConditionModel from diffusers.utils import BaseOutput, logging, USE_PEFT_BACKEND diff --git a/package.json b/package.json index c204ffe47..f1613de03 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "ruff": ". venv/bin/activate && ruff check", "pylint": ". venv/bin/activate && pylint *.py modules/ pipelines/ scripts/ extensions-builtin/ | grep -v '^*'", "pyright": ". venv/bin/activate && pyright --threads 4", - "ty": ". venv/bin/activate && ty check --force-exclude" + "ty": ". venv/bin/activate && ty check --force-exclude", + "compile": ". venv/bin/activate && python test/test-compile.py" }, "devDependencies": { "@eslint/compat": "^2.1.0", diff --git a/scripts/layerdiffuse/layerdiffuse_model.py b/scripts/layerdiffuse/layerdiffuse_model.py index 87de86672..6eebb8a20 100644 --- a/scripts/layerdiffuse/layerdiffuse_model.py +++ b/scripts/layerdiffuse/layerdiffuse_model.py @@ -11,10 +11,7 @@ from diffusers.configuration_utils import ConfigMixin, register_to_config from diffusers.models.modeling_utils import ModelMixin from diffusers.models.autoencoders.vae import DecoderOutput from diffusers.models.attention_processor import Attention, AttnProcessor -try: - from diffusers.models.unet_2d_blocks import UNetMidBlock2D, get_down_block, get_up_block -except Exception: - from diffusers.models.unets.unet_2d_blocks import UNetMidBlock2D, get_down_block, get_up_block +from diffusers.models.unets.unet_2d_blocks import UNetMidBlock2D, get_down_block, get_up_block def zero_module(module): diff --git a/scripts/mixture_tiling.py b/scripts/mixture_tiling.py index fcf7b7cf1..eefd4a819 100644 --- a/scripts/mixture_tiling.py +++ b/scripts/mixture_tiling.py @@ -9,13 +9,8 @@ checked_ok = False def check_dependencies(): global checked_ok # pylint: disable=global-statement - from installer import installed, install - packages = [ - ('ligo-segments', 'ligo-segments'), - ] - for pkg in packages: - if not installed(pkg[1], quiet=True): - install(pkg[0], pkg[1], ignore=False) + from installer import install + install('ligo-segments') try: from ligo.segments import segment # pylint: disable=unused-import checked_ok = True diff --git a/test/test-compile.py b/test/test-compile.py new file mode 100644 index 000000000..5f44b7ec8 --- /dev/null +++ b/test/test-compile.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 + +import io +import os +import sys +import ast +import logging +import contextlib +import py_compile +import importlib.util +import importlib.machinery +from pathlib import Path + + +includes = [ + { 'folder': '.', 'recursive': False, 'includes': True }, + { 'folder': 'pipelines', 'recursive': True, 'includes': True }, + { 'folder': 'modules', 'recursive': True, 'includes': False }, + { 'folder': 'scripts', 'recursive': True, 'local': True, 'includes': False }, +] +excludes = [ + 'node_modules', + '__pycache__', +] +ignores = [ + 'torch_directml', + 'intel_extension_for_pytorch', + 'torch_xla.core.xla_model', + 'flash_attn', + 'flash_attn_interface', + 'openai', + 'rembg', + 'controlnet_aux', + 'image_gen_aux', + 'torchsde', + 'ligo.segments', + 'torchdiffeq', + 'insightface', + 'pynvml', +] +output = '/tmp/pycompile' +root = Path('.') + + +def test_compile(folder: str, recursive: bool): + stats = { 'ok': [], 'failed': [], 'errors': [] } + for entry in os.scandir(folder): + if not any(exclude in entry.path for exclude in excludes) and not entry.name.startswith('.'): + if entry.is_file() and entry.name.endswith('.py'): + try: + cfile = os.path.join(output, os.path.relpath(entry.path, start='.')) + 'c' + py_compile.compile(entry.path, cfile=cfile, doraise=True) + stats['ok'].append(entry.path) + except Exception as e: + print(f'fail: file={entry.path} error={e}') + stats['failed'].append(entry.path) + stats['errors'].append(str(e)) + elif entry.is_dir() and recursive: + nested_stats = test_compile(entry.path, recursive) + stats['ok'].extend(nested_stats['ok']) + stats['failed'].extend(nested_stats['failed']) + stats['errors'].extend(nested_stats['errors']) + if len(stats["ok"]) > 0 or len(stats["failed"]) > 0: + print(f'Compile: folder={folder} ok={len(stats["ok"])} failed={len(stats["failed"])}') + return stats + + +def list_imports(path: Path): + imports = [] + tree = ast.parse(path.read_text(encoding='utf-8'), filename=str(path)) + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + imports.append((alias.name, 0, path)) + elif isinstance(node, ast.ImportFrom): + module = node.module + if node.level > 0: + if module: + imports.append((module, node.level, path)) + else: + for alias in node.names: + if alias.name != '*': + imports.append((alias.name, node.level, path)) + elif module: + imports.append((module, 0, path)) + return imports + + +def find_import(module: str | None, level: int, path: Path): + package_parts = path.relative_to(root).with_suffix('').parts + package_parts = package_parts[:-1] + if level > len(package_parts) + 1: + return None + if level == 0: + base = list(package_parts) + else: + base = list(package_parts[: -level + 1]) if level > 1 else list(package_parts) + if module: + base.extend(module.split('.')) + return '.'.join(base) if base else None + + +def local_import(path: Path) -> bool: # modules that modify sys.path to allow local imports + text = path.read_text(encoding='utf-8') + return 'sys.path.append' in text or 'sys.path.insert' in text + + +def install_import(path: Path, module_name: str): # modules that install packages at runtime and import them + text = path.read_text(encoding='utf-8') + if f'install("{module_name}' in text or f'install(\'{module_name}' in text: + return True + return False + + +def test_import(module: str | None, level: int, path: Path, local: bool = False): + module_name = find_import(module, level, path) if level > 0 else module + if not module_name: + return True + old_disable = logging.root.manager.disable + error = None + try: + logging.disable(logging.CRITICAL) + if install_import(path, module_name): + return True + with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()): + try: + spec = importlib.util.find_spec(module_name) + except ModuleNotFoundError as e: + spec = None + error = e + if spec is not None: + return True + if local or local_import(path): + for extra in [str(path.parent.parent), str(path.parent)]: + spec = importlib.machinery.PathFinder.find_spec(module_name, [extra] + sys.path) + if spec is not None: + return True + if error is not None and any(ignore in str(error) for ignore in ignores): + return True + return False + except Exception as e: + if any(ignore in str(e) for ignore in ignores): + return True + return False + finally: + logging.disable(old_disable) + + +def verify_imports(folder: str, recursive: bool, local: bool = False): + stats = { 'ok': [], 'failed': [] } + for entry in os.scandir(folder): + if not any(exclude in entry.path for exclude in excludes) and not entry.name.startswith('.'): + if entry.is_file() and entry.name.endswith('.py'): + file_path = Path(entry.path) + has_failure = False + for module, level, _path in list_imports(file_path): + if module in ignores: + continue + if not test_import(module, level, file_path, local): + stats['failed'].append(f'{entry.path}: module={module} level={level}') + has_failure = True + if not has_failure: + stats['ok'].append(entry.path) + elif entry.is_dir() and recursive: + nested_stats = verify_imports(entry.path, recursive) + stats['ok'].extend(nested_stats['ok']) + stats['failed'].extend(nested_stats['failed']) + if len(stats['ok']) > 0 or len(stats['failed']) > 0: + print(f'Imports: folder={folder} ok={len(stats["ok"])} failed={len(stats["failed"])}') + if len(stats['failed']) > 0: + for fail in stats['failed']: + print(f' {fail}') + return stats + + +if __name__ == '__main__': + os.makedirs(output, exist_ok=True) + sys.path.insert(0, str(root)) + sys.path.insert(0, str(root / 'modules' / 'control')) + for item in includes: + print(f"Test {item['folder']}") + test_compile(item['folder'], item['recursive']) + if item.get('includes', False): + verify_imports(item['folder'], item.get('recursive', False), item.get('local', False))