lvkit 0.8.3__tar.gz → 0.8.4__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 (517) hide show
  1. {lvkit-0.8.3 → lvkit-0.8.4}/PKG-INFO +1 -1
  2. {lvkit-0.8.3 → lvkit-0.8.4}/pyproject.toml +1 -1
  3. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/__init__.py +1 -1
  4. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/cache_paths.py +49 -10
  5. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/extractor.py +29 -15
  6. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/loading.py +41 -4
  7. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/parallel_parse.py +15 -6
  8. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/output_cache.py +38 -15
  9. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/metadata.py +2 -2
  10. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/vi.py +33 -7
  11. {lvkit-0.8.3 → lvkit-0.8.4}/tests/conftest.py +24 -0
  12. lvkit-0.8.4/tests/test_cache_path_bound.py +331 -0
  13. lvkit-0.8.4/tests/test_decode_element_perf.py +107 -0
  14. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_extraction_cache.py +28 -9
  15. lvkit-0.8.4/tests/test_lvlib_nonvi_member.py +53 -0
  16. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_output_cache.py +10 -6
  17. {lvkit-0.8.3 → lvkit-0.8.4}/.gitignore +0 -0
  18. {lvkit-0.8.3 → lvkit-0.8.4}/.pre-commit-config.yaml +0 -0
  19. {lvkit-0.8.3 → lvkit-0.8.4}/LICENSE +0 -0
  20. {lvkit-0.8.3 → lvkit-0.8.4}/NOTICE +0 -0
  21. {lvkit-0.8.3 → lvkit-0.8.4}/README.md +0 -0
  22. {lvkit-0.8.3 → lvkit-0.8.4}/deploy/cloudrun/README.md +0 -0
  23. {lvkit-0.8.3 → lvkit-0.8.4}/docs/_internal/xml-schema/README.md +0 -0
  24. {lvkit-0.8.3 → lvkit-0.8.4}/editors/vscode/LICENSE +0 -0
  25. {lvkit-0.8.3 → lvkit-0.8.4}/editors/vscode/README.md +0 -0
  26. {lvkit-0.8.3 → lvkit-0.8.4}/mcpb/README.md +0 -0
  27. {lvkit-0.8.3 → lvkit-0.8.4}/plugin/README.md +0 -0
  28. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/audit_primitive_consistency.py +0 -0
  29. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/audit_terminal_order.py +0 -0
  30. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/audit_unresolved.py +0 -0
  31. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/build_example_pages.sh +0 -0
  32. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/build_hero.py +0 -0
  33. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/build_ni_function_catalog.py +0 -0
  34. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/connector_geometry_audit.py +0 -0
  35. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/dump_primitive_context.py +0 -0
  36. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/extract_corpus.py +0 -0
  37. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/gen_semantics_probe.py +0 -0
  38. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/generate_docs.py +0 -0
  39. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/generate_driver_data.py +0 -0
  40. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/generate_python.py +0 -0
  41. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/import_nodes_primitives.py +0 -0
  42. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/list_unknown_primitives.py +0 -0
  43. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/populate_vilib.py +0 -0
  44. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/pull_samples.sh +0 -0
  45. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/recategorize_vilib.py +0 -0
  46. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/render_gallery.py +0 -0
  47. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/reproduce_openg_corpus.py +0 -0
  48. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/study_unwired_direction.py +0 -0
  49. {lvkit-0.8.3 → lvkit-0.8.4}/scripts/wire_decode_probe.py +0 -0
  50. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/__main__.py +0 -0
  51. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/_data.py +0 -0
  52. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/_pylabview_patches.py +0 -0
  53. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/cli.py +0 -0
  54. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/README.md +0 -0
  55. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/__init__.py +0 -0
  56. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/ast_optimizer.py +0 -0
  57. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/ast_utils.py +0 -0
  58. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/builder.py +0 -0
  59. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/__init__.py +0 -0
  60. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/_shared.py +0 -0
  61. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/config.py +0 -0
  62. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/core.py +0 -0
  63. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/init_builder.py +0 -0
  64. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/methods.py +0 -0
  65. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/naming.py +0 -0
  66. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/properties.py +0 -0
  67. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/class_builder/terminals.py +0 -0
  68. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/condition_builder.py +0 -0
  69. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/context.py +0 -0
  70. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/dataflow.py +0 -0
  71. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/elementwise.py +0 -0
  72. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/error_handler.py +0 -0
  73. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/expressions.py +0 -0
  74. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/fragment.py +0 -0
  75. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/function.py +0 -0
  76. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/imports.py +0 -0
  77. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/__init__.py +0 -0
  78. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/base.py +0 -0
  79. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/case.py +0 -0
  80. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/compound.py +0 -0
  81. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/constant.py +0 -0
  82. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/event.py +0 -0
  83. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/first_call.py +0 -0
  84. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/formula.py +0 -0
  85. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/in_place.py +0 -0
  86. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/invoke_node.py +0 -0
  87. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/loop.py +0 -0
  88. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/nmux.py +0 -0
  89. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/primitive.py +0 -0
  90. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/printf.py +0 -0
  91. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/property_node.py +0 -0
  92. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/queue_ops.py +0 -0
  93. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/sequence.py +0 -0
  94. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/nodes/subvi.py +0 -0
  95. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/stubs.py +0 -0
  96. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/codegen/unresolved.py +0 -0
  97. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/connector_geometry.py +0 -0
  98. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/connector_pane_geometry.py +0 -0
  99. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/builtin_types.json +0 -0
  100. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/connector_pane_patterns.json +0 -0
  101. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/_index.json +0 -0
  102. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/daqmx.json +0 -0
  103. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/nidcpower.json +0 -0
  104. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/nidigital.json +0 -0
  105. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/nidmm.json +0 -0
  106. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/nifgen.json +0 -0
  107. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/niscope.json +0 -0
  108. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/niswitch.json +0 -0
  109. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/serial.json +0 -0
  110. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/drivers/visa.json +0 -0
  111. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/labview_error_codes.json +0 -0
  112. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/measure_data.json +0 -0
  113. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/openg/_index.json +0 -0
  114. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/openg/array.json +0 -0
  115. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/openg/file.json +0 -0
  116. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/openg/string.json +0 -0
  117. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/openg/time.json +0 -0
  118. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/openg/variant.json +0 -0
  119. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/primitives.json +0 -0
  120. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/_index.json +0 -0
  121. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/_pending_terminals.json +0 -0
  122. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/_types.json +0 -0
  123. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/addons.json +0 -0
  124. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/application-control.json +0 -0
  125. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/array.json +0 -0
  126. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/boolean.json +0 -0
  127. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/cluster-class-variant.json +0 -0
  128. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/collection.json +0 -0
  129. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/comparison.json +0 -0
  130. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/connectivity.json +0 -0
  131. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/control-simulation.json +0 -0
  132. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/data-communication.json +0 -0
  133. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/dialog-user-interface.json +0 -0
  134. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/express.json +0 -0
  135. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/file-io.json +0 -0
  136. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/graphics-sound.json +0 -0
  137. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/instrument-io.json +0 -0
  138. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/mathematics.json +0 -0
  139. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/measurement-io.json +0 -0
  140. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/numeric.json +0 -0
  141. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/report-generation.json +0 -0
  142. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/signal-processing.json +0 -0
  143. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/string.json +0 -0
  144. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/structures.json +0 -0
  145. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/synchronization.json +0 -0
  146. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/timing.json +0 -0
  147. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/data/vilib/waveform.json +0 -0
  148. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/__init__.py +0 -0
  149. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/generate.py +0 -0
  150. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/html_generator/__init__.py +0 -0
  151. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/html_generator/assets.py +0 -0
  152. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/html_generator/class_page.py +0 -0
  153. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/html_generator/core.py +0 -0
  154. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/html_generator/index_page.py +0 -0
  155. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/html_generator/naming.py +0 -0
  156. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/html_generator/vi_page.py +0 -0
  157. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/template.css +0 -0
  158. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/docs/utils.py +0 -0
  159. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/flattened_typedesc.py +0 -0
  160. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/formula/__init__.py +0 -0
  161. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/formula/cparser.py +0 -0
  162. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/formula/emit.py +0 -0
  163. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/formula/lexer.py +0 -0
  164. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/formula/nodes.py +0 -0
  165. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/__init__.py +0 -0
  166. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/analysis.py +0 -0
  167. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/builders/__init__.py +0 -0
  168. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/builders/context.py +0 -0
  169. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/builders/operations.py +0 -0
  170. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/builders/refs.py +0 -0
  171. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/builders/structures.py +0 -0
  172. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/construction.py +0 -0
  173. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/core.py +0 -0
  174. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/describe.py +0 -0
  175. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/diff.py +0 -0
  176. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/interface_order.py +0 -0
  177. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/lvnet_grammar.py +0 -0
  178. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/lvnet_parse.py +0 -0
  179. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/lvnet_reconstruct.py +0 -0
  180. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/models.py +0 -0
  181. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/netlist.py +0 -0
  182. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/netlist_build.py +0 -0
  183. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/netlist_diff_helpers.py +0 -0
  184. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/netlist_json.py +0 -0
  185. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/netlist_models.py +0 -0
  186. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/op_walk.py +0 -0
  187. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/operations.py +0 -0
  188. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/queries.py +0 -0
  189. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/graph/render_lvnet.py +0 -0
  190. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/index/__init__.py +0 -0
  191. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/index/build.py +0 -0
  192. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/index/model.py +0 -0
  193. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/index/project.py +0 -0
  194. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/index/query.py +0 -0
  195. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/index/sql.py +0 -0
  196. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/index/store.py +0 -0
  197. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/labview_error.py +0 -0
  198. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/labview_error_codes.py +0 -0
  199. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/labview_queue.py +0 -0
  200. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/load_mode.py +0 -0
  201. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/lv_detect.py +0 -0
  202. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/__init__.py +0 -0
  203. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/schemas.py +0 -0
  204. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/__init__.py +0 -0
  205. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/__main__.py +0 -0
  206. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/_compat.py +0 -0
  207. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/app.py +0 -0
  208. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/index_tools.py +0 -0
  209. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/resolvers.py +0 -0
  210. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/roots.py +0 -0
  211. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/mcp/server/vi_tools.py +0 -0
  212. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/measure_data.py +0 -0
  213. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/models.py +0 -0
  214. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/num_format.py +0 -0
  215. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/__init__.py +0 -0
  216. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/conp_types.py +0 -0
  217. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/constants.py +0 -0
  218. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/defaults.py +0 -0
  219. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/flags.py +0 -0
  220. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/fp_heap_type.py +0 -0
  221. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/front_panel.py +0 -0
  222. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/image_resources.py +0 -0
  223. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/layout.py +0 -0
  224. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/models.py +0 -0
  225. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/naming.py +0 -0
  226. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/node_types.py +0 -0
  227. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/__init__.py +0 -0
  228. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/base.py +0 -0
  229. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/case.py +0 -0
  230. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/constant.py +0 -0
  231. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/decompose.py +0 -0
  232. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/disable.py +0 -0
  233. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/event.py +0 -0
  234. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/free_label.py +0 -0
  235. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/loop.py +0 -0
  236. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/nodes/sequence.py +0 -0
  237. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/type_mapping.py +0 -0
  238. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/type_resolution.py +0 -0
  239. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/utils.py +0 -0
  240. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/parser/wire_table.py +0 -0
  241. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/pipeline.py +0 -0
  242. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/primitive_resolver/__init__.py +0 -0
  243. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/primitive_resolver/exceptions.py +0 -0
  244. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/primitive_resolver/models.py +0 -0
  245. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/primitive_resolver/resolver.py +0 -0
  246. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/project_store.py +0 -0
  247. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/py.typed +0 -0
  248. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/ARCHITECTURE.md +0 -0
  249. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/__init__.py +0 -0
  250. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/backend.py +0 -0
  251. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/composite.py +0 -0
  252. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/connector_pane.py +0 -0
  253. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/connector_pane_panel.py +0 -0
  254. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/diff_viewer.py +0 -0
  255. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/draw.py +0 -0
  256. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyph.py +0 -0
  257. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/__init__.py +0 -0
  258. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/__init__.py +0 -0
  259. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/arrow.py +0 -0
  260. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/base.py +0 -0
  261. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/factory.py +0 -0
  262. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/fallback.py +0 -0
  263. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/frame.py +0 -0
  264. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/line.py +0 -0
  265. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/decorations/picture.py +0 -0
  266. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/__init__.py +0 -0
  267. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/arith.py +0 -0
  268. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/array_build.py +0 -0
  269. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/array_constant.py +0 -0
  270. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/array_reverse.py +0 -0
  271. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/array_search.py +0 -0
  272. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/array_size.py +0 -0
  273. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/array_sort.py +0 -0
  274. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/array_split.py +0 -0
  275. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/base.py +0 -0
  276. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/boolean_constant.py +0 -0
  277. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/boolean_gate.py +0 -0
  278. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/bundle.py +0 -0
  279. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/bundle_by_name.py +0 -0
  280. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/centered_svg.py +0 -0
  281. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/class_glyph.py +0 -0
  282. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/cluster_constant.py +0 -0
  283. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/compound_arith.py +0 -0
  284. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/constant.py +0 -0
  285. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/control_ref_const.py +0 -0
  286. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/convert.py +0 -0
  287. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/error_cluster.py +0 -0
  288. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/event_data.py +0 -0
  289. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/event_reg_node.py +0 -0
  290. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/formula_node.py +0 -0
  291. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/icon_image.py +0 -0
  292. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/in_place_element.py +0 -0
  293. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/inline_svg.py +0 -0
  294. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/invoke_node.py +0 -0
  295. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/label.py +0 -0
  296. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/local_variable.py +0 -0
  297. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/path_glyph.py +0 -0
  298. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/property_node.py +0 -0
  299. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/refnum_glyph.py +0 -0
  300. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/unbundle.py +0 -0
  301. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/variant.py +0 -0
  302. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/nodes/wrapped_box.py +0 -0
  303. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/__init__.py +0 -0
  304. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/base.py +0 -0
  305. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/case.py +0 -0
  306. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/disable.py +0 -0
  307. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/event.py +0 -0
  308. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/factory.py +0 -0
  309. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/flat_sequence.py +0 -0
  310. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/for_loop.py +0 -0
  311. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/generic.py +0 -0
  312. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/in_place.py +0 -0
  313. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/selectable.py +0 -0
  314. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/stacked_sequence.py +0 -0
  315. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/structures/while_loop.py +0 -0
  316. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/__init__.py +0 -0
  317. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/autoindex.py +0 -0
  318. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/base.py +0 -0
  319. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/concatenate.py +0 -0
  320. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/conditional.py +0 -0
  321. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/event_dyn.py +0 -0
  322. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/event_timeout.py +0 -0
  323. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/factory.py +0 -0
  324. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/generic.py +0 -0
  325. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/loop_count.py +0 -0
  326. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/selector.py +0 -0
  327. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/shift_register.py +0 -0
  328. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/glyphs/terminals/tunnel.py +0 -0
  329. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/help_tip.py +0 -0
  330. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/icons.py +0 -0
  331. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/lane_pass.py +0 -0
  332. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/nodes.py +0 -0
  333. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/properties_panel.py +0 -0
  334. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/render_viewer.py +0 -0
  335. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/scene.py +0 -0
  336. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/style.py +0 -0
  337. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/templates/diff_viewer.html +0 -0
  338. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/templates/render_viewer.html +0 -0
  339. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/theme_control.py +0 -0
  340. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/theme_web.py +0 -0
  341. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/render/wire_router.py +0 -0
  342. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/runtime/__init__.py +0 -0
  343. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/runtime/lv.py +0 -0
  344. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/__init__.py +0 -0
  345. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/lvkit/SKILL.md +0 -0
  346. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/lvkit-convert/SKILL.md +0 -0
  347. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/lvkit-describe/SKILL.md +0 -0
  348. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/lvkit-document/SKILL.md +0 -0
  349. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/lvkit-query/SKILL.md +0 -0
  350. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/lvkit-resolve/SKILL.md +0 -0
  351. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/skill_templates/lvkit-review/SKILL.md +0 -0
  352. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/structure.py +0 -0
  353. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/terminal_collector.py +0 -0
  354. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/text_encoding.py +0 -0
  355. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/tools/__init__.py +0 -0
  356. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/tools/connector_geometry_profile.py +0 -0
  357. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/type_defaults.py +0 -0
  358. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/unresolved.py +0 -0
  359. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vi_diff.py +0 -0
  360. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/__init__.py +0 -0
  361. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/exceptions.py +0 -0
  362. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/loader.py +0 -0
  363. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/lookup.py +0 -0
  364. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/models.py +0 -0
  365. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/naming.py +0 -0
  366. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/resolver.py +0 -0
  367. {lvkit-0.8.3 → lvkit-0.8.4}/src/lvkit/vilib_resolver/variants.py +0 -0
  368. {lvkit-0.8.3 → lvkit-0.8.4}/tests/__init__.py +0 -0
  369. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/PROVENANCE.md +0 -0
  370. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Lib1/Class/Class.lvclass +0 -0
  371. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Lib1/Class/Do.vi +0 -0
  372. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Lib1/Lib1.lvlib +0 -0
  373. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Lib2/Class/Class.lvclass +0 -0
  374. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Lib2/Class/Do.vi +0 -0
  375. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Lib2/Class/Test.vi +0 -0
  376. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Lib2/Lib2.lvlib +0 -0
  377. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Test LVKit.aliases +0 -0
  378. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Test LVKit.lvlps +0 -0
  379. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/29/Test LVKit/Test LVKit.lvproj +0 -0
  380. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/30/PROVENANCE.md +0 -0
  381. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/30/visible-frame-case-sequence.vi +0 -0
  382. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/30/visible-frame-conditional-disable.vi +0 -0
  383. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/31/PROVENANCE.md +0 -0
  384. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/31/disable-structure-frame-names.vi +0 -0
  385. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/32/PROVENANCE.md +0 -0
  386. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/32/comments-and-decorations.vi +0 -0
  387. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/33/PROVENANCE.md +0 -0
  388. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/33/coercion-dot-consistency.vi +0 -0
  389. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/34/PROVENANCE.md +0 -0
  390. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/34/hidden-iteration-terminal.vi +0 -0
  391. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/35/PROVENANCE.md +0 -0
  392. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/35/objects-hidden-by-structures.vi +0 -0
  393. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/36/PROVENANCE.md +0 -0
  394. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/36/bundle-unbundle-names.vi +0 -0
  395. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/37/PROVENANCE.md +0 -0
  396. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/37/structure-tunnel-wire-bends.vi +0 -0
  397. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/38/PROVENANCE.md +0 -0
  398. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/38/auto-concatenating-tunnel.vi +0 -0
  399. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/39/PROVENANCE.md +0 -0
  400. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/39/zorder-not-respected.vi +0 -0
  401. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/82/Pictures And Decorations.vi +0 -0
  402. {lvkit-0.8.3 → lvkit-0.8.4}/tests/corpus/issues/README.md +0 -0
  403. {lvkit-0.8.3 → lvkit-0.8.4}/tests/helpers.py +0 -0
  404. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_array_ops_codegen.py +0 -0
  405. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_ast_builder.py +0 -0
  406. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_ast_optimizer.py +0 -0
  407. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_case_codegen.py +0 -0
  408. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_case_parser.py +0 -0
  409. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_class_field_walkup.py +0 -0
  410. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_class_parent_linkinfo.py +0 -0
  411. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_class_properties.py +0 -0
  412. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_class_wire_appearance.py +0 -0
  413. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_cli.py +0 -0
  414. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_cli_cache.py +0 -0
  415. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_cli_describe_lvnet.py +0 -0
  416. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_cli_graph_ops.py +0 -0
  417. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_cli_query.py +0 -0
  418. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_cluster_wire_color.py +0 -0
  419. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_codegen_context.py +0 -0
  420. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_compound_codegen.py +0 -0
  421. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_condition_builder.py +0 -0
  422. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_connector_geometry.py +0 -0
  423. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_connector_pane_label_recovery.py +0 -0
  424. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_connector_pane_patterns.py +0 -0
  425. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_connector_pane_render.py +0 -0
  426. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_conp_types.py +0 -0
  427. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_constant_decoding.py +0 -0
  428. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_dependency_path_refs.py +0 -0
  429. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_determinism.py +0 -0
  430. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_diff.py +0 -0
  431. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_diff_properties.py +0 -0
  432. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_diff_viewer.py +0 -0
  433. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_disable_graph.py +0 -0
  434. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_disable_parser.py +0 -0
  435. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_docs_class_hierarchy.py +0 -0
  436. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_docs_render.py +0 -0
  437. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_driver_codegen.py +0 -0
  438. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_dynamic_dispatch.py +0 -0
  439. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_e2e_codegen.py +0 -0
  440. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_elementwise.py +0 -0
  441. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_error_codegen.py +0 -0
  442. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_error_handling.py +0 -0
  443. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_error_terminal_label_fallback.py +0 -0
  444. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_event_codegen.py +0 -0
  445. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_event_parser.py +0 -0
  446. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_extractor_concurrency.py +0 -0
  447. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_extractor_long_path.py +0 -0
  448. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_first_call_codegen.py +0 -0
  449. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_formula_codegen.py +0 -0
  450. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_formula_runtime.py +0 -0
  451. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_formula_semantics.py +0 -0
  452. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_formula_transpile.py +0 -0
  453. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_fp_heap_type.py +0 -0
  454. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_frame_attribution.py +0 -0
  455. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_frame_zplane.py +0 -0
  456. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_glyphs.py +0 -0
  457. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_graceful_degradation.py +0 -0
  458. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_help_tip.py +0 -0
  459. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_import_startup.py +0 -0
  460. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_in_place_codegen.py +0 -0
  461. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_index.py +0 -0
  462. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_index_sql.py +0 -0
  463. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_index_warm_no_downgrade.py +0 -0
  464. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_interface_order.py +0 -0
  465. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_issue_corpus.py +0 -0
  466. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_label_extraction.py +0 -0
  467. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_labview_queue.py +0 -0
  468. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_livi_vipi.py +0 -0
  469. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_load_mode.py +0 -0
  470. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_load_upgrade.py +0 -0
  471. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_loop_codegen.py +0 -0
  472. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_lv_detect.py +0 -0
  473. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_lvnet_identity.py +0 -0
  474. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_lvnet_reconstruct.py +0 -0
  475. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_lvnet_roundtrip.py +0 -0
  476. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_lvpy.py +0 -0
  477. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_mcp_cache.py +0 -0
  478. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_mcp_evals.py +0 -0
  479. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_mcp_read_vi_lvnet.py +0 -0
  480. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_mcp_roots.py +0 -0
  481. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_naming.py +0 -0
  482. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_netlist_json.py +0 -0
  483. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_new_codegen.py +0 -0
  484. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_node_properties.py +0 -0
  485. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_parallel_codegen.py +0 -0
  486. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_parallel_parse.py +0 -0
  487. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_parser.py +0 -0
  488. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_parser_regression.py +0 -0
  489. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_primitive_name_uniqueness.py +0 -0
  490. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_primitive_positional_order.py +0 -0
  491. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_primitive_resolutions.py +0 -0
  492. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_progressive_index.py +0 -0
  493. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_progressive_warm.py +0 -0
  494. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_project_store.py +0 -0
  495. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_python_structure_plan.py +0 -0
  496. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_queue_codegen.py +0 -0
  497. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_render.py +0 -0
  498. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_render_emission_order.py +0 -0
  499. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_render_lvnet.py +0 -0
  500. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_render_title_identity.py +0 -0
  501. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_render_viewer.py +0 -0
  502. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_sequence.py +0 -0
  503. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_soft_codegen.py +0 -0
  504. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_structure_lvproj.py +0 -0
  505. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_subvi_nav.py +0 -0
  506. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_text_encoding.py +0 -0
  507. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_type_driven_fixes.py +0 -0
  508. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_type_fields.py +0 -0
  509. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_type_loading.py +0 -0
  510. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_type_mapping.py +0 -0
  511. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_unknown_nodes.py +0 -0
  512. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_unresolved.py +0 -0
  513. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_vi_graph.py +0 -0
  514. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_vi_properties.py +0 -0
  515. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_viewer_properties.py +0 -0
  516. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_vilib_docurls.py +0 -0
  517. {lvkit-0.8.3 → lvkit-0.8.4}/tests/test_web_progressive_staging.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: lvkit
