blenderwright 2.2.0__tar.gz → 2.2.1__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 (203) hide show
  1. {blenderwright-2.2.0 → blenderwright-2.2.1}/PKG-INFO +1 -1
  2. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/__init__.py +1 -1
  3. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/blender_manifest.toml +1 -1
  4. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/materials.py +12 -2
  5. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/objects.py +21 -1
  6. {blenderwright-2.2.0 → blenderwright-2.2.1}/pyproject.toml +1 -1
  7. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_materials_handler.py +64 -0
  8. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_objects_handler.py +62 -0
  9. {blenderwright-2.2.0 → blenderwright-2.2.1}/uv.lock +1 -1
  10. {blenderwright-2.2.0 → blenderwright-2.2.1}/.github/FUNDING.yml +0 -0
  11. {blenderwright-2.2.0 → blenderwright-2.2.1}/.github/workflows/ci.yml +0 -0
  12. {blenderwright-2.2.0 → blenderwright-2.2.1}/.github/workflows/pylint.yml +0 -0
  13. {blenderwright-2.2.0 → blenderwright-2.2.1}/.github/workflows/release.yml +0 -0
  14. {blenderwright-2.2.0 → blenderwright-2.2.1}/.github/workflows/test-bpy51.yml +0 -0
  15. {blenderwright-2.2.0 → blenderwright-2.2.1}/.gitignore +0 -0
  16. {blenderwright-2.2.0 → blenderwright-2.2.1}/LICENSE.md +0 -0
  17. {blenderwright-2.2.0 → blenderwright-2.2.1}/README.md +0 -0
  18. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/dispatcher.py +0 -0
  19. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/__init__.py +0 -0
  20. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/animation.py +0 -0
  21. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/armature.py +0 -0
  22. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/booltool.py +0 -0
  23. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/camera.py +0 -0
  24. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/code_exec.py +0 -0
  25. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/collections.py +0 -0
  26. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/curves.py +0 -0
  27. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/file_ops.py +0 -0
  28. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/geometry_nodes.py +0 -0
  29. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/gpencil.py +0 -0
  30. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/lighting.py +0 -0
  31. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/mesh_editing.py +0 -0
  32. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/mesh_quality.py +0 -0
  33. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/modeling.py +0 -0
  34. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/physics.py +0 -0
  35. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/print3d.py +0 -0
  36. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/procedural.py +0 -0
  37. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/raster.py +0 -0
  38. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/rendering.py +0 -0
  39. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/scene.py +0 -0
  40. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/sculpting.py +0 -0
  41. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/selection.py +0 -0
  42. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/sequencer.py +0 -0
  43. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/sweep.py +0 -0
  44. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/transforms.py +0 -0
  45. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/uv.py +0 -0
  46. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/handlers/viewport.py +0 -0
  47. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/render_guard.py +0 -0
  48. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/server.py +0 -0
  49. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/thread_safety.py +0 -0
  50. {blenderwright-2.2.0 → blenderwright-2.2.1}/addon/ui_panel.py +0 -0
  51. {blenderwright-2.2.0 → blenderwright-2.2.1}/blend-ai-v1.0.0.zip +0 -0
  52. {blenderwright-2.2.0 → blenderwright-2.2.1}/build.ps1 +0 -0
  53. {blenderwright-2.2.0 → blenderwright-2.2.1}/build.sh +0 -0
  54. {blenderwright-2.2.0 → blenderwright-2.2.1}/docs/.nojekyll +0 -0
  55. {blenderwright-2.2.0 → blenderwright-2.2.1}/docs/CNAME +0 -0
  56. {blenderwright-2.2.0 → blenderwright-2.2.1}/docs/googled2f6c71abc2d6a7b.html +0 -0
  57. {blenderwright-2.2.0 → blenderwright-2.2.1}/docs/index.html +0 -0
  58. {blenderwright-2.2.0 → blenderwright-2.2.1}/docs/robots.txt +0 -0
  59. {blenderwright-2.2.0 → blenderwright-2.2.1}/docs/shuttle-launch.mp4 +0 -0
  60. {blenderwright-2.2.0 → blenderwright-2.2.1}/docs/sitemap.xml +0 -0
  61. {blenderwright-2.2.0 → blenderwright-2.2.1}/glama.json +0 -0
  62. {blenderwright-2.2.0 → blenderwright-2.2.1}/install-addon.sh +0 -0
  63. {blenderwright-2.2.0 → blenderwright-2.2.1}/install_addon.py +0 -0
  64. {blenderwright-2.2.0 → blenderwright-2.2.1}/launch_ollama.sh +0 -0
  65. {blenderwright-2.2.0 → blenderwright-2.2.1}/saloon.png +0 -0
  66. {blenderwright-2.2.0 → blenderwright-2.2.1}/screenshot.png +0 -0
  67. {blenderwright-2.2.0 → blenderwright-2.2.1}/scripts/generate_tool_docs.py +0 -0
  68. {blenderwright-2.2.0 → blenderwright-2.2.1}/shader-preview.png +0 -0
  69. {blenderwright-2.2.0 → blenderwright-2.2.1}/shuttle-launch.gif +0 -0
  70. {blenderwright-2.2.0 → blenderwright-2.2.1}/shuttle-launch.png +0 -0
  71. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/__init__.py +0 -0
  72. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/__main__.py +0 -0
  73. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/aliases.py +0 -0
  74. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/connection.py +0 -0
  75. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/enum_hints.py +0 -0
  76. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/ollama_chat.py +0 -0
  77. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/prompts/__init__.py +0 -0
  78. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/prompts/workflows.py +0 -0
  79. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/resources/__init__.py +0 -0
  80. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/resources/scene_info.py +0 -0
  81. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/server.py +0 -0
  82. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/strict.py +0 -0
  83. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tool_registry.py +0 -0
  84. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/__init__.py +0 -0
  85. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/animation.py +0 -0
  86. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/armature.py +0 -0
  87. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/booltool.py +0 -0
  88. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/camera.py +0 -0
  89. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/code_exec.py +0 -0
  90. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/collections.py +0 -0
  91. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/curves.py +0 -0
  92. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/file_ops.py +0 -0
  93. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/geometry_nodes.py +0 -0
  94. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/gpencil.py +0 -0
  95. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/lighting.py +0 -0
  96. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/materials.py +0 -0
  97. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/mesh_editing.py +0 -0
  98. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/mesh_quality.py +0 -0
  99. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/modeling.py +0 -0
  100. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/objects.py +0 -0
  101. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/physics.py +0 -0
  102. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/print3d.py +0 -0
  103. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/rendering.py +0 -0
  104. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/scene.py +0 -0
  105. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/screenshot.py +0 -0
  106. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/sculpting.py +0 -0
  107. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/selection.py +0 -0
  108. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/sequencer.py +0 -0
  109. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/sweep.py +0 -0
  110. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/transforms.py +0 -0
  111. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/uv.py +0 -0
  112. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/tools/viewport.py +0 -0
  113. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/toolsets.py +0 -0
  114. {blenderwright-2.2.0 → blenderwright-2.2.1}/src/blenderwright/validators.py +0 -0
  115. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/__init__.py +0 -0
  116. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/conftest.py +0 -0
  117. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/__init__.py +0 -0
  118. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/conftest.py +0 -0
  119. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_dispatcher.py +0 -0
  120. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handler_registration.py +0 -0
  121. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/__init__.py +0 -0
  122. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_camera_handler.py +0 -0
  123. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_code_exec_handler.py +0 -0
  124. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_geometry_nodes_handler.py +0 -0
  125. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_gpencil_handler.py +0 -0
  126. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_mesh_quality_handler.py +0 -0
  127. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_modeling_handler.py +0 -0
  128. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_print3d_handler.py +0 -0
  129. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_procedural_handler.py +0 -0
  130. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_raster_handler.py +0 -0
  131. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_rendering_handler.py +0 -0
  132. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_scene_handler.py +0 -0
  133. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_sculpting_handler.py +0 -0
  134. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_selection_handler.py +0 -0
  135. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_sequencer_handler.py +0 -0
  136. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_handlers/test_sweep_handler.py +0 -0
  137. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_layer_consistency.py +0 -0
  138. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_module_cache_purge.py +0 -0
  139. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_render_guard.py +0 -0
  140. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_server.py +0 -0
  141. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_thread_safety.py +0 -0
  142. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_addon/test_ui_panel.py +0 -0
  143. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_command_registry.py +0 -0
  144. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_connection.py +0 -0
  145. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_enum_hints.py +0 -0
  146. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_installer.py +0 -0
  147. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_long_names.py +0 -0
  148. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_object_param_naming.py +0 -0
  149. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_ollama_budget.py +0 -0
  150. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_ollama_chat.py +0 -0
  151. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_ollama_toolsets.py +0 -0
  152. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_ollama_vision.py +0 -0
  153. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_project_metadata.py +0 -0
  154. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_round_wasters.py +0 -0
  155. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_strict_parameters.py +0 -0
  156. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tool_disambiguation.py +0 -0
  157. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/__init__.py +0 -0
  158. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/conftest.py +0 -0
  159. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_animation.py +0 -0
  160. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_armature.py +0 -0
  161. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_auto_critique_prompt.py +0 -0
  162. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_booltool.py +0 -0
  163. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_camera.py +0 -0
  164. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_code_exec.py +0 -0
  165. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_collections.py +0 -0
  166. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_curves.py +0 -0
  167. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_eevee_light_path.py +0 -0
  168. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_extensions.py +0 -0
  169. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_file_ops.py +0 -0
  170. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_geometry_nodes.py +0 -0
  171. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_gpencil.py +0 -0
  172. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_issue_31_validation.py +0 -0
  173. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_lighting.py +0 -0
  174. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_materials.py +0 -0
  175. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_mesh_editing.py +0 -0
  176. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_mesh_quality.py +0 -0
  177. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_mesh_repair.py +0 -0
  178. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_modeling.py +0 -0
  179. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_negative_scale_primitives.py +0 -0
  180. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_new_nodes.py +0 -0
  181. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_numeric_text_values.py +0 -0
  182. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_objects.py +0 -0
  183. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_physics.py +0 -0
  184. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_point_camera_at.py +0 -0
  185. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_print3d.py +0 -0
  186. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_procedural.py +0 -0
  187. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_prompts.py +0 -0
  188. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_raster.py +0 -0
  189. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_rendering.py +0 -0
  190. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_scene.py +0 -0
  191. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_screenshot.py +0 -0
  192. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_sculpting.py +0 -0
  193. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_selection.py +0 -0
  194. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_selection_respected.py +0 -0
  195. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_sequencer.py +0 -0
  196. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_shader_nodes.py +0 -0
  197. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_sweep.py +0 -0
  198. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_transforms.py +0 -0
  199. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_uv.py +0 -0
  200. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_uv_slim.py +0 -0
  201. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_tools/test_viewport.py +0 -0
  202. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_toolsets.py +0 -0
  203. {blenderwright-2.2.0 → blenderwright-2.2.1}/tests/test_validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: blenderwright
