procfunc 0.35.0__tar.gz → 0.36.0__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 (112) hide show
  1. {procfunc-0.35.0/src/procfunc.egg-info → procfunc-0.36.0}/PKG-INFO +8 -5
  2. {procfunc-0.35.0 → procfunc-0.36.0}/README.md +1 -1
  3. {procfunc-0.35.0 → procfunc-0.36.0}/pyproject.toml +8 -3
  4. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/__init__.py +2 -1
  5. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/codegen/codegen.py +8 -3
  6. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/codegen/repr.py +4 -1
  7. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/compute_graph/operators_info.py +12 -0
  8. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/context.py +25 -0
  9. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/control/__init__.py +7 -1
  10. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/__init__.py +2 -0
  11. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/color.py +16 -1
  12. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/compositor.py +227 -30
  13. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_special_cases.py +121 -31
  14. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_standard.py +2 -2
  15. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/infer_runtime_data_type.py +10 -0
  16. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/func.py +15 -2
  17. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/geo.py +200 -67
  18. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/manifest.json +1107 -39
  19. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/math.py +63 -19
  20. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/shader.py +235 -18
  21. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/texture.py +131 -28
  22. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/types.py +28 -4
  23. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/util/bindings_util.py +1 -0
  24. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/util/bpy_node_info.py +0 -14
  25. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/util/node_function.py +67 -7
  26. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/_util.py +18 -13
  27. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/addons.py +11 -6
  28. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/curve.py +2 -1
  29. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/file.py +26 -14
  30. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/manifest.json +43 -0
  31. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/mesh.py +6 -5
  32. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/modifier.py +83 -14
  33. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/object.py +1 -1
  34. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/primitives/camera.py +3 -2
  35. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/primitives/curve.py +3 -2
  36. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/primitives/light.py +5 -4
  37. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/primitives/mesh.py +21 -10
  38. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transpiler/bpy_to_computegraph.py +32 -159
  39. procfunc-0.36.0/src/procfunc/transpiler/parse_attrs.py +137 -0
  40. procfunc-0.36.0/src/procfunc/transpiler/parse_special_cases.py +467 -0
  41. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/manifest.py +2 -1
  42. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/teardown.py +23 -1
  43. {procfunc-0.35.0 → procfunc-0.36.0/src/procfunc.egg-info}/PKG-INFO +8 -5
  44. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc.egg-info/SOURCES.txt +3 -0
  45. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc.egg-info/requires.txt +7 -3
  46. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_codegen.py +59 -0
  47. procfunc-0.36.0/tests/test_control.py +52 -0
  48. procfunc-0.36.0/tests/test_node_function.py +131 -0
  49. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_ops.py +166 -67
  50. procfunc-0.36.0/tests/test_teardown.py +99 -0
  51. procfunc-0.35.0/src/procfunc/transpiler/parse_special_cases.py +0 -158
  52. procfunc-0.35.0/tests/test_node_function.py +0 -28
  53. {procfunc-0.35.0 → procfunc-0.36.0}/LICENSE.md +0 -0
  54. {procfunc-0.35.0 → procfunc-0.36.0}/setup.cfg +0 -0
  55. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/cli/__init__.py +0 -0
  56. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/cli/main.py +0 -0
  57. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/codegen/__init__.py +0 -0
  58. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/codegen/identifiers.py +0 -0
  59. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/color.py +0 -0
  60. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/compute_graph/__init__.py +0 -0
  61. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/compute_graph/compute_graph.py +0 -0
  62. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/compute_graph/node.py +0 -0
  63. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/compute_graph/proxy.py +0 -0
  64. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/compute_graph/util.py +0 -0
  65. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_nodes.py +0 -0
  66. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/construct_operator.py +0 -0
  67. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/execute.py +0 -0
  68. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/realize.py +0 -0
  69. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/execute/util.py +0 -0
  70. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/nodes/util/__init__.py +0 -0
  71. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/__init__.py +0 -0
  72. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/attr.py +0 -0
  73. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/collection.py +0 -0
  74. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/primitives/__init__.py +0 -0
  75. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/ops/uv.py +0 -0
  76. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/random.py +0 -0
  77. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/tracer/__init__.py +0 -0
  78. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/tracer/decorator.py +0 -0
  79. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/tracer/patch.py +0 -0
  80. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/tracer/proxy.py +0 -0
  81. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/tracer/trace.py +0 -0
  82. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/__init__.py +0 -0
  83. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/cleanup.py +0 -0
  84. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/convert.py +0 -0
  85. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/distribution.py +0 -0
  86. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/extract_materials.py +0 -0
  87. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/infer_distribution.py +0 -0
  88. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/parameters.py +0 -0
  89. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transforms/util.py +0 -0
  90. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transpiler/__init__.py +0 -0
  91. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transpiler/main.py +0 -0
  92. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/transpiler/parse_default_values.py +0 -0
  93. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/types.py +0 -0
  94. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/__init__.py +0 -0
  95. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/bpy_data.py +0 -0
  96. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/bpy_info.py +0 -0
  97. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/camera.py +0 -0
  98. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/keyframe.py +0 -0
  99. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/log.py +0 -0
  100. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc/util/pytree.py +0 -0
  101. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc.egg-info/dependency_links.txt +0 -0
  102. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc.egg-info/entry_points.txt +0 -0
  103. {procfunc-0.35.0 → procfunc-0.36.0}/src/procfunc.egg-info/top_level.txt +0 -0
  104. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_asset.py +0 -0
  105. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_bpy_data_cleanup.py +0 -0
  106. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_cli_transpile.py +0 -0
  107. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_codegen_matrix.py +0 -0
  108. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_compute_graph.py +0 -0
  109. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_pytree.py +0 -0
  110. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_random.py +0 -0
  111. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_trace.py +0 -0
  112. {procfunc-0.35.0 → procfunc-0.36.0}/tests/test_transforms.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: procfunc