3
- Version: 0.8.3
3
+ Version: 0.8.4
4
4
  Summary: Understand and convert LabVIEW VIs to Python without a LabVIEW license
5
5
  Project-URL: Repository, https://github.com/pragmatest-dev/lvkit
6
6
  Project-URL: Issues, https://github.com/pragmatest-dev/lvkit/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "lvkit"
7
- version = "0.8.3"
7
+ version = "0.8.4"
8
8
  description = "Understand and convert LabVIEW VIs to Python without a LabVIEW license"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  from typing import TYPE_CHECKING
6
6
 
7
- __version__ = "0.8.3"
7
+ __version__ = "0.8.4"
8
8
 
9
9
  # The public API is exposed LAZILY (PEP 562 module ``__getattr__``): the graph /
10
10
  # parser / structure stacks (networkx, pydantic, pylabview, PIL — ~230 ms) load
@@ -111,6 +111,35 @@ def _slug(path: Path) -> str:
111
111
  return f"{tail}-{h}"
112
112
 
113
113
 
114
+ # The fixed short stem every MANAGED-cache artifact (extract/render/diff) uses
115
+ # instead of the real VI's filename stem — the second Windows MAX_PATH axis
116
+ # alongside the bounded ``vi-<hash>`` slot below. Owned by this module (the
117
+ # single source of the cache-layout policy); ``extractor.py`` and
118
+ # ``output_cache.py`` import it rather than repeating the literal.
119
+ MANAGED_ARTIFACT_STEM = "vi"
120
+
121
+
122
+ def _vi_slot(rel: Path) -> str:
123
+ """A per-VI cache dir name that is ALWAYS bounded, whatever the source tree's
124
+ depth: ``vi-`` + 16 hex of a sha256 of the owner-relative path.
125
+
126
+ Owned namespaces used to hang a VI's cache under ``<rel.parent>`` — the full
127
+ source-directory hierarchy reproduced beneath the cache root. A deep repo (or
128
+ a long VI filename) then pushed the final cache path past Windows' MAX_PATH
129
+ even with a short ``LVKIT_CACHE_DIR``, because BOTH the depth and the source
130
+ stem were unbounded inputs (the failure this replaces). Collapsing the whole
131
+ owner-relative path to one fixed-width hash segment removes the depth axis;
132
+ fixed short artifact names inside the slot remove the stem axis. The path is
133
+ keyed on the FULL ``rel`` (parent + filename), so every source VI maps to its
134
+ own slot and sibling VIs never collide. The real source path is NOT lost — it
135
+ is recorded as the ``source`` field of each slot's ``.meta.json`` sidecar
136
+ (see ``extractor._write_cache_meta`` / ``output_cache._write``). The
137
+ separators are normalized to ``/`` so the same VI hashes identically
138
+ regardless of how its path was spelled on this platform."""
139
+ key = rel.as_posix()
140
+ return "vi-" + hashlib.sha256(key.encode("utf-8")).hexdigest()[:16]
141
+
142
+
114
143
  def kind_fingerprint(kind: str) -> str:
115
144
  """The 8-hex build-compatibility tag stamped into a cache path for ``kind``.
116
145
 
@@ -215,14 +244,20 @@ def classify(vi_path: Path, kind: str) -> tuple[Path, str, str]:
215
244
  """Map ``vi_path`` to ``(cache_dir, source_label, namespace)`` for one
216
245
  artifact ``kind`` (``"extract"`` | ``"render"`` | ``"diff"``).
217
246
 
218
- ``cache_dir`` is ``<cache>/<ns>/<slug>/<kind>/<fp>/<rel-parent>`` — project-
247
+ ``cache_dir`` is ``<cache>/<ns>/<slug>/<kind>/<fp>/vi-<hash>`` — project-
219
248
  first: the VI's identity (namespace + slug) is named ONCE and the ``kind``
220
- hangs off it, so one project's whole cache is a single subtree and sibling VIs
221
- of the same kind + build share a dir. ``<fp>`` is the per-kind build tag
222
- (:func:`kind_fingerprint`) so two incompatible lvkit builds get separate slots
223
- instead of clobbering each other. ``namespace`` is ``"projects"``,
249
+ hangs off it, so one project's whole cache is a single subtree. ``<fp>`` is
250
+ the per-kind build tag (:func:`kind_fingerprint`) so two incompatible lvkit
251
+ builds get separate slots instead of clobbering each other. ``vi-<hash>``
252
+ (:func:`_vi_slot`) is a bounded per-VI slot standing in for the owner-relative
253
+ directory hierarchy, so an arbitrarily deep source tree can never push the
254
+ cache path past Windows' MAX_PATH; the artifact names inside it are fixed and
255
+ short (``vi_BDHb.xml`` / ``vi.<ext>``) for the same reason. ``source_label``
256
+ stays the REAL owner-relative path (``str(rel)``) so the true source is
257
+ recorded in each slot's ``.meta.json``. ``namespace`` is ``"projects"``,
224
258
  ``"shared"``, or ``"adhoc"`` — callers path-address the first two and
225
- content-address ``adhoc`` (its paths never repeat).
259
+ content-address ``adhoc`` (its paths never repeat; its dir is already a single
260
+ bounded ``_slug`` segment).
226
261
  """
227
262
  resolved = vi_path.resolve()
228
263
  cache = global_cache_root()
@@ -237,7 +272,7 @@ def classify(vi_path: Path, kind: str) -> tuple[Path, str, str]:
237
272
  rel = _rel_under(resolved, vilib)
238
273
  if rel is not None:
239
274
  _note_owner(vilib)
240
- d = cache / "shared" / "vilib" / _slug(vilib) / kind / fp / rel.parent
275
+ d = cache / "shared" / "vilib" / _slug(vilib) / kind / fp / _vi_slot(rel)
241
276
  return d, str(rel), "shared"
242
277
 
243
278
  userlib = _userlib_root
@@ -245,7 +280,8 @@ def classify(vi_path: Path, kind: str) -> tuple[Path, str, str]:
245
280
  rel = _rel_under(resolved, userlib)
246
281
  if rel is not None:
247
282
  _note_owner(userlib)
248
- d = cache / "shared" / "userlib" / _slug(userlib) / kind / fp / rel.parent
283
+ slug = _slug(userlib)
284
+ d = cache / "shared" / "userlib" / slug / kind / fp / _vi_slot(rel)
249
285
  return d, str(rel), "shared"
250
286
 
251
287
  project = _project_root_for(resolved)
@@ -253,7 +289,7 @@ def classify(vi_path: Path, kind: str) -> tuple[Path, str, str]:
253
289
  proj_abs = project.resolve()
254
290
  rel = resolved.relative_to(proj_abs)
255
291
  _note_owner(proj_abs)
256
- d = cache / "projects" / _slug(proj_abs) / kind / fp / rel.parent
292
+ d = cache / "projects" / _slug(proj_abs) / kind / fp / _vi_slot(rel)
257
293
  return d, str(rel), "projects"
258
294
 
259
295
  # adhoc has NO owner (not a project, not a library) -> no identity slug to
@@ -474,7 +510,10 @@ def write_meta(vi_path: Path, meta_path: Path, **extra: object) -> None:
474
510
  # source/fingerprint change — that is handled by the <fp> path level). A mismatch
475
511
  # triggers a one-time drop of the derived namespaces in cleanup_legacy_cache.
476
512
  # "2": project-first with a per-kind <fp> level and <tail>-<hash8> slugs.
477
- _LAYOUT_VERSION = "2"
513
+ # "3": owned VIs sit in a bounded per-VI ``vi-<hash>`` slot with fixed short
514
+ # artifact names (was the reproduced ``<rel.parent>`` hierarchy + source
515
+ # stem), so a deep source tree can't overflow Windows MAX_PATH.
516
+ _LAYOUT_VERSION = "3"
478
517
 
479
518
 
480
519
  def cleanup_legacy_cache() -> None:
@@ -34,6 +34,7 @@ install_pylabview_patches()
34
34
  # pylabview). Re-exported here so long-standing callers of ``extractor.X`` (e.g.
35
35
  # ``graph.core`` -> ``extractor.set_extraction_roots``) keep working unchanged.
36
36
  from lvkit.cache_paths import ( # noqa: E402
37
+ MANAGED_ARTIFACT_STEM,
37
38
  _slug,
38
39
  classify,
39
40
  cleanup_legacy_cache,
@@ -179,7 +180,7 @@ def _make_read_po(**overrides: object) -> argparse.Namespace:
179
180
  return argparse.Namespace(**opts)
180
181
 
181
182
 
182
- def _extract_in_process(vi_path: Path, output_dir: Path, vi_stem: str) -> None:
183
+ def _extract_in_process(vi_path: Path, output_dir: Path, artifact_stem: str) -> None:
183
184
  """Extract a VI to XML in-process, matching ``readRSRC -i <vi> -x``.
