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.
- harnice/__init__.py +0 -0
- harnice/__main__.py +4 -0
- harnice/cli.py +234 -0
- harnice/fileio.py +295 -0
- harnice/gui/launcher.py +426 -0
- harnice/lists/channel_map.py +182 -0
- harnice/lists/circuits_list.py +302 -0
- harnice/lists/disconnect_map.py +237 -0
- harnice/lists/formboard_graph.py +63 -0
- harnice/lists/instances_list.py +280 -0
- harnice/lists/library_history.py +40 -0
- harnice/lists/manifest.py +93 -0
- harnice/lists/post_harness_instances_list.py +66 -0
- harnice/lists/rev_history.py +325 -0
- harnice/lists/signals_list.py +135 -0
- harnice/products/__init__.py +1 -0
- harnice/products/cable.py +152 -0
- harnice/products/chtype.py +80 -0
- harnice/products/device.py +844 -0
- harnice/products/disconnect.py +225 -0
- harnice/products/flagnote.py +139 -0
- harnice/products/harness.py +522 -0
- harnice/products/macro.py +10 -0
- harnice/products/part.py +640 -0
- harnice/products/system.py +125 -0
- harnice/products/tblock.py +270 -0
- harnice/state.py +57 -0
- harnice/utils/appearance.py +51 -0
- harnice/utils/circuit_utils.py +326 -0
- harnice/utils/feature_tree_utils.py +183 -0
- harnice/utils/formboard_utils.py +973 -0
- harnice/utils/library_utils.py +333 -0
- harnice/utils/note_utils.py +417 -0
- harnice/utils/svg_utils.py +819 -0
- harnice/utils/system_utils.py +563 -0
- harnice-0.3.0.dist-info/METADATA +32 -0
- harnice-0.3.0.dist-info/RECORD +41 -0
- harnice-0.3.0.dist-info/WHEEL +5 -0
- harnice-0.3.0.dist-info/entry_points.txt +3 -0
- harnice-0.3.0.dist-info/licenses/LICENSE +19 -0
- harnice-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import runpy
|
|
2
|
+
import os
|
|
3
|
+
from harnice import fileio, state, cli
|
|
4
|
+
from harnice.lists import post_harness_instances_list, instances_list, library_history
|
|
5
|
+
|
|
6
|
+
default_desc = "SYSTEM, SCOPE, etc."
|
|
7
|
+
|
|
8
|
+
system_feature_tree_utils_default = """from harnice import fileio
|
|
9
|
+
from harnice.utils import system_utils, feature_tree_utils
|
|
10
|
+
from harnice.lists import instances_list, manifest, channel_map, circuits_list, disconnect_map
|
|
11
|
+
|
|
12
|
+
#===========================================================================
|
|
13
|
+
# KICAD PROCESSING
|
|
14
|
+
#===========================================================================
|
|
15
|
+
feature_tree_utils.run_macro("kicad_sch_to_pdf", "system_artifacts", "https://github.com/harnice/harnice", artifact_id="blockdiagram-1")
|
|
16
|
+
feature_tree_utils.run_macro("kicad_pro_to_bom", "system_builder", "https://github.com/harnice/harnice", artifact_id="bom-1")
|
|
17
|
+
|
|
18
|
+
#===========================================================================
|
|
19
|
+
# COLLECT AND PULL DEVICES FROM LIBRARY
|
|
20
|
+
#===========================================================================
|
|
21
|
+
system_utils.make_instances_from_bom()
|
|
22
|
+
|
|
23
|
+
#===========================================================================
|
|
24
|
+
# CHANNEL MAPPING
|
|
25
|
+
#===========================================================================
|
|
26
|
+
feature_tree_utils.run_macro("kicad_pro_to_system_connector_list", "system_builder", "https://github.com/harnice/harnice", artifact_id="system-connector-list-1")
|
|
27
|
+
manifest.new()
|
|
28
|
+
channel_map.new()
|
|
29
|
+
|
|
30
|
+
#add manual channel map commands here. key=(from_device_refdes, from_device_channel_id)
|
|
31
|
+
#channel_map.map(("MIC3", "out1"), ("PREAMP1", "in2"))
|
|
32
|
+
|
|
33
|
+
#map channels to other compatible channels by sorting alphabetically then mapping compatibles
|
|
34
|
+
feature_tree_utils.run_macro("basic_channel_mapper", "system_builder", "https://github.com/harnice/harnice", artifact_id="channel-mapper-1")
|
|
35
|
+
|
|
36
|
+
#if mapped channels must connect via disconnects, add the list of disconnects to the channel map
|
|
37
|
+
system_utils.add_chains_to_channel_map()
|
|
38
|
+
|
|
39
|
+
#map channels that must pass through disconnects to available channels inside disconnects
|
|
40
|
+
disconnect_map.new()
|
|
41
|
+
|
|
42
|
+
#add manual disconnect map commands here
|
|
43
|
+
#disconnect_map.already_assigned_disconnects_set_append(('X1', 'ch0'))
|
|
44
|
+
|
|
45
|
+
#map channels passing through disconnects to available channels inside disconnects
|
|
46
|
+
feature_tree_utils.run_macro("disconnect_mapper", "system_builder", "https://github.com/harnice/harnice", artifact_id="disconnect-mapper-1")
|
|
47
|
+
feature_tree_utils.ensure_requirements_met()
|
|
48
|
+
|
|
49
|
+
#process channel and disconnect maps to make a list of every circuit in your system
|
|
50
|
+
circuits_list.new()
|
|
51
|
+
|
|
52
|
+
#===========================================================================
|
|
53
|
+
# INSTANCES LIST
|
|
54
|
+
#===========================================================================
|
|
55
|
+
system_utils.make_instances_for_connectors_cavities_nodes_channels_circuits()
|
|
56
|
+
|
|
57
|
+
#assign mating connectors
|
|
58
|
+
#for instance in fileio.read_tsv("instances list"):
|
|
59
|
+
#if instance.get("item_type") == "connector":
|
|
60
|
+
#if instance.get("this_instance_mating_device_connector_mpn") == "XLR3M":
|
|
61
|
+
#instances_list.modify(instance.get("instance_name"),{
|
|
62
|
+
#"mpn":"D38999_26ZA98PN",
|
|
63
|
+
#"lib_repo":"https://github.com/harnice/harnice"
|
|
64
|
+
#})
|
|
65
|
+
|
|
66
|
+
#===========================================================================
|
|
67
|
+
# SYSTEM DESIGN CHECKS
|
|
68
|
+
#===========================================================================
|
|
69
|
+
connector_list = fileio.read_tsv("system connector list")
|
|
70
|
+
circuits_list = fileio.read_tsv("circuits list")
|
|
71
|
+
|
|
72
|
+
#check for circuits with no connectors
|
|
73
|
+
system_utils.find_connector_with_no_circuit(connector_list, circuits_list)
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def file_structure():
|
|
78
|
+
return {
|
|
79
|
+
f"{state.partnumber('pn-rev')}-feature_tree.py": "feature tree",
|
|
80
|
+
f"{state.partnumber('pn-rev')}-instances_list.tsv": "instances list",
|
|
81
|
+
f"{state.partnumber('pn-rev')}-library_import_history.tsv": "library history",
|
|
82
|
+
"instance_data": {},
|
|
83
|
+
"features_for_relatives": {},
|
|
84
|
+
"harnesses": {},
|
|
85
|
+
"lists": {
|
|
86
|
+
f"{state.partnumber('pn-rev')}-bom.tsv": "bom",
|
|
87
|
+
f"{state.partnumber('pn-rev')}-circuits_list.tsv": "circuits list",
|
|
88
|
+
f"{state.partnumber('pn-rev')}-post_harness_instances_list.tsv": "post harness instances list",
|
|
89
|
+
f"{state.partnumber('pn-rev')}-harness_manifest.tsv": "harness manifest",
|
|
90
|
+
f"{state.partnumber('pn-rev')}-system_connector_list.tsv": "system connector list",
|
|
91
|
+
f"{state.partnumber('pn-rev')}-mapped_channels_set.tsv": "mapped channels set",
|
|
92
|
+
f"{state.partnumber('pn-rev')}-mapped_disconnect_channels_set.tsv": "mapped disconnects set",
|
|
93
|
+
f"{state.partnumber('pn-rev')}-mapped_a_channels_through_disconnects_set.tsv": "mapped A-side channels through disconnects set",
|
|
94
|
+
},
|
|
95
|
+
"maps": {
|
|
96
|
+
f"{state.partnumber('pn-rev')}-channel_map.tsv": "channel map",
|
|
97
|
+
f"{state.partnumber('pn-rev')}-disconnect_map.tsv": "disconnect map",
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def generate_structure():
|
|
103
|
+
os.makedirs(fileio.dirpath("instance_data"), exist_ok=True)
|
|
104
|
+
os.makedirs(fileio.dirpath("features_for_relatives"), exist_ok=True)
|
|
105
|
+
os.makedirs(fileio.dirpath("harnesses"), exist_ok=True)
|
|
106
|
+
os.makedirs(fileio.dirpath("lists"), exist_ok=True)
|
|
107
|
+
os.makedirs(fileio.dirpath("maps"), exist_ok=True)
|
|
108
|
+
pass
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def render():
|
|
112
|
+
state.set_net(None)
|
|
113
|
+
|
|
114
|
+
if not os.path.exists(fileio.path("feature tree")):
|
|
115
|
+
with open(fileio.path("feature tree"), "w", encoding="utf-8") as f:
|
|
116
|
+
f.write(system_feature_tree_utils_default)
|
|
117
|
+
|
|
118
|
+
library_history.new()
|
|
119
|
+
instances_list.new()
|
|
120
|
+
cli.print_import_status_headers()
|
|
121
|
+
runpy.run_path(fileio.path("feature tree"))
|
|
122
|
+
|
|
123
|
+
post_harness_instances_list.rebuild()
|
|
124
|
+
|
|
125
|
+
print("\nSystem rendered successfully!\n")
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import xml.etree.ElementTree as ET
|
|
4
|
+
from xml.dom import minidom
|
|
5
|
+
from harnice import fileio, cli, state
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
default_desc = "TITLEBLOCK, PAPER SIZE, DESIGN"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def file_structure():
|
|
12
|
+
return {
|
|
13
|
+
f"{state.partnumber('pn-rev')}-params.json": "params",
|
|
14
|
+
f"{state.partnumber('pn-rev')}-drawing.svg": "drawing",
|
|
15
|
+
f"{state.partnumber('pn-rev')}-attributes.json": "attributes",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def generate_structure():
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def render():
|
|
24
|
+
if (
|
|
25
|
+
cli.prompt(
|
|
26
|
+
"Warning: rendering a titleblock may clear user edits to its svg. Proceed?",
|
|
27
|
+
default="yes",
|
|
28
|
+
)
|
|
29
|
+
!= "yes"
|
|
30
|
+
):
|
|
31
|
+
exit()
|
|
32
|
+
|
|
33
|
+
# === Default Parameters ===
|
|
34
|
+
params = {
|
|
35
|
+
"page_size": [11 * 96, 8.5 * 96],
|
|
36
|
+
"outer_margin": 20,
|
|
37
|
+
"inner_margin": 40,
|
|
38
|
+
"tick_spacing": 96,
|
|
39
|
+
"tb_origin_offset": [398, 48],
|
|
40
|
+
"row_heights": [24, 24],
|
|
41
|
+
"column_widths": [[264, 50, 84], [73, 126, 139, 60]],
|
|
42
|
+
"label_offset": [2, 7],
|
|
43
|
+
"key_offset_y": 16,
|
|
44
|
+
"cell_texts": [
|
|
45
|
+
[
|
|
46
|
+
("DESCRIPTION", "tblock-key-desc"),
|
|
47
|
+
("REV", "tblock-key-rev"),
|
|
48
|
+
("PAGE DESC", "tblock-key-pagedesc"),
|
|
49
|
+
],
|
|
50
|
+
[
|
|
51
|
+
("SCALE", "tblock-key-scale"),
|
|
52
|
+
("PART NUMBER", "tblock-key-pn"),
|
|
53
|
+
("DRAWN BY", "tblock-key-drawnby"),
|
|
54
|
+
("SHEET", "tblock-key-sheet"),
|
|
55
|
+
],
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# === If param file doesn't exist, create it ===
|
|
60
|
+
if not os.path.exists(fileio.path("params")):
|
|
61
|
+
with open(fileio.path("params"), "w", encoding="utf-8") as f:
|
|
62
|
+
json.dump(params, f, indent=2)
|
|
63
|
+
# if it does exist, ignore it
|
|
64
|
+
|
|
65
|
+
# === Load parameters from JSON ===
|
|
66
|
+
with open(fileio.path("params"), "r", encoding="utf-8") as f:
|
|
67
|
+
p = json.load(f)
|
|
68
|
+
|
|
69
|
+
width, height = p["page_size"]
|
|
70
|
+
svg = ET.Element(
|
|
71
|
+
"svg",
|
|
72
|
+
{
|
|
73
|
+
"xmlns": "http://www.w3.org/2000/svg",
|
|
74
|
+
"version": "1.1",
|
|
75
|
+
"width": str(width),
|
|
76
|
+
"height": str(height),
|
|
77
|
+
},
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
contents_group = ET.SubElement(svg, "g", {"id": "tblock-contents-start"})
|
|
81
|
+
|
|
82
|
+
def add_rect(parent, x, y, w, h, stroke="black", fill="none", stroke_width=1):
|
|
83
|
+
ET.SubElement(
|
|
84
|
+
parent,
|
|
85
|
+
"rect",
|
|
86
|
+
{
|
|
87
|
+
"x": str(x),
|
|
88
|
+
"y": str(y),
|
|
89
|
+
"width": str(w),
|
|
90
|
+
"height": str(h),
|
|
91
|
+
"fill": fill,
|
|
92
|
+
"stroke": stroke,
|
|
93
|
+
"stroke-width": str(stroke_width),
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def add_text(parent, x, y, text, size=8, anchor="start", bold=False, id=None):
|
|
98
|
+
style = f"font-size:{size}px;font-family:Arial"
|
|
99
|
+
if bold:
|
|
100
|
+
style += ";font-weight:bold"
|
|
101
|
+
attrs = {
|
|
102
|
+
"x": str(x),
|
|
103
|
+
"y": str(y),
|
|
104
|
+
"style": style,
|
|
105
|
+
"text-anchor": anchor,
|
|
106
|
+
}
|
|
107
|
+
if id:
|
|
108
|
+
attrs["id"] = id
|
|
109
|
+
ET.SubElement(parent, "text", attrs).text = text
|
|
110
|
+
|
|
111
|
+
# === Border Group ===
|
|
112
|
+
border_group = ET.SubElement(contents_group, "g", {"id": "border"})
|
|
113
|
+
|
|
114
|
+
x_ticks = int((width - 2 * p["inner_margin"]) // p["tick_spacing"])
|
|
115
|
+
for i in range(x_ticks):
|
|
116
|
+
x0 = p["inner_margin"] + i * p["tick_spacing"]
|
|
117
|
+
x_center = x0 + p["tick_spacing"] / 2
|
|
118
|
+
ET.SubElement(
|
|
119
|
+
border_group,
|
|
120
|
+
"line",
|
|
121
|
+
{
|
|
122
|
+
"x1": str(x0),
|
|
123
|
+
"y1": str(p["outer_margin"]),
|
|
124
|
+
"x2": str(x0),
|
|
125
|
+
"y2": str(height - p["outer_margin"]),
|
|
126
|
+
"stroke": "black",
|
|
127
|
+
"stroke-width": "0.5",
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
label_y_top = (p["outer_margin"] + p["inner_margin"]) / 2
|
|
131
|
+
label_y_bot = height - label_y_top
|
|
132
|
+
add_text(border_group, x_center, label_y_top, str(i + 1), anchor="middle")
|
|
133
|
+
add_text(border_group, x_center, label_y_bot, str(i + 1), anchor="middle")
|
|
134
|
+
|
|
135
|
+
x_end = p["inner_margin"] + x_ticks * p["tick_spacing"]
|
|
136
|
+
ET.SubElement(
|
|
137
|
+
border_group,
|
|
138
|
+
"line",
|
|
139
|
+
{
|
|
140
|
+
"x1": str(x_end),
|
|
141
|
+
"y1": str(p["outer_margin"]),
|
|
142
|
+
"x2": str(x_end),
|
|
143
|
+
"y2": str(height - p["outer_margin"]),
|
|
144
|
+
"stroke": "black",
|
|
145
|
+
"stroke-width": "0.5",
|
|
146
|
+
},
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
y_ticks = int((height - 2 * p["inner_margin"]) // p["tick_spacing"])
|
|
150
|
+
for j in range(y_ticks):
|
|
151
|
+
y0 = p["inner_margin"] + j * p["tick_spacing"]
|
|
152
|
+
y_center = y0 + p["tick_spacing"] / 2
|
|
153
|
+
ET.SubElement(
|
|
154
|
+
border_group,
|
|
155
|
+
"line",
|
|
156
|
+
{
|
|
157
|
+
"x1": str(p["outer_margin"]),
|
|
158
|
+
"y1": str(y0),
|
|
159
|
+
"x2": str(width - p["outer_margin"]),
|
|
160
|
+
"y2": str(y0),
|
|
161
|
+
"stroke": "black",
|
|
162
|
+
"stroke-width": "0.5",
|
|
163
|
+
},
|
|
164
|
+
)
|
|
165
|
+
label = chr(ord("A") + j)
|
|
166
|
+
label_x_left = (p["outer_margin"] + p["inner_margin"]) / 2
|
|
167
|
+
label_x_right = width - label_x_left
|
|
168
|
+
add_text(border_group, label_x_left, y_center + 4, label, anchor="middle")
|
|
169
|
+
add_text(border_group, label_x_right, y_center + 4, label, anchor="middle")
|
|
170
|
+
|
|
171
|
+
y_end = p["inner_margin"] + y_ticks * p["tick_spacing"]
|
|
172
|
+
ET.SubElement(
|
|
173
|
+
border_group,
|
|
174
|
+
"line",
|
|
175
|
+
{
|
|
176
|
+
"x1": str(p["outer_margin"]),
|
|
177
|
+
"y1": str(y_end),
|
|
178
|
+
"x2": str(width - p["outer_margin"]),
|
|
179
|
+
"y2": str(y_end),
|
|
180
|
+
"stroke": "black",
|
|
181
|
+
"stroke-width": "0.5",
|
|
182
|
+
},
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
add_rect(
|
|
186
|
+
border_group,
|
|
187
|
+
p["outer_margin"],
|
|
188
|
+
p["outer_margin"],
|
|
189
|
+
width - 2 * p["outer_margin"],
|
|
190
|
+
height - 2 * p["outer_margin"],
|
|
191
|
+
)
|
|
192
|
+
add_rect(
|
|
193
|
+
border_group,
|
|
194
|
+
p["inner_margin"],
|
|
195
|
+
p["inner_margin"],
|
|
196
|
+
width - 2 * p["inner_margin"],
|
|
197
|
+
height - 2 * p["inner_margin"],
|
|
198
|
+
stroke="black",
|
|
199
|
+
fill="white",
|
|
200
|
+
stroke_width=1,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# === Logo Group ===
|
|
204
|
+
tb_origin_x = width - p["inner_margin"] - p["tb_origin_offset"][0]
|
|
205
|
+
tb_origin_y = height - p["inner_margin"] - p["tb_origin_offset"][1]
|
|
206
|
+
logo_width = 1.25 * 96
|
|
207
|
+
logo_height = sum(p["row_heights"])
|
|
208
|
+
logo_group = ET.SubElement(contents_group, "g", {"id": "logo"})
|
|
209
|
+
add_rect(logo_group, tb_origin_x - logo_width, tb_origin_y, logo_width, logo_height)
|
|
210
|
+
|
|
211
|
+
# === Titleblock Cell Groups ===
|
|
212
|
+
y_cursor = tb_origin_y
|
|
213
|
+
for row_idx, row_height in enumerate(p["row_heights"]):
|
|
214
|
+
row_cols = p["column_widths"][row_idx]
|
|
215
|
+
row_cells = p["cell_texts"][row_idx]
|
|
216
|
+
x_cursor = tb_origin_x
|
|
217
|
+
for col_idx, col_width in enumerate(row_cols):
|
|
218
|
+
label, key_id = row_cells[col_idx]
|
|
219
|
+
group_id = (
|
|
220
|
+
label.lower().replace(" ", "-")
|
|
221
|
+
if label
|
|
222
|
+
else f"cell-r{row_idx}-c{col_idx}"
|
|
223
|
+
)
|
|
224
|
+
cell_group = ET.SubElement(contents_group, "g", {"id": group_id})
|
|
225
|
+
add_rect(cell_group, x_cursor, y_cursor, col_width, row_height)
|
|
226
|
+
|
|
227
|
+
if label:
|
|
228
|
+
add_text(
|
|
229
|
+
cell_group,
|
|
230
|
+
x_cursor + p["label_offset"][0],
|
|
231
|
+
y_cursor + p["label_offset"][1],
|
|
232
|
+
label,
|
|
233
|
+
size=7,
|
|
234
|
+
bold=True,
|
|
235
|
+
)
|
|
236
|
+
if key_id:
|
|
237
|
+
center_x = x_cursor + col_width / 2
|
|
238
|
+
add_text(
|
|
239
|
+
cell_group,
|
|
240
|
+
center_x,
|
|
241
|
+
y_cursor + p["key_offset_y"],
|
|
242
|
+
key_id,
|
|
243
|
+
size=7,
|
|
244
|
+
anchor="middle",
|
|
245
|
+
id=key_id,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
x_cursor += col_width
|
|
249
|
+
y_cursor += row_height
|
|
250
|
+
|
|
251
|
+
ET.SubElement(svg, "g", {"id": "tblock-contents-end"})
|
|
252
|
+
rough_string = ET.tostring(svg, encoding="utf-8")
|
|
253
|
+
pretty = minidom.parseString(rough_string).toprettyxml(indent=" ")
|
|
254
|
+
with open(fileio.path("drawing"), "w", encoding="utf-8") as f:
|
|
255
|
+
f.write(pretty)
|
|
256
|
+
|
|
257
|
+
# === Write attributes file ===
|
|
258
|
+
periphery_json = {
|
|
259
|
+
"page_size_in": [
|
|
260
|
+
round(p["page_size"][0] / 96, 3),
|
|
261
|
+
round(p["page_size"][1] / 96, 3),
|
|
262
|
+
],
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
with open(fileio.path("attributes"), "w", encoding="utf-8") as f:
|
|
266
|
+
json.dump(periphery_json, f, indent=2)
|
|
267
|
+
|
|
268
|
+
print()
|
|
269
|
+
print(f"Titleblock '{state.partnumber('pn')}' updated")
|
|
270
|
+
print()
|
harnice/state.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# not initializing these variables so that a NameError is raised if they are not set
|
|
5
|
+
def set_pn(x):
|
|
6
|
+
global pn
|
|
7
|
+
pn = x
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def set_rev(x):
|
|
11
|
+
global rev
|
|
12
|
+
rev = x
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def set_net(x):
|
|
16
|
+
global net
|
|
17
|
+
net = x
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def set_file_structure(x):
|
|
21
|
+
global file_structure
|
|
22
|
+
file_structure = x
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def partnumber(format):
|
|
26
|
+
# Returns part numbers in various formats based on the current working directory
|
|
27
|
+
|
|
28
|
+
# given a part number "pppppp-revR"
|
|
29
|
+
|
|
30
|
+
# format options:
|
|
31
|
+
# "pn-rev" returns "pppppp-revR"
|
|
32
|
+
# "pn" returns "pppppp"
|
|
33
|
+
# "rev" returns "revR"
|
|
34
|
+
# "R" returns "R"
|
|
35
|
+
|
|
36
|
+
pn_rev = f"{pn}-rev{rev}"
|
|
37
|
+
|
|
38
|
+
if format == "pn-rev":
|
|
39
|
+
return pn_rev
|
|
40
|
+
|
|
41
|
+
elif format == "pn":
|
|
42
|
+
match = re.search(r"-rev", pn_rev)
|
|
43
|
+
if match:
|
|
44
|
+
return pn_rev[: match.start()]
|
|
45
|
+
|
|
46
|
+
elif format == "rev":
|
|
47
|
+
match = re.search(r"-rev", pn_rev)
|
|
48
|
+
if match:
|
|
49
|
+
return pn_rev[match.start() + 1 :]
|
|
50
|
+
|
|
51
|
+
elif format == "R":
|
|
52
|
+
match = re.search(r"-rev", pn_rev)
|
|
53
|
+
if match:
|
|
54
|
+
return pn_rev[match.start() + 4 :]
|
|
55
|
+
|
|
56
|
+
else:
|
|
57
|
+
raise ValueError("Function 'partnumber' not presented with a valid format")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import webcolors
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Appearance guide:
|
|
6
|
+
color lookup: https://www.w3.org/TR/SVG11/types.html#ColorKeywords
|
|
7
|
+
add the following dictionary-formatted string to a field in the instances list
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
format: design your macros to be able to parse this, define your cables to conform to this
|
|
11
|
+
{"base_color":"","parallelstripe":["",""],"perpstripe":[], "twisted":None}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def parse(val):
|
|
18
|
+
"""
|
|
19
|
+
Parse appearance dictionary, converting color names and shorthand hex to full hex.
|
|
20
|
+
No validation or safeguards.
|
|
21
|
+
"""
|
|
22
|
+
if not val:
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
data = val if isinstance(val, dict) else ast.literal_eval(str(val))
|
|
26
|
+
result = {}
|
|
27
|
+
|
|
28
|
+
for key, value in data.items():
|
|
29
|
+
# lists → normalize each element
|
|
30
|
+
if isinstance(value, list):
|
|
31
|
+
parsed = []
|
|
32
|
+
for c in value:
|
|
33
|
+
c = c.strip().lower()
|
|
34
|
+
if c.startswith("#") and len(c) == 4:
|
|
35
|
+
c = "#" + "".join(ch * 2 for ch in c[1:])
|
|
36
|
+
if not c.startswith("#"):
|
|
37
|
+
c = webcolors.name_to_hex(c)
|
|
38
|
+
parsed.append(c)
|
|
39
|
+
result[key] = parsed
|
|
40
|
+
# single string → normalize directly
|
|
41
|
+
elif isinstance(value, str):
|
|
42
|
+
c = value.strip().lower()
|
|
43
|
+
if c.startswith("#") and len(c) == 4:
|
|
44
|
+
c = "#" + "".join(ch * 2 for ch in c[1:])
|
|
45
|
+
if not c.startswith("#"):
|
|
46
|
+
c = webcolors.name_to_hex(c)
|
|
47
|
+
result[key] = c
|
|
48
|
+
else:
|
|
49
|
+
result[key] = value
|
|
50
|
+
|
|
51
|
+
return result
|