pyedb 0.2.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.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +17 -0
- pyedb/dotnet/__init__.py +0 -0
- pyedb/dotnet/application/Variables.py +2261 -0
- pyedb/dotnet/application/__init__.py +0 -0
- pyedb/dotnet/clr_module.py +103 -0
- pyedb/dotnet/edb.py +4237 -0
- pyedb/dotnet/edb_core/__init__.py +1 -0
- pyedb/dotnet/edb_core/cell/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
- pyedb/dotnet/edb_core/components.py +2669 -0
- pyedb/dotnet/edb_core/configuration.py +423 -0
- pyedb/dotnet/edb_core/definition/__init__.py +0 -0
- pyedb/dotnet/edb_core/definition/component_def.py +166 -0
- pyedb/dotnet/edb_core/definition/component_model.py +30 -0
- pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
- pyedb/dotnet/edb_core/definition/definitions.py +12 -0
- pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
- pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
- pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
- pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
- pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
- pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
- pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
- pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
- pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
- pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
- pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
- pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
- pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
- pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
- pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
- pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
- pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
- pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
- pyedb/dotnet/edb_core/general.py +181 -0
- pyedb/dotnet/edb_core/hfss.py +1646 -0
- pyedb/dotnet/edb_core/layout.py +1244 -0
- pyedb/dotnet/edb_core/layout_validation.py +272 -0
- pyedb/dotnet/edb_core/materials.py +939 -0
- pyedb/dotnet/edb_core/net_class.py +335 -0
- pyedb/dotnet/edb_core/nets.py +1215 -0
- pyedb/dotnet/edb_core/padstack.py +1389 -0
- pyedb/dotnet/edb_core/siwave.py +1427 -0
- pyedb/dotnet/edb_core/stackup.py +2703 -0
- pyedb/edb_logger.py +396 -0
- pyedb/generic/__init__.py +0 -0
- pyedb/generic/constants.py +1063 -0
- pyedb/generic/data_handlers.py +320 -0
- pyedb/generic/design_types.py +104 -0
- pyedb/generic/filesystem.py +150 -0
- pyedb/generic/general_methods.py +1535 -0
- pyedb/generic/plot.py +1840 -0
- pyedb/generic/process.py +285 -0
- pyedb/generic/settings.py +224 -0
- pyedb/ipc2581/__init__.py +0 -0
- pyedb/ipc2581/bom/__init__.py +0 -0
- pyedb/ipc2581/bom/bom.py +21 -0
- pyedb/ipc2581/bom/bom_item.py +32 -0
- pyedb/ipc2581/bom/characteristics.py +37 -0
- pyedb/ipc2581/bom/refdes.py +16 -0
- pyedb/ipc2581/content/__init__.py +0 -0
- pyedb/ipc2581/content/color.py +38 -0
- pyedb/ipc2581/content/content.py +55 -0
- pyedb/ipc2581/content/dictionary_color.py +29 -0
- pyedb/ipc2581/content/dictionary_fill.py +28 -0
- pyedb/ipc2581/content/dictionary_line.py +30 -0
- pyedb/ipc2581/content/entry_color.py +13 -0
- pyedb/ipc2581/content/entry_line.py +14 -0
- pyedb/ipc2581/content/fill.py +15 -0
- pyedb/ipc2581/content/layer_ref.py +10 -0
- pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
- pyedb/ipc2581/ecad/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
- pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
- pyedb/ipc2581/ecad/cad_data/component.py +41 -0
- pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
- pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
- pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
- pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
- pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
- pyedb/ipc2581/ecad/cad_data/package.py +104 -0
- pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
- pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
- pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
- pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
- pyedb/ipc2581/ecad/cad_data/path.py +89 -0
- pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
- pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
- pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
- pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
- pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
- pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
- pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
- pyedb/ipc2581/ecad/cad_data/step.py +275 -0
- pyedb/ipc2581/ecad/cad_header.py +33 -0
- pyedb/ipc2581/ecad/ecad.py +19 -0
- pyedb/ipc2581/ecad/spec.py +46 -0
- pyedb/ipc2581/history_record.py +37 -0
- pyedb/ipc2581/ipc2581.py +387 -0
- pyedb/ipc2581/logistic_header.py +25 -0
- pyedb/misc/__init__.py +0 -0
- pyedb/misc/aedtlib_personalib_install.py +14 -0
- pyedb/misc/downloads.py +322 -0
- pyedb/misc/misc.py +67 -0
- pyedb/misc/pyedb.runtimeconfig.json +13 -0
- pyedb/misc/siw_feature_config/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
- pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
- pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
- pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
- pyedb/misc/utilities.py +27 -0
- pyedb/modeler/geometry_operators.py +2082 -0
- pyedb-0.2.0.dist-info/LICENSE +21 -0
- pyedb-0.2.0.dist-info/METADATA +208 -0
- pyedb-0.2.0.dist-info/RECORD +128 -0
- pyedb-0.2.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from collections import OrderedDict
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
import json
|
|
5
|
+
import math
|
|
6
|
+
import random
|
|
7
|
+
import re
|
|
8
|
+
import string
|
|
9
|
+
|
|
10
|
+
from pyedb.generic.general_methods import pyedb_function_handler, settings
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pyedb_function_handler()
|
|
14
|
+
def format_decimals(el): # pragma: no cover
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
Parameters
|
|
18
|
+
----------
|
|
19
|
+
el :
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
if float(el) > 1000:
|
|
27
|
+
num = "{:,.0f}".format(Decimal(el))
|
|
28
|
+
elif float(el) > 1:
|
|
29
|
+
num = "{:,.3f}".format(Decimal(el))
|
|
30
|
+
else:
|
|
31
|
+
num = "{:.3E}".format(Decimal(el))
|
|
32
|
+
return num
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pyedb_function_handler()
|
|
36
|
+
def random_string(length=6, only_digits=False, char_set=None): # pragma: no cover
|
|
37
|
+
"""Generate a random string
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
length :
|
|
42
|
+
length of the random string (Default value = 6)
|
|
43
|
+
only_digits : bool, optional
|
|
44
|
+
``True`` if only digits are to be included.
|
|
45
|
+
char_set : str, optional
|
|
46
|
+
Custom character set to pick the characters from. By default chooses from
|
|
47
|
+
ASCII and digit characters or just digits if ``only_digits`` is ``True``.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
type
|
|
52
|
+
random string
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
if not char_set:
|
|
56
|
+
if only_digits:
|
|
57
|
+
char_set = string.digits
|
|
58
|
+
else:
|
|
59
|
+
char_set = string.ascii_uppercase + string.digits
|
|
60
|
+
random_str = "".join(random.choice(char_set) for _ in range(int(length)))
|
|
61
|
+
return random_str
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@pyedb_function_handler()
|
|
65
|
+
def unique_string_list(element_list, only_string=True): # pragma: no cover
|
|
66
|
+
"""Return a unique list of strings from an element list.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
element_list :
|
|
71
|
+
|
|
72
|
+
only_string :
|
|
73
|
+
(Default value = True)
|
|
74
|
+
|
|
75
|
+
Returns
|
|
76
|
+
-------
|
|
77
|
+
|
|
78
|
+
"""
|
|
79
|
+
if element_list:
|
|
80
|
+
if isinstance(element_list, list):
|
|
81
|
+
element_list = set(element_list)
|
|
82
|
+
elif isinstance(element_list, str):
|
|
83
|
+
element_list = [element_list]
|
|
84
|
+
else:
|
|
85
|
+
error_message = "Invalid list data"
|
|
86
|
+
try:
|
|
87
|
+
error_message += " {}".format(element_list)
|
|
88
|
+
except:
|
|
89
|
+
pass
|
|
90
|
+
raise Exception(error_message)
|
|
91
|
+
|
|
92
|
+
if only_string:
|
|
93
|
+
non_string_entries = [x for x in element_list if type(x) is not str]
|
|
94
|
+
assert not non_string_entries, "Invalid list entries {} are not a string!".format(non_string_entries)
|
|
95
|
+
|
|
96
|
+
return element_list
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@pyedb_function_handler()
|
|
100
|
+
def string_list(element_list): # pragma: no cover
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
element_list :
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
|
|
111
|
+
"""
|
|
112
|
+
if isinstance(element_list, str):
|
|
113
|
+
element_list = [element_list]
|
|
114
|
+
else:
|
|
115
|
+
assert isinstance(element_list, str), "Input must be a list or a string"
|
|
116
|
+
return element_list
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@pyedb_function_handler()
|
|
120
|
+
def ensure_list(element_list): # pragma: no cover
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
element_list :
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
Returns
|
|
129
|
+
-------
|
|
130
|
+
|
|
131
|
+
"""
|
|
132
|
+
if not isinstance(element_list, list):
|
|
133
|
+
element_list = [element_list]
|
|
134
|
+
return element_list
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@pyedb_function_handler()
|
|
138
|
+
def from_rkm(code): # pragma: no cover
|
|
139
|
+
"""Convert an RKM code string to a string with a decimal point.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
code : str
|
|
144
|
+
RKM code string.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
str
|
|
149
|
+
String with a decimal point and an R value.
|
|
150
|
+
|
|
151
|
+
Examples
|
|
152
|
+
--------
|
|
153
|
+
>>> from_rkm('R47')
|
|
154
|
+
'0.47'
|
|
155
|
+
|
|
156
|
+
>>> from_rkm('4R7')
|
|
157
|
+
'4.7'
|
|
158
|
+
|
|
159
|
+
>>> from_rkm('470R')
|
|
160
|
+
'470'
|
|
161
|
+
|
|
162
|
+
>>> from_rkm('4K7')
|
|
163
|
+
'4.7k'
|
|
164
|
+
|
|
165
|
+
>>> from_rkm('47K')
|
|
166
|
+
'47k'
|
|
167
|
+
|
|
168
|
+
>>> from_rkm('47K3')
|
|
169
|
+
'47.3k'
|
|
170
|
+
|
|
171
|
+
>>> from_rkm('470K')
|
|
172
|
+
'470k'
|
|
173
|
+
|
|
174
|
+
>>> from_rkm('4M7')
|
|
175
|
+
'4.7M'
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
# Matches RKM codes that start with a digit.
|
|
180
|
+
# fd_pattern = r'([0-9]+)([LREkKMGTFmuµUnNpP]+)([0-9]*)'
|
|
181
|
+
fd_pattern = r"([0-9]+)([{}]+)([0-9]*)".format(
|
|
182
|
+
"".join(RKM_MAPS.keys()),
|
|
183
|
+
)
|
|
184
|
+
# matches rkm codes that end with a digit
|
|
185
|
+
# ld_pattern = r'([0-9]*)([LREkKMGTFmuµUnNpP]+)([0-9]+)'
|
|
186
|
+
ld_pattern = r"([0-9]*)([{}]+)([0-9]+)".format("".join(RKM_MAPS.keys()))
|
|
187
|
+
|
|
188
|
+
fd_regex = re.compile(fd_pattern, re.I)
|
|
189
|
+
ld_regex = re.compile(ld_pattern, re.I)
|
|
190
|
+
|
|
191
|
+
for regex in [fd_regex, ld_regex]:
|
|
192
|
+
m = regex.match(code)
|
|
193
|
+
if m:
|
|
194
|
+
fd, base, ld = m.groups()
|
|
195
|
+
ps = RKM_MAPS[base]
|
|
196
|
+
|
|
197
|
+
if ld:
|
|
198
|
+
return_str = "".join([fd, ".", ld, ps])
|
|
199
|
+
else:
|
|
200
|
+
return_str = "".join([fd, ps])
|
|
201
|
+
return return_str
|
|
202
|
+
return code
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def str_to_bool(s): # pragma: no cover
|
|
206
|
+
"""Convert a ``"True"`` or ``"False"`` string to its corresponding Boolean value.
|
|
207
|
+
|
|
208
|
+
If the passed arguments are not relevant in the context of conversion, the argument
|
|
209
|
+
itself is returned. This method can be called using the ``map()`` function to
|
|
210
|
+
ensure conversion of Boolean strings in a list.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
s: str
|
|
215
|
+
|
|
216
|
+
Returns
|
|
217
|
+
-------
|
|
218
|
+
bool or str
|
|
219
|
+
The method is not case-sensitive.
|
|
220
|
+
- ``True`` is returned if the input is ``"true"``, ``"1"``,
|
|
221
|
+
`"yes"``, or ``"y"``,
|
|
222
|
+
- ``False`` is returned if the input is ``"false"``, ``"no"``,
|
|
223
|
+
``"n``, or ``"0"``.
|
|
224
|
+
- Otherwise, the input value is passed through the method unchanged.
|
|
225
|
+
|
|
226
|
+
"""
|
|
227
|
+
if type(s) == str:
|
|
228
|
+
if s.lower() in ["true", "yes", "y", "1"]:
|
|
229
|
+
return True
|
|
230
|
+
elif s.lower() in ["false", "no", "n", "0"]:
|
|
231
|
+
return False
|
|
232
|
+
else:
|
|
233
|
+
return s
|
|
234
|
+
elif type(s) == int:
|
|
235
|
+
return False if s == 0 else True
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
unit_val = {
|
|
239
|
+
"": 1.0,
|
|
240
|
+
"uV": 1e-6,
|
|
241
|
+
"mV": 1e-3,
|
|
242
|
+
"V": 1.0,
|
|
243
|
+
"kV": 1e3,
|
|
244
|
+
"MegV": 1e6,
|
|
245
|
+
"ns": 1e-9,
|
|
246
|
+
"us": 1e-6,
|
|
247
|
+
"ms": 1e-3,
|
|
248
|
+
"s": 1.0,
|
|
249
|
+
"min": 60,
|
|
250
|
+
"hour": 3600,
|
|
251
|
+
"rad": 1.0,
|
|
252
|
+
"deg": math.pi / 180,
|
|
253
|
+
"Hz": 1.0,
|
|
254
|
+
"kHz": 1e3,
|
|
255
|
+
"MHz": 1e6,
|
|
256
|
+
"nm": 1e-9,
|
|
257
|
+
"um": 1e-6,
|
|
258
|
+
"mm": 1e-3,
|
|
259
|
+
"in": 0.0254,
|
|
260
|
+
"inches": 0.0254,
|
|
261
|
+
"mil": 2.54e-5,
|
|
262
|
+
"cm": 1e-2,
|
|
263
|
+
"dm": 1e-1,
|
|
264
|
+
"meter": 1.0,
|
|
265
|
+
"km": 1e3,
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@pyedb_function_handler()
|
|
270
|
+
def float_units(val_str, units=""): # pragma: no cover
|
|
271
|
+
"""Retrieve units for a value.
|
|
272
|
+
|
|
273
|
+
Parameters
|
|
274
|
+
----------
|
|
275
|
+
val_str : str
|
|
276
|
+
Name of the float value.
|
|
277
|
+
|
|
278
|
+
units : str, optional
|
|
279
|
+
The default is ``""``.
|
|
280
|
+
|
|
281
|
+
Returns
|
|
282
|
+
-------
|
|
283
|
+
|
|
284
|
+
"""
|
|
285
|
+
if not units in unit_val:
|
|
286
|
+
raise Exception("Specified unit string " + units + " not known!")
|
|
287
|
+
|
|
288
|
+
loc = re.search("[a-zA-Z]", val_str)
|
|
289
|
+
try:
|
|
290
|
+
b = loc.span()[0]
|
|
291
|
+
var = [float(val_str[0:b]), val_str[b:]]
|
|
292
|
+
val = var[0] * unit_val[var[1]]
|
|
293
|
+
except:
|
|
294
|
+
val = float(val_str)
|
|
295
|
+
|
|
296
|
+
val = val / unit_val[units]
|
|
297
|
+
return val
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@pyedb_function_handler()
|
|
301
|
+
def json_to_dict(fn): # pragma: no cover
|
|
302
|
+
"""Load Json File to a dictionary.
|
|
303
|
+
|
|
304
|
+
Parameters
|
|
305
|
+
----------
|
|
306
|
+
fn : str
|
|
307
|
+
json file full path.
|
|
308
|
+
|
|
309
|
+
Returns
|
|
310
|
+
-------
|
|
311
|
+
dict
|
|
312
|
+
"""
|
|
313
|
+
json_data = {}
|
|
314
|
+
with open(fn) as json_file:
|
|
315
|
+
try:
|
|
316
|
+
json_data = json.load(json_file)
|
|
317
|
+
except json.JSONDecodeError as e: # pragma: no cover
|
|
318
|
+
error = "Error reading json: {} at line {}".format(e.msg, e.lineno)
|
|
319
|
+
settings.logger.error(error)
|
|
320
|
+
return json_data
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# lazy imports
|
|
5
|
+
def Edb(
|
|
6
|
+
edbpath=None,
|
|
7
|
+
cellname=None,
|
|
8
|
+
isreadonly=False,
|
|
9
|
+
edbversion=None,
|
|
10
|
+
isaedtowned=False,
|
|
11
|
+
oproject=None,
|
|
12
|
+
student_version=False,
|
|
13
|
+
use_ppe=False,
|
|
14
|
+
technology_file=None,
|
|
15
|
+
):
|
|
16
|
+
"""Provides the EDB application interface.
|
|
17
|
+
|
|
18
|
+
This module inherits all objects that belong to EDB.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
edbpath : str, optional
|
|
23
|
+
Full path to the ``aedb`` folder. The variable can also contain
|
|
24
|
+
the path to a layout to import. Allowed formats are BRD,
|
|
25
|
+
XML (IPC2581), GDS, and DXF. The default is ``None``.
|
|
26
|
+
For GDS import, the Ansys control file (also XML) should have the same
|
|
27
|
+
name as the GDS file. Only the file extension differs.
|
|
28
|
+
cellname : str, optional
|
|
29
|
+
Name of the cell to select. The default is ``None``.
|
|
30
|
+
isreadonly : bool, optional
|
|
31
|
+
Whether to open EBD in read-only mode when it is
|
|
32
|
+
owned by HFSS 3D Layout. The default is ``False``.
|
|
33
|
+
edbversion : str, optional
|
|
34
|
+
Version of EDB to use. The default is ``"2021.2"``.
|
|
35
|
+
isaedtowned : bool, optional
|
|
36
|
+
Whether to launch EDB from HFSS 3D Layout. The
|
|
37
|
+
default is ``False``.
|
|
38
|
+
oproject : optional
|
|
39
|
+
Reference to the AEDT project object.
|
|
40
|
+
student_version : bool, optional
|
|
41
|
+
Whether to open the AEDT student version. The default is ``False.``
|
|
42
|
+
technology_file : str, optional
|
|
43
|
+
Full path to technology file to be converted to xml before importing or xml. Supported by GDS format only.
|
|
44
|
+
|
|
45
|
+
Returns
|
|
46
|
+
-------
|
|
47
|
+
:class:`pyedb.dotnet.edb.Edb`, :class:`pyedb.grpc.edb.Edb`
|
|
48
|
+
|
|
49
|
+
Examples
|
|
50
|
+
--------
|
|
51
|
+
Create an ``Edb`` object and a new EDB cell.
|
|
52
|
+
|
|
53
|
+
>>> from pyedb import Edb
|
|
54
|
+
>>> app = Edb()
|
|
55
|
+
|
|
56
|
+
Add a new variable named "s1" to the ``Edb`` instance.
|
|
57
|
+
|
|
58
|
+
>>> app['s1'] = "0.25 mm"
|
|
59
|
+
>>> app['s1'].tofloat
|
|
60
|
+
>>> 0.00025
|
|
61
|
+
>>> app['s1'].tostring
|
|
62
|
+
>>> "0.25mm"
|
|
63
|
+
|
|
64
|
+
or add a new parameter with description:
|
|
65
|
+
|
|
66
|
+
>>> app['s2'] = ["20um", "Spacing between traces"]
|
|
67
|
+
>>> app['s2'].value
|
|
68
|
+
>>> 1.9999999999999998e-05
|
|
69
|
+
>>> app['s2'].description
|
|
70
|
+
>>> 'Spacing between traces'
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
Create an ``Edb`` object and open the specified project.
|
|
74
|
+
|
|
75
|
+
>>> app = Edb("myfile.aedb")
|
|
76
|
+
|
|
77
|
+
Create an ``Edb`` object from GDS and control files.
|
|
78
|
+
The XML control file resides in the same directory as the GDS file: (myfile.xml).
|
|
79
|
+
|
|
80
|
+
>>> app = Edb("/path/to/file/myfile.gds")
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
# Use EDB legacy (default choice)
|
|
85
|
+
if bool(os.getenv("PYEDB_USE_DOTNET", "1")):
|
|
86
|
+
from pyedb.dotnet.edb import Edb as app
|
|
87
|
+
|
|
88
|
+
return app(
|
|
89
|
+
edbpath=edbpath,
|
|
90
|
+
cellname=cellname,
|
|
91
|
+
isreadonly=isreadonly,
|
|
92
|
+
edbversion=edbversion,
|
|
93
|
+
isaedtowned=isaedtowned,
|
|
94
|
+
oproject=oproject,
|
|
95
|
+
student_version=student_version,
|
|
96
|
+
use_ppe=use_ppe,
|
|
97
|
+
technology_file=technology_file,
|
|
98
|
+
)
|
|
99
|
+
# TODO: Use EDB gRPC
|
|
100
|
+
else:
|
|
101
|
+
raise Exception("not implemented yet.")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
app_map = {"EDB": Edb}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import random
|
|
3
|
+
import shutil
|
|
4
|
+
import string
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def search_files(dirname, pattern="*"):
|
|
8
|
+
"""Search for files inside a directory given a specific pattern.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
dirname : str
|
|
13
|
+
pattern :str, optional
|
|
14
|
+
|
|
15
|
+
Returns
|
|
16
|
+
-------
|
|
17
|
+
list
|
|
18
|
+
"""
|
|
19
|
+
from pyedb.generic.general_methods import is_ironpython
|
|
20
|
+
|
|
21
|
+
if is_ironpython:
|
|
22
|
+
import glob
|
|
23
|
+
|
|
24
|
+
return list(glob.glob(os.path.join(dirname, pattern)))
|
|
25
|
+
else:
|
|
26
|
+
import pathlib
|
|
27
|
+
|
|
28
|
+
return [os.path.abspath(i) for i in pathlib.Path(dirname).glob(pattern)]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def my_location():
|
|
32
|
+
""" """
|
|
33
|
+
return os.path.normpath(os.path.dirname(__file__))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Scratch:
|
|
37
|
+
""" """
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def path(self):
|
|
41
|
+
""" """
|
|
42
|
+
return self._scratch_path
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def is_empty(self):
|
|
46
|
+
""" """
|
|
47
|
+
return self._cleaned
|
|
48
|
+
|
|
49
|
+
def __init__(self, local_path, permission=0o777, volatile=False):
|
|
50
|
+
self._volatile = volatile
|
|
51
|
+
self._cleaned = True
|
|
52
|
+
char_set = string.ascii_uppercase + string.digits
|
|
53
|
+
self._scratch_path = os.path.normpath(os.path.join(local_path, "scratch" + "".join(random.sample(char_set, 6))))
|
|
54
|
+
if os.path.exists(self._scratch_path):
|
|
55
|
+
try:
|
|
56
|
+
self.remove()
|
|
57
|
+
except:
|
|
58
|
+
self._cleaned = False
|
|
59
|
+
if self._cleaned:
|
|
60
|
+
try:
|
|
61
|
+
os.mkdir(self.path)
|
|
62
|
+
os.chmod(self.path, permission)
|
|
63
|
+
except FileNotFoundError as fnf_error: # Raise error if folder doesn't exist.
|
|
64
|
+
print(fnf_error)
|
|
65
|
+
|
|
66
|
+
def remove(self):
|
|
67
|
+
""" """
|
|
68
|
+
try:
|
|
69
|
+
# TODO check why on Anaconda 3.7 get errors with os.path.exists
|
|
70
|
+
shutil.rmtree(self._scratch_path, ignore_errors=True)
|
|
71
|
+
except:
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
def copyfile(self, src_file, dst_filename=None):
|
|
75
|
+
"""
|
|
76
|
+
Copy a file to the scratch directory. The target filename is optional.
|
|
77
|
+
If omitted, the target file name is identical to the source file name.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
src_file : str
|
|
82
|
+
Source file with fullpath.
|
|
83
|
+
dst_filename : str, optional
|
|
84
|
+
Destination filename with the extension. The default is ``None``,
|
|
85
|
+
in which case the destination file is given the same name as the
|
|
86
|
+
source file.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
dst_file : str
|
|
92
|
+
Full path and file name of the copied file.
|
|
93
|
+
|
|
94
|
+
"""
|
|
95
|
+
if dst_filename:
|
|
96
|
+
dst_file = os.path.join(self.path, dst_filename)
|
|
97
|
+
else:
|
|
98
|
+
dst_file = os.path.join(self.path, os.path.basename(src_file))
|
|
99
|
+
if os.path.exists(dst_file):
|
|
100
|
+
try:
|
|
101
|
+
os.unlink(dst_file)
|
|
102
|
+
except OSError: # pragma: no cover
|
|
103
|
+
pass
|
|
104
|
+
try:
|
|
105
|
+
shutil.copy2(src_file, dst_file)
|
|
106
|
+
except FileNotFoundError as fnf_error:
|
|
107
|
+
print(fnf_error)
|
|
108
|
+
|
|
109
|
+
return dst_file
|
|
110
|
+
|
|
111
|
+
def copyfolder(self, src_folder, destfolder):
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
src_folder :
|
|
117
|
+
|
|
118
|
+
destfolder :
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
Returns
|
|
122
|
+
-------
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
from distutils.dir_util import copy_tree
|
|
126
|
+
|
|
127
|
+
copy_tree(src_folder, destfolder)
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
def __enter__(self):
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
def __exit__(self, ex_type, ex_value, ex_traceback):
|
|
134
|
+
if ex_type or self._volatile:
|
|
135
|
+
self.remove()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_json_files(start_folder):
|
|
139
|
+
"""
|
|
140
|
+
Get the absolute path to all *.json files in start_folder.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
start_folder, str
|
|
145
|
+
Path to the folder where the json files are located.
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
"""
|
|
150
|
+
return [y for x in os.walk(start_folder) for y in search_files(x[0], "*.json")]
|