lvkit 0.8.2__tar.gz → 0.8.3__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.
- {lvkit-0.8.2 → lvkit-0.8.3}/PKG-INFO +1 -1
- {lvkit-0.8.2 → lvkit-0.8.3}/pyproject.toml +1 -1
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/__init__.py +1 -1
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/builders/operations.py +6 -2
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/loading.py +132 -17
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/models.py +9 -8
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/metadata.py +24 -7
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/node_types.py +30 -24
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/vi.py +32 -15
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/base.py +88 -7
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/invoke_node.py +20 -19
- lvkit-0.8.3/src/lvkit/render/glyphs/nodes/property_node.py +78 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/nodes.py +111 -32
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/scene.py +15 -6
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/style.py +26 -2
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/theme_web.py +1 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/structure.py +61 -9
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_class_parent_linkinfo.py +22 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_class_wire_appearance.py +54 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_constant_decoding.py +45 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_parser.py +144 -0
- lvkit-0.8.3/tests/test_python_structure_plan.py +55 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_render.py +316 -12
- lvkit-0.8.2/src/lvkit/render/glyphs/nodes/property_node.py +0 -115
- {lvkit-0.8.2 → lvkit-0.8.3}/.gitignore +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/.pre-commit-config.yaml +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/LICENSE +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/NOTICE +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/deploy/cloudrun/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/docs/_internal/xml-schema/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/editors/vscode/LICENSE +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/editors/vscode/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/mcpb/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/plugin/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/audit_primitive_consistency.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/audit_terminal_order.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/audit_unresolved.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/build_example_pages.sh +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/build_hero.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/build_ni_function_catalog.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/connector_geometry_audit.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/dump_primitive_context.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/extract_corpus.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/gen_semantics_probe.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/generate_docs.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/generate_driver_data.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/generate_python.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/import_nodes_primitives.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/list_unknown_primitives.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/populate_vilib.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/pull_samples.sh +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/recategorize_vilib.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/render_gallery.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/reproduce_openg_corpus.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/study_unwired_direction.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/scripts/wire_decode_probe.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/__main__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/_data.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/_pylabview_patches.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/cache_paths.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/cli.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/ast_optimizer.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/ast_utils.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/builder.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/_shared.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/config.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/core.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/init_builder.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/methods.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/naming.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/properties.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/class_builder/terminals.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/condition_builder.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/context.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/dataflow.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/elementwise.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/error_handler.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/expressions.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/fragment.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/function.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/imports.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/base.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/case.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/compound.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/constant.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/event.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/first_call.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/formula.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/in_place.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/invoke_node.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/loop.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/nmux.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/primitive.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/printf.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/property_node.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/queue_ops.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/sequence.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/nodes/subvi.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/stubs.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/codegen/unresolved.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/connector_geometry.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/connector_pane_geometry.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/builtin_types.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/connector_pane_patterns.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/_index.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/daqmx.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/nidcpower.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/nidigital.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/nidmm.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/nifgen.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/niscope.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/niswitch.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/serial.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/drivers/visa.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/labview_error_codes.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/measure_data.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/openg/_index.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/openg/array.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/openg/file.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/openg/string.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/openg/time.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/openg/variant.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/primitives.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/_index.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/_pending_terminals.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/_types.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/addons.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/application-control.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/array.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/boolean.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/cluster-class-variant.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/collection.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/comparison.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/connectivity.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/control-simulation.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/data-communication.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/dialog-user-interface.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/express.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/file-io.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/graphics-sound.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/instrument-io.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/mathematics.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/measurement-io.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/numeric.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/report-generation.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/signal-processing.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/string.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/structures.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/synchronization.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/timing.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/data/vilib/waveform.json +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/generate.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/html_generator/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/html_generator/assets.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/html_generator/class_page.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/html_generator/core.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/html_generator/index_page.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/html_generator/naming.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/html_generator/vi_page.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/template.css +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/docs/utils.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/extractor.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/flattened_typedesc.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/formula/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/formula/cparser.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/formula/emit.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/formula/lexer.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/formula/nodes.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/analysis.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/builders/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/builders/context.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/builders/refs.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/builders/structures.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/construction.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/core.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/describe.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/diff.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/interface_order.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/lvnet_grammar.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/lvnet_parse.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/lvnet_reconstruct.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/netlist.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/netlist_build.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/netlist_diff_helpers.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/netlist_json.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/netlist_models.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/op_walk.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/operations.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/parallel_parse.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/queries.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/graph/render_lvnet.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/index/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/index/build.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/index/model.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/index/project.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/index/query.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/index/sql.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/index/store.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/labview_error.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/labview_error_codes.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/labview_queue.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/load_mode.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/lv_detect.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/schemas.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/__main__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/_compat.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/app.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/index_tools.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/resolvers.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/roots.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/mcp/server/vi_tools.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/measure_data.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/models.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/num_format.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/output_cache.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/conp_types.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/constants.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/defaults.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/flags.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/fp_heap_type.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/front_panel.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/image_resources.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/layout.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/models.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/naming.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/base.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/case.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/constant.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/decompose.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/disable.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/event.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/free_label.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/loop.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/nodes/sequence.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/type_mapping.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/type_resolution.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/utils.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/parser/wire_table.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/pipeline.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/primitive_resolver/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/primitive_resolver/exceptions.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/primitive_resolver/models.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/primitive_resolver/resolver.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/project_store.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/py.typed +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/ARCHITECTURE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/backend.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/composite.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/connector_pane.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/connector_pane_panel.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/diff_viewer.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/draw.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyph.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/arrow.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/base.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/factory.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/fallback.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/frame.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/line.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/decorations/picture.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/arith.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/array_build.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/array_constant.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/array_reverse.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/array_search.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/array_size.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/array_sort.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/array_split.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/boolean_constant.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/boolean_gate.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/bundle.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/bundle_by_name.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/centered_svg.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/class_glyph.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/cluster_constant.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/compound_arith.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/constant.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/control_ref_const.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/convert.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/error_cluster.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/event_data.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/event_reg_node.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/formula_node.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/icon_image.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/in_place_element.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/inline_svg.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/label.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/local_variable.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/path_glyph.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/refnum_glyph.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/unbundle.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/variant.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/nodes/wrapped_box.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/base.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/case.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/disable.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/event.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/factory.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/flat_sequence.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/for_loop.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/generic.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/in_place.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/selectable.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/stacked_sequence.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/structures/while_loop.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/autoindex.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/base.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/concatenate.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/conditional.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/event_dyn.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/event_timeout.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/factory.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/generic.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/loop_count.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/selector.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/shift_register.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/glyphs/terminals/tunnel.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/help_tip.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/icons.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/lane_pass.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/properties_panel.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/render_viewer.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/templates/diff_viewer.html +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/templates/render_viewer.html +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/theme_control.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/render/wire_router.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/runtime/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/runtime/lv.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/lvkit/SKILL.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/lvkit-convert/SKILL.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/lvkit-describe/SKILL.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/lvkit-document/SKILL.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/lvkit-query/SKILL.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/lvkit-resolve/SKILL.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/skill_templates/lvkit-review/SKILL.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/terminal_collector.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/text_encoding.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/tools/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/tools/connector_geometry_profile.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/type_defaults.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/unresolved.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vi_diff.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/exceptions.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/loader.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/lookup.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/models.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/naming.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/resolver.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/src/lvkit/vilib_resolver/variants.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/__init__.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/conftest.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Lib1/Class/Class.lvclass +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Lib1/Class/Do.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Lib1/Lib1.lvlib +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Lib2/Class/Class.lvclass +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Lib2/Class/Do.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Lib2/Class/Test.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Lib2/Lib2.lvlib +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Test LVKit.aliases +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Test LVKit.lvlps +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/29/Test LVKit/Test LVKit.lvproj +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/30/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/30/visible-frame-case-sequence.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/30/visible-frame-conditional-disable.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/31/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/31/disable-structure-frame-names.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/32/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/32/comments-and-decorations.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/33/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/33/coercion-dot-consistency.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/34/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/34/hidden-iteration-terminal.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/35/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/35/objects-hidden-by-structures.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/36/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/36/bundle-unbundle-names.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/37/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/37/structure-tunnel-wire-bends.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/38/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/38/auto-concatenating-tunnel.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/39/PROVENANCE.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/39/zorder-not-respected.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/82/Pictures And Decorations.vi +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/corpus/issues/README.md +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/helpers.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_array_ops_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_ast_builder.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_ast_optimizer.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_case_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_case_parser.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_class_field_walkup.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_class_properties.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_cli.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_cli_cache.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_cli_describe_lvnet.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_cli_graph_ops.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_cli_query.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_cluster_wire_color.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_codegen_context.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_compound_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_condition_builder.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_connector_geometry.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_connector_pane_label_recovery.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_connector_pane_patterns.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_connector_pane_render.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_conp_types.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_dependency_path_refs.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_determinism.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_diff.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_diff_properties.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_diff_viewer.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_disable_graph.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_disable_parser.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_docs_class_hierarchy.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_docs_render.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_driver_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_dynamic_dispatch.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_e2e_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_elementwise.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_error_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_error_handling.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_error_terminal_label_fallback.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_event_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_event_parser.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_extraction_cache.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_extractor_concurrency.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_extractor_long_path.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_first_call_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_formula_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_formula_runtime.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_formula_semantics.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_formula_transpile.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_fp_heap_type.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_frame_attribution.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_frame_zplane.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_glyphs.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_graceful_degradation.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_help_tip.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_import_startup.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_in_place_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_index.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_index_sql.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_index_warm_no_downgrade.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_interface_order.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_issue_corpus.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_label_extraction.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_labview_queue.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_livi_vipi.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_load_mode.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_load_upgrade.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_loop_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_lv_detect.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_lvnet_identity.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_lvnet_reconstruct.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_lvnet_roundtrip.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_lvpy.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_mcp_cache.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_mcp_evals.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_mcp_read_vi_lvnet.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_mcp_roots.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_naming.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_netlist_json.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_new_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_node_properties.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_output_cache.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_parallel_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_parallel_parse.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_parser_regression.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_primitive_name_uniqueness.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_primitive_positional_order.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_primitive_resolutions.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_progressive_index.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_progressive_warm.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_project_store.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_queue_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_render_emission_order.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_render_lvnet.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_render_title_identity.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_render_viewer.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_sequence.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_soft_codegen.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_structure_lvproj.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_subvi_nav.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_text_encoding.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_type_driven_fixes.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_type_fields.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_type_loading.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_type_mapping.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_unknown_nodes.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_unresolved.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_vi_graph.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_vi_properties.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_viewer_properties.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/tests/test_vilib_docurls.py +0 -0
- {lvkit-0.8.2 → lvkit-0.8.3}/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
|
+
Version: 0.8.3
|
|
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 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
|
-
__version__ = "0.8.
|
|
7
|
+
__version__ = "0.8.3"
|
|
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
|
|
@@ -99,6 +99,12 @@ class PrimitiveBuildHandler(NodeBuildHandler):
|
|
|
99
99
|
if isinstance(node, (PropertyNode, InvokeNode, EventRegNode)):
|
|
100
100
|
prim_kwargs["object_name"] = node.object_name
|
|
101
101
|
prim_kwargs["object_method_id"] = node.object_method_id
|
|
102
|
+
# Property/Invoke nodes share the SAME implicit-binding fields
|
|
103
|
+
# (task #51/#55) -- EventRegNode has neither, so it's excluded
|
|
104
|
+
# here rather than duplicating this pair per elif branch below.
|
|
105
|
+
if isinstance(node, (PropertyNode, InvokeNode)):
|
|
106
|
+
prim_kwargs["bound_control_uid"] = node.bound_control_uid
|
|
107
|
+
prim_kwargs["bound_control_type"] = node.bound_control_type
|
|
102
108
|
if isinstance(node, PropertyNode):
|
|
103
109
|
prim_kwargs["properties"] = [
|
|
104
110
|
PropertyDef(name=p.get("name", "")) if isinstance(p, dict) else p
|
|
@@ -107,8 +113,6 @@ class PrimitiveBuildHandler(NodeBuildHandler):
|
|
|
107
113
|
prim_kwargs["property_value_terminal_ids"] = [
|
|
108
114
|
ctx.qid(uid) for uid in node.dco_terminal_uids
|
|
109
115
|
]
|
|
110
|
-
prim_kwargs["bound_control_uid"] = node.bound_control_uid
|
|
111
|
-
prim_kwargs["bound_control_type"] = node.bound_control_type
|
|
112
116
|
elif isinstance(node, InvokeNode):
|
|
113
117
|
prim_kwargs["method_name"] = node.method_name
|
|
114
118
|
prim_kwargs["method_code"] = node.method_code
|
|
@@ -647,13 +647,14 @@ class LoadingMixin:
|
|
|
647
647
|
search_paths: list[Path] | None = None,
|
|
648
648
|
owner_chain: list[str] | None = None,
|
|
649
649
|
) -> str:
|
|
650
|
-
"""Load a .lvclass file. Returns the
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
650
|
+
"""Load a .lvclass file. Returns the dep-graph KEY (the resolved
|
|
651
|
+
``.lvclass`` path) it was registered under — mirrors ``load_lvlib``/
|
|
652
|
+
``load_typedef``: callers add ownership/reference edges to THIS key,
|
|
653
|
+
never to the qname (``cls_qname``, built from the ON-DISK file's own
|
|
654
|
+
stem casing — the CALLER may have referenced this class under a
|
|
655
|
+
different casing, e.g. a type reference's recorded casing can differ
|
|
656
|
+
from the file's actual casing, so the qname alone isn't a safe edge
|
|
657
|
+
target; see ``_load_dependency``'s ``.lvclass`` branch).
|
|
657
658
|
|
|
658
659
|
``MINIMAL`` is an INTERFACE load: add the class's private-data fields
|
|
659
660
|
(and its parent chain's, via walk-up — nMux field indices run into the
|
|
@@ -686,7 +687,9 @@ class LoadingMixin:
|
|
|
686
687
|
# walks follow it by IDENTITY (a name can hit duplicates; a path
|
|
687
688
|
# can't). None when the parent isn't on disk.
|
|
688
689
|
parent = cls.parent_class
|
|
689
|
-
parent_file, parent_intended = self._resolve_parent(
|
|
690
|
+
parent_file, parent_intended = self._resolve_parent(
|
|
691
|
+
cls, lvclass_path, search_paths
|
|
692
|
+
)
|
|
690
693
|
# The parent's KEY is its recorded path whether or not the file is staged
|
|
691
694
|
# yet — so progressive (web) staging can NAME + fetch a not-yet-present
|
|
692
695
|
# parent (an ``.exists()`` gate would drop the whole inherited surface).
|
|
@@ -832,6 +835,18 @@ class LoadingMixin:
|
|
|
832
835
|
try:
|
|
833
836
|
pd_fields = private_data_from_lvclass_xml(lvclass_path)
|
|
834
837
|
except Exception:
|
|
838
|
+
# Intentional hard best-effort boundary, not a narrowable
|
|
839
|
+
# set: private_data_from_lvclass_xml decodes a possibly
|
|
840
|
+
# malformed/legacy embedded RSRC container through
|
|
841
|
+
# pylabview's OWN VI-resource parser (parse_flattened_
|
|
842
|
+
# private_data -> lv_rsrc.VI(...).parseData()), whose
|
|
843
|
+
# exception surface on untrusted/old-format binary data
|
|
844
|
+
# isn't a documented closed set (struct/index/value/key
|
|
845
|
+
# errors and more have all been observed from that parser
|
|
846
|
+
# elsewhere) -- this docstring's own contract is "a
|
|
847
|
+
# malformed/older embedded control must never break class
|
|
848
|
+
# loading", so any failure here degrades to "no fields
|
|
849
|
+
# recovered", never propagates.
|
|
835
850
|
logger.debug(
|
|
836
851
|
"flattened private-data recovery failed for %s",
|
|
837
852
|
lvclass_path,
|
|
@@ -841,23 +856,119 @@ class LoadingMixin:
|
|
|
841
856
|
fields = [private_data_field_to_cluster_field(f) for f in pd_fields]
|
|
842
857
|
return fields
|
|
843
858
|
|
|
859
|
+
def _resolve_vilib_class_ref(
|
|
860
|
+
self,
|
|
861
|
+
parent_name: str,
|
|
862
|
+
path_tokens: list[str],
|
|
863
|
+
lvclass_path: Path,
|
|
864
|
+
search_paths: list[Path],
|
|
865
|
+
) -> tuple[Path | None, Path | None]:
|
|
866
|
+
"""Resolve a ``<vilib>``-rooted class reference's TOKENS (already
|
|
867
|
+
split — ``path_tokens[0] == "<vilib>"``) -> ``(parent_file,
|
|
868
|
+
parent_intended)``, via ``ParsedDependencyRef.resolve_against`` — the
|
|
869
|
+
EXACT SAME machinery a SubVI/type ``<vilib>`` dependency already
|
|
870
|
+
resolves through (``_resolve_dependency_path``), never a new
|
|
871
|
+
resolver. Shared by BOTH ``<vilib>``-rooted sources ``_resolve_parent``
|
|
872
|
+
can see (a plain-XML ``Parent`` Item's URL, and the binary
|
|
873
|
+
``ParentClassLinkInfo``'s own recorded path — issue #84's #F1
|
|
874
|
+
correction: the URL case was previously naively joined, leaving a
|
|
875
|
+
literal ``<vilib>`` path component that never exists).
|
|
876
|
+
|
|
877
|
+
A configured ``vilib_root`` gives an exact, scan-free hit; otherwise
|
|
878
|
+
``<vilib>`` maps onto ``search_paths`` (this loader's already-
|
|
879
|
+
configured SubVI roots) the same way, with ``_find_file``'s existing
|
|
880
|
+
bounded per-search-path lookup (used for every other unresolved
|
|
881
|
+
dependency) actually LOCATING the file when it's nested deeper than
|
|
882
|
+
a direct join reaches (e.g. actor-framework vendors ``Actor.lvclass``
|
|
883
|
+
under an extra ``Core/`` level the recorded path itself doesn't
|
|
884
|
+
record — LabVIEW's own vi.lib layout has no such prefix).
|
|
885
|
+
``parent_intended`` is still produced via pure path math even when
|
|
886
|
+
no local file is found (one of ``vilib_root``/``search_paths[0]``),
|
|
887
|
+
so progressive/web staging can NAME + fetch it — never
|
|
888
|
+
``.exists()``-gated away, same contract as the method-path code in
|
|
889
|
+
``load_lvclass`` above."""
|
|
890
|
+
parent_file: Path | None = None
|
|
891
|
+
parent_intended: Path | None = None
|
|
892
|
+
dep_ref = ParsedDependencyRef(
|
|
893
|
+
name=parent_name + ".lvclass", path_tokens=path_tokens
|
|
894
|
+
)
|
|
895
|
+
candidate = dep_ref.resolve_against(
|
|
896
|
+
lvclass_path,
|
|
897
|
+
vilib_root=self._vilib_root,
|
|
898
|
+
userlib_root=self._userlib_root,
|
|
899
|
+
instrlib_root=self._instrlib_root,
|
|
900
|
+
)
|
|
901
|
+
if candidate is not None:
|
|
902
|
+
parent_intended = candidate
|
|
903
|
+
if candidate.exists():
|
|
904
|
+
parent_file = candidate
|
|
905
|
+
# Both the search_paths glob AND the search_paths[0]-as-vilib_root
|
|
906
|
+
# intended-path fallback are skipped once EITHER parent_file OR
|
|
907
|
+
# parent_intended is already known -- no point globbing when the
|
|
908
|
+
# exact vilib_root candidate already resolved, and no point
|
|
909
|
+
# recomputing parent_intended once parent_file has resolved (it's
|
|
910
|
+
# only ever consulted as parent_file's own fallback, never both).
|
|
911
|
+
if parent_file is None and parent_intended is None and search_paths:
|
|
912
|
+
parent_file = self._find_file(
|
|
913
|
+
parent_name + ".lvclass", search_paths, lvclass_path.parent
|
|
914
|
+
)
|
|
915
|
+
if parent_file is None and parent_intended is None and search_paths:
|
|
916
|
+
# No configured vilib_root — map <vilib> onto the first search
|
|
917
|
+
# root instead, so an absent parent still gets a deterministic
|
|
918
|
+
# (pure path math, no scan) intended path for web staging to
|
|
919
|
+
# name.
|
|
920
|
+
parent_intended = dep_ref.resolve_against(
|
|
921
|
+
lvclass_path, vilib_root=search_paths[0]
|
|
922
|
+
)
|
|
923
|
+
return parent_file, parent_intended
|
|
924
|
+
|
|
844
925
|
def _resolve_parent(
|
|
845
|
-
self, cls: LVClass, lvclass_path: Path
|
|
926
|
+
self, cls: LVClass, lvclass_path: Path, search_paths: list[Path]
|
|
846
927
|
) -> tuple[Path | None, Path | None]:
|
|
847
928
|
"""The parent class's file (when present) and its INTENDED path
|
|
848
929
|
(present or not) -> ``(parent_file, parent_intended)``.
|
|
849
930
|
|
|
850
931
|
PREFERS the parent's own recorded URL (a DIRECT relative path — the
|
|
851
932
|
parent commonly lives in a sibling subtree an up-tree walk can't
|
|
852
|
-
reach, e.g. ``../../Layer/Layer.lvclass``)
|
|
853
|
-
|
|
854
|
-
|
|
933
|
+
reach, e.g. ``../../Layer/Layer.lvclass``) — UNLESS that URL is
|
|
934
|
+
itself ``<vilib>``-rooted (``cls.is_vilib_parent``, e.g.
|
|
935
|
+
``"/<vilib>/ActorFramework/Actor/Actor.lvclass"``, verified against
|
|
936
|
+
Event Receiver Actor.lvclass's real ``Parent`` Item — a LEADING
|
|
937
|
+
SLASH, the marker, then forward-slash path components, NOT a normal
|
|
938
|
+
relative path), in which case it's tokenized and resolved via
|
|
939
|
+
``_resolve_vilib_class_ref`` like any other vi.lib reference (issue
|
|
940
|
+
#84's #F1 correction — the naive join used to leave a literal
|
|
941
|
+
``<vilib>`` path component that never exists).
|
|
942
|
+
|
|
943
|
+
When there's no URL but the parent's binary link record is
|
|
944
|
+
``<vilib>``-rooted (``cls.parent_link_path``, issue #84 — e.g.
|
|
945
|
+
``["<vilib>", "ActorFramework", "Actor", "Actor.lvclass"]``),
|
|
946
|
+
resolves it the SAME way via ``_resolve_vilib_class_ref``.
|
|
947
|
+
|
|
948
|
+
A NON-vilib link record (the "in-repo" PTH0 shape — no recorded
|
|
949
|
+
URL, parent lives elsewhere in the same tree) is deliberately left
|
|
950
|
+
to the existing bare-name walk-up below — ``resolve_against``'s
|
|
951
|
+
generic (non-``<vilib>``) branch reads leading EMPTY tokens as
|
|
952
|
+
``..`` hops, a shape not verified against a real in-repo PTH0
|
|
953
|
+
record, so this stays scoped to what issue #84 actually asked for
|
|
954
|
+
rather than risking the already-working walk-up.
|
|
955
|
+
|
|
956
|
+
Falls back to a bare-name walk-up (``_walk_up_find`` —
|
|
957
|
+
filesystem-only, no search_paths, so it can't reach a cross-subtree
|
|
958
|
+
or vi.lib parent) when NEITHER a URL nor a resolved vilib link path
|
|
959
|
+
was found. Both None when the class has no parent (or its parent is
|
|
960
|
+
the root ``LabVIEW Object``).
|
|
855
961
|
"""
|
|
856
962
|
parent = cls.parent_class
|
|
857
963
|
parent_file: Path | None = None
|
|
858
964
|
parent_intended: Path | None = None
|
|
859
965
|
if parent and parent != "LabVIEW Object":
|
|
860
|
-
if cls.parent_url:
|
|
966
|
+
if cls.parent_url and cls.is_vilib_parent:
|
|
967
|
+
tokens = [t for t in cls.parent_url.split("/") if t]
|
|
968
|
+
parent_file, parent_intended = self._resolve_vilib_class_ref(
|
|
969
|
+
parent, tokens, lvclass_path, search_paths
|
|
970
|
+
)
|
|
971
|
+
elif cls.parent_url:
|
|
861
972
|
# LabVIEW ``.lvclass`` URLs are relative to the class FILE
|
|
862
973
|
# treated as a directory (members read ``../X.vi``), so
|
|
863
974
|
# resolve against ``lvclass_path`` itself — that absorbs the
|
|
@@ -865,6 +976,10 @@ class LoadingMixin:
|
|
|
865
976
|
parent_intended = (lvclass_path / cls.parent_url).resolve()
|
|
866
977
|
if parent_intended.exists():
|
|
867
978
|
parent_file = parent_intended
|
|
979
|
+
elif cls.is_vilib_parent and cls.parent_link_path:
|
|
980
|
+
parent_file, parent_intended = self._resolve_vilib_class_ref(
|
|
981
|
+
parent, cls.parent_link_path, lvclass_path, search_paths
|
|
982
|
+
)
|
|
868
983
|
if parent_file is None and parent_intended is None:
|
|
869
984
|
parent_file = self._walk_up_find(
|
|
870
985
|
lvclass_path.parent, parent + ".lvclass"
|
|
@@ -1639,19 +1754,19 @@ class LoadingMixin:
|
|
|
1639
1754
|
owner_chain = parts[:-1] if len(parts) > 1 else None
|
|
1640
1755
|
# MINIMAL: field-load the class (no method bodies) — enough for
|
|
1641
1756
|
# by-name field names. FULL: load its whole method tree for codegen.
|
|
1642
|
-
|
|
1757
|
+
loaded_key = self.load_lvclass(
|
|
1643
1758
|
resolved,
|
|
1644
1759
|
mode,
|
|
1645
1760
|
search_paths=search_paths,
|
|
1646
1761
|
owner_chain=owner_chain,
|
|
1647
1762
|
)
|
|
1648
1763
|
if caller_qname:
|
|
1649
|
-
self._dep_graph.add_edge(caller_qname,
|
|
1764
|
+
self._dep_graph.add_edge(caller_qname, loaded_key)
|
|
1650
1765
|
# See the walk-up branch above: alias rather than let a
|
|
1651
1766
|
# differently-cased reference create a second, empty dep_graph
|
|
1652
1767
|
# node that shadows the real (populated) one.
|
|
1653
|
-
if qualified_name !=
|
|
1654
|
-
self._qualified_aliases[qualified_name] =
|
|
1768
|
+
if qualified_name != loaded_key:
|
|
1769
|
+
self._qualified_aliases[qualified_name] = loaded_key
|
|
1655
1770
|
elif leaf.endswith(".lvlib"):
|
|
1656
1771
|
lib_key = self.load_lvlib(resolved, mode, search_paths=search_paths)
|
|
1657
1772
|
if caller_qname:
|
|
@@ -158,17 +158,18 @@ class PrimitiveNode(GraphNode):
|
|
|
158
158
|
# reference terminal, but this structural id list always can. See
|
|
159
159
|
# ``op_walk.correlate_property_terminals``.
|
|
160
160
|
property_value_terminal_ids: list[str] = []
|
|
161
|
-
# Property node only: the BOUND front-panel control's own ddo uid
|
|
162
|
-
# unqualified -- not this node's own qualified id) when this
|
|
163
|
-
#
|
|
164
|
-
# "Abort" boolean property node
|
|
165
|
-
# a wired reference). See
|
|
166
|
-
#
|
|
167
|
-
#
|
|
161
|
+
# Property/Invoke node only: the BOUND front-panel control's own ddo uid
|
|
162
|
+
# (RAW, unqualified -- not this node's own qualified id) when this node
|
|
163
|
+
# is IMPLICIT (permanently tied to a specific control, e.g. GTR's
|
|
164
|
+
# "Abort" boolean property node or its "Test Hierarchy Tree" invoke
|
|
165
|
+
# node) -- "" for an EXPLICIT one (identity from a wired reference). See
|
|
166
|
+
# ``parser.node_types.PropertyNode``/``InvokeNode``'s class docstrings
|
|
167
|
+
# for the full heap discriminator (a direct ``<ddo>`` child + a
|
|
168
|
+
# ``<label>`` naming the control, both absent when explicit).
|
|
168
169
|
bound_control_uid: str = ""
|
|
169
170
|
# The bound control's reconstructed LVType (``parser.fp_heap_type.
|
|
170
171
|
# reconstruct_control_lvtype``, resolved at PARSE time against the
|
|
171
|
-
# front-panel heap -- see ``parser.vi.
|
|
172
|
+
# front-panel heap -- see ``parser.vi._resolve_bound_control_types``).
|
|
172
173
|
# None for an explicit node, or an implicit one whose control class isn't
|
|
173
174
|
# modeled by that reconstructor.
|
|
174
175
|
bound_control_type: LVType | None = None
|
|
@@ -406,7 +406,7 @@ def parse_polymorphic_info(root: ET.Element) -> dict[str, Any]:
|
|
|
406
406
|
|
|
407
407
|
# Check for AllowPolyTypeAdapt flag - this indicates a polymorphic wrapper
|
|
408
408
|
# VIs that call polymorphic VIs have PolyVI TypeDesc but AllowPolyTypeAdapt="0"
|
|
409
|
-
exec2 = root.find(".//LVSR
|
|
409
|
+
exec2 = root.find(".//LVSR/Section/Execution2")
|
|
410
410
|
if exec2 is None or exec2.get("AllowPolyTypeAdapt") != "1":
|
|
411
411
|
# Also check for selector-based polymorphic (ShowPolySelector)
|
|
412
412
|
if exec2 is None or exec2.get("ShowPolySelector") != "1":
|
|
@@ -515,11 +515,26 @@ def _decode_pth0_components(
|
|
|
515
515
|
``end`` bounds how far the decode may read (exclusive) -- either
|
|
516
516
|
``len(data)`` for a whole-file scan or a caller-defined record boundary.
|
|
517
517
|
Reads the component count at ``pth0_offset+10:+12`` (guarded to
|
|
518
|
-
``0
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
518
|
+
``0 <= ncomp <= 64`` -- a sanity bound against a garbage length; ``0`` is
|
|
519
|
+
a REAL, legitimate value -- LabVIEW's own encoding for an empty/unset
|
|
520
|
+
Path, e.g. ``PTH0 00 00 00 04 00 00 00 00`` -- never rejected as
|
|
521
|
+
"truncated": see issue #91, where treating ncomp==0 as an error made
|
|
522
|
+
``_walk_path`` return ``consumed=0`` for a genuinely empty path, which
|
|
523
|
+
left the CALLER's byte offset stuck. For a cluster field, every
|
|
524
|
+
subsequent field then decoded from that stale offset -- e.g. GTR's SMUI
|
|
525
|
+
cluster's ``TestMethods``/``TestProjectClasses`` arrays (variable-size,
|
|
526
|
+
confirmed by their type descriptor's ``FixedSize="0xFFFFFF"`` sentinel,
|
|
527
|
+
never a fixed bound) read a residual `"PTH0"` tag as their 4-byte
|
|
528
|
+
element count once an earlier empty ``Open Path``/``Test Project``
|
|
529
|
+
field desynced them -- a real leading count IS present and correct once
|
|
530
|
+
alignment holds), then decodes each component as a pascal string
|
|
531
|
+
(1-byte length prefix + native text). Returns ``([], pth0_offset)`` if
|
|
532
|
+
the record is truncated (would read past ``end``) or the count is out
|
|
533
|
+
of range -- a partial token list is never returned, so a truncated
|
|
534
|
+
record reads as "no components" to every caller. An empty path
|
|
535
|
+
(``ncomp==0``) is NOT truncated -- it returns ``([], pth0_offset + 12)``,
|
|
536
|
+
the byte offset just past its magic+length+ncomp fields (see the
|
|
537
|
+
12-byte-record math above), so the caller's alignment stays correct.
|
|
523
538
|
``next_idx`` is the byte offset just past the last decoded component --
|
|
524
539
|
the single source of both the decoded tokens AND the consumed-byte count,
|
|
525
540
|
shared by every caller that needs to keep reading past this record (e.g.
|
|
@@ -529,8 +544,10 @@ def _decode_pth0_components(
|
|
|
529
544
|
if pth0_offset + 12 > end:
|
|
530
545
|
return [], pth0_offset
|
|
531
546
|
ncomp = int.from_bytes(data[pth0_offset + 10 : pth0_offset + 12], "big")
|
|
532
|
-
if not (0
|
|
547
|
+
if not (0 <= ncomp <= 64):
|
|
533
548
|
return [], pth0_offset
|
|
549
|
+
if ncomp == 0:
|
|
550
|
+
return [], pth0_offset + 12
|
|
534
551
|
idx = pth0_offset + 12
|
|
535
552
|
tokens: list[str] = []
|
|
536
553
|
for _ in range(ncomp):
|
|
@@ -60,18 +60,6 @@ class ArrayBuildNode(ParsedNode):
|
|
|
60
60
|
pass # No extra fields yet
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
@dataclass
|
|
64
|
-
class ArrayInitNode(ParsedNode):
|
|
65
|
-
"""Initialize Array node (class="aInit").
|
|
66
|
-
|
|
67
|
-
Builds an N-dimensional array from an element value and one size input per
|
|
68
|
-
dimension. Terminals (element + dimension sizes → array) carry on the base
|
|
69
|
-
ParsedNode; no extra fields.
|
|
70
|
-
"""
|
|
71
|
-
|
|
72
|
-
pass
|
|
73
|
-
|
|
74
|
-
|
|
75
63
|
@dataclass
|
|
76
64
|
class FormulaNode(ParsedNode):
|
|
77
65
|
"""A Formula Node (class="fBox") with an embedded C-like script.
|
|
@@ -498,17 +486,6 @@ class ArrayBuildHandler(NodeTypeHandler):
|
|
|
498
486
|
return ArrayBuildNode(**common)
|
|
499
487
|
|
|
500
488
|
|
|
501
|
-
class ArrayInitHandler(NodeTypeHandler):
|
|
502
|
-
"""Handler for Initialize Array nodes (class="aInit")."""
|
|
503
|
-
|
|
504
|
-
xml_class = "aInit"
|
|
505
|
-
display_name = "Initialize Array"
|
|
506
|
-
|
|
507
|
-
def parse(self, elem: ET.Element) -> ArrayInitNode:
|
|
508
|
-
common = self._extract_common(elem)
|
|
509
|
-
return ArrayInitNode(**common)
|
|
510
|
-
|
|
511
|
-
|
|
512
489
|
class WhileLoopHandler(NodeTypeHandler):
|
|
513
490
|
"""Handler for While Loop nodes (class="whileLoop")."""
|
|
514
491
|
|
|
@@ -687,6 +664,17 @@ class InvokeNode(ParsedNode):
|
|
|
687
664
|
sides of a row, but only wireable sides get a real type. See the
|
|
688
665
|
render layer (``render/nodes.py:_invoke_node_glyph``), which is where
|
|
689
666
|
that Void check happens (type resolution isn't available at parse time).
|
|
667
|
+
|
|
668
|
+
Like ``PropertyNode``, an Invoke Node draws in one of two forms
|
|
669
|
+
depending on whether it is permanently bound to a specific front-panel
|
|
670
|
+
control (IMPLICIT) or takes its identity from a wired reference
|
|
671
|
+
(EXPLICIT) -- the SAME heap discriminator: an IMPLICIT node carries a
|
|
672
|
+
direct ``<ddo uid="...">`` CHILD (a sibling of its own ``<termList>``,
|
|
673
|
+
never a part of it) naming the bound control, plus a ``<label>``
|
|
674
|
+
showing that control's NAME instead of the generic node name (verified
|
|
675
|
+
on GTR's "Test Hierarchy Tree" invoke node, uid 11387, bound-control ddo
|
|
676
|
+
uid 12, ``<methName>"Custom Item Symbols.Revert Symbols"``). An EXPLICIT
|
|
677
|
+
node has neither.
|
|
690
678
|
"""
|
|
691
679
|
|
|
692
680
|
object_name: str = ""
|
|
@@ -694,6 +682,18 @@ class InvokeNode(ParsedNode):
|
|
|
694
682
|
method_name: str = ""
|
|
695
683
|
method_code: int = 0
|
|
696
684
|
row_terminal_uids: list[str] = field(default_factory=list)
|
|
685
|
+
# The BOUND control's own ddo uid (see class docstring) -- "" for an
|
|
686
|
+
# EXPLICIT invoke node (no such binding). The sole discriminator: never
|
|
687
|
+
# inferred from the label text or from wiring (those only corroborate).
|
|
688
|
+
bound_control_uid: str = ""
|
|
689
|
+
# The bound control's reconstructed LVType (via
|
|
690
|
+
# ``fp_heap_type.reconstruct_control_lvtype`` on ``bound_control_uid``'s
|
|
691
|
+
# ddo in the FRONT-PANEL heap -- resolved by ``_parse_block_diagram``,
|
|
692
|
+
# which has both heaps, never by ``render/`` reading heap XML itself).
|
|
693
|
+
# None for an explicit node, OR an implicit one whose control class this
|
|
694
|
+
# reconstructor doesn't model (see that function's own docstring) --
|
|
695
|
+
# never a guessed color in either case.
|
|
696
|
+
bound_control_type: LVType | None = None
|
|
697
697
|
|
|
698
698
|
|
|
699
699
|
@dataclass
|
|
@@ -788,6 +788,12 @@ class InvokeNodeHandler(NodeTypeHandler):
|
|
|
788
788
|
meth_code = int(meth_code_text)
|
|
789
789
|
except ValueError:
|
|
790
790
|
meth_code = 0
|
|
791
|
+
# An IMPLICIT invoke node's DIRECT <ddo> CHILD (a sibling of its own
|
|
792
|
+
# <termList>, never a part of it) names the front-panel control it's
|
|
793
|
+
# permanently bound to (see InvokeNode's class docstring) -- absent
|
|
794
|
+
# entirely for an EXPLICIT one.
|
|
795
|
+
bound_ddo = elem.find("ddo")
|
|
796
|
+
bound_control_uid = bound_ddo.get("uid", "") if bound_ddo is not None else ""
|
|
791
797
|
return InvokeNode(
|
|
792
798
|
**common,
|
|
793
799
|
object_name=clean_labview_string(elem.findtext("nodeName")),
|
|
@@ -795,6 +801,7 @@ class InvokeNodeHandler(NodeTypeHandler):
|
|
|
795
801
|
method_name=clean_labview_string(elem.findtext("methName")),
|
|
796
802
|
method_code=meth_code,
|
|
797
803
|
row_terminal_uids=_dco_list_terminal_uids(elem),
|
|
804
|
+
bound_control_uid=bound_control_uid,
|
|
798
805
|
)
|
|
799
806
|
|
|
800
807
|
|
|
@@ -1319,7 +1326,6 @@ _HANDLERS: list[NodeTypeHandler] = [
|
|
|
1319
1326
|
FeedbackSlaveHandler(),
|
|
1320
1327
|
CpdArithHandler(),
|
|
1321
1328
|
ArrayBuildHandler(),
|
|
1322
|
-
ArrayInitHandler(),
|
|
1323
1329
|
WhileLoopHandler(),
|
|
1324
1330
|
ForLoopHandler(),
|
|
1325
1331
|
SelectHandler(),
|
|
@@ -64,7 +64,7 @@ from .models import (
|
|
|
64
64
|
ParsedWire,
|
|
65
65
|
SelectorTable,
|
|
66
66
|
)
|
|
67
|
-
from .node_types import PropertyNode, parse_node
|
|
67
|
+
from .node_types import InvokeNode, PropertyNode, parse_node
|
|
68
68
|
from .nodes import (
|
|
69
69
|
extract_case_structures,
|
|
70
70
|
extract_constants,
|
|
@@ -374,7 +374,7 @@ def _parse_block_diagram(
|
|
|
374
374
|
root = tree.getroot()
|
|
375
375
|
|
|
376
376
|
nodes = _extract_nodes(root)
|
|
377
|
-
|
|
377
|
+
_resolve_bound_control_types(nodes, fp_xml)
|
|
378
378
|
constants = extract_constants(root)
|
|
379
379
|
labels = extract_free_labels(root)
|
|
380
380
|
wires = _extract_wires(root)
|
|
@@ -615,21 +615,25 @@ def _extract_nodes(root: ET.Element) -> list[ParsedNode]:
|
|
|
615
615
|
return nodes
|
|
616
616
|
|
|
617
617
|
|
|
618
|
-
def
|
|
618
|
+
def _resolve_bound_control_types(
|
|
619
619
|
nodes: list[ParsedNode], fp_xml: Path | str | None
|
|
620
620
|
) -> None:
|
|
621
|
-
"""Resolve each IMPLICIT ``PropertyNode``'s
|
|
622
|
-
the FRONT-PANEL heap (see
|
|
623
|
-
``bound_control_uid`` discriminator
|
|
621
|
+
"""Resolve each IMPLICIT ``PropertyNode``/``InvokeNode``'s
|
|
622
|
+
``bound_control_type`` from the FRONT-PANEL heap (see each class's own
|
|
623
|
+
docstring for the ``bound_control_uid`` discriminator -- the SAME direct
|
|
624
|
+
``<ddo>``-child convention for both node kinds) -- in-place, mutating
|
|
625
|
+
``nodes``.
|
|
624
626
|
|
|
625
|
-
This is the one place render's "implicit vs explicit"
|
|
627
|
+
This is the one place render's "implicit vs explicit" node-identity
|
|
626
628
|
distinction touches the front-panel heap: done here at PARSE time (this
|
|
627
629
|
module owns both heaps), never in ``render/``, which only ever reads the
|
|
628
630
|
already-decoded graph/``Layout`` (see ``layout.py``'s own module
|
|
629
631
|
docstring). The FP root is parsed at most ONCE per VI, only when at
|
|
630
|
-
least one
|
|
631
|
-
bound: list[PropertyNode] = [
|
|
632
|
-
n
|
|
632
|
+
least one node actually needs it."""
|
|
633
|
+
bound: list[PropertyNode | InvokeNode] = [
|
|
634
|
+
n
|
|
635
|
+
for n in nodes
|
|
636
|
+
if isinstance(n, (PropertyNode, InvokeNode)) and n.bound_control_uid
|
|
633
637
|
]
|
|
634
638
|
if not bound or not fp_xml:
|
|
635
639
|
return
|
|
@@ -637,10 +641,10 @@ def _resolve_property_node_bound_types(
|
|
|
637
641
|
if not fp_path.exists():
|
|
638
642
|
return
|
|
639
643
|
fp_root = ET.parse(fp_path).getroot()
|
|
640
|
-
for
|
|
641
|
-
ddo = fp_root.find(f".//*[@uid='{
|
|
644
|
+
for bound_node in bound:
|
|
645
|
+
ddo = fp_root.find(f".//*[@uid='{bound_node.bound_control_uid}']")
|
|
642
646
|
if ddo is not None:
|
|
643
|
-
|
|
647
|
+
bound_node.bound_control_type = reconstruct_control_lvtype(ddo)
|
|
644
648
|
|
|
645
649
|
|
|
646
650
|
def _extract_wires(root: ET.Element) -> list[ParsedWire]:
|
|
@@ -1691,11 +1695,24 @@ def _decode_element(data: bytes, elem_type: LVType | None) -> tuple[str | None,
|
|
|
1691
1695
|
if underlying in ("LVVariant", "Variant"):
|
|
1692
1696
|
return "Variant()", len(data)
|
|
1693
1697
|
|
|
1694
|
-
# MeasureData (timestamp): 16 bytes
|
|
1698
|
+
# MeasureData (timestamp): 16 bytes -- LabVIEW's 128-bit timestamp is an
|
|
1699
|
+
# i64 whole-second count (data[:8]) plus a u64 FRACTION of a second
|
|
1700
|
+
# (data[8:16], fraction = u64/2**64 sec) -- both halves threaded through
|
|
1701
|
+
# so a real (non-epoch) timestamp shows its actual sub-second value
|
|
1702
|
+
# (task #66 follow-up) instead of always truncating to ".000". Emitted
|
|
1703
|
+
# as decimal microseconds (matching datetime.timedelta's own resolution
|
|
1704
|
+
# ceiling -- finer precision would be silently rounded away by the
|
|
1705
|
+
# renderer's timedelta(seconds=...) reconstruction anyway), carrying
|
|
1706
|
+
# into the whole-second count on the (rare) round-up-to-1.0 edge.
|
|
1695
1707
|
if underlying == "MeasureData":
|
|
1696
1708
|
if len(data) >= 16:
|
|
1697
1709
|
secs = int.from_bytes(data[:8], "big", signed=True)
|
|
1698
|
-
|
|
1710
|
+
frac_u64 = int.from_bytes(data[8:16], "big", signed=False)
|
|
1711
|
+
frac_micros = round(frac_u64 * 1_000_000 / 2**64)
|
|
1712
|
+
if frac_micros >= 1_000_000:
|
|
1713
|
+
secs += 1
|
|
1714
|
+
frac_micros = 0
|
|
1715
|
+
return f"Timestamp({secs}.{frac_micros:06d})", 16
|
|
1699
1716
|
return "Timestamp(0)", len(data)
|
|
1700
1717
|
|
|
1701
1718
|
return None, 0
|
|
@@ -410,17 +410,41 @@ def _draw_node_tile(
|
|
|
410
410
|
# fixed left gutter wide enough for one arrow, so a row's label starts at the
|
|
411
411
|
# same x whether or not that row actually draws a left arrow.
|
|
412
412
|
_ROW_LPAD = 3.0
|
|
413
|
-
|
|
414
|
-
# Shared drawer-row geometry for PropertyNodeGlyph and InvokeNodeGlyph: a
|
|
415
|
-
# fixed left gutter wide enough for one arrow, so a row's label starts at the
|
|
416
|
-
# same x whether or not that row actually draws a left arrow.
|
|
417
|
-
_ROW_LPAD = 3.0
|
|
418
|
-
_ROW_ARROW_W = 7.0
|
|
419
|
-
|
|
420
413
|
_ROW_ARROW_W = 7.0
|
|
421
414
|
_ROW_GUTTER = _ROW_ARROW_W + _ROW_LPAD
|
|
422
415
|
|
|
423
416
|
|
|
417
|
+
@dataclass(frozen=True)
|
|
418
|
+
class DrawerHeaderGlyphBase:
|
|
419
|
+
"""Common implicit/explicit-binding fields shared by ``PropertyNodeGlyph``
|
|
420
|
+
and ``InvokeNodeGlyph`` (task #51/#55) -- both draw a HEADER band (see
|
|
421
|
+
``draw_drawer_header``) above a DRAWER of named rows, keyed by whether
|
|
422
|
+
the node is permanently bound to a specific front-panel control:
|
|
423
|
+
|
|
424
|
+
- EXPLICIT (``is_implicit=False``): the header names the object CLASS
|
|
425
|
+
the wired reference is of (``⚙ <class_name>``); the reference/error
|
|
426
|
+
terminals thread the box edges at the header level, placed by the
|
|
427
|
+
scene, not drawn here.
|
|
428
|
+
- IMPLICIT (``is_implicit=True``): the header names the BOUND control
|
|
429
|
+
itself (``target_name``), and a TYPE-COLOR BAR (``bar_color``) draws
|
|
430
|
+
under the header instead. No reference terminals thread through.
|
|
431
|
+
|
|
432
|
+
Subclasses add only their own row tuple (the drawer's per-row shape
|
|
433
|
+
differs — a property row is ``(name, is_read)``, an invoke row is
|
|
434
|
+
``(name, show_left, show_right)``) plus any glyph-specific fields
|
|
435
|
+
(``InvokeNodeGlyph``'s ``method``/``return_present``), and their own
|
|
436
|
+
``cell_h`` denominator (one header cell + one per row for a property
|
|
437
|
+
node; header + method + one per param for an invoke node)."""
|
|
438
|
+
|
|
439
|
+
class_name: str = "" # object class shown in the header (e.g. "VI")
|
|
440
|
+
is_implicit: bool = False
|
|
441
|
+
target_name: str = "" # the bound control's own name (implicit only)
|
|
442
|
+
bar_color: str | None = None # the bound control's wire color (implicit only)
|
|
443
|
+
fill_attr: str = "prim_fill"
|
|
444
|
+
stroke_attr: str = "prim_stroke"
|
|
445
|
+
text_attr: str = "prim_text"
|
|
446
|
+
|
|
447
|
+
|
|
424
448
|
def _draw_drawer_row(
|
|
425
449
|
backend: Backend,
|
|
426
450
|
x1: float,
|
|
@@ -466,3 +490,60 @@ def _draw_drawer_row(
|
|
|
466
490
|
lsize,
|
|
467
491
|
fill=text_fill,
|
|
468
492
|
)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def draw_drawer_header(
|
|
496
|
+
backend: Backend,
|
|
497
|
+
x1: float,
|
|
498
|
+
x2: float,
|
|
499
|
+
y1: float,
|
|
500
|
+
cell_h: float,
|
|
501
|
+
*,
|
|
502
|
+
is_implicit: bool,
|
|
503
|
+
target_name: str,
|
|
504
|
+
class_name: str,
|
|
505
|
+
bar_color: str | None,
|
|
506
|
+
stroke: str,
|
|
507
|
+
text_fill: str,
|
|
508
|
+
lsize: float,
|
|
509
|
+
) -> float:
|
|
510
|
+
"""Shared header band for ``PropertyNodeGlyph``/``InvokeNodeGlyph``: the
|
|
511
|
+
object class (explicit) or the BOUND CONTROL's own name (implicit) —
|
|
512
|
+
see either glyph's class docstring for the full implicit/explicit
|
|
513
|
+
contract — with a divider beneath. For an EXPLICIT node this is the row
|
|
514
|
+
the reference + error terminals thread through (drawn by the scene, not
|
|
515
|
+
here); an implicit node has none to thread, and instead draws a
|
|
516
|
+
TYPE-COLOR BAR (``bar_color``) in a thin band under the header text.
|
|
517
|
+
Returns ``hy2``, the header band's bottom y (where the caller's own
|
|
518
|
+
method/property drawer rows start)."""
|
|
519
|
+
lpad = _ROW_LPAD
|
|
520
|
+
hy2 = y1 + cell_h
|
|
521
|
+
if is_implicit and target_name:
|
|
522
|
+
header = target_name
|
|
523
|
+
else:
|
|
524
|
+
header = f"⚙ {class_name}".strip() if class_name else "⚙ class"
|
|
525
|
+
bar_h = min(5.0, cell_h * 0.3) if is_implicit else 0.0
|
|
526
|
+
text_cy = y1 + (cell_h - bar_h) / 2
|
|
527
|
+
backend.text(
|
|
528
|
+
(x1 + x2) / 2,
|
|
529
|
+
text_cy + lsize * 0.34,
|
|
530
|
+
fit_label(header, (x2 - x1) - 2 * lpad, backend, lsize),
|
|
531
|
+
lsize,
|
|
532
|
+
fill=text_fill,
|
|
533
|
+
)
|
|
534
|
+
if bar_h >= 1.0 and bar_color:
|
|
535
|
+
# The TYPE-COLOR BAR: a thin band in the bound control's own wire
|
|
536
|
+
# color, filling most of the header's width — LabVIEW's own cue for
|
|
537
|
+
# "this node's identity is a specific control of THIS type",
|
|
538
|
+
# replacing the (absent) reference terminals. Guarded to bar_h>=1.0
|
|
539
|
+
# (not just >0): the rect's own top/bottom are hy2-bar_h/hy2-1.0, so
|
|
540
|
+
# a bar_h under 1px would draw with NEGATIVE height (top below
|
|
541
|
+
# bottom) — an inverted rect — for a very short cell (cell_h below
|
|
542
|
+
# ~3.3px, since bar_h = min(5.0, cell_h*0.3)).
|
|
543
|
+
bar_pad = (x2 - x1) * 0.12
|
|
544
|
+
backend.rect(
|
|
545
|
+
x1 + bar_pad, hy2 - bar_h, x2 - bar_pad, hy2 - 1.0,
|
|
546
|
+
fill=bar_color, stroke="none",
|
|
547
|
+
)
|
|
548
|
+
backend.line(x1, hy2, x2, hy2, stroke=stroke, stroke_width=1.0)
|
|
549
|
+
return hy2
|