184
185
 
185
186
  pylabview places each block's sidecar XML (``_BDHb.xml`` etc.) in
@@ -190,17 +191,21 @@ def _extract_in_process(vi_path: Path, output_dir: Path, vi_stem: str) -> None:
190
191
  request concurrency. This avoids the per-call interpreter boot + pylabview
191
192
  re-import that the subprocess path pays on every extraction.
192
193
 
194
+ ``artifact_stem`` names the produced files — the caller's real VI stem for a
195
+ caller-owned ``output_dir``, or the fixed ``MANAGED_ARTIFACT_STEM`` in the
196
+ managed cache; it is NOT necessarily ``vi_path.stem``.
197
+
193
198
  Mirrors the option set that ``readRSRC.main()`` builds for the ``-x``
194
199
  (extract) subcommand via argparse.
195
200
  """
196
- xml_path = output_dir / f"{vi_stem}.xml"
201
+ xml_path = output_dir / f"{artifact_stem}.xml"
197
202
  po = _make_read_po(
198
203
  rsrc=str(vi_path),
199
204
  xml=str(xml_path),
200
205
  textcp="mac_roman",
201
206
  raw_connectors=False,
202
207
  keep_names=False,
203
- filebase=vi_stem,
208
+ filebase=artifact_stem,
204
209
  list=False,
205
210
  dump=False,
206
211
  extract=True,
@@ -214,8 +219,8 @@ def _extract_in_process(vi_path: Path, output_dir: Path, vi_stem: str) -> None:
214
219
  with open(xml_path, "wb") as xml_fh:
215
220
  tree.write(xml_fh, encoding="utf-8", xml_declaration=True)
216
221
  for path in output_dir.iterdir():
217
- belongs_to_vi = path.name == f"{vi_stem}.xml" or path.name.startswith(
218
- f"{vi_stem}_"
222
+ belongs_to_vi = path.name == f"{artifact_stem}.xml" or path.name.startswith(
223
+ f"{artifact_stem}_"
219
224
  )
220
225
  if path.suffix == ".xml" and belongs_to_vi:
221
226
  normalize_extracted_xml(path)
@@ -249,15 +254,24 @@ def extract_vi_xml(
249
254
  """
250
255
  vi_path = Path(vi_path).resolve()
251
256
 
252
- if output_dir is None:
257
+ # A caller-supplied output_dir is caller-owned, so keep the real source stem
258
+ # in the artifact names there. The MANAGED cache (output_dir is None) uses a
259
+ # FIXED short stem instead: a long source filename would otherwise overflow
260
+ # the cache path once a ``_BDHb.xml`` suffix is appended — the second Windows
261
+ # MAX_PATH axis, paired with the bounded per-VI slot dir (cache_paths._vi_slot).
262
+ # The real source name/path is preserved for callers: the graph loader keys
263
+ # every node on the source path (never on this stem), and the ``source`` field
264
+ # of the ``.meta.json`` records the real owner-relative path.
265
+ managed = output_dir is None
266
+ if managed:
253
267
  output_dir = _cache_target(vi_path)
254
268
  output_dir.mkdir(parents=True, exist_ok=True)
255
269
 
256
- vi_stem = vi_path.stem
257
- bd_xml = output_dir / f"{vi_stem}_BDHb.xml"
258
- fp_xml = output_dir / f"{vi_stem}_FPHb.xml"
259
- main_xml = output_dir / f"{vi_stem}.xml"
260
- meta_path = output_dir / f"{vi_stem}.meta.json"
270
+ artifact_stem = MANAGED_ARTIFACT_STEM if managed else vi_path.stem
271
+ bd_xml = output_dir / f"{artifact_stem}_BDHb.xml"
272
+ fp_xml = output_dir / f"{artifact_stem}_FPHb.xml"
273
+ main_xml = output_dir / f"{artifact_stem}.xml"
274
+ meta_path = output_dir / f"{artifact_stem}.meta.json"
261
275
 
262
276
  # Cache hit: XML present and the recorded content-hash (or mtime/size
263
277
  # fast-path) still matches the VI. The extraction-code compatibility check is
@@ -316,15 +330,15 @@ def extract_vi_xml(
316
330
  tmp_dir = Path(tempfile.mkdtemp(prefix=".x-", dir=_staging_root()))
317
331
  try:
318
332
  try:
319
- _extract_in_process(vi_path, tmp_dir, vi_stem)
333
+ _extract_in_process(vi_path, tmp_dir, artifact_stem)
320
334
  except Exception as exc:
321
335
  raise RuntimeError(
322
336
  f"pylabview extraction failed for {vi_path.name}: {exc}"
323
- f"{_windows_long_path_hint(tmp_dir / f'{vi_stem}_BDHb.xml')}"
337
+ f"{_windows_long_path_hint(tmp_dir / f'{artifact_stem}_BDHb.xml')}"
324
338
  ) from exc
325
339
 
326
- if not (tmp_dir / f"{vi_stem}_BDHb.xml").exists():
327
- raise RuntimeError(f"Block diagram XML not found: {vi_stem}_BDHb.xml")
340
+ if not (tmp_dir / f"{artifact_stem}_BDHb.xml").exists():
341
+ raise RuntimeError(f"Block diagram XML not found: {artifact_stem}_BDHb.xml")
328
342
 
329
343
  # Publish every produced artifact atomically (same filesystem as the
330
344
  # temp dir), then meta.json last so its appearance marks the cache valid.
@@ -496,8 +496,10 @@ class LoadingMixin:
496
496
 
497
497
  for member in lib.members:
498
498
  if member.member_type == "VI":
499
- member_name = Path(member.url).name
500
- if member_name.lower().endswith(".ctl"):
499
+ member_url = Path(member.url)
500
+ member_name = member_url.name
501
+ member_suffix = member_url.suffix.lower()
502
+ if member_suffix == ".ctl":
501
503
  # .ctl members are type definitions, not loadable VIs
502
504
  typedef_qname = lib_qname + ":" + member_name
503
505
  ctl_path = lvlib_path.parent / member.url
@@ -528,7 +530,7 @@ class LoadingMixin:
528
530
  caller=lib_key,
529
531
  rel="owns",
530
532
  )
531
- else:
533
+ elif member_suffix == ".vi":
532
534
  member_qname = lib_qname + ":" + member_name
533
535
  vi_path = lvlib_path.parent / member.url
534
536
  if not vi_path.exists():
@@ -558,6 +560,21 @@ class LoadingMixin:
558
560
  caller=lib_key,
559
561
  rel="owns",
560
562
  )
563
+ else:
564
+ # A member the library XML declares Type="VI" but whose URL
565
+ # is neither .vi nor .ctl -- a source-metadata anomaly, not
566
+ # a code entity. No node, no stub (a stub means "a VI we
567
+ # expect to resolve later", which is wrong here): warn and
568
+ # move on rather than sending a non-VI file to load_vi
569
+ # (which raises ValueError and would abort the whole load).
570
+ logger.warning(
571
+ 'library %s declares member %r as Type="VI" but its '
572
+ "URL %r is not a loadable .vi or .ctl file — skipping "
573
+ "it.",
574
+ lvlib_path.name,
575
+ member.name,
576
+ member.url,
577
+ )
561
578
  elif member.member_type == "LVClass":
562
579
  class_name = Path(member.url).name
563
580
  class_path = lvlib_path.parent / member.url
@@ -1220,6 +1237,7 @@ class LoadingMixin:
1220
1237
  main_xml: Path | None,
1221
1238
  search_paths: list[Path],
1222
1239
  visited: set[str],
1240
+ *,
1223
1241
  source_dir: Path | None = None,
1224
1242
  source_override: Path | None = None,
1225
1243
  mode: LoadMode = LoadMode.FULL,
@@ -1251,6 +1269,9 @@ class LoadingMixin:
1251
1269
  bd_xml=bd_xml,
1252
1270
  fp_xml=fp_xml if fp_xml and fp_xml.exists() else None,
1253
1271
  main_xml=main_xml if main_xml and main_xml.exists() else None,
1272
+ # Pin the parser's identity (name, source_path, warnings) to the
1273
+ # real source path, not the fixed ``vi_BDHb.xml`` cache name.
1274
+ source_override=source_override,
1254
1275
  layout=self._want_layout,
1255
1276
  )
1256
1277
  )
@@ -1260,7 +1281,19 @@ class LoadingMixin:
1260
1281
  fp = vi.front_panel
1261
1282
  conpane = vi.connector_pane
1262
1283
 
1263
- unqualified_name = bd_xml.name.replace("_BDHb.xml", ".vi")
1284
+ # The VI's real unqualified name comes from its SOURCE path when we have
1285
+ # one (``source_override``), NOT from the extracted BD XML filename: the
1286
+ # managed extraction cache names every artifact ``vi_BDHb.xml`` (a bounded
1287
+ # fixed name — see ``extractor.extract_vi_xml``), so deriving the name from
1288
+ # the XML would make every VI ``vi.vi``. The source path is authoritative
1289
+ # and is threaded here for the top-level VI (``load_vi``) and every SubVI
1290
+ # dependency (``_leaf_load_vi``). Only a raw ``*_BDHb.xml`` handed in
1291
+ # directly (no source path) falls back to the XML-derived name.
1292
+ unqualified_name = (
1293
+ source_override.name
1294
+ if source_override is not None
1295
+ else bd_xml.name.replace("_BDHb.xml", ".vi")
1296
+ )
1264
1297
  # own_qname is this VI's (possibly NON-unique) qualified name — kept only
1265
1298
  # for the self-dependency compare below and the qname reverse index. It
1266
1299
  # is NOT the identity: two on-disk copies (a source VI + its stripped
@@ -1826,6 +1859,10 @@ class LoadingMixin:
1826
1859
  search_paths=search_paths,
1827
1860
  visited=set(),
1828
1861
  source_dir=resolved.parent,
1862
+ # ``resolved`` is this SubVI's real source ``.vi`` path — pin the
1863
+ # VI's identity (key + unqualified name) to it, never to the
1864
+ # fixed-name ``vi_BDHb.xml`` in the extraction cache.
1865
+ source_override=resolved,
1829
1866
  mode=child_mode,
1830
1867
  )
1831
1868
  if loaded_name:
@@ -47,18 +47,27 @@ PARALLEL_THRESHOLD = 50
47
47
  # process-pool scheduling/pickling overhead across many small XML files.
48
48
  _BATCH_SIZE = 20
49
49
 
50
- _ParseItem = tuple[Path, Path | None, Path | None]
50
+ # (vi_path, bd_xml, fp_xml, main_xml): vi_path is the REAL source .vi, carried so
51
+ # the worker can pin the parser's identity to it — the managed cache names BD XML
52
+ # ``vi_BDHb.xml`` (a bounded fixed name), so parsing without the real path would
53
+ # label every VI ``vi.vi`` (see parse_vi's source_override).
54
+ _ParseItem = tuple[Path, Path, Path | None, Path | None]
51
55
 
52
56
 
53
57
  def _parse_batch(items: list[_ParseItem]) -> dict[str, ParsedVI]:
54
- """Worker entry point: parse a batch of (bd_xml, fp_xml, main_xml)
55
- triples. Runs in a worker process. A single unparseable VI is skipped,
58
+ """Worker entry point: parse a batch of (vi_path, bd_xml, fp_xml, main_xml)
59
+ tuples. Runs in a worker process. A single unparseable VI is skipped,
56
60
  not fatal to the rest of the batch -- the caller's serial path parses it
57
61
  (and reports its error, same as today) when it finds no cache entry."""
58
62
  out: dict[str, ParsedVI] = {}
59
- for bd_xml, fp_xml, main_xml in items:
63
+ for vi_path, bd_xml, fp_xml, main_xml in items:
60
64
  try:
61
- out[str(bd_xml)] = parse_vi(bd_xml=bd_xml, fp_xml=fp_xml, main_xml=main_xml)
65
+ out[str(bd_xml)] = parse_vi(
66
+ bd_xml=bd_xml,
67
+ fp_xml=fp_xml,
68
+ main_xml=main_xml,
69
+ source_override=vi_path,
70
+ )
62
71
  except Exception:
63
72
  logger.debug("parallel parse: skipping %s", bd_xml, exc_info=True)
64
73
  return out
@@ -93,7 +102,7 @@ def parallel_parse_directory(
93
102
  except Exception:
94
103
  # Extraction failure -- let the serial path hit (and report) it.
95
104
  continue
96
- resolved.append((bd_xml, fp_xml, main_xml))
105
+ resolved.append((vi_path, bd_xml, fp_xml, main_xml))
97
106
 
98
107
  if not resolved:
99
108
  return {}
@@ -92,13 +92,17 @@ def _ext_for(fmt: str) -> str:
92
92
  # ── path resolution ─────────────────────────────────────────────────────────
93
93
 
94
94
 
95
- def _render_paths(input_path: Path, fmt: str) -> tuple[Path, Path, bool]:
96
- """``(body_path, meta_path, is_adhoc)`` for a render of ``input_path``.
95
+ def _render_paths(input_path: Path, fmt: str) -> tuple[Path, Path, str, bool]:
96
+ """``(body_path, meta_path, source_label, is_adhoc)`` for a render of
97
+ ``input_path``.
97
98
 
98
99
  Path-addressed for project/shared VIs; flat content-addressed for adhoc.
100
+ ``source_label`` is ``classify()``'s real owner-relative path (or, for
101
+ adhoc, the bare filename) — the caller writes it into the cache entry's
102
+ meta so the fixed ``vi.<ext>`` body name doesn't lose which VI it is.
99
103
  """
100
104
  ext = _ext_for(fmt)
101
- d, _, ns = cache_paths.classify(input_path, "render")
105
+ d, source_label, ns = cache_paths.classify(input_path, "render")
102
106
  if ns == "adhoc":
103
107
  # Flat content-addressed pool, but still per-build: the <fp> keeps two
104
108
  # lvkit builds from colliding on the same <sha>.<ext> (classify's dir is
@@ -111,8 +115,12 @@ def _render_paths(input_path: Path, fmt: str) -> tuple[Path, Path, bool]:
111
115
  )
112
116
  base = f"{cache_paths.sha256_file(input_path)}.{ext}"
113
117
  else:
114
- base = f"{input_path.stem}.{ext}"
115
- return d / base, d / f"{base}.meta.json", ns == "adhoc"
118
+ # classify's dir is now a bounded per-VI slot (vi-<hash>), so the source
119
+ # stem in the filename is both redundant AND a MAX_PATH hazard (a long VI
120
+ # name overflows the path) — use a fixed short base. The slot holds one
121
+ # source VI, so ``vi.<ext>`` is unique per format.
122
+ base = f"{cache_paths.MANAGED_ARTIFACT_STEM}.{ext}"
123
+ return d / base, d / f"{base}.meta.json", source_label, ns == "adhoc"
116
124
 
117
125
 
118
126
  def _diff_ext(fmt: str) -> str:
@@ -121,17 +129,20 @@ def _diff_ext(fmt: str) -> str:
121
129
 
122
130
  def _diff_paths(
123
131
  before_path: Path, after_path: Path, fmt: str
124
- ) -> tuple[Path, Path, str, bool]:
125
- """``(body_path, meta_path, before_sha, is_adhoc)`` for a diff.
132
+ ) -> tuple[Path, Path, str, str, bool]:
133
+ """``(body_path, meta_path, before_sha, source_label, is_adhoc)`` for a diff.
126
134
 
127
135
  Path-addressed by the AFTER (working-tree) VI — the side lvkit is handed as a
128
136
  real path — with the before-content hash and the format in the filename
129
137
  (lvkit is git-agnostic; the before side arrives only as bytes). Flat
130
- content-addressed when even the after side is adhoc.
138
+ content-addressed when even the after side is adhoc. ``source_label`` is the
139
+ AFTER VI's real owner-relative path (or, for adhoc, its bare filename) — the
140
+ caller writes it into the cache entry's meta so the fixed ``vi.<sha>.<ext>``
141
+ body name doesn't lose which VI it is.
131
142
  """
132
143
  ext = _diff_ext(fmt)
133
144
  before_sha = cache_paths.sha256_file(before_path)
134
- d, _, ns = cache_paths.classify(after_path, "diff")
145
+ d, source_label, ns = cache_paths.classify(after_path, "diff")
135
146
  if ns == "adhoc":
136
147
  after_sha = cache_paths.sha256_file(after_path)
137
148
  d = (
@@ -142,8 +153,12 @@ def _diff_paths(
142
153
  )
143
154
  base = f"{before_sha[:16]}_{after_sha[:16]}.{ext}"
144
155
  else:
145
- base = f"{after_path.stem}.{before_sha[:16]}.{ext}"
146
- return d / base, d / f"{base}.meta.json", before_sha, ns == "adhoc"
156
+ # classify's dir is a bounded per-VI slot (vi-<hash>) holding one AFTER
157
+ # VI, so the after-stem in the filename is redundant AND a MAX_PATH
158
+ # hazard — a fixed short base plus the before-content hash still
159
+ # distinguishes every (before, format) pair.
160
+ base = f"{cache_paths.MANAGED_ARTIFACT_STEM}.{before_sha[:16]}.{ext}"
161
+ return d / base, d / f"{base}.meta.json", before_sha, source_label, ns == "adhoc"
147
162
 
148
163
 
149
164
  # ── read / write ────────────────────────────────────────────────────────────
@@ -200,7 +215,7 @@ def diff_slot(before_path: Path, after_path: Path, fmt: str) -> Path:
200
215
 
201
216
  def lookup_render(input_path: Path, fmt: str, options: str, version: str) -> str | None:
202
217
  """Return cached render output for ``input_path`` if fresh, else ``None``."""
203
- body_path, meta_path, _ = _render_paths(input_path, fmt)
218
+ body_path, meta_path, _, _ = _render_paths(input_path, fmt)
204
219
  return _read_if_fresh(
205
220
  input_path,
206
221
  body_path,
@@ -217,7 +232,7 @@ def store_render(
217
232
  input_path: Path, fmt: str, options: str, version: str, body: str
218
233
  ) -> Path:
219
234
  """Cache ``body`` as the render of ``input_path``; return the slot path."""
220
- body_path, meta_path, _ = _render_paths(input_path, fmt)
235
+ body_path, meta_path, source_label, _ = _render_paths(input_path, fmt)
221
236
  _write(
222
237
  body_path,
223
238
  meta_path,
@@ -228,6 +243,9 @@ def store_render(
228
243
  "options": options,
229
244
  "kind": "render",
230
245
  "text_encoding": labview_text_encoding(),
246
+ # The fixed ``vi.<ext>`` body name carries no source info by
247
+ # itself — record the real path (mirrors extraction's meta.json).
248
+ "source": source_label,
231
249
  },
232
250
  )
233
251
  return body_path
@@ -237,7 +255,7 @@ def lookup_diff(
237
255
  before_path: Path, after_path: Path, fmt: str, options: str, version: str
238
256
  ) -> str | None:
239
257
  """Return cached diff output for the ``(before, after)`` pair if fresh."""
240
- body_path, meta_path, before_sha, _ = _diff_paths(before_path, after_path, fmt)
258
+ body_path, meta_path, before_sha, _, _ = _diff_paths(before_path, after_path, fmt)
241
259
  return _read_if_fresh(
242
260
  after_path,
243
261
  body_path,
@@ -260,7 +278,9 @@ def store_diff(
260
278
  body: str,
261
279
  ) -> Path:
262
280
  """Cache ``body`` as the diff of ``(before, after)``; return the slot path."""
263
- body_path, meta_path, before_sha, _ = _diff_paths(before_path, after_path, fmt)
281
+ body_path, meta_path, before_sha, source_label, _ = _diff_paths(
282
+ before_path, after_path, fmt
283
+ )
264
284
  _write(
265
285
  body_path,
266
286
  meta_path,
@@ -272,6 +292,9 @@ def store_diff(
272
292
  "before_sha": before_sha,
273
293
  "kind": "diff",
274
294
  "text_encoding": labview_text_encoding(),
295
+ # The fixed ``vi.<sha>.<ext>`` body name carries no source info by
296
+ # itself — record the AFTER VI's real path (mirrors extraction).
297
+ "source": source_label,
275
298
  },
276
299
  )
277
300
  return body_path
@@ -506,7 +506,7 @@ def parse_iuse_from_libd(libd_path: Path) -> dict[str, str]:
506
506
 
507
507
 
508
508
  def _decode_pth0_components(
509
- data: bytes, pth0_offset: int, end: int
509
+ data: bytes | memoryview, pth0_offset: int, end: int
510
510
  ) -> tuple[list[str], int]:
511
511
  """Decode one ``PTH0`` record's pascal-string path components ->
512
512
  ``(tokens, next_idx)``.
