harnice 0.3.0__py3-none-any.whl

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 (41) hide show
  1. harnice/__init__.py +0 -0
  2. harnice/__main__.py +4 -0
  3. harnice/cli.py +234 -0
  4. harnice/fileio.py +295 -0
  5. harnice/gui/launcher.py +426 -0
  6. harnice/lists/channel_map.py +182 -0
  7. harnice/lists/circuits_list.py +302 -0
  8. harnice/lists/disconnect_map.py +237 -0
  9. harnice/lists/formboard_graph.py +63 -0
  10. harnice/lists/instances_list.py +280 -0
  11. harnice/lists/library_history.py +40 -0
  12. harnice/lists/manifest.py +93 -0
  13. harnice/lists/post_harness_instances_list.py +66 -0
  14. harnice/lists/rev_history.py +325 -0
  15. harnice/lists/signals_list.py +135 -0
  16. harnice/products/__init__.py +1 -0
  17. harnice/products/cable.py +152 -0
  18. harnice/products/chtype.py +80 -0
  19. harnice/products/device.py +844 -0
  20. harnice/products/disconnect.py +225 -0
  21. harnice/products/flagnote.py +139 -0
  22. harnice/products/harness.py +522 -0
  23. harnice/products/macro.py +10 -0
  24. harnice/products/part.py +640 -0
  25. harnice/products/system.py +125 -0
  26. harnice/products/tblock.py +270 -0
  27. harnice/state.py +57 -0
  28. harnice/utils/appearance.py +51 -0
  29. harnice/utils/circuit_utils.py +326 -0
  30. harnice/utils/feature_tree_utils.py +183 -0
  31. harnice/utils/formboard_utils.py +973 -0
  32. harnice/utils/library_utils.py +333 -0
  33. harnice/utils/note_utils.py +417 -0
  34. harnice/utils/svg_utils.py +819 -0
  35. harnice/utils/system_utils.py +563 -0
  36. harnice-0.3.0.dist-info/METADATA +32 -0
  37. harnice-0.3.0.dist-info/RECORD +41 -0
  38. harnice-0.3.0.dist-info/WHEEL +5 -0
  39. harnice-0.3.0.dist-info/entry_points.txt +3 -0
  40. harnice-0.3.0.dist-info/licenses/LICENSE +19 -0
  41. harnice-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,522 @@
