horde-engine 3.1.2__tar.gz → 3.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. {horde_engine-3.1.2 → horde_engine-3.2.2}/PKG-INFO +16 -11
  2. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/_version.py +2 -2
  3. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/api.py +22 -0
  4. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/comfy_horde.py +4 -5
  5. horde_engine-3.2.2/hordelib/feature_requirements.py +115 -0
  6. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/installation/installer.py +17 -9
  7. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/__init__.py +2 -1
  8. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/realesrgan_utils.py +2 -1
  9. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/preload.py +22 -0
  10. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/gpuinfo.py +12 -6
  11. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/image_utils.py +7 -1
  12. horde_engine-3.2.2/hordelib/utils/optional_deps.py +74 -0
  13. horde_engine-3.2.2/hordelib/utils/torch_memory.py +278 -0
  14. {horde_engine-3.1.2 → horde_engine-3.2.2}/pyproject.toml +44 -15
  15. horde_engine-3.1.2/hordelib/utils/torch_memory.py +0 -63
  16. {horde_engine-3.1.2 → horde_engine-3.2.2}/.gitignore +0 -0
  17. {horde_engine-3.1.2 → horde_engine-3.2.2}/LICENSE +0 -0
  18. {horde_engine-3.1.2 → horde_engine-3.2.2}/README.md +0 -0
  19. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/__init__.py +0 -0
  20. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/__pyinstaller.py +0 -0
  21. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/benchmark.py +0 -0
  22. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/beta_models.py +0 -0
  23. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/config_path.py +0 -0
  24. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/consts.py +0 -0
  25. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/exceptions.py +0 -0
  26. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/__init__.py +0 -0
  27. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/comfy_patches.py +0 -0
  28. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/graph_utils.py +0 -0
  29. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/in_process.py +0 -0
  30. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/interface.py +0 -0
  31. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/phase_timing.py +0 -0
  32. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/progress_hook.py +0 -0
  33. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/execution/sampling_lease.py +0 -0
  34. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/feature_impact.py +0 -0
  35. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/horde.py +0 -0
  36. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/initialisation.py +0 -0
  37. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/installation/__init__.py +0 -0
  38. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/installation/__main__.py +0 -0
  39. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/installation/manifest.json +0 -0
  40. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/installation/manifest.py +0 -0
  41. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/integrations/__init__.py +0 -0
  42. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/integrations/logfire_comfy_internals.py +0 -0
  43. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/integrations/logfire_setup.py +0 -0
  44. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/metrics.py +0 -0
  45. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_database/db_dep.json +0 -0
  46. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_database/db_embeds.json +0 -0
  47. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_database/diffusers.json +0 -0
  48. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_database/med_config.json +0 -0
  49. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/__init__.py +0 -0
  50. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/base.py +0 -0
  51. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/civitai_adhoc.py +0 -0
  52. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/civitai_provider.py +0 -0
  53. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/civitai_records.py +0 -0
  54. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/codeformer.py +0 -0
  55. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/compvis.py +0 -0
  56. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/controlnet.py +0 -0
  57. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/diffusers.py +0 -0
  58. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/esrgan.py +0 -0
  59. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/gfpgan.py +0 -0
  60. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/hyper.py +0 -0
  61. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/lora.py +0 -0
  62. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/miscellaneous.py +0 -0
  63. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/safety_checker.py +0 -0
  64. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/model_manager/ti.py +0 -0
  65. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/__init__.py +0 -0
  66. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/LICENSE +0 -0
  67. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/README.md +0 -0
  68. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/__init__.py +0 -0
  69. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_cond_example.json +0 -0
  70. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_cond_fg_all.json +0 -0
  71. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_cond_joint_bg.json +0 -0
  72. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_cond_joint_fg.json +0 -0
  73. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_diff_bg.json +0 -0
  74. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_diff_bg_stop_at.json +0 -0
  75. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_diff_fg.json +0 -0
  76. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_fg_example.json +0 -0
  77. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_fg_example_rgba.json +0 -0
  78. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/examples/layer_diffusion_joint.json +0 -0
  79. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/layered_diffusion.py +0 -0
  80. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/lib_layerdiffusion/__init__.py +0 -0
  81. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/lib_layerdiffusion/attention_sharing.py +0 -0
  82. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/lib_layerdiffusion/enums.py +0 -0
  83. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/lib_layerdiffusion/models.py +0 -0
  84. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/lib_layerdiffusion/utils.py +0 -0
  85. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/pyproject.toml +0 -0
  86. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/comfyui_layerdiffuse/requirements.txt +0 -0
  87. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/LICENSE +0 -0
  88. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/README.md +0 -0
  89. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/VERSION +0 -0
  90. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/__init__.py +0 -0
  91. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/archs/__init__.py +0 -0
  92. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/archs/arcface_arch.py +0 -0
  93. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/archs/arch_util.py +0 -0
  94. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/archs/codeformer_arch.py +0 -0
  95. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/archs/rrdbnet_arch.py +0 -0
  96. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/archs/vgg_arch.py +0 -0
  97. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/archs/vqgan_arch.py +0 -0
  98. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/data/__init__.py +0 -0
  99. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/data/data_sampler.py +0 -0
  100. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/data/data_util.py +0 -0
  101. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/data/prefetch_dataloader.py +0 -0
  102. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/data/transforms.py +0 -0
  103. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/losses/__init__.py +0 -0
  104. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/losses/loss_util.py +0 -0
  105. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/losses/losses.py +0 -0
  106. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/metrics/__init__.py +0 -0
  107. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/metrics/metric_util.py +0 -0
  108. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/metrics/psnr_ssim.py +0 -0
  109. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/models/__init__.py +0 -0
  110. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/__init__.py +0 -0
  111. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/dcn/__init__.py +0 -0
  112. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/dcn/deform_conv.py +0 -0
  113. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/dcn/src/deform_conv_cuda.cpp +0 -0
  114. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/dcn/src/deform_conv_cuda_kernel.cu +0 -0
  115. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/dcn/src/deform_conv_ext.cpp +0 -0
  116. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/fused_act/__init__.py +0 -0
  117. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/fused_act/fused_act.py +0 -0
  118. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/fused_act/src/fused_bias_act.cpp +0 -0
  119. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/fused_act/src/fused_bias_act_kernel.cu +0 -0
  120. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/upfirdn2d/__init__.py +0 -0
  121. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/upfirdn2d/src/upfirdn2d.cpp +0 -0
  122. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/upfirdn2d/src/upfirdn2d_kernel.cu +0 -0
  123. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/ops/upfirdn2d/upfirdn2d.py +0 -0
  124. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/setup.py +0 -0
  125. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/train.py +0 -0
  126. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/__init__.py +0 -0
  127. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/dist_util.py +0 -0
  128. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/download_util.py +0 -0
  129. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/file_client.py +0 -0
  130. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/img_util.py +0 -0
  131. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/lmdb_util.py +0 -0
  132. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/logger.py +0 -0
  133. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/matlab_functions.py +0 -0
  134. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/misc.py +0 -0
  135. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/options.py +0 -0
  136. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/utils/registry.py +0 -0
  137. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/basicsr/version.py +0 -0
  138. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/__init__.py +0 -0
  139. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/__init__.py +0 -0
  140. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/align_trans.py +0 -0
  141. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/matlab_cp2tform.py +0 -0
  142. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/retinaface/retinaface.py +0 -0
  143. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/retinaface/retinaface_net.py +0 -0
  144. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/retinaface/retinaface_utils.py +0 -0
  145. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/__init__.py +0 -0
  146. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/face_detector.py +0 -0
  147. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/models/__init__.py +0 -0
  148. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/models/common.py +0 -0
  149. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/models/experimental.py +0 -0
  150. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/models/yolo.py +0 -0
  151. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/models/yolov5l.yaml +0 -0
  152. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/models/yolov5n.yaml +0 -0
  153. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/utils/__init__.py +0 -0
  154. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/utils/autoanchor.py +0 -0
  155. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/utils/datasets.py +0 -0
  156. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/utils/extract_ckpt.py +0 -0
  157. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/utils/general.py +0 -0
  158. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/detection/yolov5face/utils/torch_utils.py +0 -0
  159. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/parsing/__init__.py +0 -0
  160. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/parsing/bisenet.py +0 -0
  161. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/parsing/parsenet.py +0 -0
  162. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/parsing/resnet.py +0 -0
  163. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/utils/__init__.py +0 -0
  164. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/utils/face_restoration_helper.py +0 -0
  165. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/utils/face_utils.py +0 -0
  166. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/facelib/utils/misc.py +0 -0
  167. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/r_chainner/README.md +0 -0
  168. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/r_chainner/__init__.py +0 -0
  169. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/r_chainner/gfpganv1_clean_arch.py +0 -0
  170. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/r_chainner/model_loading.py +0 -0
  171. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/r_chainner/stylegan2_clean_arch.py +0 -0
  172. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/facerestore_cf/r_chainner/types.py +0 -0
  173. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/node_controlnet_model_loader.py +0 -0
  174. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/node_image_loader.py +0 -0
  175. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/node_image_output.py +0 -0
  176. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/node_lora_loader.py +0 -0
  177. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/node_model_loader.py +0 -0
  178. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/nodes/node_upscale_model_loader.py +0 -0
  179. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/__init__.py +0 -0
  180. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/constants.py +0 -0
  181. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/context.py +0 -0
  182. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/families/__init__.py +0 -0
  183. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/families/image.py +0 -0
  184. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/families/post_processing.py +0 -0
  185. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/graph.py +0 -0
  186. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/horde_compat.py +0 -0
  187. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/patches.py +0 -0
  188. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/payload.py +0 -0
  189. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/payload_pp.py +0 -0
  190. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/registry.py +0 -0
  191. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/resolution.py +0 -0
  192. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline/template.py +0 -0
  193. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_controlnet.json +0 -0
  194. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_controlnet_annotator.json +0 -0
  195. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_controlnet_hires_fix.json +0 -0
  196. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_flux.json +0 -0
  197. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_image_facefix.json +0 -0
  198. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_image_upscale.json +0 -0
  199. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_qr_code.json +0 -0
  200. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_qwen.json +0 -0
  201. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_stable_cascade.json +0 -0
  202. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_stable_cascade_2pass.json +0 -0
  203. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_stable_cascade_remix.json +0 -0
  204. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_stable_diffusion.json +0 -0
  205. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_stable_diffusion_hires_fix.json +0 -0
  206. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_stable_diffusion_img2img_mask.json +0 -0
  207. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipeline_designs/pipeline_stable_diffusion_paint.json +0 -0
  208. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_controlnet.json +0 -0
  209. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_controlnet_annotator.json +0 -0
  210. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_controlnet_hires_fix.json +0 -0
  211. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_flux.json +0 -0
  212. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_image_facefix.json +0 -0
  213. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_image_upscale.json +0 -0
  214. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_qr_code.json +0 -0
  215. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_qwen.json +0 -0
  216. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_stable_cascade.json +0 -0
  217. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_stable_cascade_2pass.json +0 -0
  218. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_stable_cascade_remix.json +0 -0
  219. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_stable_diffusion.json +0 -0
  220. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_stable_diffusion_hires_fix.json +0 -0
  221. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_stable_diffusion_img2img_mask.json +0 -0
  222. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pipelines/pipeline_stable_diffusion_paint.json +0 -0
  223. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/py.typed +0 -0
  224. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pyinstaller_hooks/__init__.py +0 -0
  225. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/pyinstaller_hooks/hook-hordelib.horde.py +0 -0
  226. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/safety.py +0 -0
  227. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/safety_checker.py +0 -0
  228. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/settings.py +0 -0
  229. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/shared_model_manager.py +0 -0
  230. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/train.py +0 -0
  231. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/__init__.py +0 -0
  232. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/distance.py +0 -0
  233. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/dynamicprompt.py +0 -0
  234. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/ioredirect.py +0 -0
  235. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/logger.py +0 -0
  236. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/sanitizer.py +0 -0
  237. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/switch.py +0 -0
  238. {horde_engine-3.1.2 → horde_engine-3.2.2}/hordelib/utils/torch_build.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: horde-engine