3
- Version: 2.2.0
3
+ Version: 2.2.1
4
4
  Summary: The most intuitive and efficient MCP Server for Blender
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE.md
@@ -8,7 +8,7 @@ Blender's Python API.
8
8
  bl_info = {
9
9
  "name": "blenderwright",
10
10
  "author": "blenderwright",
11
- "version": (2, 2, 0),
11
+ "version": (2, 2, 1),
12
12
  "blender": (4, 2, 0),
13
13
  "location": "View3D > Sidebar > blenderwright",
14
14
  "description": "MCP Server integration for AI-assisted 3D workflows",
@@ -1,7 +1,7 @@
1
1
  schema_version = "1.0.0"
2
2
 
3
3
  id = "blenderwright"
4
- version = "2.2.0"
4
+ version = "2.2.1"
5
5
  name = "blenderwright"
6
6
  tagline = "MCP server integration for AI-assisted 3D workflows"
7
7
  maintainer = "jabberwock <88205+jabberwock@users.noreply.github.com>"
@@ -55,9 +55,19 @@ def handle_assign_material(params: dict) -> dict:
55
55
  obj.active_material_index = i
56
56
  return {"object": obj.name, "material": mat.name, "action": "already_assigned", "slot": i}
57
57
 
58
+ # Fill the first empty slot before adding one. A boolean modifier
59
+ # leaves an empty slot 0 that every face points at; appending puts
60
+ # the material in slot 1 and the object still renders grey.
61
+ for i, slot_mat in enumerate(obj.data.materials):
62
+ if slot_mat is None:
63
+ obj.data.materials[i] = mat
64
+ obj.active_material_index = i
65
+ return {"object": obj.name, "material": mat.name, "action": "assigned", "slot": i}
66
+
58
67
  obj.data.materials.append(mat)
59
- obj.active_material_index = len(obj.data.materials) - 1
60
- return {"object": obj.name, "material": mat.name, "action": "assigned", "slot": len(obj.data.materials) - 1}
68
+ slot = len(obj.data.materials) - 1
69
+ obj.active_material_index = slot
70
+ return {"object": obj.name, "material": mat.name, "action": "assigned", "slot": slot}
61
71
  except Exception as e:
62
72
  raise RuntimeError(f"Failed to assign material: {e}")
63
73
 
@@ -39,6 +39,21 @@ def _get_primitive_op(ptype: str):
39
39
  return ops_map.get(ptype)
40
40
 
41
41
 
42
+ def _bake_scale(obj, scale) -> None:
43
+ """Apply a creation scale the way primitive_cube_add does: into the mesh.
44
+
45
+ Mesh data is transformed so the object keeps unit scale and modifiers
46
+ see the real size. An empty has no mesh, so it gets object scale.
47
+ """
48
+ sx, sy, sz = (float(v) for v in scale)
49
+ if (sx, sy, sz) == (1.0, 1.0, 1.0):
50
+ return
51
+ if obj.data is not None and hasattr(obj.data, "transform"):
52
+ obj.data.transform(mathutils.Matrix.Diagonal((sx, sy, sz, 1)))
53
+ else:
54
+ obj.scale = (sx, sy, sz)
55
+
56
+
42
57
  def _extent(obj) -> dict:
43
58
  """The object's size and where it ends, in world space.
44
59
 
@@ -77,9 +92,14 @@ def handle_create_object(params: dict) -> dict:
77
92
  op_func = _get_primitive_op(obj_type)
78
93
  if op_func is None:
79
94
  raise ValueError(f"Unknown object type: {obj_type}")
80
- op_func(location=location, rotation=rotation, scale=scale)
95
+ # Created at unit scale on purpose: the scale is baked below.
96
+ # Blender 5.1's primitive_plane_add and primitive_circle_add
97
+ # silently ignore their scale argument while primitive_cube_add
98
+ # bakes it into the mesh, so the op cannot be trusted with it.
99
+ op_func(location=location, rotation=rotation)
81
100
 
82
101
  obj = bpy.context.active_object
102
+ _bake_scale(obj, scale)
83
103
  if name:
84
104
  obj.name = name
85
105
  if obj.data:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "blenderwright"
7
- version = "2.2.0"
7
+ version = "2.2.1"
8
8
  description = "The most intuitive and efficient MCP Server for Blender"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -481,3 +481,67 @@ class TestRegistration:
481
481
  "set_color_ramp_interpolation",
482
482
  "get_color_ramp",
483
483
  } <= registered
484
+
485
+
486
+ # ---------------------------------------------------------------------------
487
+ # assign_material fills an empty slot before adding one
488
+ # ---------------------------------------------------------------------------
489
+
490
+
491
+ class TestAssignMaterialSlots:
492
+ """An object that has been through a boolean modifier carries an empty
493
+ material slot 0. Appending put the material in slot 1, every face still
494
+ pointed at slot 0, and the wall rendered grey. The first empty slot is
495
+ filled instead; a new slot is only added when none is empty."""
496
+
497
+ def _obj(self, slots):
498
+ obj = MagicMock()
499
+ obj.name = "Wall"
500
+ obj.data.materials = list(slots)
501
+ return obj
502
+
503
+ def _mat(self, name):
504
+ mat = MagicMock()
505
+ mat.name = name
506
+ return mat
507
+
508
+ def _patch(self, monkeypatch, obj, mat):
509
+ import bpy
510
+ monkeypatch.setattr(bpy.data.objects, "get", lambda n: obj)
511
+ monkeypatch.setattr(bpy.data.materials, "get", lambda n: mat)
512
+
513
+ def test_fills_the_empty_slot(self, mh, monkeypatch):
514
+ sage = self._mat("Wall_Sage")
515
+ obj = self._obj([None])
516
+ self._patch(monkeypatch, obj, sage)
517
+ result = mh.handle_assign_material({"object_name": "Wall", "material_name": "Wall_Sage"})
518
+ assert obj.data.materials == [sage]
519
+ assert result["slot"] == 0
520
+ assert result["action"] == "assigned"
521
+
522
+ def test_fills_the_first_empty_slot_only(self, mh, monkeypatch):
523
+ sage = self._mat("Wall_Sage")
524
+ other = self._mat("Other")
525
+ obj = self._obj([other, None, None])
526
+ self._patch(monkeypatch, obj, sage)
527
+ result = mh.handle_assign_material({"object_name": "Wall", "material_name": "Wall_Sage"})
528
+ assert obj.data.materials == [other, sage, None]
529
+ assert result["slot"] == 1
530
+
531
+ def test_appends_when_no_slot_is_empty(self, mh, monkeypatch):
532
+ sage = self._mat("Wall_Sage")
533
+ other = self._mat("Other")
534
+ obj = self._obj([other])
535
+ self._patch(monkeypatch, obj, sage)
536
+ result = mh.handle_assign_material({"object_name": "Wall", "material_name": "Wall_Sage"})
537
+ assert obj.data.materials == [other, sage]
538
+ assert result["slot"] == 1
539
+
540
+ def test_already_assigned_is_reported(self, mh, monkeypatch):
541
+ sage = self._mat("Wall_Sage")
542
+ obj = self._obj([None, sage])
543
+ self._patch(monkeypatch, obj, sage)
544
+ result = mh.handle_assign_material({"object_name": "Wall", "material_name": "Wall_Sage"})
545
+ assert result["action"] == "already_assigned"
546
+ assert result["slot"] == 1
547
+ assert obj.data.materials == [None, sage]
@@ -544,3 +544,65 @@ class TestCreateReturnsExtent:
544
544
  result = objects_handler.handle_create_object({"type": "CUBE"})
545
545
  assert result["name"] == "Fuselage"
546
546
  assert "bounds" not in result
547
+
548
+
549
+ # ---------------------------------------------------------------------------
550
+ # create_object bakes the scale itself
551
+ # ---------------------------------------------------------------------------
552
+
553
+
554
+ class TestCreateBakesScale:
555
+ """Blender 5.1's primitive_plane_add and primitive_circle_add silently
556
+ ignore their scale argument, while primitive_cube_add bakes it into the
557
+ mesh. A hallway floor asked for at scale (3, 4.5, 1) came back 2m square.
558
+ The handler now creates every primitive at unit scale and bakes the scale
559
+ into the mesh itself, so every type behaves the way the cube always did."""
560
+
561
+ def _obj(self, bpy):
562
+ obj = MagicMock()
563
+ obj.name = "Floor"
564
+ obj.type = "MESH"
565
+ obj.location = [0, 0, 0]
566
+ obj.dimensions = [6.0, 9.0, 0.0]
567
+ obj.bound_box = None
568
+ for op in ("primitive_plane_add", "primitive_cube_add", "primitive_circle_add"):
569
+ getattr(bpy.ops.mesh, op).side_effect = None
570
+ bpy.context.active_object = obj
571
+ return obj
572
+
573
+ def test_plane_scale_is_baked_into_the_mesh(self, objects_handler):
574
+ import bpy
575
+ import mathutils
576
+ bpy.reset_mock()
577
+ mathutils.Matrix.reset_mock()
578
+ obj = self._obj(bpy)
579
+ objects_handler.handle_create_object({
580
+ "type": "PLANE", "location": (0, 4.5, 0), "scale": (3, 4.5, 1),
581
+ })
582
+ mathutils.Matrix.Diagonal.assert_called_once_with((3, 4.5, 1, 1))
583
+ obj.data.transform.assert_called_once_with(mathutils.Matrix.Diagonal.return_value)
584
+
585
+ def test_the_op_is_not_asked_to_scale(self, objects_handler):
586
+ """Passing scale to the op as well would double it on the cube."""
587
+ import bpy
588
+ bpy.reset_mock()
589
+ self._obj(bpy)
590
+ objects_handler.handle_create_object({"type": "CUBE", "scale": (2, 2, 2)})
591
+ assert "scale" not in bpy.ops.mesh.primitive_cube_add.call_args.kwargs
592
+
593
+ def test_unit_scale_does_not_touch_the_mesh(self, objects_handler):
594
+ import bpy
595
+ bpy.reset_mock()
596
+ obj = self._obj(bpy)
597
+ objects_handler.handle_create_object({"type": "CIRCLE", "scale": (1, 1, 1)})
598
+ obj.data.transform.assert_not_called()
599
+
600
+ def test_empty_gets_object_scale(self, objects_handler):
601
+ """An empty has no mesh to bake into, so its object scale is set."""
602
+ import bpy
603
+ bpy.reset_mock()
604
+ obj = self._obj(bpy)
605
+ obj.type = "EMPTY"
606
+ obj.data = None
607
+ objects_handler.handle_create_object({"type": "EMPTY", "scale": (2, 3, 4)})
608
+ assert tuple(obj.scale) == (2, 3, 4)
@@ -51,7 +51,7 @@ wheels = [
51
51
 
52
52
  [[package]]
53
53
  name = "blenderwright"
54
- version = "2.2.0"
54
+ version = "2.2.1"
55
55
  source = { editable = "." }
56
56
  dependencies = [
57
57
  { name = "mcp" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes