procfunc 0.30.0__py3-none-any.whl
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.
- procfunc/__init__.py +87 -0
- procfunc/color.py +57 -0
- procfunc/compute_graph/__init__.py +28 -0
- procfunc/compute_graph/compute_graph.py +115 -0
- procfunc/compute_graph/node.py +200 -0
- procfunc/compute_graph/operators_info.py +92 -0
- procfunc/compute_graph/proxy.py +173 -0
- procfunc/compute_graph/util.py +282 -0
- procfunc/context.py +115 -0
- procfunc/control.py +174 -0
- procfunc/nodes/__init__.py +66 -0
- procfunc/nodes/bindings_util.py +196 -0
- procfunc/nodes/bpy_node_info.py +280 -0
- procfunc/nodes/compositor.py +2242 -0
- procfunc/nodes/execute/construct_nodes.py +571 -0
- procfunc/nodes/execute/construct_special_cases.py +246 -0
- procfunc/nodes/execute/execute.py +548 -0
- procfunc/nodes/execute/infer_runtime_data_type.py +195 -0
- procfunc/nodes/execute/util.py +247 -0
- procfunc/nodes/func.py +1417 -0
- procfunc/nodes/geo.py +4240 -0
- procfunc/nodes/manifest.json +8769 -0
- procfunc/nodes/math.py +644 -0
- procfunc/nodes/node_function.py +160 -0
- procfunc/nodes/shader.py +2359 -0
- procfunc/nodes/types.py +347 -0
- procfunc/ops/__init__.py +35 -0
- procfunc/ops/_util.py +275 -0
- procfunc/ops/addons.py +59 -0
- procfunc/ops/attr.py +426 -0
- procfunc/ops/collection.py +90 -0
- procfunc/ops/curve.py +18 -0
- procfunc/ops/file.py +126 -0
- procfunc/ops/manifest.json +39149 -0
- procfunc/ops/mesh.py +1510 -0
- procfunc/ops/modifier.py +603 -0
- procfunc/ops/object.py +258 -0
- procfunc/ops/primitives/__init__.py +31 -0
- procfunc/ops/primitives/camera.py +45 -0
- procfunc/ops/primitives/curve.py +71 -0
- procfunc/ops/primitives/light.py +114 -0
- procfunc/ops/primitives/mesh.py +358 -0
- procfunc/ops/uv.py +271 -0
- procfunc/random.py +247 -0
- procfunc/tracer/__init__.py +43 -0
- procfunc/tracer/decorator.py +121 -0
- procfunc/tracer/patch.py +494 -0
- procfunc/tracer/proxy.py +127 -0
- procfunc/tracer/trace.py +222 -0
- procfunc/transforms/__init__.py +49 -0
- procfunc/transforms/cleanup.py +214 -0
- procfunc/transforms/convert.py +20 -0
- procfunc/transforms/distribution.py +191 -0
- procfunc/transforms/extract_materials.py +116 -0
- procfunc/transforms/infer_distribution.py +326 -0
- procfunc/transforms/parameters.py +15 -0
- procfunc/transforms/util.py +35 -0
- procfunc/transpiler/__init__.py +24 -0
- procfunc/transpiler/bpy_to_computegraph.py +1348 -0
- procfunc/transpiler/codegen.py +919 -0
- procfunc/transpiler/identifiers.py +595 -0
- procfunc/transpiler/main.py +299 -0
- procfunc/types.py +380 -0
- procfunc/util/__init__.py +0 -0
- procfunc/util/bpy_info.py +145 -0
- procfunc/util/camera.py +0 -0
- procfunc/util/keyframe.py +70 -0
- procfunc/util/log.py +96 -0
- procfunc/util/manifest.py +121 -0
- procfunc/util/pytree.py +343 -0
- procfunc/util/teardown.py +37 -0
- procfunc-0.30.0.dist-info/METADATA +120 -0
- procfunc-0.30.0.dist-info/RECORD +76 -0
- procfunc-0.30.0.dist-info/WHEEL +5 -0
- procfunc-0.30.0.dist-info/licenses/LICENSE.md +11 -0
- procfunc-0.30.0.dist-info/top_level.txt +1 -0
procfunc/__init__.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# ruff: noqa: I001, F401
|
|
2
|
+
# ensure this gets imported first so that mathutils etc is available even if later modules dont import bpy
|
|
3
|
+
import bpy
|
|
4
|
+
|
|
5
|
+
__version__ = "0.30.0"
|
|
6
|
+
|
|
7
|
+
from numpy.random import Generator as RNG
|
|
8
|
+
|
|
9
|
+
# ensure these are always imported first and in the right order
|
|
10
|
+
import bpy as _bpy
|
|
11
|
+
import mathutils as _mu
|
|
12
|
+
|
|
13
|
+
from . import (
|
|
14
|
+
compute_graph,
|
|
15
|
+
control,
|
|
16
|
+
nodes,
|
|
17
|
+
ops,
|
|
18
|
+
random,
|
|
19
|
+
tracer,
|
|
20
|
+
util,
|
|
21
|
+
context,
|
|
22
|
+
color,
|
|
23
|
+
transforms,
|
|
24
|
+
)
|
|
25
|
+
from .types import (
|
|
26
|
+
Vector,
|
|
27
|
+
Color,
|
|
28
|
+
Euler,
|
|
29
|
+
Quaternion,
|
|
30
|
+
Matrix,
|
|
31
|
+
BVHTree,
|
|
32
|
+
Object,
|
|
33
|
+
CameraObject,
|
|
34
|
+
MeshObject,
|
|
35
|
+
CurveObject,
|
|
36
|
+
VolumeObject,
|
|
37
|
+
EmptyObject,
|
|
38
|
+
ArmatureObject,
|
|
39
|
+
HairObject,
|
|
40
|
+
LatticeObject,
|
|
41
|
+
LightObject,
|
|
42
|
+
LightProbeObject,
|
|
43
|
+
MetaObject,
|
|
44
|
+
Material,
|
|
45
|
+
Texture,
|
|
46
|
+
Collection,
|
|
47
|
+
Image,
|
|
48
|
+
ViewLayer,
|
|
49
|
+
Asset,
|
|
50
|
+
World,
|
|
51
|
+
)
|
|
52
|
+
from .nodes import ProcNode, Shader, NodeDataType
|
|
53
|
+
from .tracer import trace, autowrap_module, add_search_scope
|
|
54
|
+
from .util.manifest import module_path
|
|
55
|
+
|
|
56
|
+
autowrap_module(random)
|
|
57
|
+
autowrap_module(color)
|
|
58
|
+
add_search_scope(nodes)
|
|
59
|
+
add_search_scope(ops)
|
|
60
|
+
|
|
61
|
+
__all__ = [
|
|
62
|
+
# Subpackages
|
|
63
|
+
"compute_graph",
|
|
64
|
+
"control",
|
|
65
|
+
"context",
|
|
66
|
+
"color",
|
|
67
|
+
"nodes",
|
|
68
|
+
"ops",
|
|
69
|
+
"random",
|
|
70
|
+
"tracer",
|
|
71
|
+
"transforms",
|
|
72
|
+
"util",
|
|
73
|
+
# Node graph primitives
|
|
74
|
+
"ProcNode",
|
|
75
|
+
"Shader",
|
|
76
|
+
"NodeDataType",
|
|
77
|
+
# Tracing entrypoints
|
|
78
|
+
"trace",
|
|
79
|
+
# Utilities
|
|
80
|
+
"RNG",
|
|
81
|
+
"module_path",
|
|
82
|
+
# NOTE: Blender wrapper types (Object, MeshObject, Material, Texture, ...)
|
|
83
|
+
# are re-exported above for convenience but live in procfunc.types — see
|
|
84
|
+
# that page for documentation. Blender/mathutils re-exports (Vector, Color,
|
|
85
|
+
# Euler, Quaternion, Matrix, BVHTree, NodeGroup, Scene, ViewLayer) are
|
|
86
|
+
# likewise kept importable but documented upstream by Blender.
|
|
87
|
+
]
|
procfunc/color.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from procfunc import types as t
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def hsv_color(
|
|
7
|
+
hsv: np.ndarray | tuple | None = None,
|
|
8
|
+
*,
|
|
9
|
+
hue: float | None = None,
|
|
10
|
+
saturation: float | None = None,
|
|
11
|
+
value: float | None = None,
|
|
12
|
+
) -> t.Color:
|
|
13
|
+
color = t.Color()
|
|
14
|
+
if hsv is not None:
|
|
15
|
+
color.hsv = hsv
|
|
16
|
+
else:
|
|
17
|
+
color.hsv = (hue, saturation, value)
|
|
18
|
+
return color
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
hsv_to_rgba = hsv_color
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def rgb_color(
|
|
25
|
+
r: float | None = None,
|
|
26
|
+
g: float | None = None,
|
|
27
|
+
b: float | None = None,
|
|
28
|
+
rgb: np.ndarray | None = None,
|
|
29
|
+
) -> t.Color:
|
|
30
|
+
color = t.Color()
|
|
31
|
+
if rgb is not None:
|
|
32
|
+
color.r, color.g, color.b = rgb
|
|
33
|
+
else:
|
|
34
|
+
color.r, color.g, color.b = r, g, b
|
|
35
|
+
return color
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _srgb_to_linearrgb(c):
|
|
39
|
+
if c < 0:
|
|
40
|
+
return 0
|
|
41
|
+
elif c < 0.04045:
|
|
42
|
+
return c / 12.92
|
|
43
|
+
else:
|
|
44
|
+
return ((c + 0.055) / 1.055) ** 2.4
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _hex_to_rgb(h: int, alpha: float = 1):
|
|
48
|
+
r = (h & 0xFF0000) >> 16
|
|
49
|
+
g = (h & 0x00FF00) >> 8
|
|
50
|
+
b = h & 0x0000FF
|
|
51
|
+
return tuple([_srgb_to_linearrgb(c / 0xFF) for c in (r, g, b)])
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def hex_color(h: int, alpha: float = 1):
|
|
55
|
+
c = t.Color()
|
|
56
|
+
c.r, c.g, c.b = _hex_to_rgb(h, alpha)
|
|
57
|
+
return c
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from .compute_graph import (
|
|
2
|
+
ComputeGraph,
|
|
3
|
+
)
|
|
4
|
+
from .node import (
|
|
5
|
+
ConstantNode,
|
|
6
|
+
FunctionCallNode,
|
|
7
|
+
GetAttributeNode,
|
|
8
|
+
InputPlaceholderNode,
|
|
9
|
+
MethodCallNode,
|
|
10
|
+
MutatedArgumentNode,
|
|
11
|
+
Node,
|
|
12
|
+
ProceduralNode,
|
|
13
|
+
SubgraphCallNode,
|
|
14
|
+
normalize_args_to_kwargs,
|
|
15
|
+
)
|
|
16
|
+
from .operators_info import OperatorType
|
|
17
|
+
from .proxy import AttributeProxy, Proxy
|
|
18
|
+
from .util import (
|
|
19
|
+
LiteralConstant,
|
|
20
|
+
graph_nodes_equal,
|
|
21
|
+
transform_compute_graph,
|
|
22
|
+
transform_nodetree,
|
|
23
|
+
traverse_breadth_first,
|
|
24
|
+
traverse_depth_first,
|
|
25
|
+
traverse_depth_first_node,
|
|
26
|
+
traverse_nested_graphs,
|
|
27
|
+
usages_per_node,
|
|
28
|
+
)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import logging
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from procfunc.util.pytree import PyTree
|
|
7
|
+
|
|
8
|
+
from .node import Node
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _evaluate_node(node: Node) -> Any:
|
|
14
|
+
if node.result is not None:
|
|
15
|
+
return node.result
|
|
16
|
+
|
|
17
|
+
for arg in itertools.chain(node.args, node.kwargs.values()):
|
|
18
|
+
if isinstance(arg, Node):
|
|
19
|
+
arg.result = _evaluate_node(arg)
|
|
20
|
+
|
|
21
|
+
arg_eval, kwarg_eval = node.inputs.map(
|
|
22
|
+
lambda x: x.result if isinstance(x, Node) else x
|
|
23
|
+
).obj()
|
|
24
|
+
|
|
25
|
+
# match node:
|
|
26
|
+
# case cg.FunctionCallNode:
|
|
27
|
+
# return node.func(*arg_vals, **kwarg_vals)
|
|
28
|
+
# case cg.PlaceholderNode:
|
|
29
|
+
# raise NotImplementedError(
|
|
30
|
+
# f"Placeholder {node!r} or '<unnamed>'} should not be evaluated - "
|
|
31
|
+
# "its .result should be populated in advance"
|
|
32
|
+
# )
|
|
33
|
+
# case cg.MutatedArgumentNode:
|
|
34
|
+
# # Evaluate the mutation call first (for side effects), then return the original object
|
|
35
|
+
# mutation_call_node = node.args[1]
|
|
36
|
+
# _evaluate_node(mutation_call_node)
|
|
37
|
+
# return (
|
|
38
|
+
# node.args[0].result if isinstance(node.args[0], Node) else node.args[0]
|
|
39
|
+
# )
|
|
40
|
+
# case _:
|
|
41
|
+
# raise NotImplementedError(f"Unsupported node operation: {node.kind}")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _clear_node_results(node: Node):
|
|
45
|
+
node.result = None
|
|
46
|
+
for arg in itertools.chain(node.args, node.kwargs.values()):
|
|
47
|
+
if isinstance(arg, Node) and arg.result is not None:
|
|
48
|
+
_clear_node_results(arg)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class ComputeGraph:
|
|
53
|
+
inputs: PyTree[Any, Node]
|
|
54
|
+
outputs: PyTree[Any, Node]
|
|
55
|
+
name: str
|
|
56
|
+
metadata: dict[str, Any]
|
|
57
|
+
|
|
58
|
+
def __post_init__(self):
|
|
59
|
+
# input_names = set(self.inputs.names())
|
|
60
|
+
# if len(input_names) != len(set(input_names)):
|
|
61
|
+
# raise ValueError(f"Input names had duplicates: {input_names}")
|
|
62
|
+
|
|
63
|
+
# output_names = set(self.outputs.names())
|
|
64
|
+
# if len(output_names) != len(set(output_names)):
|
|
65
|
+
# raise ValueError(f"Output names had duplicates: {output_names}")
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
def __repr__(self):
|
|
69
|
+
return f"{self.__class__.__name__}({self.name!r})"
|
|
70
|
+
|
|
71
|
+
def clear_values(self):
|
|
72
|
+
for node in self.outputs.values():
|
|
73
|
+
_clear_node_results(node)
|
|
74
|
+
|
|
75
|
+
def __call__(
|
|
76
|
+
self,
|
|
77
|
+
*args,
|
|
78
|
+
allow_clear: bool = True,
|
|
79
|
+
**kwargs,
|
|
80
|
+
):
|
|
81
|
+
"""
|
|
82
|
+
Execute the compute graph. If this graph came from a tracer,
|
|
83
|
+
this should be exactly equivelant to executing the original python function.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
raise NotImplementedError("Not implemented")
|
|
87
|
+
|
|
88
|
+
if len(args) != len(self.inputs):
|
|
89
|
+
raise ValueError(f"Expected {len(self.inputs)} arguments, got {len(args)}")
|
|
90
|
+
|
|
91
|
+
if allow_clear:
|
|
92
|
+
self.clear_values()
|
|
93
|
+
|
|
94
|
+
extra_kwargs = self.kwarg_nodes.keys() - kwargs.keys()
|
|
95
|
+
if extra_kwargs:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
f"{self.__class__.__name__} {self.name!r} got unexpected keyword arguments: {extra_kwargs}"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
missing_kwargs = kwargs.keys() - self.kwarg_nodes.keys()
|
|
101
|
+
if missing_kwargs:
|
|
102
|
+
raise ValueError(
|
|
103
|
+
f"{self.__class__.__name__} {self.name!r} had missing keyword arguments: {missing_kwargs}"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
for arg, arg_node in zip(args, self.arg_nodes):
|
|
107
|
+
arg_node.result = arg
|
|
108
|
+
|
|
109
|
+
for k, v in kwargs.items():
|
|
110
|
+
self.kwarg_nodes[k].result = v
|
|
111
|
+
|
|
112
|
+
for node in self.outputs.values():
|
|
113
|
+
_evaluate_node(node)
|
|
114
|
+
|
|
115
|
+
return {name: node.result for name, node in self.outputs.items()}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import logging
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from procfunc.compute_graph.compute_graph import ComputeGraph
|
|
8
|
+
|
|
9
|
+
from procfunc.util.pytree import PyTree
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Node:
|
|
15
|
+
def __init__(self, args: tuple, kwargs: dict, metadata: dict[str, Any] = None):
|
|
16
|
+
assert isinstance(args, tuple), args
|
|
17
|
+
assert isinstance(kwargs, dict), kwargs
|
|
18
|
+
self.args = args
|
|
19
|
+
self.kwargs = kwargs
|
|
20
|
+
if metadata is None:
|
|
21
|
+
metadata = {}
|
|
22
|
+
self.metadata = metadata
|
|
23
|
+
|
|
24
|
+
def inputs_pytree(self) -> PyTree:
|
|
25
|
+
return PyTree((self.args, self.kwargs))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SubgraphCallNode(Node):
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
subgraph: "ComputeGraph",
|
|
32
|
+
args: tuple,
|
|
33
|
+
kwargs: dict,
|
|
34
|
+
metadata: dict[str, Any] = None,
|
|
35
|
+
):
|
|
36
|
+
super().__init__(args, kwargs, metadata)
|
|
37
|
+
self.subgraph = subgraph
|
|
38
|
+
|
|
39
|
+
def __repr__(self):
|
|
40
|
+
return f"{self.__class__.__name__}({self.subgraph.name}, ...)"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class FunctionCallNode(Node):
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
func: Callable[..., Any],
|
|
47
|
+
args: tuple,
|
|
48
|
+
kwargs: dict,
|
|
49
|
+
metadata: dict[str, Any] = None,
|
|
50
|
+
):
|
|
51
|
+
super().__init__(args=args, kwargs=kwargs, metadata=metadata)
|
|
52
|
+
self.func = func
|
|
53
|
+
|
|
54
|
+
def __repr__(self):
|
|
55
|
+
return f"{self.__class__.__name__}({self.func.__name__}, ...)"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class MethodCallNode(Node):
|
|
59
|
+
"""
|
|
60
|
+
represents an {args[0]}.{method_name}(*args[1:], **kwargs) call
|
|
61
|
+
|
|
62
|
+
- the node to be used as `self` is the first arg, since it is a dynamic value
|
|
63
|
+
- the method name is assumed to be const
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
callee: Node,
|
|
69
|
+
method_name: str,
|
|
70
|
+
args: tuple,
|
|
71
|
+
kwargs: dict,
|
|
72
|
+
metadata: dict[str, Any] = None,
|
|
73
|
+
):
|
|
74
|
+
super().__init__(args=(callee, *args), kwargs=kwargs, metadata=metadata)
|
|
75
|
+
self.method_name = method_name
|
|
76
|
+
|
|
77
|
+
def __repr__(self):
|
|
78
|
+
return f"{self.__class__.__name__}({self.method_name}, ...)"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class GetAttributeNode(Node):
|
|
83
|
+
def __init__(
|
|
84
|
+
self, source: Node, attribute_name: str, metadata: dict[str, Any] = None
|
|
85
|
+
):
|
|
86
|
+
# store source as args since it is a Node and may need to be recursively constructed
|
|
87
|
+
super().__init__(args=(source,), kwargs={}, metadata=metadata)
|
|
88
|
+
self.attribute_name = attribute_name
|
|
89
|
+
|
|
90
|
+
def __repr__(self):
|
|
91
|
+
return f"{self.__class__.__name__}({self.attribute_name})"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclass
|
|
95
|
+
class ProceduralNode(Node):
|
|
96
|
+
def __init__(
|
|
97
|
+
self,
|
|
98
|
+
node_type: str,
|
|
99
|
+
attrs: dict[str, Any],
|
|
100
|
+
kwargs: dict,
|
|
101
|
+
metadata: dict[str, Any] = None,
|
|
102
|
+
):
|
|
103
|
+
super().__init__(args=(), kwargs=kwargs, metadata=metadata)
|
|
104
|
+
self.node_type = node_type
|
|
105
|
+
|
|
106
|
+
for k, v in attrs.items():
|
|
107
|
+
if isinstance(v, Node):
|
|
108
|
+
raise ValueError(
|
|
109
|
+
f"{self.__class__.__name__}({node_type=}) recieved attrs with non-constant value {k}={v}. "
|
|
110
|
+
"(Node values are not allowed as attrs)"
|
|
111
|
+
)
|
|
112
|
+
self.attrs = attrs
|
|
113
|
+
|
|
114
|
+
def __repr__(self):
|
|
115
|
+
return f"{self.__class__.__name__}({self.node_type}, ...)"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class MutatedArgumentNode(Node):
|
|
119
|
+
def __init__(
|
|
120
|
+
self,
|
|
121
|
+
original_node: "Node",
|
|
122
|
+
mutator_call_node: "FunctionCallNode | MethodCallNode",
|
|
123
|
+
metadata: dict[str, Any] = None,
|
|
124
|
+
):
|
|
125
|
+
# store orig/mutator as args() since they are Node and may need to be recursively constructed
|
|
126
|
+
super().__init__(
|
|
127
|
+
args=(original_node, mutator_call_node), kwargs={}, metadata=metadata
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
def __repr__(self):
|
|
131
|
+
return f"{self.__class__.__name__}(...)"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class ConstantNode(Node):
|
|
135
|
+
def __init__(self, value: Any, metadata: dict[str, Any] = None):
|
|
136
|
+
super().__init__(args=(), kwargs={}, metadata=metadata)
|
|
137
|
+
self.value = value
|
|
138
|
+
|
|
139
|
+
def __repr__(self):
|
|
140
|
+
return f"{self.__class__.__name__}({self.value})"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class InputPlaceholderNode(Node):
|
|
144
|
+
def __init__(self, name: str, default_value: Any, metadata: dict[str, Any] = None):
|
|
145
|
+
super().__init__(args=(), kwargs={}, metadata=metadata)
|
|
146
|
+
self.input_name = name
|
|
147
|
+
self.default_value = default_value
|
|
148
|
+
|
|
149
|
+
def __repr__(self):
|
|
150
|
+
return f"{self.__class__.__name__}({self.default_value})"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
T = TypeVar("T")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def normalize_args_to_kwargs(
|
|
157
|
+
func: Callable,
|
|
158
|
+
args: tuple,
|
|
159
|
+
kwargs: dict,
|
|
160
|
+
) -> tuple[tuple, dict]:
|
|
161
|
+
"""
|
|
162
|
+
Try to fully populate kwargs, by moving over positional args & filling in defaults
|
|
163
|
+
|
|
164
|
+
Some args may not be able to be converted to kwargs, e.g. *args have no names that work
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
func: The function whose signature we should respect
|
|
168
|
+
args: The original positional arguments to the function
|
|
169
|
+
kwargs: The keyword arguments to the function
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
A tuple of (args, kwargs) where args is a tuple of positional arguments and kwargs is a dictionary of keyword arguments.
|
|
173
|
+
|
|
174
|
+
GUARANTEE: func(*returned_args, **returned_kwargs) == func(*args, **kwargs) and does not crash
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
sig = inspect.signature(func)
|
|
178
|
+
bound = sig.bind(*args, **kwargs)
|
|
179
|
+
bound.apply_defaults() # optional: fills in default values
|
|
180
|
+
|
|
181
|
+
# Extract any *args parameter back to args tuple
|
|
182
|
+
remaining_args = ()
|
|
183
|
+
updated_kwargs = {}
|
|
184
|
+
|
|
185
|
+
for param_name, value in bound.arguments.items():
|
|
186
|
+
param = sig.parameters[param_name]
|
|
187
|
+
if param.kind == inspect.Parameter.VAR_POSITIONAL: # *args
|
|
188
|
+
remaining_args = value
|
|
189
|
+
elif param.kind == inspect.Parameter.VAR_KEYWORD: # **kwargs
|
|
190
|
+
# Unpack **kwargs back to individual kwargs instead of wrapping in dict
|
|
191
|
+
updated_kwargs.update(value)
|
|
192
|
+
else:
|
|
193
|
+
updated_kwargs[param_name] = value
|
|
194
|
+
|
|
195
|
+
if False and logger.isEnabledFor(logging.DEBUG):
|
|
196
|
+
logger.debug(
|
|
197
|
+
f"normalized {func.__name__} with {args=} {kwargs=} to {remaining_args=} {updated_kwargs=}"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return remaining_args, updated_kwargs
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import operator
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class OperatorType(Enum):
|
|
6
|
+
ADD = "add"
|
|
7
|
+
SUB = "sub"
|
|
8
|
+
MUL = "mul"
|
|
9
|
+
DIV = "div"
|
|
10
|
+
TRUEDIV = "truediv"
|
|
11
|
+
POW = "pow"
|
|
12
|
+
MOD = "mod"
|
|
13
|
+
LESS_THAN = "lt"
|
|
14
|
+
LESS_THAN_EQUAL = "le"
|
|
15
|
+
GREATER_THAN = "gt"
|
|
16
|
+
GREATER_THAN_EQUAL = "ge"
|
|
17
|
+
EQUAL = "eq"
|
|
18
|
+
NOT_EQUAL = "ne"
|
|
19
|
+
AND = "and"
|
|
20
|
+
OR = "or"
|
|
21
|
+
NOT = "invert"
|
|
22
|
+
LSHIFT = "lshift"
|
|
23
|
+
RSHIFT = "rshift"
|
|
24
|
+
BIT_AND = "and"
|
|
25
|
+
BIT_OR = "or"
|
|
26
|
+
BIT_XOR = "xor"
|
|
27
|
+
|
|
28
|
+
GETITEM = "getitem"
|
|
29
|
+
|
|
30
|
+
VECTOR_PACK = "VECTOR_PACK"
|
|
31
|
+
NOOP = "NOOP"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
OPERATOR_TEMPLATES = {
|
|
35
|
+
OperatorType.ADD: "{} + {}",
|
|
36
|
+
OperatorType.SUB: "{} - {}",
|
|
37
|
+
OperatorType.MUL: "{} * {}",
|
|
38
|
+
OperatorType.DIV: "{} / {}",
|
|
39
|
+
OperatorType.POW: "{} ** {}",
|
|
40
|
+
OperatorType.MOD: "{} % {}",
|
|
41
|
+
OperatorType.LESS_THAN: "{} < {}",
|
|
42
|
+
OperatorType.LESS_THAN_EQUAL: "{} <= {}",
|
|
43
|
+
OperatorType.GREATER_THAN: "{} > {}",
|
|
44
|
+
OperatorType.GREATER_THAN_EQUAL: "{} >= {}",
|
|
45
|
+
OperatorType.EQUAL: "{} == {}",
|
|
46
|
+
OperatorType.NOT_EQUAL: "{} != {}",
|
|
47
|
+
OperatorType.VECTOR_PACK: "({}, {}, {})",
|
|
48
|
+
OperatorType.NOOP: "{}",
|
|
49
|
+
OperatorType.LSHIFT: "{} << {}",
|
|
50
|
+
OperatorType.RSHIFT: "{} >> {}",
|
|
51
|
+
OperatorType.BIT_AND: "{} & {}",
|
|
52
|
+
OperatorType.BIT_OR: "{} | {}",
|
|
53
|
+
OperatorType.BIT_XOR: "{} ^ {}",
|
|
54
|
+
OperatorType.GETITEM: "{}[{}]",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
OPERATORS_TO_FUNCTIONS = {
|
|
58
|
+
OperatorType.ADD: operator.add,
|
|
59
|
+
OperatorType.SUB: operator.sub,
|
|
60
|
+
OperatorType.MUL: operator.mul,
|
|
61
|
+
OperatorType.DIV: operator.truediv,
|
|
62
|
+
OperatorType.MOD: operator.mod,
|
|
63
|
+
OperatorType.POW: operator.pow,
|
|
64
|
+
OperatorType.LESS_THAN: operator.lt,
|
|
65
|
+
OperatorType.LESS_THAN_EQUAL: operator.le,
|
|
66
|
+
OperatorType.GREATER_THAN: operator.gt,
|
|
67
|
+
OperatorType.GREATER_THAN_EQUAL: operator.ge,
|
|
68
|
+
OperatorType.EQUAL: operator.eq,
|
|
69
|
+
OperatorType.NOT_EQUAL: operator.ne,
|
|
70
|
+
OperatorType.LSHIFT: operator.lshift,
|
|
71
|
+
OperatorType.RSHIFT: operator.rshift,
|
|
72
|
+
OperatorType.BIT_AND: operator.and_,
|
|
73
|
+
OperatorType.BIT_OR: operator.or_,
|
|
74
|
+
OperatorType.BIT_XOR: operator.xor,
|
|
75
|
+
OperatorType.GETITEM: operator.getitem,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
FUNCTIONS_TO_OPERATORS = {v: k for k, v in OPERATORS_TO_FUNCTIONS.items()}
|
|
79
|
+
|
|
80
|
+
REFLECTABLE_OPERATORS = {
|
|
81
|
+
OperatorType.ADD,
|
|
82
|
+
OperatorType.SUB,
|
|
83
|
+
OperatorType.MUL,
|
|
84
|
+
OperatorType.DIV,
|
|
85
|
+
OperatorType.MOD,
|
|
86
|
+
OperatorType.POW,
|
|
87
|
+
OperatorType.LSHIFT,
|
|
88
|
+
OperatorType.RSHIFT,
|
|
89
|
+
OperatorType.BIT_AND,
|
|
90
|
+
OperatorType.BIT_OR,
|
|
91
|
+
OperatorType.BIT_XOR,
|
|
92
|
+
}
|