3
- Version: 3.1.2
3
+ Version: 3.2.2
4
4
  Summary: A wrapper around ComfyUI to allow use by AI Horde.
5
5
  Project-URL: Homepage, https://github.com/Haidra-Org/hordelib
6
6
  Project-URL: Bug Tracker, https://github.com/Haidra-Org/hordelib/issues
@@ -679,17 +679,15 @@ Requires-Dist: aiohttp>=3.11.8
679
679
  Requires-Dist: alembic
680
680
  Requires-Dist: av>=16.0.0
681
681
  Requires-Dist: blake3
682
- Requires-Dist: clip-anytorch>=2.6.0
683
682
  Requires-Dist: comfy-aimdo==0.4.9
684
683
  Requires-Dist: comfy-kitchen==0.2.10
685
684
  Requires-Dist: comfyui-embedded-docs==0.5.3
686
685
  Requires-Dist: comfyui-frontend-package==1.45.15
687
686
  Requires-Dist: comfyui-workflow-templates==0.9.98
688
- Requires-Dist: diffusers>=0.25.0
689
687
  Requires-Dist: distro>=1.9.0
690
688
  Requires-Dist: einops
691
- Requires-Dist: fairscale>=0.4.13
692
689
  Requires-Dist: filelock
690
+ Requires-Dist: ftfy
693
691
  Requires-Dist: fuzzywuzzy>=0.18.0