3
- Version: 0.35.0
3
+ Version: 0.36.0
4
4
  Summary: Function-Oriented Abstractions for Procedural 3D Generation in Python
5
5
  License-Expression: BSD-3-Clause
6
6
  Project-URL: Homepage, https://github.com/princeton-vl/procfunc
@@ -9,15 +9,18 @@ Requires-Python: <3.12,>=3.11
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE.md
11
11
  Requires-Dist: bpy==4.2.0
12
- Requires-Dist: numpy<2
13
- Requires-Dist: pandas
12
+ Requires-Dist: numpy<2,>=1.23.5
13
+ Requires-Dist: pandas>=1.5
14
+ Provides-Extra: test
15
+ Requires-Dist: pytest<10,>=7.2; extra == "test"
14
16
  Provides-Extra: dev
15
- Requires-Dist: pytest; extra == "dev"
17
+ Requires-Dist: pytest<10,>=7.2; extra == "dev"
16
18
  Requires-Dist: pytest-xdist; extra == "dev"
17
19
  Requires-Dist: ruff<0.16,>=0.15; extra == "dev"
18
20
  Requires-Dist: ty; extra == "dev"
19
21
  Requires-Dist: imageio; extra == "dev"
20
22
  Requires-Dist: matplotlib; extra == "dev"
23
+ Requires-Dist: coverage; extra == "dev"
21
24
  Provides-Extra: docs
22
25
  Requires-Dist: sphinx; extra == "docs"
23
26
  Requires-Dist: sphinx-rtd-theme; extra == "docs"
@@ -34,7 +37,7 @@ Dynamic: license-file
34
37
 
35
38
  This repository contains only the Primitives API, Transpiler and Tracer from our research paper.
36
39
 
