meshwire 0.5.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 (168) hide show
  1. meshwire-0.5.0/.editorconfig +24 -0
  2. meshwire-0.5.0/.git-blame-ignore-revs +2 -0
  3. meshwire-0.5.0/.github/ISSUE_TEMPLATE/bug_report.yml +77 -0
  4. meshwire-0.5.0/.github/ISSUE_TEMPLATE/feature_request.yml +54 -0
  5. meshwire-0.5.0/.github/PULL_REQUEST_TEMPLATE.md +31 -0
  6. meshwire-0.5.0/.github/dependabot.yml +19 -0
  7. meshwire-0.5.0/.github/workflows/blender.yml +206 -0
  8. meshwire-0.5.0/.github/workflows/ci.yml +97 -0
  9. meshwire-0.5.0/.github/workflows/codeql.yml +33 -0
  10. meshwire-0.5.0/.github/workflows/release.yml +135 -0
  11. meshwire-0.5.0/.gitignore +99 -0
  12. meshwire-0.5.0/CHANGELOG.md +583 -0
  13. meshwire-0.5.0/CLA.md +82 -0
  14. meshwire-0.5.0/CONTRIBUTING.md +339 -0
  15. meshwire-0.5.0/LICENSE +661 -0
  16. meshwire-0.5.0/PKG-INFO +476 -0
  17. meshwire-0.5.0/README.md +446 -0
  18. meshwire-0.5.0/SECURITY.md +104 -0
  19. meshwire-0.5.0/addon/blender_mcp_addon/__init__.py +331 -0
  20. meshwire-0.5.0/addon/blender_mcp_addon/blender_manifest.toml +20 -0
  21. meshwire-0.5.0/addon/blender_mcp_addon/compat.py +543 -0
  22. meshwire-0.5.0/addon/blender_mcp_addon/external/__init__.py +1 -0
  23. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/__init__.py +579 -0
  24. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/base.py +274 -0
  25. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/comfyui.py +705 -0
  26. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/hunyuan3d.py +556 -0
  27. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/meshy.py +272 -0
  28. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/multiview.py +161 -0
  29. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/ollama_vision.py +504 -0
  30. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/rodin.py +540 -0
  31. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/stable_fast_3d.py +155 -0
  32. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/tripo_ai.py +186 -0
  33. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/triposg.py +150 -0
  34. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/triposr.py +562 -0
  35. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/workflows/controlnet_texture.json +92 -0
  36. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/workflows/inpaint.json +87 -0
  37. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/workflows/multiview_to_3d.json +110 -0
  38. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/workflows/pbr_texture.json +97 -0
  39. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/workflows/reference_image.json +68 -0
  40. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/workflows/stable_fast_3d.json +32 -0
  41. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_backends/workflows/triposg.json +84 -0
  42. meshwire-0.5.0/addon/blender_mcp_addon/external/ai_models.py +1008 -0
  43. meshwire-0.5.0/addon/blender_mcp_addon/external/cache.py +358 -0
  44. meshwire-0.5.0/addon/blender_mcp_addon/external/job_queue.py +553 -0
  45. meshwire-0.5.0/addon/blender_mcp_addon/external/mesh_processing.py +792 -0
  46. meshwire-0.5.0/addon/blender_mcp_addon/external/pipeline.py +420 -0
  47. meshwire-0.5.0/addon/blender_mcp_addon/external/polyhaven.py +611 -0
  48. meshwire-0.5.0/addon/blender_mcp_addon/external/refinement.py +107 -0
  49. meshwire-0.5.0/addon/blender_mcp_addon/external/texture_applicator.py +136 -0
  50. meshwire-0.5.0/addon/blender_mcp_addon/handlers/__init__.py +473 -0
  51. meshwire-0.5.0/addon/blender_mcp_addon/handlers/_helpers.py +1240 -0
  52. meshwire-0.5.0/addon/blender_mcp_addon/handlers/ai.py +1123 -0
  53. meshwire-0.5.0/addon/blender_mcp_addon/handlers/animation.py +129 -0
  54. meshwire-0.5.0/addon/blender_mcp_addon/handlers/annotations.py +432 -0
  55. meshwire-0.5.0/addon/blender_mcp_addon/handlers/armature.py +1556 -0
  56. meshwire-0.5.0/addon/blender_mcp_addon/handlers/baking.py +1464 -0
  57. meshwire-0.5.0/addon/blender_mcp_addon/handlers/collections.py +360 -0
  58. meshwire-0.5.0/addon/blender_mcp_addon/handlers/export_import.py +188 -0
  59. meshwire-0.5.0/addon/blender_mcp_addon/handlers/geonodes.py +813 -0
  60. meshwire-0.5.0/addon/blender_mcp_addon/handlers/materials.py +737 -0
  61. meshwire-0.5.0/addon/blender_mcp_addon/handlers/measurement.py +918 -0
  62. meshwire-0.5.0/addon/blender_mcp_addon/handlers/mesh_editing.py +2751 -0
  63. meshwire-0.5.0/addon/blender_mcp_addon/handlers/modifiers.py +163 -0
  64. meshwire-0.5.0/addon/blender_mcp_addon/handlers/msfs.py +404 -0
  65. meshwire-0.5.0/addon/blender_mcp_addon/handlers/objects.py +276 -0
  66. meshwire-0.5.0/addon/blender_mcp_addon/handlers/physics.py +479 -0
  67. meshwire-0.5.0/addon/blender_mcp_addon/handlers/render.py +248 -0
  68. meshwire-0.5.0/addon/blender_mcp_addon/handlers/scene.py +53 -0
  69. meshwire-0.5.0/addon/blender_mcp_addon/handlers/sculpt.py +677 -0
  70. meshwire-0.5.0/addon/blender_mcp_addon/msfs/__init__.py +108 -0
  71. meshwire-0.5.0/addon/blender_mcp_addon/msfs/animation.py +397 -0
  72. meshwire-0.5.0/addon/blender_mcp_addon/msfs/collision.py +334 -0
  73. meshwire-0.5.0/addon/blender_mcp_addon/msfs/export.py +421 -0
  74. meshwire-0.5.0/addon/blender_mcp_addon/msfs/livery/__init__.py +53 -0
  75. meshwire-0.5.0/addon/blender_mcp_addon/msfs/livery/export.py +538 -0
  76. meshwire-0.5.0/addon/blender_mcp_addon/msfs/livery/painting.py +545 -0
  77. meshwire-0.5.0/addon/blender_mcp_addon/msfs/livery/templates.py +329 -0
  78. meshwire-0.5.0/addon/blender_mcp_addon/msfs/livery/transfer.py +653 -0
  79. meshwire-0.5.0/addon/blender_mcp_addon/msfs/lod.py +286 -0
  80. meshwire-0.5.0/addon/blender_mcp_addon/msfs/materials.py +387 -0
  81. meshwire-0.5.0/addon/blender_mcp_addon/security.py +25 -0
  82. meshwire-0.5.0/addon/blender_mcp_addon/socket_server.py +725 -0
  83. meshwire-0.5.0/addon/blender_mcp_addon/utils.py +173 -0
  84. meshwire-0.5.0/addon/blender_mcp_addon/validation.py +226 -0
  85. meshwire-0.5.0/addon/blender_mcp_addon/wire.py +478 -0
  86. meshwire-0.5.0/assets/logo.svg +19 -0
  87. meshwire-0.5.0/build-constraints.txt +93 -0
  88. meshwire-0.5.0/deploy/comfyui/custom_nodes.txt +11 -0
  89. meshwire-0.5.0/deploy/comfyui/docker-compose.yml +44 -0
  90. meshwire-0.5.0/deploy/comfyui/download_models.sh +105 -0
  91. meshwire-0.5.0/docs/MSFS_ROADMAP.md +498 -0
  92. meshwire-0.5.0/docs/architecture.md +87 -0
  93. meshwire-0.5.0/docs/index.md +53 -0
  94. meshwire-0.5.0/docs/tools.md +258 -0
  95. meshwire-0.5.0/docs/usage.md +166 -0
  96. meshwire-0.5.0/pyproject.toml +76 -0
  97. meshwire-0.5.0/scripts/changelog_section.py +41 -0
  98. meshwire-0.5.0/scripts/fetch_blender.py +104 -0
  99. meshwire-0.5.0/scripts/package_addon.py +90 -0
  100. meshwire-0.5.0/scripts/smoke_extension.py +145 -0
  101. meshwire-0.5.0/scripts/smoke_extension_boot.py +35 -0
  102. meshwire-0.5.0/scripts/tool_status.py +306 -0
  103. meshwire-0.5.0/src/mcp_blender/__init__.py +3 -0
  104. meshwire-0.5.0/src/mcp_blender/blender_client.py +685 -0
  105. meshwire-0.5.0/src/mcp_blender/py.typed +0 -0
  106. meshwire-0.5.0/src/mcp_blender/server.py +6528 -0
  107. meshwire-0.5.0/src/mcp_blender/tools/__init__.py +21 -0
  108. meshwire-0.5.0/src/mcp_blender/tools/animation.py +75 -0
  109. meshwire-0.5.0/src/mcp_blender/tools/export.py +80 -0
  110. meshwire-0.5.0/src/mcp_blender/tools/external.py +553 -0
  111. meshwire-0.5.0/src/mcp_blender/tools/materials.py +96 -0
  112. meshwire-0.5.0/src/mcp_blender/tools/modifiers.py +66 -0
  113. meshwire-0.5.0/src/mcp_blender/tools/objects.py +136 -0
  114. meshwire-0.5.0/src/mcp_blender/tools/render.py +74 -0
  115. meshwire-0.5.0/src/mcp_blender/tools/scene.py +56 -0
  116. meshwire-0.5.0/src/mcp_blender/types.py +106 -0
  117. meshwire-0.5.0/src/mcp_blender/wire.py +478 -0
  118. meshwire-0.5.0/tests/__init__.py +1 -0
  119. meshwire-0.5.0/tests/blender_integration_test.py +675 -0
  120. meshwire-0.5.0/tests/harness/__init__.py +0 -0
  121. meshwire-0.5.0/tests/harness/assets.py +88 -0
  122. meshwire-0.5.0/tests/harness/baselines/blender-4.2.json +883 -0
  123. meshwire-0.5.0/tests/harness/baselines/blender-4.3.json +883 -0
  124. meshwire-0.5.0/tests/harness/baselines/blender-4.4.json +883 -0
  125. meshwire-0.5.0/tests/harness/baselines/blender-4.5.json +883 -0
  126. meshwire-0.5.0/tests/harness/baselines/blender-5.0.json +883 -0
  127. meshwire-0.5.0/tests/harness/baselines/blender-5.1.json +883 -0
  128. meshwire-0.5.0/tests/harness/baselines/blender-5.2.json +883 -0
  129. meshwire-0.5.0/tests/harness/baselines/socket-lane.json +303 -0
  130. meshwire-0.5.0/tests/harness/cases.py +64 -0
  131. meshwire-0.5.0/tests/harness/catalog.py +15 -0
  132. meshwire-0.5.0/tests/harness/classify.py +57 -0
  133. meshwire-0.5.0/tests/harness/driver.py +293 -0
  134. meshwire-0.5.0/tests/harness/env.py +31 -0
  135. meshwire-0.5.0/tests/harness/fixtures.py +291 -0
  136. meshwire-0.5.0/tests/harness/runner.py +113 -0
  137. meshwire-0.5.0/tests/harness/scene.py +148 -0
  138. meshwire-0.5.0/tests/harness/socket_boot.py +94 -0
  139. meshwire-0.5.0/tests/harness/socket_lane.py +2371 -0
  140. meshwire-0.5.0/tests/result_cases.py +21 -0
  141. meshwire-0.5.0/tests/static_gate_baseline.json +10 -0
  142. meshwire-0.5.0/tests/test_ai_handlers.py +170 -0
  143. meshwire-0.5.0/tests/test_bake_restore.py +194 -0
  144. meshwire-0.5.0/tests/test_changelog_section.py +56 -0
  145. meshwire-0.5.0/tests/test_client.py +1014 -0
  146. meshwire-0.5.0/tests/test_comfyui_workflows.py +180 -0
  147. meshwire-0.5.0/tests/test_compat.py +571 -0
  148. meshwire-0.5.0/tests/test_handler_signatures.py +99 -0
  149. meshwire-0.5.0/tests/test_harness_driver.py +267 -0
  150. meshwire-0.5.0/tests/test_harness_socket_lane.py +350 -0
  151. meshwire-0.5.0/tests/test_harness_unit.py +561 -0
  152. meshwire-0.5.0/tests/test_instances.py +1068 -0
  153. meshwire-0.5.0/tests/test_msfs_logic.py +107 -0
  154. meshwire-0.5.0/tests/test_object_separate.py +46 -0
  155. meshwire-0.5.0/tests/test_path_handlers.py +84 -0
  156. meshwire-0.5.0/tests/test_pipeline_failure.py +119 -0
  157. meshwire-0.5.0/tests/test_readme.py +95 -0
  158. meshwire-0.5.0/tests/test_security_doc.py +21 -0
  159. meshwire-0.5.0/tests/test_security_settings.py +409 -0
  160. meshwire-0.5.0/tests/test_server.py +489 -0
  161. meshwire-0.5.0/tests/test_socket_server.py +1498 -0
  162. meshwire-0.5.0/tests/test_static_gates.py +1145 -0
  163. meshwire-0.5.0/tests/test_tools.py +338 -0
  164. meshwire-0.5.0/tests/test_undo_gating.py +112 -0
  165. meshwire-0.5.0/tests/test_validation.py +101 -0
  166. meshwire-0.5.0/tests/test_version.py +144 -0
  167. meshwire-0.5.0/tests/test_wire.py +485 -0
  168. meshwire-0.5.0/uv.lock +964 -0
@@ -0,0 +1,24 @@
1
+ # EditorConfig helps maintain consistent coding styles
2
+ # https://editorconfig.org
3
+
4
+ root = true
5
+
6
+ [*]
7
+ indent_style = space
8
+ indent_size = 4
9
+ end_of_line = lf
10
+ charset = utf-8
11
+ trim_trailing_whitespace = true
12
+ insert_final_newline = true
13
+
14
+ [*.py]
15
+ max_line_length = 100
16
+
17
+ [*.md]
18
+ trim_trailing_whitespace = false
19
+
20
+ [*.{json,yaml,yml,toml}]
21
+ indent_size = 2
22
+
23
+ [Makefile]
24
+ indent_style = tab
@@ -0,0 +1,2 @@
1
+ # Repo-wide ruff format. GitHub and `git blame --ignore-revs-file` skip it.
2
+ de1429cf354857f08fca8225585b762500b82241
@@ -0,0 +1,77 @@
1
+ name: Bug Report
2
+ description: Report a bug or unexpected behavior
3
+ title: "[Bug]: "
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for reporting! Please fill out the details below.
10
+ - type: input
11
+ id: blender-version
12
+ attributes:
13
+ label: Blender Version
14
+ description: "e.g., 4.2.19 LTS, 5.0"
15
+ placeholder: "4.2.19"
16
+ validations:
17
+ required: true
18
+ - type: input
19
+ id: mcp-version
20
+ attributes:
21
+ label: MCP Server Version
22
+ description: "e.g., 0.2.0"
23
+ placeholder: "0.2.0"
24
+ validations:
25
+ required: true
26
+ - type: input
27
+ id: tool-name
28
+ attributes:
29
+ label: Tool Name
30
+ description: "Which MCP tool is affected? e.g., blender_object_create"
31
+ placeholder: "blender_"
32
+ - type: textarea
33
+ id: description
34
+ attributes:
35
+ label: Description
36
+ description: What happened? What did you expect to happen?
37
+ validations:
38
+ required: true
39
+ - type: textarea
40
+ id: steps
41
+ attributes:
42
+ label: Steps to Reproduce
43
+ description: Minimal steps to reproduce the issue
44
+ value: |
45
+ 1.
46
+ 2.
47
+ 3.
48
+ validations:
49
+ required: true
50
+ - type: textarea
51
+ id: error
52
+ attributes:
53
+ label: Error Output
54
+ description: Paste any error messages or logs
55
+ render: shell
56
+ - type: dropdown
57
+ id: os
58
+ attributes:
59
+ label: Operating System
60
+ options:
61
+ - Windows
62
+ - macOS
63
+ - Linux
64
+ validations:
65
+ required: true
66
+ - type: dropdown
67
+ id: mcp-client
68
+ attributes:
69
+ label: MCP Client
70
+ options:
71
+ - Claude Desktop
72
+ - Claude Code
73
+ - Cursor
74
+ - VS Code + Continue
75
+ - Other
76
+ validations:
77
+ required: true
@@ -0,0 +1,54 @@
1
+ name: Feature Request
2
+ description: Suggest a new tool or enhancement
3
+ title: "[Feature]: "
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for suggesting an improvement! Please describe what you'd like.
10
+ - type: dropdown
11
+ id: category
12
+ attributes:
13
+ label: Tool Category
14
+ description: Which area does this feature relate to?
15
+ options:
16
+ - Scene / Object Management
17
+ - Modeling / Mesh Editing
18
+ - Materials / Shaders
19
+ - Sculpting
20
+ - Rigging / Armature
21
+ - Animation
22
+ - Rendering
23
+ - Baking
24
+ - Geometry Nodes
25
+ - Physics Simulation
26
+ - Export / Import
27
+ - AI Generation Pipeline
28
+ - MSFS Content Creation
29
+ - Livery System
30
+ - Measurement / Validation
31
+ - Collections / System
32
+ - Annotations
33
+ - Other
34
+ validations:
35
+ required: true
36
+ - type: textarea
37
+ id: description
38
+ attributes:
39
+ label: Description
40
+ description: Describe the feature or tool you'd like to see
41
+ validations:
42
+ required: true
43
+ - type: textarea
44
+ id: use-case
45
+ attributes:
46
+ label: Use Case
47
+ description: How would you use this? What workflow does it enable?
48
+ validations:
49
+ required: true
50
+ - type: textarea
51
+ id: alternatives
52
+ attributes:
53
+ label: Alternatives Considered
54
+ description: Any workarounds you've tried (e.g., using execute_script)
@@ -0,0 +1,31 @@
1
+ ## Summary
2
+
3
+ Brief description of what this PR does.
4
+
5
+ ## Changes
6
+
7
+ -
8
+
9
+ ## Tool Changes
10
+
11
+ - [ ] New tools added (update tool count in test_server.py)
12
+ - [ ] Existing tools modified
13
+ - [ ] Handler registrations added in `addon/blender_mcp_addon/handlers/`
14
+ - [ ] Handler implementations added
15
+
16
+ ## Testing
17
+
18
+ - [ ] `pytest tests/ --ignore=tests/blender_integration_test.py` passes
19
+ - [ ] Truth harness baselines updated if any tool result class changed (see CONTRIBUTING.md)
20
+ - [ ] `ruff check .` passes
21
+ - [ ] Tested with Blender (version: )
22
+ - [ ] Tested via MCP client (client: )
23
+
24
+ ## Checklist
25
+
26
+ - [ ] Tool definitions use `"type": "number"` (not `"integer"`) for numeric params
27
+ - [ ] Handler returns `{"success": True, ...}` or `{"error": "..."}`
28
+ - [ ] README updated if new tools added
29
+ - [ ] CHANGELOG updated
30
+
31
+ - [ ] I have read and agree to [CLA.md](../CLA.md) for this contribution.
@@ -0,0 +1,19 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: uv
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ open-pull-requests-limit: 2
8
+ groups:
9
+ python-minor-patch:
10
+ update-types: [minor, patch]
11
+
12
+ - package-ecosystem: github-actions
13
+ directory: /
14
+ schedule:
15
+ interval: weekly
16
+ open-pull-requests-limit: 2
17
+ groups:
18
+ actions-minor-patch:
19
+ update-types: [minor, patch]
@@ -0,0 +1,206 @@
1
+ name: Blender harness
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "17 4 * * *"
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: blender-${{ github.event_name }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
17
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
18
+
19
+ env:
20
+ BLENDER_DEPS: >-
21
+ xvfb xauth libgl1 libegl1 libglx-mesa0 libgl1-mesa-dri libxi6 libxxf86vm1
22
+ libxfixes3 libxrender1 libxkbcommon0 libsm6 libice6 libxkbcommon-x11-0 libdbus-1-3
23
+
24
+ jobs:
25
+ # Gated: an unrecorded behavior change on a supported Blender fails the run.
26
+ gated:
27
+ name: Blender ${{ matrix.version }}
28
+ runs-on: ubuntu-24.04
29
+ timeout-minutes: 45
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ include:
34
+ - version: "4.5.15"
35
+ series: "4.5"
36
+ - version: "5.2.3"
37
+ series: "5.2"
38
+ steps:
39
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
40
+ with:
41
+ persist-credentials: false
42
+
43
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
44
+
45
+ - name: Install system libraries
46
+ run: |
47
+ sudo apt-get update
48
+ # shellcheck disable=SC2086
49
+ sudo apt-get install -y --no-install-recommends $BLENDER_DEPS
50
+
51
+ # Only the tarball is cached. fetch_blender.py re-checks its sha256 on
52
+ # every use, so a poisoned cache entry is rejected.
53
+ - name: Cache Blender tarball
54
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
55
+ with:
56
+ path: ~/.cache/meshwire/*.tar.xz
57
+ key: blender-${{ matrix.version }}-${{ hashFiles('scripts/fetch_blender.py') }}
58
+
59
+ - name: Install test dependencies
60
+ run: uv sync --locked --extra dev --python 3.12
61
+
62
+ - name: Fetch Blender
63
+ id: fetch
64
+ run: |
65
+ set -e
66
+ bin="$(uv run --locked --python 3.12 python scripts/fetch_blender.py ${{ matrix.version }} --dest "$RUNNER_TEMP/blender")"
67
+ test -x "$bin"
68
+ echo "bin=$bin" >> "$GITHUB_OUTPUT"
69
+
70
+ - name: Run harness driver
71
+ env:
72
+ BLENDER_BIN: ${{ steps.fetch.outputs.bin }}
73
+ run: >-
74
+ xvfb-run -a uv run --locked --python 3.12 python -m tests.harness.driver
75
+ --blender "$BLENDER_BIN"
76
+ --out "$RUNNER_TEMP/runs/driver-${{ matrix.series }}"
77
+ --check-baseline tests/harness/baselines/blender-${{ matrix.series }}.json
78
+
79
+ # The release attaches this ZIP, so test the built ZIP and not the source tree: validate it,
80
+ # install it into a fresh Blender user folder, enable bl_ext.user_default.meshwire, start its
81
+ # server, then run the full handshake and ping with the real client.
82
+ - name: Test the built extension ZIP
83
+ timeout-minutes: 10
84
+ if: ${{ !cancelled() && steps.fetch.outcome == 'success' }}
85
+ env:
86
+ BLENDER_BIN: ${{ steps.fetch.outputs.bin }}
87
+ PYTHONPATH: src
88
+ run: |
89
+ set -e
90
+ uv run --locked --python 3.12 python scripts/package_addon.py --output "$RUNNER_TEMP/meshwire-addon.zip"
91
+ uv run --locked --python 3.12 python scripts/smoke_extension.py \
92
+ --blender "$BLENDER_BIN" \
93
+ --zip "$RUNNER_TEMP/meshwire-addon.zip" \
94
+ --work "$RUNNER_TEMP/extension-smoke-${{ matrix.series }}"
95
+
96
+ # Runs even when the driver step failed so one failure does not hide the
97
+ # other. The failed driver step still fails the job.
98
+ - name: Run socket lane
99
+ if: ${{ !cancelled() && steps.fetch.outcome == 'success' }}
100
+ env:
101
+ BLENDER_BIN: ${{ steps.fetch.outputs.bin }}
102
+ run: >-
103
+ xvfb-run -a uv run --locked --python 3.12 python -m tests.harness.socket_lane
104
+ --blender "$BLENDER_BIN"
105
+ --out "$RUNNER_TEMP/runs/socket-${{ matrix.series }}"
106
+ --check-baseline tests/harness/baselines/socket-lane.json
107
+
108
+ - name: Upload results
109
+ if: always()
110
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
111
+ with:
112
+ name: harness-${{ matrix.version }}
113
+ path: |
114
+ ${{ runner.temp }}/runs
115
+ !${{ runner.temp }}/runs/**/*.blend
116
+ !${{ runner.temp }}/runs/**/*.blend1
117
+ !${{ runner.temp }}/runs/**/tmp/**
118
+ if-no-files-found: ignore
119
+ retention-days: 14
120
+
121
+ # Best effort: every series other than 4.5 and 5.2 runs nightly. Late in a full
122
+ # run, 4.2 and 4.3 sometimes segfault inside Blender, on a different heavy case
123
+ # each time, and the case passes alone. --retry-crashes reruns each crash alone
124
+ # and names it as a session crash when it passes. The gated jobs never pass it.
125
+ # Results never gate anything and nothing may depend on this job.
126
+ nightly:
127
+ name: Blender ${{ matrix.version }} (best effort)
128
+ if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }}
129
+ runs-on: ubuntu-24.04
130
+ timeout-minutes: 60
131
+ continue-on-error: true
132
+ strategy:
133
+ fail-fast: false
134
+ matrix:
135
+ include:
136
+ - {version: "4.2.23", series: "4.2"}
137
+ - {version: "4.3.2", series: "4.3"}
138
+ - {version: "4.4.3", series: "4.4"}
139
+ - {version: "5.0.1", series: "5.0"}
140
+ - {version: "5.1.2", series: "5.1"}
141
+ steps:
142
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
143
+ with:
144
+ persist-credentials: false
145
+
146
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
147
+
148
+ - name: Install system libraries
149
+ run: |
150
+ sudo apt-get update
151
+ # shellcheck disable=SC2086
152
+ sudo apt-get install -y --no-install-recommends $BLENDER_DEPS
153
+
154
+ - name: Cache Blender tarball
155
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
156
+ with:
157
+ path: ~/.cache/meshwire/*.tar.xz
158
+ key: blender-${{ matrix.version }}-${{ hashFiles('scripts/fetch_blender.py') }}
159
+
160
+ - name: Install test dependencies
161
+ run: uv sync --locked --extra dev --python 3.12
162
+
163
+ - name: Fetch Blender
164
+ id: fetch
165
+ run: |
166
+ set -e
167
+ bin="$(uv run --locked --python 3.12 python scripts/fetch_blender.py ${{ matrix.version }} --dest "$RUNNER_TEMP/blender")"
168
+ test -x "$bin"
169
+ echo "bin=$bin" >> "$GITHUB_OUTPUT"
170
+
171
+ - name: Run harness driver
172
+ env:
173
+ BLENDER_BIN: ${{ steps.fetch.outputs.bin }}
174
+ run: >-
175
+ xvfb-run -a uv run --locked --python 3.12 python -m tests.harness.driver
176
+ --blender "$BLENDER_BIN"
177
+ --out "$RUNNER_TEMP/runs/driver-${{ matrix.series }}"
178
+ --check-baseline tests/harness/baselines/blender-${{ matrix.series }}.json
179
+ --retry-crashes
180
+
181
+ # Runs even when the driver step failed so one failure does not hide the
182
+ # other. Best effort like the driver step: a failing check shows in the
183
+ # log and gates nothing.
184
+ - name: Run socket lane
185
+ if: ${{ !cancelled() && steps.fetch.outcome == 'success' }}
186
+ continue-on-error: true
187
+ env:
188
+ BLENDER_BIN: ${{ steps.fetch.outputs.bin }}
189
+ run: >-
190
+ xvfb-run -a uv run --locked --python 3.12 python -m tests.harness.socket_lane
191
+ --blender "$BLENDER_BIN"
192
+ --out "$RUNNER_TEMP/runs/socket-${{ matrix.series }}"
193
+ --check-baseline tests/harness/baselines/socket-lane.json
194
+
195
+ - name: Upload results
196
+ if: always()
197
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
198
+ with:
199
+ name: harness-${{ matrix.version }}
200
+ path: |
201
+ ${{ runner.temp }}/runs
202
+ !${{ runner.temp }}/runs/**/*.blend
203
+ !${{ runner.temp }}/runs/**/*.blend1
204
+ !${{ runner.temp }}/runs/**/tmp/**
205
+ if-no-files-found: ignore
206
+ retention-days: 14
@@ -0,0 +1,97 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.event_name }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
14
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
15
+
16
+ jobs:
17
+ lint:
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
21
+ with:
22
+ persist-credentials: false
23
+
24
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
25
+
26
+ - name: Run Ruff
27
+ run: uv run --locked --extra dev --python 3.11 ruff check .
28
+
29
+ - name: Check formatting
30
+ run: uv run --locked --extra dev --python 3.11 ruff format --check .
31
+
32
+ test:
33
+ runs-on: ubuntu-latest
34
+ strategy:
35
+ matrix:
36
+ python-version: ["3.10", "3.11", "3.12"]
37
+
38
+ steps:
39
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
40
+ with:
41
+ persist-credentials: false
42
+
43
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
44
+
45
+ - name: Install dependencies
46
+ run: uv sync --locked --extra dev --python ${{ matrix.python-version }}
47
+
48
+ - name: Run unit tests
49
+ run: uv run --locked --extra dev --python ${{ matrix.python-version }} pytest tests/ --ignore=tests/blender_integration_test.py -v
50
+
51
+ # The socket, token and instance-file code behaves differently per platform (Windows
52
+ # binds exclusively and has no POSIX modes; macOS has its own rules for overlapping binds).
53
+ test-platforms:
54
+ name: test (${{ matrix.os }})
55
+ runs-on: ${{ matrix.os }}
56
+ strategy:
57
+ fail-fast: false
58
+ matrix:
59
+ os: [windows-latest, macos-latest]
60
+
61
+ steps:
62
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
63
+ with:
64
+ persist-credentials: false
65
+
66
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
67
+
68
+ - name: Install dependencies
69
+ run: uv sync --locked --extra dev --python 3.12
70
+
71
+ - name: Run platform tests
72
+ run: uv run --locked --extra dev --python 3.12 pytest tests/test_wire.py tests/test_instances.py tests/test_socket_server.py -v
73
+
74
+ build:
75
+ runs-on: ubuntu-latest
76
+ needs: [lint, test]
77
+ steps:
78
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
79
+ with:
80
+ persist-credentials: false
81
+
82
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
83
+
84
+ - name: Build package
85
+ run: uv build --build-constraint build-constraints.txt --require-hashes
86
+
87
+ - name: Build addon ZIP
88
+ run: uv run --locked --python 3.11 python scripts/package_addon.py
89
+
90
+ - name: Upload artifacts
91
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
92
+ with:
93
+ name: dist
94
+ path: |
95
+ dist/*.whl
96
+ dist/*.tar.gz
97
+ dist/*.zip
@@ -0,0 +1,33 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ schedule:
9
+ - cron: "31 5 * * 1"
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ analyze:
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 30
18
+ permissions:
19
+ contents: read
20
+ security-events: write
21
+ steps:
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+
26
+ - uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
27
+ with:
28
+ languages: python
29
+ build-mode: none
30
+
31
+ - uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
32
+ with:
33
+ category: "/language:python"
@@ -0,0 +1,135 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-24.04
14
+ timeout-minutes: 15
15
+ steps:
16
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
17
+ with:
18
+ fetch-depth: 0
19
+ persist-credentials: false
20
+
21
+ - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
22
+ with:
23
+ version: "0.13.6"
24
+
25
+ # PyPI never lets a version be reused, so catch mistakes here. This check and the version
26
+ # check below are not a security boundary, because a tagged commit can edit this file. The
27
+ # repository's tag ruleset and the pypi environment's tag policy restrict publishing.
28
+ - name: Refuse a tag that is not on main
29
+ run: git merge-base --is-ancestor "$GITHUB_SHA" origin/main
30
+
31
+ # No unlocked code runs from here to the upload: uv.lock pins dependencies with hashes,
32
+ # build-constraints.txt does the same for the build backend, and --no-build rules out any
33
+ # dependency's own build step. Keep it that way, because this job produces what gets published.
34
+ - name: Install locked dependencies
35
+ run: uv sync --locked --no-install-project --no-build --extra dev --python 3.12
36
+
37
+ - name: Run tests
38
+ env:
39
+ PYTHONPATH: src
40
+ run: .venv/bin/python -m pytest tests/ --ignore=tests/blender_integration_test.py -q
41
+
42
+ - name: Build package
43
+ run: uv build --build-constraint build-constraints.txt --require-hashes
44
+
45
+ - name: Refuse a tag that does not match the package version
46
+ run: test -f "dist/meshwire-${GITHUB_REF_NAME#v}-py3-none-any.whl"
47
+
48
+ - name: Run the built wheel
49
+ run: |
50
+ uv pip install --no-deps "dist/meshwire-${GITHUB_REF_NAME#v}-py3-none-any.whl"
51
+ actual="$(.venv/bin/meshwire --version)"
52
+ test "$actual" = "meshwire ${GITHUB_REF_NAME#v}"
53
+
54
+ # Built outside dist/: the PyPI action uploads everything in that folder.
55
+ - name: Build addon ZIP
56
+ run: |
57
+ mkdir addon-zip
58
+ .venv/bin/python scripts/package_addon.py
59
+ mv dist/*.zip addon-zip/
60
+ base="${GITHUB_REF_NAME#v}"
61
+ base="$(printf '%s' "$base" | sed -E 's/(a|b|rc)[0-9]+$//')"
62
+ test -f "addon-zip/meshwire-addon-${base}.zip"
63
+
64
+ - name: Upload package
65
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
66
+ with:
67
+ name: dist
68
+ path: dist/
69
+ if-no-files-found: error
70
+
71
+ - name: Upload addon ZIP
72
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
73
+ with:
74
+ name: addon-zip
75
+ path: addon-zip/
76
+ if-no-files-found: error
77
+
78
+ publish:
79
+ needs: build
80
+ runs-on: ubuntu-24.04
81
+ timeout-minutes: 15
82
+ environment:
83
+ name: pypi
84
+ url: https://pypi.org/p/meshwire
85
+ permissions:
86
+ id-token: write
87
+ steps:
88
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
89
+ with:
90
+ name: dist
91
+ path: dist
92
+
93
+ - name: Publish to PyPI
94
+ uses: pypa/gh-action-pypi-publish@7245906fb61fa33a13554f9d5fb856fe61758086 # v1.14.3
95
+
96
+ github-release:
97
+ needs: publish
98
+ runs-on: ubuntu-24.04
99
+ timeout-minutes: 15
100
+ permissions:
101
+ contents: write
102
+ steps:
103
+ # First, because checkout cleans the workspace. Only the changelog is needed.
104
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
105
+ with:
106
+ persist-credentials: false
107
+ sparse-checkout: |
108
+ CHANGELOG.md
109
+ scripts/changelog_section.py
110
+ sparse-checkout-cone-mode: false
111
+
112
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
113
+ with:
114
+ name: dist
115
+ path: dist
116
+
117
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
118
+ with:
119
+ name: addon-zip
120
+ path: addon-zip
121
+
122
+ - name: Create the GitHub release
123
+ env:
124
+ GH_TOKEN: ${{ github.token }}
125
+ GH_REPO: ${{ github.repository }}
126
+ run: |
127
+ flags=""
128
+ case "$GITHUB_REF_NAME" in
129
+ *a*|*b*|*rc*) flags="--prerelease" ;;
130
+ esac
131
+ # The release notes open with this version's CHANGELOG section; the generated list of
132
+ # pull requests follows it.
133
+ python3 scripts/changelog_section.py "${GITHUB_REF_NAME#v}" < CHANGELOG.md > notes.md
134
+ gh release create "$GITHUB_REF_NAME" --verify-tag --generate-notes --notes-file notes.md \
135
+ $flags dist/* addon-zip/*