@@ -557,7 +557,7 @@ def _decode_pth0_components(
557
557
  idx += 1
558
558
  if idx + ln > end:
559
559
  return [], pth0_offset
560
- tokens.append(decode_labview_text(data[idx : idx + ln]))
560
+ tokens.append(decode_labview_text(bytes(data[idx : idx + ln])))
561
561
  idx += ln
562
562
  return tokens, idx
563
563
 
@@ -134,6 +134,7 @@ def parse_vi(
134
134
  bd_xml: Path | str | None = None,
135
135
  fp_xml: Path | str | None = None,
136
136
  main_xml: Path | str | None = None,
137
+ source_override: Path | str | None = None,
137
138
  layout: bool = False,
138
139
  ) -> ParsedVI:
139
140
  """Parse a VI file into all components.
@@ -146,6 +147,11 @@ def parse_vi(
146
147
  bd_xml: Path to *_BDHb.xml (for direct XML parsing)
147
148
  fp_xml: Path to *_FPHb.xml (optional)
148
149
  main_xml: Path to main *.xml (optional)
150
+ source_override: the VI's real source path, when the caller already
151
+ knows it and ``bd_xml`` lives under a fixed cache name (e.g.
152
+ ``vi_BDHb.xml``) that can't itself supply it. Pins the parsed VI's
153
+ name/``source_path``/warnings to this path instead of deriving them
154
+ from ``bd_xml``'s filename. Takes precedence over ``vi_path``.
149
155
  layout: also decode block-diagram GEOMETRY (node/terminal/wire bounds)
150
156
  from the same parsed heap and attach it as ``ParsedVI.layout``. Off
151
157
  by default — codegen needs no positions. Rendering passes True so
@@ -180,9 +186,17 @@ def parse_vi(
180
186
  )
181
187
  fp_xml = None
182
188
 
183
- # Derive source .vi path. Prefer the explicit vi_path argument since BD XML
184
- # may now live in a temp cache dir rather than next to the source file.
185
- if vi_path is not None:
189
+ # Derive source .vi path. Prefer an explicit real source path — the caller
190
+ # passes ``source_override`` (the graph loader / parallel pre-parse) or
191
+ # ``vi_path`` — because the BD XML now lives in the managed cache under a
192
+ # bounded FIXED name (``vi_BDHb.xml``; see ``extractor.extract_vi_xml``).
193
+ # Deriving identity from that filename would mislabel every VI ``vi.vi`` (its
194
+ # name, ``metadata.source_path``, and every warning), so the source path is
195
+ # authoritative. ``source_override`` is NOT ``.exists()``-gated: the real .vi
196
+ # need not sit beside the cached XML.
197
+ if source_override is not None:
198
+ source_path_str = str(Path(source_override).resolve())
199
+ elif vi_path is not None:
186
200
  source_path_str = str(Path(vi_path).resolve())
187
201
  else:
188
202
  source_path = bd_xml.with_name(bd_xml.name.replace("_BDHb.xml", ".vi"))
@@ -1450,7 +1464,7 @@ def _decode_default_data(
1450
1464
  return None
1451
1465
 
1452
1466
 
1453
- def _walk_path(data: bytes) -> tuple[str | None, int]:
1467
+ def _walk_path(data: bytes | memoryview) -> tuple[str | None, int]:
1454
1468
  """Walk a ``PTH0`` path DefaultData blob ONCE -> ``(value, bytes_consumed)``.
1455
1469
 
1456
1470
  Delegates the pascal-string component decode to
@@ -1460,7 +1474,9 @@ def _walk_path(data: bytes) -> tuple[str | None, int]:
1460
1474
  cluster stays aligned with the following field. Returns ``(None, 0)``
1461
1475
  when ``data`` is not a ``PTH0`` blob.
1462
1476
  """
1463
- if not data.startswith(b"PTH0"):
1477
+ # An equality slice (not ``.startswith``, which memoryview lacks) works for
1478
+ # both ``bytes`` and ``memoryview`` callers.
1479
+ if data[:4] != b"PTH0":
1464
1480
  return None, 0
1465
1481
  parts, idx = _decode_pth0_components(data, 0, len(data))
1466
1482
  return (f'Path("{"/".join(parts)}")' if parts else None), idx
@@ -1505,7 +1521,9 @@ def _decode_numeric_default(data: bytes) -> str | None:
1505
1521
  return None
1506
1522
 
1507
1523
 
1508
- def _decode_element(data: bytes, elem_type: LVType | None) -> tuple[str | None, int]:
1524
+ def _decode_element(
1525
+ data: bytes | memoryview, elem_type: LVType | None
1526
+ ) -> tuple[str | None, int]:
1509
1527
  """Decode a single element and return (value, bytes_consumed).
1510
1528
 
1511
1529
  Handles all LabVIEW types recursively: primitives, enums,
@@ -1521,6 +1539,14 @@ def _decode_element(data: bytes, elem_type: LVType | None) -> tuple[str | None,
1521
1539
  if not elem_type or len(data) == 0:
1522
1540
  return None, 0
1523
1541
 
1542
+ # A memoryview instead of bytes so the ARRAY/CLUSTER branches' recursive
1543
+ # ``data[idx:]`` slices below are non-copying subviews -- an array/cluster
1544
+ # element decode used to re-copy the whole remaining payload bytes object
1545
+ # on every recursive call, making a large array's decode O(N^2) (a
1546
+ # 65,160,056-byte NumInt32 array default effectively hung parse_vi()).
1547
+ if isinstance(data, bytes):
1548
+ data = memoryview(data)
1549
+
1524
1550
  underlying = elem_type.underlying_type or ""
1525
1551
  kind = elem_type.kind
1526
1552
 
@@ -1531,7 +1557,7 @@ def _decode_element(data: bytes, elem_type: LVType | None) -> tuple[str | None,
1531
1557
  str_len = int.from_bytes(data[:4], "big")
1532
1558
  if len(data) < 4 + str_len:
1533
1559
  return None, 0
1534
- string_val = decode_labview_text(data[4 : 4 + str_len])
1560
+ string_val = decode_labview_text(bytes(data[4 : 4 + str_len]))
1535
1561
  escaped = string_val.replace("\\", "\\\\").replace("'", "\\'")
1536
1562
  return f"'{escaped}'", 4 + str_len
1537
1563
 
@@ -29,6 +29,30 @@ def pytest_collection_modifyitems(config, items):
29
29
  item.add_marker(skip)
30
30
 
31
31
 
32
+ @pytest.fixture(autouse=True)
33
+ def _sanitize_git_env(monkeypatch):
34
+ """Strip git's repo-locating env vars so a test's ``git -C <sample repo>``
35
+ subprocess resolves THAT repo, not whatever the ambient environment points at.
36
+
37
+ Under the pre-commit hook the suite runs with ``GIT_DIR`` / ``GIT_WORK_TREE`` /
38
+ ``GIT_INDEX_FILE`` (and friends) exported, pointing at the lvkit repo. A child
39
+ ``git -C <other repo> show`` then INHERITS them, they take precedence over
40
+ ``-C``, git looks the ref up in the wrong repo, and the call fails with exit
41
+ 128 (yielding an empty / unreadable VI). That flake appears ONLY under
42
+ pre-commit — never in a bare ``pytest`` run — so it is invisible until commit
43
+ time. Clearing these makes ``-C`` authoritative for every git-extracting test
44
+ (test_diff, test_class_field_walkup, …) in one place."""
45
+ for var in (
46
+ "GIT_DIR",
47
+ "GIT_WORK_TREE",
48
+ "GIT_INDEX_FILE",
49
+ "GIT_OBJECT_DIRECTORY",
50
+ "GIT_COMMON_DIR",
51
+ "GIT_PREFIX",
52
+ ):
53
+ monkeypatch.delenv(var, raising=False)
54
+
55
+
32
56
  @pytest.fixture(autouse=True)
33
57
  def _hermetic_cache(tmp_path_factory, monkeypatch):
34
58
  """Point the extraction cache at a per-test tmp dir so no test ever writes