/
name.py
182 lines (144 loc) · 5.1 KB
/
name.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
"""Define names, clean values for names.
"""
import hashlib
from typing import Any
import pydantic
MAX_NAME_LENGTH = 32
@pydantic.validate_arguments
def get_name_short(name: str, max_name_length=MAX_NAME_LENGTH) -> str:
"""Returns a short name."""
if len(name) > max_name_length:
name_hash = hashlib.md5(name.encode()).hexdigest()[:8]
name = f"{name[:(max_name_length - 9)]}_{name_hash}"
return name
def join_first_letters(name: str) -> str:
"""Join the first letter of a name separated with underscores.
taper_length -> TL
"""
return "".join([x[0] for x in name.split("_") if x])
# replace function_name prefix for some components
component_type_to_name = dict(phidl="phidl")
def get_component_name(component_type: str, *args, **kwargs) -> str:
"""Returns concatenated kwargs Key_Value."""
name = component_type + "_".join([clean_value(a) for a in args])
for k, v in component_type_to_name.items():
name = name.replace(k, v)
if kwargs:
name += f"_{dict2name(**kwargs)}"
return name
def dict2hash(**kwargs) -> str:
ignore_from_name = kwargs.pop("ignore_from_name", [])
h = hashlib.sha256()
for key in sorted(kwargs):
if key not in ignore_from_name:
value = kwargs[key]
value = clean_value(value)
h.update(f"{key}{value}".encode())
return h.hexdigest()
def dict2name(prefix: str = "", **kwargs) -> str:
"""Returns name from a dict."""
ignore_from_name = kwargs.pop("ignore_from_name", [])
kv = []
kwargs = kwargs.copy()
kwargs.pop("layer_to_inclusion", "")
for key in sorted(kwargs):
if key not in ignore_from_name and isinstance(key, str):
value = kwargs[key]
# key = join_first_letters(key).upper()
if value is not None:
kv += [f"{key}{clean_value(value)}"]
label = prefix + "_".join(kv)
return clean_name(label)
def assert_first_letters_are_different(**kwargs):
"""Assert that the first letters for each key are different.
Avoids different args that start with the same first letter getting the same hash.
"""
first_letters = [join_first_letters(k) for k in kwargs.keys()]
if len(set(first_letters)) != len(first_letters):
raise ValueError(
f"Possible name collision! {kwargs.keys()} repeats first letters {first_letters}",
"you can separate your arguments with underscores",
" (delta_length -> DL, delta_width -> DW",
)
def print_first_letters_warning(**kwargs) -> None:
"""Prints kwargs that have same cell."""
first_letters = [join_first_letters(k) for k in kwargs.keys()]
if len(set(first_letters)) != len(first_letters):
print(
f"Possible name collision! {kwargs.keys()} "
f"repeats first letters {first_letters}"
"you can separate your arguments with underscores"
" (delta_length -> DL, delta_width -> DW"
)
def clean_name(name: str, remove_dots: bool = False) -> str:
"""Return a string with correct characters for a cell name.
[a-zA-Z0-9]
FIXME: only a few characters are currently replaced.
This function has been updated only on case-by-case basis
"""
replace_map = {
" ": "_",
"!": "",
"?": "",
"#": "_",
"%": "_",
"(": "",
")": "",
"*": "_",
",": "_",
"-": "m",
".": "p",
"/": "_",
":": "_",
"=": "",
"@": "_",
"[": "",
"]": "",
"{": "",
"}": "",
"$": "",
}
if remove_dots:
replace_map["."] = ""
for k, v in list(replace_map.items()):
name = name.replace(k, v)
return name
def clean_value(value: Any) -> str:
from gdsfactory.serialization import clean_value_json
return str(clean_value_json(value))
# def testclean_value_json() -> None:
# assert clean_value(0.5) == "500n"
# assert clean_value(5) == "5"
# assert clean_value(5.0) == "5"
# assert clean_value(11.001) == "11p001"
def test_clean_name() -> None:
assert clean_name("wg(:_=_2852") == "wg___2852"
if __name__ == "__main__":
# test_cell()
# testclean_value_json()
# import gdsfactory as gf
# print(clean_value(gf.components.straight))
# c = gf.components.straight(polarization="TMeraer")
# print(c.settings["polarization"])
# print(clean_value(11.001))
# c = gf.components.straight(length=10)
# c = gf.components.straight(length=10)
# print(c.name)
# print(c)
# c.show(show_ports=True)
# print(clean_name("Waveguidenol1_(:_=_2852"))
# print(clean_value(1.2))
# print(clean_value(0.2))
# print(clean_value([1, [2.4324324, 3]]))
# print(clean_value([1, 2.4324324, 3]))
# print(clean_value((0.001, 24)))
# print(clean_value({"a": 1, "b": 2}))
import gdsfactory as gf
d = {
"X": gf.components.crossing45(port_spacing=40.0),
"-": gf.components.compensation_path(
crossing45=gf.components.crossing45(port_spacing=40.0)
),
}
d2 = clean_value(d)
print(d2)