relative imports

This commit is contained in:
Alexander G. Morano
2025-01-07 23:56:10 -05:00
parent 563cd3db77
commit 9de94b2a20
9 changed files with 123 additions and 95 deletions
+4
View File
@@ -33,6 +33,10 @@
## UPDATES
**2024/01/07** @1.0.3:
* relative imports
* node names cleaned
**2024/01/05** @1.0.2:
* reorganized imports
+83 -15
View File
@@ -22,7 +22,7 @@
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
__author__ = """Alexander G. Morano"""
__email__ = "amorano@gmail.com"
__version__ = "1.0.2"
__version__ = "1.0.3"
import os
import sys
@@ -30,6 +30,7 @@ import json
import inspect
import importlib
from pathlib import Path
from types import ModuleType
from loguru import logger
@@ -50,7 +51,59 @@ JOV_INTERNAL = os.getenv("JOV_INTERNAL", 'false').strip().lower() in ('true', '1
JOV_LOG_LEVEL = os.getenv("JOV_LOG_LEVEL", "INFO")
logger.configure(handlers=[{"sink": sys.stdout, "level": JOV_LOG_LEVEL}])
JOV_PACKAGE = "Jovi_GLSL"
JOV_PACKAGE = "JOV_GL"
# ==============================================================================
# === CORE NODES ===
# ==============================================================================
class JOVBaseNode:
NOT_IDEMPOTENT = True
CATEGORY = f"{JOV_PACKAGE} 🦚"
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK")
RETURN_NAMES = ('RGBA', 'RGB', 'MASK')
FUNCTION = "run"
@classmethod
def VALIDATE_INPUTS(cls, *arg, **kw) -> bool:
return True
@classmethod
def INPUT_TYPES(cls, prompt:bool=False, extra_png:bool=False, dynprompt:bool=False) -> dict:
data = {
"required": {},
"optional": {},
"outputs": {
0: ("IMAGE", {"tooltips":"Full channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output."}),
1: ("IMAGE", {"tooltips":"Three channel [RGB] image. There will be no alpha."}),
2: ("MASK", {"tooltips":"Single channel mask output."}),
},
"hidden": {
"ident": "UNIQUE_ID"
}
}
if prompt:
data["hidden"]["prompt"] = "PROMPT"
if extra_png:
data["hidden"]["extra_pnginfo"] = "EXTRA_PNGINFO"
if dynprompt:
data["hidden"]["dynprompt"] = "DYNPROMPT"
return data
# ==============================================================================
# === TYPE ===
# ==============================================================================
class AnyType(str):
"""AnyType input wildcard trick taken from pythongossss's:
https://github.com/pythongosssss/ComfyUI-Custom-Scripts
"""
def __ne__(self, __value: object) -> bool:
return False
JOV_TYPE_ANY = AnyType("*")
# ==============================================================================
# === SUPPORT ===
@@ -67,6 +120,27 @@ def load_file(fname: str) -> str | None:
# === LOADER ===
# ==============================================================================
def load_module(name: str) -> None|ModuleType:
module = inspect.getmodule(inspect.stack()[0][0]).__name__
try:
route = str(name).replace("\\", "/")
route = route.split(f"{module}/core/")[1]
route = route.split('.')[0].replace('/', '.')
except Exception as e:
logger.warning(f"module failed {name}")
logger.warning(str(e))
return
try:
module = f"{module}.core.{route}"
module = importlib.import_module(module)
except Exception as e:
logger.warning(f"module failed {module}")
logger.warning(str(e))
return
return module
def loader():
global NODE_DISPLAY_NAME_MAPPINGS, NODE_CLASS_MAPPINGS
NODE_LIST_MAP = {}
@@ -75,39 +149,33 @@ def loader():
if fname.stem.startswith('_'):
continue
try:
route = str(fname).replace("\\", "/").split(f"{JOV_PACKAGE}/core/")[1]
route = route.split('.')[0].replace('/', '.')
module = f"{JOV_PACKAGE}.core.{route}"
module = importlib.import_module(module)
except Exception as e:
logger.warning(f"module failed {fname}")
logger.warning(str(e))
if (module := load_module(fname)) is None:
continue
# check if there is a dynamic register function....
try:
for class_name, class_def in module.import_dynamic():
setattr(module, class_name, class_def)
# logger.debug(f"shader: {class_name}")
except Exception as e:
pass
classes = inspect.getmembers(module, inspect.isclass)
for class_name, class_object in classes:
if not class_name.endswith('BaseNode') and hasattr(class_object, 'NAME') and hasattr(class_object, 'CATEGORY'):
name = class_object.NAME
name = f"{class_object.NAME} ({JOV_PACKAGE})"
NODE_DISPLAY_NAME_MAPPINGS[name] = name
NODE_CLASS_MAPPINGS[name] = class_object
desc = class_object.DESCRIPTION if hasattr(class_object, 'DESCRIPTION') else name
NODE_LIST_MAP[name] = desc.split('.')[0].strip('\n')
if class_object.SORT < 5000:
desc = class_object.DESCRIPTION if hasattr(class_object, 'DESCRIPTION') else name
NODE_LIST_MAP[name] = desc.split('.')[0].strip('\n')
NODE_CLASS_MAPPINGS = {x[0] : x[1] for x in sorted(NODE_CLASS_MAPPINGS.items(),
key=lambda item: getattr(item[1], 'SORT', 0))}
keys = NODE_CLASS_MAPPINGS.keys()
for name in keys:
logger.debug(f"✅ {name} :: {NODE_DISPLAY_NAME_MAPPINGS[name]}")
logger.debug(f"✅ {name}")
logger.info(f"{len(keys)} nodes loaded")
# only do the list on local runs...
+3 -44
View File
@@ -15,7 +15,9 @@ import torch
import numpy as np
from loguru import logger
from Jovi_GLSL import JOV_PACKAGE, ROOT, load_file
from .. import JOV_TYPE_ANY, ROOT, \
JOVBaseNode, \
load_file
# ==============================================================================
# === SHADER LOADER ===
@@ -90,48 +92,6 @@ class Singleton(type):
# === CORE NODES ===
# ==============================================================================
class JOVBaseNode:
NOT_IDEMPOTENT = True
CATEGORY = f"{JOV_PACKAGE.upper()} 🦚"
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK")
RETURN_NAMES = ('RGBA', 'RGB', 'MASK')
FUNCTION = "run"
@classmethod
def VALIDATE_INPUTS(cls, *arg, **kw) -> bool:
return True
@classmethod
def INPUT_TYPES(cls, prompt:bool=False, extra_png:bool=False, dynprompt:bool=False) -> dict:
data = {
"required": {},
"optional": {},
"outputs": {
0: ("IMAGE", {"tooltips":"Full channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output."}),
1: ("IMAGE", {"tooltips":"Three channel [RGB] image. There will be no alpha."}),
2: ("MASK", {"tooltips":"Single channel mask output."}),
},
"hidden": {
"ident": "UNIQUE_ID"
}
}
if prompt:
data["hidden"]["prompt"] = "PROMPT"
if extra_png:
data["hidden"]["extra_pnginfo"] = "EXTRA_PNGINFO"
if dynprompt:
data["hidden"]["dynprompt"] = "DYNPROMPT"
return data
class AnyType(str):
"""AnyType input wildcard trick taken from pythongossss's:
https://github.com/pythongosssss/ComfyUI-Custom-Scripts
"""
def __ne__(self, __value: object) -> bool:
return False
class JOVBaseGLSLNode(JOVBaseNode):
NOT_IDEMPOTENT = True
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK")
@@ -220,7 +180,6 @@ JOV_TYPE_NUMBER = f"{JOV_TYPE_COMFY}|{JOV_TYPE_VECTOR}"
JOV_TYPE_IMAGE = "IMAGE|MASK"
JOV_TYPE_FULL = f"{JOV_TYPE_NUMBER}|{JOV_TYPE_IMAGE}"
JOV_TYPE_ANY = AnyType("*")
JOV_TYPE_COMFY = JOV_TYPE_ANY
JOV_TYPE_VECTOR = JOV_TYPE_ANY
JOV_TYPE_NUMBER = JOV_TYPE_ANY
+9 -12
View File
@@ -13,22 +13,20 @@ from loguru import logger
from comfy.utils import ProgressBar
from Jovi_GLSL import load_file
from .. import load_file
from Jovi_GLSL.core import GLSL_PROGRAMS, JOV_TYPE_IMAGE, PTYPE, RE_VARIABLE, \
from ..core import GLSL_PROGRAMS, JOV_TYPE_IMAGE, PTYPE, RE_VARIABLE, \
ROOT_GLSL, IMAGE_SIZE_MIN, IMAGE_SIZE_DEFAULT, IMAGE_SIZE_MAX, \
CompileException, JOVBaseGLSLNode, EnumConvertType, \
cv2tensor_full, image_convert, parse_param, parse_value, tensor2cv, zip_longest_fill
cv2tensor_full, image_convert, parse_param, parse_value, \
tensor2cv, zip_longest_fill
from Jovi_GLSL.core.glsl_shader import GLSLShader
from ..core.glsl_shader import GLSLShader
# ==============================================================================
# === CONSTANT ===
# ==============================================================================
GLSL_INTERNAL = '🌈'
GLSL_CUSTOM = '🦄'
RE_INCLUDE = re.compile(r"^\s*#include\s+([A-Za-z_\-\.\\\/]{3,})$", re.MULTILINE)
RE_SHADER_META = re.compile(r"^\/\/\s?([A-Za-z_]{3,}):\s?(.+)$", re.MULTILINE)
@@ -297,7 +295,7 @@ def load_file_glsl(fname: str) -> str:
def import_dynamic() -> Tuple[str,...]:
ret = []
sort = 4000
sort = 5000
root = str(ROOT_GLSL)
for name, fname in GLSL_PROGRAMS['fragment'].items():
if (shader := load_file_glsl(fname)) is None:
@@ -312,18 +310,17 @@ def import_dynamic() -> Tuple[str,...]:
class_name = name.title().replace(' ', '_')
class_name = f'GLSLNode_{class_name}'
emoji = GLSL_CUSTOM
sort_order = sort
# put custom user nodes last
if fname.startswith(root):
emoji = GLSL_INTERNAL
sort_order -= 2500
sort_order -= 5000
category = GLSLNodeDynamic.CATEGORY
if (sub := meta.get('category', None)) is not None:
category += f'/{sub}'
class_def = type(class_name, (GLSLNodeDynamic,), {
"NAME": f'GLSL {name} (JOV_GL) {emoji}'.upper(),
"NAME": name,
"DESCRIPTION": meta.get('desc', name),
"CATEGORY": category.upper(),
"FRAGMENT": shader,
+1 -1
View File
@@ -8,7 +8,7 @@ import gc
import glfw
from loguru import logger
from Jovi_GLSL.core import Singleton
from ..core import Singleton
# ==============================================================================
# === MANAGER ===
+2 -2
View File
@@ -13,12 +13,12 @@ import numpy as np
import OpenGL.GL as gl
from loguru import logger
from Jovi_GLSL.core import IMAGE_SIZE_MAX, IMAGE_SIZE_MIN, PROG_VERTEX, \
from ..core import IMAGE_SIZE_MAX, IMAGE_SIZE_MIN, PROG_VERTEX, \
PROG_FRAGMENT, PROG_FOOTER, PROG_HEADER, PTYPE, RE_VARIABLE, \
CompileException, \
image_convert, parse_value
from Jovi_GLSL.core.glsl_manager import GLSLManager
from ..core.glsl_manager import GLSLManager
# ==============================================================================
# === CONSTANT ===
+19 -19
View File
@@ -1,21 +1,21 @@
{
"GLSL BLEND LINEAR (JOV_GL) \ud83c\udf08": "Simple linear blend between two images",
"GLSL COLOR CONVERSION (JOV_GL) \ud83c\udf08": "Convert an image from one color space (RGB, HSV, LAB, XYZ) to another",
"GLSL COLOR PALETTE (JOV_GL) \ud83c\udf08": "Color palette creation using the formula: color(t) = a + b * cos[tau(c*t+d)]",
"GLSL CONICAL GRADIENT (JOV_GL) \ud83c\udf08": "Generate a conical gradient from black to white",
"GLSL DIRECTIONAL WARP (JOV_GL) \ud83c\udf08": "Domain warp an image with a direction and distortion map",
"GLSL FILTER RANGE (JOV_GL) \ud83c\udf08": "Select pixels from start color through end color",
"GLSL GRAYSCALE (JOV_GL) \ud83c\udf08": "Convert input to grayscale",
"GLSL HSV ADJUST (JOV_GL) \ud83c\udf08": "Hue, Saturation and Value adjustment control",
"GLSL INVERT (JOV_GL) \ud83c\udf08": "Invert the channels of an image along a scalar [0",
"GLSL MIN MAX (JOV_GL) \ud83c\udf08": "Gets the minimum and maximum of an image",
"GLSL NOISE PERLIN (JOV_GL) \ud83c\udf08": "Classic Perlin noise",
"GLSL NOISE SIMPLEX (JOV_GL) \ud83c\udf08": "Simplex noise, simply",
"GLSL NOISE WORLEY (JOV_GL) \ud83c\udf08": "Worley noise with the best",
"GLSL NORMAL (JOV_GL) \ud83c\udf08": "Convert input into a Normal map",
"GLSL NORMAL BLEND (JOV_GL) \ud83c\udf08": "Blend two Normal maps",
"GLSL PIXELATE (JOV_GL) \ud83c\udf08": "Pixelate input image",
"GLSL POSTERIZE (JOV_GL) \ud83c\udf08": "Reduce the pixel color data range",
"GLSL SOBEL (JOV_GL) \ud83c\udf08": "Finds the edges of an image",
"GLSL TRANSFORM (JOV_GL) \ud83c\udf08": "Move, Rotate, Scale and Tile an image"
"BLEND LINEAR (JOV_GL)": "Simple linear blend between two images",
"COLOR CONVERSION (JOV_GL)": "Convert an image from one color space (RGB, HSV, LAB, XYZ) to another",
"COLOR PALETTE (JOV_GL)": "Color palette creation using the formula: color(t) = a + b * cos[tau(c*t+d)]",
"CONICAL GRADIENT (JOV_GL)": "Generate a conical gradient from black to white",
"DIRECTIONAL WARP (JOV_GL)": "Domain warp an image with a direction and distortion map",
"FILTER RANGE (JOV_GL)": "Select pixels from start color through end color",
"GRAYSCALE (JOV_GL)": "Convert input to grayscale",
"HSV ADJUST (JOV_GL)": "Hue, Saturation and Value adjustment control",
"INVERT (JOV_GL)": "Invert the channels of an image along a scalar [0",
"MIN MAX (JOV_GL)": "Gets the minimum and maximum of an image",
"NOISE PERLIN (JOV_GL)": "Classic Perlin noise",
"NOISE SIMPLEX (JOV_GL)": "Simplex noise, simply",
"NOISE WORLEY (JOV_GL)": "Worley noise with the best",
"NORMAL (JOV_GL)": "Convert input into a Normal map",
"NORMAL BLEND (JOV_GL)": "Blend two Normal maps",
"PIXELATE (JOV_GL)": "Pixelate input image",
"POSTERIZE (JOV_GL)": "Reduce the pixel color data range",
"SOBEL (JOV_GL)": "Finds the edges of an image",
"TRANSFORM (JOV_GL)": "Move, Rotate, Scale and Tile an image"
}
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "jovi_glsl"
description = "Integrates GLSL shader support."
version = "1.0.2"
version = "1.0.3"
license = { file = "LICENSE" }
dependencies = [
"aenum>=3.1.15",
+1 -1
View File
@@ -12,7 +12,7 @@ const _id = "GLSL DYNAMIC (JOV_GL)";
app.registerExtension({
name: 'jovi_glsl.node.' + _id,
async beforeRegisterNodeDef(nodeType, nodeData) {
if ((!nodeData.name.endsWith("(JOV_GL) 🌈") && !nodeData.name.endsWith("(JOV_GL) 🦄"))) {
if (!nodeData.name.endsWith("(JOV_GL)")) {
return;
}