694
692
  Requires-Dist: gitpython>=3.1.45
695
693
  Requires-Dist: horde-model-reference<6.0.0,>=5.1.1
@@ -697,11 +695,9 @@ Requires-Dist: horde-sdk>=0.20.1
697
695
  Requires-Dist: kornia>=0.7.1
698
696
  Requires-Dist: logfire[system-metrics]==4.14.2
699
697
  Requires-Dist: loguru>=0.7.3
700
- Requires-Dist: lpips>=0.1.4
701
698
  Requires-Dist: matplotlib>=3.10.9
702
699
  Requires-Dist: numpy>=1.25.0
703
700
  Requires-Dist: omegaconf>=2.3.0
704
- Requires-Dist: open-clip-torch>=2.32.0
705
701
  Requires-Dist: opencv-contrib-python>=4.11.0.86
706
702
  Requires-Dist: opencv-python>=4.11.0.86
707
703
  Requires-Dist: opentelemetry-instrumentation-aiohttp-client>=0.59b0
@@ -712,22 +708,17 @@ Requires-Dist: pydantic-settings~=2.0
712
708
  Requires-Dist: pydantic~=2.0
713
709
  Requires-Dist: pynvml>=13.0.1
714
710
  Requires-Dist: python-dotenv>=1.2.1