1
+ import runpy
2
+ import os
3
+ from harnice import fileio, cli, state
4
+ from harnice.lists import instances_list, library_history
5
+
6
+ default_desc = "HARNESS, DOES A, FOR B"
7
+
8
+
9
+ def file_structure():
10
+ return {
11
+ f"{state.partnumber('pn-rev')}-feature_tree.py": "feature tree",
12
+ f"{state.partnumber('pn-rev')}-instances_list.tsv": "instances list",
13
+ f"{state.partnumber('pn-rev')}-formboard_graph_definition.png": "formboard graph definition png",
14
+ f"{state.partnumber('pn-rev')}-library_import_history.tsv": "library history",
15
+ "interactive_files": {
16
+ f"{state.partnumber('pn-rev')}.formboard_graph_definition.tsv": "formboard graph definition",
17
+ },
18
+ }
19
+
20
+
21
+ def generate_structure():
22
+ os.makedirs(
23
+ fileio.dirpath("interactive_files", structure_dict=file_structure()),
24
+ exist_ok=True,
25
+ )
26
+
27
+
28
+ def render():
29
+ """
30
+ Main harness rendering entrypoint.
31
+ """
32
+
33
+ feature_tree_path = fileio.path("feature tree", structure_dict=file_structure())
34
+
35
+ # ======================================================================
36
+ # 1. Feature tree does not exist: prompt user and create it
37
+ # ======================================================================
38
+ if not os.path.exists(feature_tree_path):
39
+ # ------------------------------------------------------------------
40
+ # Ask whether this harness pulls from a system or not
41
+ # ------------------------------------------------------------------
42
+ print(
43
+ " 's' Enter 's' for system (or just hit enter) "
44
+ "if this harness is pulling data from a system instances list"
45
+ )
46
+ print(
47
+ " 'n' Enter 'n' for none to build your harness entirely "
48
+ "out of rules in feature tree (you're hardcore)"
49
+ )
50
+ build_macro = cli.prompt("")
51
+
52
+ # ------------------------------------------------------------------
53
+ # If harness is built from a system, ask for system parameters
54
+ # ------------------------------------------------------------------
55
+ if build_macro in (None, "", "s"):
56
+ system_pn = cli.prompt("Enter the system part number")
57
+ system_rev = cli.prompt("Enter the system revision id (ex. rev1)")
58
+ target_net = cli.prompt("Enter the net you want to build this harness from")
59
+
60
+ # Inject actual values into template
61
+ build_macro_block = default_build_macro_block(
62
+ system_pn, system_rev, target_net
63
+ )
64
+ push_block = default_push_block()
65
+
66
+ # ------------------------------------------------------------------
67
+ # Hardcore mode — no system importing
68
+ # ------------------------------------------------------------------
69
+ elif build_macro == "n":
70
+ build_macro_block = ""
71
+ push_block = ""
72
+
73
+ else:
74
+ print(
75
+ "Unrecognized input. If you meant to select a template not listed, "
76
+ "just select a template, delete the contents and start over manually. rip."
77
+ )
78
+ exit()
79
+
80
+ # ------------------------------------------------------------------
81
+ # Write feature tree file
82
+ # ------------------------------------------------------------------
83
+ feature_tree_text = _make_feature_tree(build_macro_block, push_block)
84
+
85
+ with open(feature_tree_path, "w", encoding="utf-8") as f:
86
+ f.write(feature_tree_text)
87
+
88
+ # ======================================================================
89
+ # 2. Init library + instances list
90
+ # ======================================================================
91
+ library_history.new()
92
+ instances_list.new()
93
+ instances_list.new_instance(
94
+ "origin",
95
+ {
96
+ "instance_name": "origin",
97
+ "item_type": "origin",
98
+ "location_type": "node",
99
+ },
100
+ )
101
+
102
+ # ======================================================================
103
+ # 3. Run the feature tree
104
+ # ======================================================================
105
+ cli.print_import_status_headers()
106
+ runpy.run_path(feature_tree_path, run_name="__main__")
107
+
108
+ print(f"Harnice: harness {state.partnumber('pn')} rendered successfully!\n")
109
+
110
+
111
+ # ======================================================================
112
+ # Helper: prompt for system/no-system
113
+ # ======================================================================
114
+ def _prompt_build_macro():
115
+ print(
116
+ " 's' Enter 's' for system (or just hit enter) "
117
+ "if this harness is pulling data from a system instances list"
118
+ )
119
+ print(
120
+ " 'n' Enter 'n' for none to build your harness entirely "
121
+ "out of rules in feature tree (you're hardcore)"
122
+ )
123
+ return cli.prompt("")
124
+
125
+
126
+ # ======================================================================
127
+ # Helper: build the complete feature tree file text
128
+ # ======================================================================
129
+ def _make_feature_tree(build_macro_block: str, push_block: str) -> str:
130
+ """
131
+ Insert build_macro_block and push_block into your exact template.
132
+ """
133
+
134
+ return f"""
135
+ import os
136
+ from harnice import fileio, state
137
+ from harnice.utils import (
138
+ circuit_utils,
139
+ formboard_utils,
140
+ note_utils,
141
+ library_utils,
142
+ feature_tree_utils,
143
+ )
144
+ from harnice.lists import (
145
+ instances_list,
146
+ post_harness_instances_list,
147
+ rev_history,
148
+ )
149
+
150
+ {build_macro_block}
151
+
152
+ # ===========================================================================
153
+ # HARNESS BUILD RULES
154
+ # ===========================================================================
155
+ # example: assign a special contact to one specific conductor
156
+ instances = fileio.read_tsv("instances list")
157
+ circuit_instance = None
158
+ connector_at_end_a = None
159
+ for instance in instances:
160
+ if instance.get("channel_group") == "channel-MIC2.out1-PREAMP1.in2":
161
+ if instance.get("signal_of_channel_type") == "pos":
162
+ if instance.get("item_type") == "circuit":
163
+ circuit_instance = instance
164
+ connector_at_end_a = instances_list.attribute_of(instance.get("node_at_end_a"), "connector_group")
165
+ new_instance_name = f"{{circuit_instance.get("instance_name")}}-special_contact"
166
+ circuit_id = int(circuit_instance.get("circuit_id"))
167
+ instances_list.new_instance(
168
+ new_instance_name, {{
169
+ "bom_line_number": True,
170
+ "mpn": "TXPS20",
171
+ "item_type": "contact",
172
+ "location_type": "node",
173
+ "circuit_id": circuit_id,
174
+ "connector_group": connector_at_end_a
175
+ }}
176
+ )
177
+ circuit_utils.squeeze_instance_between_ports_in_circuit(
178
+ new_instance_name, circuit_id, 1
179
+ )
180
+
181
+ # example: add a backshell
182
+ for instance in instances:
183
+ if instance.get("instance_name") in ["X1.B.conn", "PREAMP2.in2.conn"]:
184
+ instances_list.new_instance(f"{{instance.get("connector_group")}}.bs", {{
185
+ "bom_line_number": True,
186
+ "mpn": "M85049-90_9Z03",
187
+ "item_type": "backshell",
188
+ "parent_instance": instance.get("instance_name"),
189
+ "location_type": "node",
190
+ "connector_group": instance.get("connector_group"),
191
+ "parent_csys_instance_name": (instances_list.instance_in_connector_group_with_item_type(instance.get("connector_group"), "node")).get("instance_name"),
192
+ "parent_csys_outputcsys_name": "origin",
193
+ "lib_repo": "https://github.com/harnice/harnice"
194
+ }})
195
+ instances_list.modify(instance.get("instance_name"), {{
196
+ "parent_csys_instance_name": f"{{instance.get("connector_group")}}.bs",
197
+ "parent_csys_outputcsys_name": "connector",
198
+ }})
199
+
200
+
201
+ # ===========================================================================
202
+ # IMPORT PARTS FROM LIBRARY FOR GENERAL USE
203
+ # ===========================================================================
204
+ for instance in fileio.read_tsv("instances list"):
205
+ if instance.get("item_type") in ["connector", "backshell"]:
206
+ if instance.get("instance_name") not in ["X100"]:
207
+ if instance.get("mpn") not in ["TXPA20"]:
208
+ library_utils.pull(instance)
209
+
210
+ # ===========================================================================
211
+ # PROCESS HARNESS LAYOUT GRAPH
212
+ # ===========================================================================
213
+ formboard_utils.validate_nodes()
214
+
215
+ instances = fileio.read_tsv("instances list")
216
+ for instance in instances:
217
+ if instance.get("item_type") == "cable":
218
+ for instance2 in instances:
219
+ if instance2.get("parent_instance") == instance.get("instance_name"):
220
+ if instance2.get("item_type") == "conductor":
221
+ instances_list.modify(
222
+ instance.get("instance_name"),
223
+ {{
224
+ "node_at_end_a": instances_list.instance_in_connector_group_with_item_type(
225
+ instances_list.attribute_of(
226
+ instance2.get("node_at_end_a"), "connector_group"
227
+ ),
228
+ "node",
229
+ ).get("instance_name"),
230
+ "node_at_end_b": instances_list.instance_in_connector_group_with_item_type(
231
+ instances_list.attribute_of(
232
+ instance2.get("node_at_end_b"), "connector_group"
233
+ ),
234
+ "node",
235
+ ).get("instance_name"),
236
+ }},
237
+ )
238
+ break
239
+
240
+ for instance in fileio.read_tsv("instances list"):
241
+ if instance.get("item_type") in ["conductor", "cable", "net-channel"]:
242
+ formboard_utils.map_instance_to_segments(instance)
243
+
244
+ for instance in fileio.read_tsv("instances list"):
245
+ if instance.get("item_type") in ["conductor", "cable"]:
246
+ length = 0
247
+ for instance2 in fileio.read_tsv("instances list"):
248
+ if instance2.get("parent_instance") == instance.get("instance_name"):
249
+ if instance2.get("length", "").strip():
250
+ length += int(instance2.get("length").strip())
251
+ instances_list.modify(instance.get("instance_name"), {{"length": length}})
252
+
253
+ # ===========================================================================
254
+ # ASSIGN BOM LINE NUMBERS
255
+ # ===========================================================================
256
+ for instance in fileio.read_tsv("instances list"):
257
+ if instance.get("item_type") in ["connector", "cable", "backshell"]:
258
+ instances_list.modify(instance.get("instance_name"), {{"bom_line_number": True}})
259
+ instances_list.assign_bom_line_numbers()
260
+
261
+ # ===========================================================================
262
+ # ASSIGN PRINT NAMES
263
+ # ===========================================================================
264
+ for x in range(2):
265
+ for instance in fileio.read_tsv("instances list"):
266
+ if instance.get("item_type") == "connector_cavity":
267
+ instance_name = instance.get("instance_name", "")
268
+ print_name = f"cavity {{instance_name.split(".")[-1] if "." in instance_name else instance_name}}"
269
+ instances_list.modify(instance_name, {{"print_name": print_name}})
270
+
271
+ elif instance.get("item_type") in ["conductor", "conductor-segment"]:
272
+ instances_list.modify(instance.get("instance_name"), {{
273
+ "print_name": f"'{{instance.get("cable_identifier")}}' of '{{instances_list.attribute_of(instance.get("cable_group"), "print_name")}}'"
274
+ }})
275
+
276
+ elif instance.get("item_type") == "net-channel":
277
+ print_name = f"'{{instance.get("this_channel_from_device_channel_id")}}' of '{{instance.get("this_channel_from_device_refdes")}}' to '{{instance.get("this_channel_to_device_channel_id")}}' of '{{instance.get("this_channel_to_device_refdes")}}'"
278
+ instances_list.modify(instance.get("instance_name"), {{"print_name": print_name}})
279
+
280
+ elif instance.get("item_type") == "net-channel-segment":
281
+ print_name = f"'{{instances_list.attribute_of(instance.get("parent_instance"), "this_channel_from_device_channel_id")}}' of '{{instances_list.attribute_of(instance.get("parent_instance"), "this_channel_from_device_refdes")}}' to '{{instances_list.attribute_of(instance.get("parent_instance"), "this_channel_to_device_channel_id")}}' of '{{instances_list.attribute_of(instance.get("parent_instance"), "this_channel_to_device_refdes")}}'"
282
+ instances_list.modify(instance.get("instance_name"), {{"print_name": print_name}})
283
+
284
+ elif instance.get("item_type") == "connector":
285
+ print_name = f"{{instance.get("connector_group")}}"
286
+ instances_list.modify(instance.get("instance_name"), {{"print_name": print_name}})
287
+
288
+ elif instance.get("item_type") == "cable-segment":
289
+ print_name = f"{{instance.get("cable_group")}}"
290
+ instances_list.modify(instance.get("instance_name"), {{"print_name": print_name}})
291
+
292
+ elif instance.get("item_type") == "contact":
293
+ print_name = instance.get("mpn")
294
+ instances_list.modify(
295
+ instance.get("instance_name"),
296
+ {{"print_name": print_name}}
297
+ )
298
+
299
+ else:
300
+ instances_list.modify(instance.get("instance_name"), {{"print_name": instance.get("instance_name")}})
301
+
302
+ # ===========================================================================
303
+ # ADD BUILD NOTES
304
+ # ===========================================================================
305
+ for rev_row in fileio.read_tsv("revision history"):
306
+ if rev_row.get("rev") == state.rev:
307
+ note_utils.make_rev_history_notes(rev_row)
308
+
309
+ for instance in fileio.read_tsv("instances list"):
310
+ for note in note_utils.get_lib_build_notes(instance):
311
+ note_utils.new_note(
312
+ "build_note",
313
+ note,
314
+ affectedinstances=[instance.get("instance_name")]
315
+ )
316
+
317
+ note_utils.assign_buildnote_numbers()
318
+
319
+ # example: add notes to describe actions
320
+ # note_utils.new_note(
321
+ # "build_note",
322
+ # "do this",
323
+ # affectedinstances=["X1.B.conn"]
324
+ # )
325
+ # note_utils.new_note(
326
+ # "build_note",
327
+ # "do that"
328
+ # )
329
+
330
+ # example: combine buildnotes if their texts are similar
331
+ #note_utils.combine_notes("Torque backshell to connector at 40 in-lbs","Torque backshell to connector at about 40 in-lbs")
332
+
333
+
334
+ # ===========================================================================
335
+ # PUT TOGETHER FORMBOARD SVG INSTANCE CONTENT
336
+ # ===========================================================================
337
+ instances = fileio.read_tsv("instances list")
338
+ note_instances = []
339
+ for instance in instances:
340
+ if instance.get("item_type") == "note":
341
+ note_instances.append(note_utils.parse_note_instance(instance))
342
+
343
+ formboard_overview_instances = []
344
+ formboard_detail_instances = []
345
+ for instance in instances:
346
+ if instance.get("item_type") not in ["connector", "backshell", "segment", "node", "origin"]:
347
+ continue
348
+
349
+ formboard_overview_instances.append(instance)
350
+ formboard_detail_instances.append(instance)
351
+
352
+ detail_flag_note_counter = 1
353
+ overview_flag_note_counter = 1
354
+
355
+ if instance.get("item_type") in ["connector", "backshell"]:
356
+ formboard_detail_instances.append(note_utils.make_bom_flagnote(instance, f"flagnote-{{detail_flag_note_counter}}"))
357
+ detail_flag_note_counter += 1
358
+
359
+ formboard_detail_instances.append(note_utils.make_part_name_flagnote(instance, f"flagnote-{{detail_flag_note_counter}}"))
360
+ detail_flag_note_counter += 1
361
+
362
+ if instance.get("item_type") == "connector":
363
+ formboard_overview_instances.append(note_utils.make_part_name_flagnote(instance, f"flagnote-{{overview_flag_note_counter}}"))
364
+ overview_flag_note_counter += 1
365
+
366
+ for note_instance in note_instances:
367
+ if note_instance.get("note_type") == "build_note":
368
+ if instance.get("instance_name") in note_instance.get("note_affected_instances"):
369
+ formboard_detail_instances.append(
370
+ note_utils.make_buildnote_flagnote(note_instance, instance, f"flagnote-{{detail_flag_note_counter}}")
371
+ )
372
+ detail_flag_note_counter += 1
373
+
374
+ if note_instance.get("note_type") == "rev_change_callout":
375
+ if instance.get("instance_name") in note_instance.get("note_affected_instances"):
376
+ formboard_detail_instances.append(
377
+ note_utils.make_rev_change_flagnote(note_instance, instance, f"flagnote-{{detail_flag_note_counter}}")
378
+ )
379
+ detail_flag_note_counter += 1
380
+
381
+ # ===========================================================================
382
+ # BUILD HARNESS OUTPUTS
383
+ # ===========================================================================
384
+ instances = fileio.read_tsv("instances list")
385
+ scales = {{"A": 0.25, "B": 0.3, "C": 1}}
386
+
387
+ feature_tree_utils.run_macro(
388
+ "bom_exporter_bottom_up",
389
+ "harness_artifacts",
390
+ "https://github.com/harnice/harnice",
391
+ artifact_id="bom-1",
392
+ )
393
+ feature_tree_utils.run_macro(
394
+ "standard_harnice_formboard",
395
+ "harness_artifacts",
396
+ "https://github.com/harnice/harnice",
397
+ artifact_id="formboard-overview",
398
+ scale=scales.get("A"),
399
+ input_instances=formboard_overview_instances,
400
+ )
401
+ feature_tree_utils.run_macro(
402
+ "standard_harnice_formboard",
403
+ "harness_artifacts",
404
+ "https://github.com/harnice/harnice",
405
+ artifact_id="formboard-detail",
406
+ scale=scales.get("C"),
407
+ input_instances=formboard_detail_instances,
408
+ )
409
+ feature_tree_utils.run_macro(
410
+ "segment_visualizer",
411
+ "harness_artifacts",
412
+ "https://github.com/harnice/harnice",
413
+ artifact_id="cable_layout-1",
414
+ scale=scales.get("A"),
415
+ item_type="cable-segment",
416
+ segment_spacing_inches=0.1,
417
+ )
418
+ feature_tree_utils.run_macro(
419
+ "segment_visualizer",
420
+ "harness_artifacts",
421
+ "https://github.com/harnice/harnice",
422
+ artifact_id="conductor-layout-1",
423
+ scale=scales.get("A"),
424
+ item_type="conductor-segment",
425
+ segment_spacing_inches=0.1,
426
+ )
427
+ feature_tree_utils.run_macro(
428
+ "segment_visualizer",
429
+ "harness_artifacts",
430
+ "https://github.com/harnice/harnice",
431
+ artifact_id="channel-layout-1",
432
+ scale=scales.get("B"),
433
+ item_type="net-channel-segment",
434
+ segment_spacing_inches=0.1,
435
+ )
436
+ feature_tree_utils.run_macro(
437
+ "circuit_visualizer",
438
+ "harness_artifacts",
439
+ "https://github.com/harnice/harnice",
440
+ artifact_id="circuitviz-1",
441
+ input_circuits=instances,
442
+ )
443
+ feature_tree_utils.run_macro(
444
+ "revision_history_table",
445
+ "harness_artifacts",
446
+ "https://github.com/harnice/harnice",
447
+ artifact_id="revhistory-1",
448
+ )
449
+
450
+ build_notes_list_instances = []
451
+ for instance in fileio.read_tsv("instances list"):
452
+ if instance.get("item_type") == "note" and instance.get("note_type") == "build_note":
453
+ build_notes_list_instances.append(instance)
454
+
455
+ feature_tree_utils.run_macro(
456
+ "build_notes_table",
457
+ "harness_artifacts",
458
+ "https://github.com/harnice/harnice",
459
+ artifact_id="build_notes_table-1",
460
+ input_instances=build_notes_list_instances,
461
+ )
462
+ feature_tree_utils.run_macro(
463
+ "pdf_generator",
464
+ "harness_artifacts",
465
+ "https://github.com/harnice/harnice",
466
+ artifact_id="pdf_drawing-1",
467
+ scales=scales,
468
+ )
469
+
470
+ {push_block}
471
+
472
+ # for convenience, move any pdf to the base directory of the harness
473
+ feature_tree_utils.copy_pdfs_to_cwd()
474
+ """
475
+
476
+
477
+ # ======================================================================
478
+ # BLOCKS FOR BUILDING THE HARNESS FROM A SYSTEM
479
+ # ======================================================================
480
+
481
+
482
+ def default_build_macro_block(system_pn, system_rev, target_net):
483
+ return f"""
484
+ # ===========================================================================
485
+ # build_macro SCRIPTING
486
+ # ===========================================================================
487
+ system_pn = "{system_pn}" # enter your system part number
488
+ system_rev = "{system_rev}" # enter your system revision
489
+ system_base_directory = fileio.get_path_to_project(system_pn) # add the path to project_locations.csv in the root of harnice
490
+ system_target_net = "{target_net}" # enter the net you're building from
491
+
492
+ feature_tree_utils.run_macro(
493
+ "import_harness_from_harnice_system",
494
+ "harness_builder",
495
+ "https://github.com/harnice/harnice",
496
+ "harness-from-system-1",
497
+ system_pn=f"{{system_pn}}",
498
+ system_rev=f"{{system_rev}}",
499
+ path_to_system_rev=os.path.join(
500
+ system_base_directory,
501
+ f"{{system_pn}}-{{system_rev}}",
502
+ ),
503
+ target_net=system_target_net,
504
+ manifest_nets=[system_target_net],
505
+ )
506
+
507
+ rev_history.overwrite(
508
+ {{
509
+ "desc": f"HARNESS '{{system_target_net}}' FROM SYSTEM '{{system_pn}}-{{system_rev}}'",
510
+ }}
511
+ )
512
+ """
513
+
514
+
515
+ def default_push_block():
516
+ return """
517
+ # ensure the system that this harness was built from contains the complete updated instances list
518
+ post_harness_instances_list.push(
519
+ system_base_directory,
520
+ (system_pn, system_rev),
521
+ )
522
+ """
@@ -0,0 +1,10 @@
1
+ def file_structure():
2
+ return {}
3
+
4
+
5
+ def generate_structure():
6
+ pass
7
+
8
+
9
+ def render():
10
+ print("\nMacro rendered successfully!\n")