37
- The pre-made procedural generators are coming soon as part of [infinigen](https://github.com/princeton-vl/infinigen).
40
+ Please see the infinigen2 [documentation](https://infinigen.cs.princeton.edu/docs/latest/) and [sourcecode](https://github.com/princeton-vl/infinigen/tree/3f58bb886bb1bda681d41240344fe3126ac0e9bd/src/infinigen2) to access the paper's library of new procedural generators
38
41
 
39
42
  ### Installation
40
43
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  This repository contains only the Primitives API, Transpiler and Tracer from our research paper.
10
10
 
11
- The pre-made procedural generators are coming soon as part of [infinigen](https://github.com/princeton-vl/infinigen).
11
+ Please see the infinigen2 [documentation](https://infinigen.cs.princeton.edu/docs/latest/) and [sourcecode](https://github.com/princeton-vl/infinigen/tree/3f58bb886bb1bda681d41240344fe3126ac0e9bd/src/infinigen2) to access the paper's library of new procedural generators
12
12
 
13
13
  ### Installation
14
14
 
@@ -11,8 +11,8 @@ license = "BSD-3-Clause"
11
11
  requires-python = ">=3.11,<3.12"
12
12
  dependencies = [
13
13
  "bpy==4.2.0",
14
- "numpy<2",
15
- "pandas",
14
+ "numpy>=1.23.5,<2",
15
+ "pandas>=1.5",
16
16
  ]
17
17
 
18
18
  [project.urls]
@@ -23,13 +23,17 @@ Repository = "https://github.com/princeton-vl/procfunc"
23
23
  procfunc = "procfunc.cli:cli"
24
24
 
25
25
  [project.optional-dependencies]
26
+ test = [
27
+ "pytest>=7.2,<10",
28
+ ]
26
29
  dev = [
27
- "pytest",
30
+ "pytest>=7.2,<10",
28
31
  "pytest-xdist",
29
32
  "ruff>=0.15,<0.16",
30
33
  "ty",
31
34
  "imageio",
32
35
  "matplotlib",
36
+ "coverage",
33
37
  ]
34
38
  docs = [
35
39
  "sphinx",
@@ -48,6 +52,7 @@ procfunc = ["nodes/manifest.json", "ops/manifest.json"]
48
52
 
49
53
  [tool.pytest.ini_options]
50
54
  testpaths = "tests"
55
+ markers = ["render: requires a render-capable Blender environment"]
51
56
 
52
57
  [tool.ruff]
53
58
  exclude = ["examples", "experiments"]
@@ -2,7 +2,7 @@
2
2
  # ensure this gets imported first so that mathutils etc is available even if later modules dont import bpy
3
3
  import bpy
4
4
 
5
- __version__ = "0.35.0"
5
+ __version__ = "0.36.0"
6
6
 
7
7
  from numpy.random import Generator as RNG
8
8
 
@@ -54,6 +54,7 @@ from .nodes import ProcNode, Shader, NodeDataType
54
54
  from .tracer import trace, autowrap_module, add_search_scope
55
55
  from .util.manifest import module_path
56
56
 
57
+ bpy.context.preferences.edit.use_global_undo = False
57
58
  autowrap_module(random)
58
59
  autowrap_module(color)
59
60
  add_search_scope(nodes)
@@ -240,9 +240,12 @@ def _operator_call_operands(
240
240
 
241
241
  operands = [bound.arguments[name] for name in operand_names]
242
242
 
243
- # a default epsilon stays tolerant unlike exact ==/!=, so require exact operands
244
- if template in _EPSILON_EQUALITY_TEMPLATES and not all(
245
- _is_exact_compare_operand(v) for v in operands
243
+ operator_type = FUNCTIONS_TO_OPERATORS.get(node.func)
244
+ native_equality = operator_type in (OperatorType.EQUAL, OperatorType.NOT_EQUAL)
245
+ if (
246
+ template in _EPSILON_EQUALITY_TEMPLATES
247
+ and not native_equality
248
+ and not all(_is_exact_compare_operand(v) for v in operands)
246
249
  ):
247
250
  return None
248
251
 
@@ -713,6 +716,8 @@ def _resolve_func(func: Any) -> tuple[str | None, str]:
713
716
  raise NotImplementedError(f"Unsupported function: {func}")
714
717
  elif module == "builtins":
715
718
  return None, func.__name__
719
+ elif module == "_operator":
720
+ return "import operator", f"operator.{func.__name__}"
716
721
  elif module.startswith("procfunc."):
717
722
  callsite = "pf." + module[len("procfunc.") :] + "." + func.__name__
718
723
  importstring = "import procfunc as pf"
@@ -27,7 +27,8 @@ def repr_type(x: Any) -> str:
27
27
  if origin is Union or origin is types.UnionType:
28
28
  first_args = get_args(args[0])
29
29
  if (
30
- get_origin(args[0]) is nt.ProcNode
30
+ len(args) == 2
31
+ and get_origin(args[0]) is nt.ProcNode
31
32
  and first_args
32
33
  and first_args[0] is args[1]
33
34
  ):
@@ -82,6 +83,8 @@ def repr_value(value: Any) -> str:
82
83
 
83
84
  if isinstance(value, np.random.Generator):
84
85
  return "np.random.default_rng()"
86
+ elif get_origin(value) in (Union, types.UnionType, nt.ProcNode):
87
+ return repr_type(value)
85
88
  elif isinstance(value, type):
86
89
  return repr_type(value)
87
90
  elif isinstance(value, np.ndarray):
@@ -7,6 +7,7 @@ class OperatorType(Enum):
7
7
  SUB = "sub"
8
8
  MUL = "mul"
9
9
  DIV = "div"
10
+ FLOOR_DIV = "floordiv"
10
11
  TRUEDIV = "truediv"
11
12
  POW = "pow"
12
13
  MOD = "mod"
@@ -17,6 +18,8 @@ class OperatorType(Enum):
17
18
  EQUAL = "eq"
18
19
  NOT_EQUAL = "ne"
19
20
  NOT = "invert"
21
+ NEG = "neg"
22
+ POS = "pos"
20
23
  LSHIFT = "lshift"
21
24
  RSHIFT = "rshift"
22
25
  BIT_AND = "and"
@@ -34,6 +37,7 @@ OPERATOR_TEMPLATES = {
34
37
  OperatorType.SUB: "{} - {}",
35
38
  OperatorType.MUL: "{} * {}",
36
39
  OperatorType.DIV: "{} / {}",
40
+ OperatorType.FLOOR_DIV: "{} // {}",
37
41
  OperatorType.POW: "{} ** {}",
38
42
  OperatorType.MOD: "{} % {}",
39
43
  OperatorType.LESS_THAN: "{} < {}",
@@ -42,6 +46,9 @@ OPERATOR_TEMPLATES = {
42
46
  OperatorType.GREATER_THAN_EQUAL: "{} >= {}",
43
47
  OperatorType.EQUAL: "{} == {}",
44
48
  OperatorType.NOT_EQUAL: "{} != {}",
49
+ OperatorType.NOT: "~{}",
50
+ OperatorType.NEG: "-{}",
51
+ OperatorType.POS: "+{}",
45
52
  OperatorType.VECTOR_PACK: "({}, {}, {})",
46
53
  OperatorType.NOOP: "{}",
47
54
  OperatorType.LSHIFT: "{} << {}",
@@ -57,6 +64,7 @@ OPERATORS_TO_FUNCTIONS = {
57
64
  OperatorType.SUB: operator.sub,
58
65
  OperatorType.MUL: operator.mul,
59
66
  OperatorType.DIV: operator.truediv,
67
+ OperatorType.FLOOR_DIV: operator.floordiv,
60
68
  OperatorType.MOD: operator.mod,
61
69
  OperatorType.POW: operator.pow,
62
70
  OperatorType.LESS_THAN: operator.lt,
@@ -65,6 +73,9 @@ OPERATORS_TO_FUNCTIONS = {
65
73
  OperatorType.GREATER_THAN_EQUAL: operator.ge,
66
74
  OperatorType.EQUAL: operator.eq,
67
75
  OperatorType.NOT_EQUAL: operator.ne,
76
+ OperatorType.NOT: operator.invert,
77
+ OperatorType.NEG: operator.neg,
78
+ OperatorType.POS: operator.pos,
68
79
  OperatorType.LSHIFT: operator.lshift,
69
80
  OperatorType.RSHIFT: operator.rshift,
70
81
  OperatorType.BIT_AND: operator.and_,
@@ -80,6 +91,7 @@ REFLECTABLE_OPERATORS = {
80
91
  OperatorType.SUB,
81
92
  OperatorType.MUL,
82
93
  OperatorType.DIV,
94
+ OperatorType.FLOOR_DIV,
83
95
  OperatorType.MOD,
84
96
  OperatorType.POW,
85
97
  OperatorType.LSHIFT,
@@ -19,6 +19,21 @@ class ProcfuncContext:
19
19
  'ignore' silently returns an empty mesh, 'warn' logs a warning, 'throw' raises an error.
20
20
  """
21
21
 
22
+ warn_mode_transpile_dropped_attrs: Literal["ignore", "warn", "throw"]
23
+ """
24
+ Controls behavior when transpiling a bpy node whose attributes carry render-affecting
25
+ state procfunc has no binding for, so the transpiled result would render differently
26
+ (e.g. a non-identity texture_mapping on a ShaderNodeTex* node).
27
+ 'ignore' drops it silently, 'warn' logs a warning, 'throw' raises an error.
28
+ """
29
+
30
+ record_node_definitions: bool = False
31
+ """
32
+ Record the user-space file/line/function that constructed each ProcNode, used only to
33
+ enrich node-instantiation error messages. Walks the stack once per node, which can
34
+ dominate build time in node-heavy callers, so off by default.
35
+ """
36
+
22
37
  def __post_init__(self):
23
38
  """Initialize computed fields after dataclass creation."""
24
39
  if self.num_cpu_cores <= 0:
@@ -27,10 +42,12 @@ class ProcfuncContext:
27
42
  def set_strict(self):
28
43
  """Set all warning modes to 'throw'"""
29
44
  self.warn_mode_empty_geonodes = "throw"
45
+ self.warn_mode_transpile_dropped_attrs = "throw"
30
46
 
31
47
  def set_warn(self):
32
48
  """Set all warning modes to 'warn'"""
33
49
  self.warn_mode_empty_geonodes = "warn"
50
+ self.warn_mode_transpile_dropped_attrs = "warn"
34
51
 
35
52
 
36
53
  # Global context instance
@@ -40,10 +57,18 @@ warn_modes = ["ignore", "warn", "throw"]
40
57
  _warn_mode_empty_geonodes = os.environ.get("PROCFUNC_WARN_MODE_EMPTY_GEONODES", "warn")
41
58
  assert _warn_mode_empty_geonodes in warn_modes
42
59
 
60
+ _warn_mode_transpile_dropped_attrs = os.environ.get(
61
+ "PROCFUNC_WARN_MODE_TRANSPILE_DROPPED_ATTRS", "throw"
62
+ )
63
+ assert _warn_mode_transpile_dropped_attrs in warn_modes
64
+
43
65
  globals = ProcfuncContext(
44
66
  num_cpu_cores=int(os.environ.get("PROCFUNC_NUM_CPU_CORES", 0)),
45
67
  warn_mode_empty_geonodes=_warn_mode_empty_geonodes, # type: ignore[invalid-assignment]
68
+ warn_mode_transpile_dropped_attrs=_warn_mode_transpile_dropped_attrs, # type: ignore[invalid-assignment]
46
69
  current_trace_level=None,
70
+ record_node_definitions=os.environ.get("PROCFUNC_RECORD_NODE_DEFINITIONS", "0")
71
+ == "1",
47
72
  )
48
73
 
49
74
 
@@ -33,6 +33,7 @@ def choice_idx(rng: np.random.Generator, weights: list[float]) -> int:
33
33
  def _peekthrough_execute_all_choices(
34
34
  choice_options: list[tuple[Callable[..., T], float]],
35
35
  chosen_idx: int,
36
+ choice_rng: cg.Node,
36
37
  args: tuple,
37
38
  kwargs: dict,
38
39
  ) -> cg.Proxy:
@@ -43,6 +44,7 @@ def _peekthrough_execute_all_choices(
43
44
  evald.append((res, weight))
44
45
 
45
46
  new_kwargs = dict(
47
+ choice_rng=choice_rng,
46
48
  choice_options=evald,
47
49
  chosen_idx=chosen_idx,
48
50
  )
@@ -67,6 +69,7 @@ class ChoiceResultProxy(cg.Proxy):
67
69
  return _peekthrough_execute_all_choices(
68
70
  self.node.kwargs["choice_options"],
69
71
  self.node.kwargs["chosen_idx"],
72
+ self.node.kwargs["choice_rng"],
70
73
  args,
71
74
  kwargs,
72
75
  )
@@ -92,13 +95,16 @@ def _choice_create_custom_tracer_wrapper(
92
95
  @functools.wraps(choice)
93
96
  def wrapper(
94
97
  choice_rng: RngProxy,
95
- choice_options: list[tuple[T, float]] | None = None,
98
+ choice_options: list[tuple[T, float]],
96
99
  chosen_idx: int | None = None,
97
100
  ):
98
101
  choice_values, choice_weights = zip(*choice_options)
99
102
  if chosen_idx is None:
100
103
  chosen_idx = choice_idx(choice_rng.rng, choice_weights)
101
104
 
105
+ if patcher.trace_level < TraceLevel.RANDOM_CONTROL:
106
+ return choice_values[chosen_idx]
107
+
102
108
  unwrapped_options = [
103
109
  (pytree.PyTree(v).map(_unwrap_proxy).obj(), w) for v, w in choice_options
104
110
  ]
@@ -28,6 +28,7 @@ from .execute.execute import (
28
28
  )
29
29
  from .execute.util import NODE_OPERATOR_TABLE
30
30
  from .types import (
31
+ HandleType,
31
32
  ProcNode,
32
33
  Shader,
33
34
  SocketOrVal,
@@ -51,6 +52,7 @@ __all__ = [
51
52
  "ProcNode",
52
53
  "Shader",
53
54
  "SocketOrVal",
55
+ "HandleType",
54
56
  "NodeDataType",
55
57
  "NodeGroupType",
56
58
  "SocketType",
@@ -61,16 +61,31 @@ def rgb_curve(
61
61
  fac: nt.SocketOrVal[float],
62
62
  color: nt.SocketOrVal[pt.Color],
63
63
  curves: list[np.ndarray] | np.ndarray | None = None,
64
+ handle_types: list[list[nt.HandleType]] | None = None,
65
+ use_clip: bool = True,
66
+ extend: Literal["HORIZONTAL", "EXTRAPOLATED"] = "EXTRAPOLATED",
67
+ clip_min: tuple[float, float] | None = None,
68
+ clip_max: tuple[float, float] | None = None,
64
69
  ) -> nt.ProcNode:
65
70
  """
66
71
  Uses a RGBCurve Shader Node.
67
72
 
73
+ `handle_types[i]` contains the handles for the i-th curve, and
74
+ `handle_types[i][j]` is the handle type for `curves[i][j]`.
75
+
68
76
  See: https://docs.blender.org/manual/en/4.2/render/shader_nodes/color/rgb_curves.html
69
77
  """
70
78
  return nt.ProcNode.from_nodetype(
71
79
  node_type="ShaderNodeRGBCurve",
72
80
  inputs={"Fac": fac, "Color": color},
73
- attrs={"curves": curves},
81
+ attrs={
82
+ "curves": curves,
83
+ "handle_types": handle_types,
84
+ "use_clip": use_clip,
85
+ "extend": extend,
86
+ "clip_min": clip_min,
87
+ "clip_max": clip_max,
88
+ },
74
89
  )
75
90
 
76
91