715
- Requires-Dist: pytorch-lightning>=2.5.6
716
711
  Requires-Dist: pyyaml
717
712
  Requires-Dist: qrcode==7.4.2
718
- Requires-Dist: rembg[cpu]>=2.0.67
719
713
  Requires-Dist: requests
720
714
  Requires-Dist: safetensors>=0.4.2
721
715
  Requires-Dist: scikit-image>=0.25.2
722
716
  Requires-Dist: scipy
723
717
  Requires-Dist: sentencepiece
724
718
  Requires-Dist: simpleeval>=1.0.0
725
- Requires-Dist: soundfile>=0.13.1
726
- Requires-Dist: spandrel-extra-arches>=0.2.0
727
719
  Requires-Dist: spandrel>=0.4.1
728
720
  Requires-Dist: sqlalchemy>=2.0.0
729
721
  Requires-Dist: strenum>=0.4.15
730
- Requires-Dist: timm==0.9.16
731
722
  Requires-Dist: tokenizers>=0.13.3
732
723
  Requires-Dist: torchdiffeq>=0.2.5
733
724
  Requires-Dist: torchsde
@@ -738,6 +729,14 @@ Requires-Dist: typing-extensions>=4.15.0
738
729
  Requires-Dist: unidecode>=1.4.0
739
730
  Requires-Dist: yapf>=0.43.0
740
731
  Requires-Dist: yarl>=1.18.0
732
+ Provides-Extra: controlnet
733
+ Requires-Dist: albumentations; extra == 'controlnet'
734
+ Requires-Dist: fvcore; extra == 'controlnet'
735
+ Requires-Dist: mediapipe>=0.10; extra == 'controlnet'
736
+ Requires-Dist: onnxruntime>=1.16; extra == 'controlnet'
737
+ Requires-Dist: scikit-learn; extra == 'controlnet'
738
+ Requires-Dist: trimesh[easy]; extra == 'controlnet'
739
+ Requires-Dist: yacs; extra == 'controlnet'
741
740
  Provides-Extra: cpu
742
741
  Requires-Dist: torch; extra == 'cpu'
743
742
  Requires-Dist: torchvision; extra == 'cpu'
@@ -750,6 +749,12 @@ Requires-Dist: torchvision; extra == 'cu130'
750
749
  Provides-Extra: cu132
751
750
  Requires-Dist: torch; extra == 'cu132'
752
751
  Requires-Dist: torchvision; extra == 'cu132'
752
+ Provides-Extra: layerdiffuse
753
+ Requires-Dist: diffusers>=0.25.0; extra == 'layerdiffuse'
754
+ Provides-Extra: rembg
755
+ Requires-Dist: rembg[cpu]>=2.0.67; extra == 'rembg'
756
+ Provides-Extra: upscale-extra
757
+ Requires-Dist: spandrel-extra-arches>=0.2.0; extra == 'upscale-extra'
753
758
  Description-Content-Type: text/markdown
754
759
 
755
760
  # horde-engine
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '3.1.2'
22
- __version_tuple__ = version_tuple = (3, 1, 2)
21
+ __version__ = version = '3.2.2'
22
+ __version_tuple__ = version_tuple = (3, 2, 2)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -31,6 +31,14 @@ from hordelib.feature_impact import (
31
31
  get_baseline_burden,
32
32
  get_feature_impact_registry,
33
33
  )
34
+ from hordelib.feature_requirements import (
35
+ FeatureRequirement,
36
+ available_features,
37
+ feature_available,
38
+ get_feature_requirement,
39
+ get_feature_requirement_registry,
40
+ missing_packages,
41
+ )
34
42
  from hordelib.horde import (
35
43
  HordeLib,
36
44
  ProgressReport,
@@ -58,6 +66,10 @@ from hordelib.shared_model_manager import SharedModelManager
58
66
  from hordelib.utils.ioredirect import ComfyUIProgress, ComfyUIProgressUnit
59
67
  from hordelib.utils.logger import HordeLog
60
68
  from hordelib.utils.torch_memory import (
69
+ AcceleratorInfo,
70
+ AcceleratorKind,
71
+ clear_accelerator_cache,
72
+ enumerate_accelerators,
61
73
  get_free_ram_mb,
62
74
  get_torch_free_vram_mb,
63
75
  get_torch_total_vram_mb,
@@ -66,6 +78,8 @@ from hordelib.utils.torch_memory import (
66
78
 
67
79
  __all__ = [
68
80
  "FEATURE_KIND",
81
+ "AcceleratorInfo",
82
+ "AcceleratorKind",
69
83
  "BaselineBurden",
70
84
  "BurdenEstimate",
71
85
  "CalibrationSample",
@@ -75,6 +89,7 @@ __all__ = [
75
89
  "DownloadTrigger",
76
90
  "FeatureImpact",
77
91
  "FeatureImpactRegistry",
92
+ "FeatureRequirement",
78
93
  "ExecutionBackend",
79
94
  "FacefixPayload",
80
95
  "HordeLib",
@@ -96,10 +111,17 @@ __all__ = [
96
111
  "StripBackgroundPayload",
97
112
  "UpscalePayload",
98
113
  "VRAMStats",
114
+ "available_features",
99
115
  "classify_post_processor",
116
+ "clear_accelerator_cache",
117
+ "enumerate_accelerators",
100
118
  "estimate_job_burden",
119
+ "feature_available",
101
120
  "get_baseline_burden",
102
121
  "get_feature_impact_registry",
122
+ "get_feature_requirement",
123
+ "get_feature_requirement_registry",
124
+ "missing_packages",
103
125
  "get_free_ram_mb",
104
126
  "get_metrics_collector",
105
127
  "get_torch_free_vram_mb",
@@ -32,6 +32,7 @@ from hordelib.utils.ioredirect import ComfyUIProgress, OutputCollector
32
32
  from hordelib.config_path import get_hordelib_path
33
33
  from hordelib.execution import comfy_patches
34
34
  from hordelib.execution.graph_utils import GraphDict
35
+ from hordelib.utils.torch_memory import clear_accelerator_cache
35
36
 
36
37
  # Note It may not be abundantly clear with no context what is going on below, and I will attempt to clarify:
37
38
  #
@@ -374,11 +375,9 @@ def do_comfy_import(
374
375
 
375
376
 
376
377
  def clear_gc_and_torch_cache() -> None:
377
- """Clear the garbage collector and the PyTorch cache."""
378
+ """Clear the garbage collector and the active backend's device cache."""
378
379
  gc.collect()
379
- from torch.cuda import empty_cache
380
-
381
- empty_cache()
380
+ clear_accelerator_cache()
382
381
 
383
382
 
384
383
  def pin_models_in_vram() -> bool:
@@ -1079,7 +1078,7 @@ class Comfy_Horde:
1079
1078
  _mc.record_phase("pipeline_validate", _validate_seconds)
1080
1079
  _mc.record_phase("pipeline_execute", _execute_seconds)
1081
1080
  _mc.record_phase("pipeline_finalize", time.perf_counter() - _t_post_execute)
1082
- except Exception: # noqa: BLE001 - instrumentation must never break a run
1081
+ except Exception:
1083
1082
  pass
1084
1083
 
1085
1084
  # Record pipeline duration
@@ -0,0 +1,115 @@
1
+ """Which optional features are actually installable in this environment.
2
+
3
+ Some hordelib features depend on heavy, platform-constrained native packages that are not
4
+ part of the lean base install (they have no wheels for some accelerators, e.g. Intel XPU /
5
+ Apple MPS / Ascend, so forcing them into base would block a base install there). Those
6
+ packages live in ``horde-engine`` feature extras (see ``[project.optional-dependencies]``)
7
+ and the feature's call site guards its import via :mod:`hordelib.utils.optional_deps`.
8
+
9
+ This module is the single, typed source of truth mapping each such feature to the extra and
10
+ the import-names that back it, plus a runtime probe (:func:`feature_available`) so a consumer
11
+ (notably the worker) can decide what to advertise *before* a job arrives rather than failing
12
+ mid-job. It is the one place to edit when ComfyUI's (or a node's) backend support changes.
13
+
14
+ Features with no entry here have no optional dependency and are always considered available
15
+ (core inference, the safety classifier, ESRGAN upscalers and the CodeFormer/GFPGAN face
16
+ fixers are all pure PyTorch and run on every backend). Detection only: this module never
17
+ installs anything; extras are resolved at lock/sync time by the packaging tool.
18
+
19
+ This module is comfy-free and import-safe before ``hordelib.initialise()``; it is part of the
20
+ public API surface re-exported from :mod:`hordelib.api`.
21
+ """
22
+
23
+ import importlib.util
24
+
25
+ from pydantic import BaseModel
26
+
27
+ from hordelib.feature_impact import FEATURE_KIND
28
+
29
+ __all__ = [
30
+ "FeatureRequirement",
31
+ "available_features",
32
+ "feature_available",
33
+ "get_feature_requirement",
34
+ "get_feature_requirement_registry",
35
+ "missing_packages",
36
+ ]
37
+
38
+
39
+ class FeatureRequirement(BaseModel):
40
+ """The optional packages one feature needs, and the extra that provides them."""
41
+
42
+ feature: FEATURE_KIND
43
+ packages: tuple[str, ...]
44
+ """Top-level import names that must ALL be importable for the feature to be available."""
45
+ extra: str
46
+ """The ``horde-engine`` extra that installs ``packages`` (e.g. ``rembg`` -> ``[rembg]``)."""
47
+ label: str
48
+ """Human-readable feature name, used in "install this extra" messages."""
49
+
50
+
51
+ # Only the backend-constrained features appear here. controlnet gates on onnxruntime alone: of the
52
+ # preprocessors hordelib exposes as horde control_types (CONTROLNET_IMAGE_PREPROCESSOR_MAP), only
53
+ # Openpose (DWPose) needs a blocker dep, and that dep is onnxruntime. mediapipe backs only
54
+ # mediapipe_face / mesh_graphormer, which are not horde control_types, so it is shipped in the
55
+ # `controlnet` extra for node parity but is not required to serve controlnet jobs.
56
+ _REQUIREMENT_SEEDS: list[FeatureRequirement] = [
57
+ FeatureRequirement(
58
+ feature=FEATURE_KIND.strip_background,
59
+ packages=("rembg",),
60
+ extra="rembg",
61
+ label="strip_background (background removal)",
62
+ ),
63
+ FeatureRequirement(
64
+ feature=FEATURE_KIND.controlnet,
65
+ packages=("onnxruntime",),
66
+ extra="controlnet",
67
+ label="controlnet preprocessing (annotators)",
68
+ ),
69
+ ]
70
+
71
+ _REGISTRY: dict[FEATURE_KIND, FeatureRequirement] = {req.feature: req for req in _REQUIREMENT_SEEDS}
72
+
73
+
74
+ def _is_importable(package: str) -> bool:
75
+ """Return whether *package* can be found in the environment, never raising.
76
+
77
+ ``find_spec`` can raise (e.g. ``ModuleNotFoundError`` for a missing parent, or ``ValueError``)
78
+ rather than returning ``None``; for a capability probe any failure means "not available".
79
+ """
80
+ try:
81
+ return importlib.util.find_spec(package) is not None
82
+ except (ImportError, ValueError):
83
+ return False
84
+
85
+
86
+ def get_feature_requirement_registry() -> dict[FEATURE_KIND, FeatureRequirement]:
87
+ """Return the mapping of features to their optional-dependency requirements."""
88
+ return _REGISTRY
89
+
90
+
91
+ def get_feature_requirement(feature: FEATURE_KIND) -> FeatureRequirement | None:
92
+ """Return the requirement for *feature*, or None when it has no optional dependency."""
93
+ return _REGISTRY.get(feature)
94
+
95
+
96
+ def missing_packages(feature: FEATURE_KIND) -> tuple[str, ...]:
97
+ """Return the requirement's packages that are not importable (empty when all present)."""
98
+ requirement = _REGISTRY.get(feature)
99
+ if requirement is None:
100
+ return ()
101
+ return tuple(package for package in requirement.packages if not _is_importable(package))
102
+
103
+
104
+ def feature_available(feature: FEATURE_KIND) -> bool:
105
+ """Return whether *feature* can run here.
106
+
107
+ A feature with no requirement entry is always available; otherwise every package its
108
+ requirement names must be importable.
109
+ """
110
+ return not missing_packages(feature)
111
+
112
+
113
+ def available_features() -> set[FEATURE_KIND]:
114
+ """Return the set of features runnable in this environment (always-available ones included)."""
115
+ return {feature for feature in FEATURE_KIND if feature_available(feature)}
@@ -24,16 +24,24 @@ def _run_git(args: list[str], cwd: Path) -> str:
24
24
  """Run a git command, returning stripped stdout.
25
25
 
26
26
  Raises:
27
- GitCommandError: If git exits non-zero.
27
+ GitCommandError: If git is not installed/on PATH, or exits non-zero.
28
28
  """
29
- result = subprocess.run(
30
- ["git", *args],
31
- cwd=str(cwd),
32
- text=True,
33
- capture_output=True,
34
- encoding="utf-8",
35
- errors="replace",
36
- )
29
+ try:
30
+ result = subprocess.run(
31
+ ["git", *args],
32
+ cwd=str(cwd),
33
+ text=True,
34
+ capture_output=True,
35
+ encoding="utf-8",
36
+ errors="replace",
37
+ )
38
+ except FileNotFoundError as exc:
39
+ # A bare-name "git" that the OS cannot find raises FileNotFoundError, not a non-zero exit. Turn it
40
+ # into the same actionable error all callers already handle, naming why git is needed.
41
+ raise GitCommandError(
42
+ "git was not found on PATH. hordelib needs git to fetch and pin ComfyUI and its custom nodes; "
43
+ "install git (https://git-scm.com/downloads) and make sure it is on PATH, then retry.",
44
+ ) from exc
37
45
  if result.returncode != 0:
38
46
  raise GitCommandError(f"git {' '.join(args)} failed in {cwd}: {result.stderr.strip()}")
39
47
  return result.stdout.strip()
@@ -175,7 +175,8 @@ class FaceRestoreCFWithModel:
175
175
  output = facerestore_model(cropped_face_t, w=codeformer_fidelity)[0]
176
176
  restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))
177
177
  del output
178
- torch.cuda.empty_cache()
178
+ if torch.cuda.is_available():
179
+ torch.cuda.empty_cache()
179
180
  except Exception as error:
180
181
  print(f"\tFailed inference for CodeFormer: {error}", file=sys.stderr)
181
182
  restored_face = tensor2img(cropped_face_t, rgb2bgr=True, min_max=(-1, 1))
@@ -221,7 +221,8 @@ class RealESRGANer:
221
221
  if img_mode == "L":
222
222
  output_img = cv2.cvtColor(output_img, cv2.COLOR_BGR2GRAY)
223
223
  del output_img_t
224
- torch.cuda.empty_cache()
224
+ if torch.cuda.is_available():
225
+ torch.cuda.empty_cache()
225
226
  except RuntimeError as error:
226
227
  output_img = cv2.resize(
227
228
  self.img_pre_pad,
@@ -45,6 +45,12 @@ _ANNOTATOR_NODE_NAME = "comfyui_controlnet_aux"
45
45
  # pinned annotator commit so later processes can skip it. See module docstring.
46
46
  _PRELOAD_MARKER_NAME = ".hordelib_preload_complete"
47
47
 
48
+ # comfyui_controlnet_aux preprocessors that cannot import without an optional `controlnet`-extra
49
+ # package, so they must be dropped from the preload on a lean base install (their node_wrapper is
50
+ # guarded and simply does not register). Openpose's DWPose detector is the only horde-exposed
51
+ # preprocessor that needs onnxruntime; running it without the extra would abort the whole preload.
52
+ _ONNXRUNTIME_GATED_PREPROCESSORS = frozenset({"OpenposePreprocessor"})
53
+
48
54
 
49
55
  def _midas_already_cached() -> bool:
50
56
  """Return whether the transformers-based MiDaS annotator is fully in the HF cache.
@@ -167,6 +173,22 @@ def _run_preload(*, force_offline: bool) -> bool:
167
173
  aio_preprocessor_class = get_node_class("AIO_Preprocessor")
168
174
 
169
175
  preprocessors = sorted(set(HordeLib.CONTROLNET_IMAGE_PREPROCESSOR_MAP.values()))
176
+ # On a lean base install (no `controlnet` extra) the onnxruntime-backed detectors never
177
+ # registered; preloading them would raise and abort the whole run. Drop them and preload the
178
+ # rest, which are pure-torch / transformers and work without the extra.
179
+ from hordelib.feature_impact import FEATURE_KIND
180
+ from hordelib.feature_requirements import feature_available
181
+
182
+ if not feature_available(FEATURE_KIND.controlnet):
183
+ skipped = sorted(_ONNXRUNTIME_GATED_PREPROCESSORS.intersection(preprocessors))
184
+ if skipped:
185
+ logger.info(
186
+ "Skipping controlnet annotators that need the 'controlnet' extra (onnxruntime "
187
+ "absent): preprocessors={}",
188
+ skipped,
189
+ )
190
+ preprocessors = [p for p in preprocessors if p not in _ONNXRUNTIME_GATED_PREPROCESSORS]
191
+
170
192
  # A tiny gray test card; enough for every detector to run its model once
171
193
  test_image = torch.full((1, 64, 64, 3), 0.5)
172
194
 
@@ -92,7 +92,12 @@ class GPUInfo:
92
92
 
93
93
  def get_info(self):
94
94
  if not self.is_nvidia():
95
- return GPUInfoResult.get_empty_info()
95
+ from hordelib.utils.torch_memory import get_torch_free_vram_mb, get_torch_total_vram_mb
96
+
97
+ return GPUInfoResult.get_empty_info(
98
+ vram_total_mb=get_torch_total_vram_mb(),
99
+ vram_free_mb=get_torch_free_vram_mb(),
100
+ )
96
101
 
97
102
  data = self._get_gpu_data()
98
103
  if not data:
@@ -180,16 +185,17 @@ class GPUInfoResult(BaseModel):
180
185
  return final_string
181
186
 
182
187
  @classmethod
183
- def get_empty_info(cls):
188
+ def get_empty_info(cls, vram_total_mb: int = 0, vram_free_mb: int = 0):
189
+ vram_used_mb = max(vram_total_mb - vram_free_mb, 0)
184
190
  return GPUInfoResult(
185
191
  supported=False,
186
- product="unknown (stats with AMD not supported)",
192
+ product="unknown (detailed stats unavailable on this backend)",
187
193
  pci_gen="?",
188
194
  pci_width="?",
189
195
  fan_speed=("0", Unit.percent),
190
- vram_total=(0, Unit.megabytes),
191
- vram_used=(0, Unit.megabytes),
192
- vram_free=(0, Unit.megabytes),
196
+ vram_total=(vram_total_mb, Unit.megabytes),
197
+ vram_used=(vram_used_mb, Unit.megabytes),
198
+ vram_free=(vram_free_mb, Unit.megabytes),
193
199
  load=(0, Unit.percent),
194
200
  temp=(0, Unit.degrees_celsius),
195
201
  power=(0, Unit.watts),
@@ -1,7 +1,6 @@
1
1
  import base64
2
2
 
3
3
  import numpy as np
4
- import rembg # type: ignore
5
4
  from loguru import logger
6
5
  from PIL import Image, ImageOps, PngImagePlugin, UnidentifiedImageError
7
6
 
@@ -317,6 +316,13 @@ class ImageUtils:
317
316
 
318
317
  @classmethod
319
318
  def strip_background(cls, image: Image.Image):
319
+ # rembg (and its onnxruntime backend) is imported lazily and is no longer a base dependency:
320
+ # it lives in the optional [rembg] extra (onnxruntime has no XPU/MPS/Ascend wheels). On a lean
321
+ # base install this gate raises an actionable MissingOptionalDependency rather than dragging the
322
+ # heavy onnxruntime stack onto every ImageUtils import. See hordelib.feature_requirements.
323
+ from hordelib.utils.optional_deps import import_optional
324
+
325
+ rembg = import_optional("rembg", extra="rembg", feature="strip_background (background removal)")
320
326
  session = rembg.new_session("u2net")
321
327
  image = rembg.remove(
322
328
  image,
@@ -0,0 +1,74 @@
1
+ """Lazy optional-dependency gating for hordelib.
2
+
3
+ hordelib aims to stay close to base ComfyUI: heavy or platform-constrained features are
4
+ guarded so that the packages they need are only required when the feature is actually used.
5
+ A call site asks for an optional package via :func:`require` or :func:`import_optional`; if
6
+ the package is absent the caller gets an actionable "install this extra" error instead of a
7
+ bare ``ModuleNotFoundError`` surfacing from deep in the call stack.
8
+
9
+ This module intentionally only DETECTS dependencies (via ``importlib.util.find_spec``); it
10
+ never installs anything at runtime. Extras are resolved at lock/sync time by the packaging
11
+ tool, which keeps environments reproducible and auditable (the opposite of runtime
12
+ ``pip install`` machinery).
13
+ """
14
+
15
+ import importlib
16
+ import importlib.util
17
+ from types import ModuleType
18
+
19
+ __all__ = ["MissingOptionalDependency", "import_optional", "require"]
20
+
21
+ # The PyPI distribution name differs from the import name (`hordelib`); install hints must use
22
+ # the distribution name so `pip install ...[extra]` actually works.
23
+ _DISTRIBUTION_NAME = "horde-engine"
24
+
25
+
26
+ class MissingOptionalDependency(ImportError):
27
+ """Raised when an optional feature is used but its backing package is not installed."""
28
+
29
+ def __init__(self, package: str, *, extra: str, feature: str) -> None:
30
+ self.package = package
31
+ self.extra = extra
32
+ self.feature = feature
33
+ super().__init__(
34
+ f"{feature} requires the optional package '{package}', which is not installed. "
35
+ f"Install it with: pip install {_DISTRIBUTION_NAME}[{extra}]",
36
+ )
37
+
38
+
39
+ def require(package: str, *, extra: str, feature: str) -> None:
40
+ """Ensure an optional dependency is importable, or raise an actionable error.
41
+
42
+ Args:
43
+ package: The top-level import name to probe (e.g. ``"rembg"``).
44
+ extra: The ``horde-engine`` extra that provides it (e.g. ``"rembg"``).
45
+ feature: Human-readable name of the feature needing it, used in the error message.
46
+
47
+ Raises:
48
+ MissingOptionalDependency: If ``package`` cannot be found in the environment.
49
+ """
50
+ if importlib.util.find_spec(package) is None:
51
+ raise MissingOptionalDependency(package, extra=extra, feature=feature)
52
+
53
+
54
+ def import_optional(module: str, *, extra: str, feature: str) -> ModuleType:
55
+ """Import and return an optional module, raising an actionable error if it is absent.
56
+
57
+ The presence probe uses the top-level package of ``module`` so that, for example,
58
+ ``import_optional("horde_image_utilities.rembg", ...)`` reports the installable package
59
+ rather than the dotted submodule.
60
+
61
+ Args:
62
+ module: The (possibly dotted) module path to import.
63
+ extra: The ``horde-engine`` extra that provides it.
64
+ feature: Human-readable name of the feature needing it, used in the error message.
65
+
66
+ Returns:
67
+ The imported module.
68
+
69
+ Raises:
70
+ MissingOptionalDependency: If the module's top-level package is not installed.
71
+ """
72
+ top_level = module.split(".", 1)[0]
73
+ require(top_level, extra=extra, feature=feature)
74
+ return importlib.import_module(module)