pyibis-ami 7.2.3__py3-none-any.whl → 7.2.5__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.
pyibisami/__init__.py CHANGED
@@ -1,22 +1,22 @@
1
- """A package of Python modules, used to configure and test IBIS-AMI models.
2
-
3
- .. moduleauthor:: David Banas <capn.freako@gmail.com>
4
-
5
- Original Author: David Banas <capn.freako@gmail.com>
6
-
7
- Original Date: 3 July 2012
8
-
9
- Copyright (c) 2012 by David Banas; All rights reserved World wide.
10
- """
11
-
12
- from importlib.metadata import version as _get_version
13
-
14
- # Set PEP396 version attribute
15
- try:
16
- __version__ = _get_version("PyIBIS-AMI")
17
- except Exception as err: # pylint: disable=broad-exception-caught
18
- __version__ = f"{err} (dev)"
19
-
20
- __date__ = "October 12, 2023"
21
- __authors__ = "David Banas & David Patterson"
22
- __copy__ = "Copyright (c) 2012 David Banas, 2019 David Patterson"
1
+ """A package of Python modules, used to configure and test IBIS-AMI models.
2
+
3
+ .. moduleauthor:: David Banas <capn.freako@gmail.com>
4
+
5
+ Original Author: David Banas <capn.freako@gmail.com>
6
+
7
+ Original Date: 3 July 2012
8
+
9
+ Copyright (c) 2012 by David Banas; All rights reserved World wide.
10
+ """
11
+
12
+ from importlib.metadata import version as _get_version
13
+
14
+ # Set PEP396 version attribute
15
+ try:
16
+ __version__ = _get_version("PyIBIS-AMI")
17
+ except Exception as err: # pylint: disable=broad-exception-caught
18
+ __version__ = f"{err} (dev)"
19
+
20
+ __date__ = "October 12, 2023"
21
+ __authors__ = "David Banas & David Patterson"
22
+ __copy__ = "Copyright (c) 2012 David Banas, 2019 David Patterson"
pyibisami/__main__.py CHANGED
@@ -1,7 +1,7 @@
1
- """A package of Python modules, used to configure and test IBIS-AMI models."""
2
-
3
- print("pyibisami is a package of sub-modules, and is not directly executable.")
4
- print("Perhaps, you meant:")
5
- print(" - pyibisami.ami.config")
6
- print(" - pyibisami.tools.run_tests")
7
- raise RuntimeError("pyibisami is not executable.")
1
+ """A package of Python modules, used to configure and test IBIS-AMI models."""
2
+
3
+ print("pyibisami is a package of sub-modules, and is not directly executable.")
4
+ print("Perhaps, you meant:")
5
+ print(" - pyibisami.ami.config")
6
+ print(" - pyibisami.tools.run_tests")
7
+ raise RuntimeError("pyibisami is not executable.")
pyibisami/ami/config.py CHANGED
@@ -1,297 +1,297 @@
1
- #! /usr/bin/env python
2
-
3
- """IBIS-AMI model source code, AMI file, and IBIS file configuration utility.
4
-
5
- Original author: David Banas
6
-
7
- Original date: February 26, 2016
8
-
9
- Copyright (c) 2016 David Banas; all rights reserved World wide.
10
-
11
- **Note:** The following use model has been deprecated!
12
- The preferred approach is to make *executable* model configurators,
13
- which draw what they need from this module.
14
-
15
- This script gets called from a makefile, when any of the following need rebuilding:
16
-
17
- * a C++ source code file
18
- * a ``*.AMI`` file
19
- * a ``*.IBS`` file
20
- * a ``*.TST`` file (a dummy place-holder indicating that the test run config. files have been made)
21
-
22
- All files will be rebuilt.
23
- (We rebuild all files, because it doesn't take very long, and we can
24
- ensure consistency this way.)
25
-
26
- This gets triggered by one of two things:
27
-
28
- #. The common model configuration information has changed, or
29
- #. One of the EmPy template files was updated.
30
-
31
- The idea here is that the ``*.IBS`` file, the ``*.AMI`` file, the C++ source file,
32
- and the test run configuration files should be configured from a common model
33
- configuration file, so as to ensure consistency between them all.
34
- """
35
-
36
- import importlib.util
37
- from datetime import date
38
- from pathlib import Path
39
- from typing import Any, NewType
40
-
41
- import click
42
- import em
43
-
44
- ParamDict = NewType("ParamDict", dict[str, Any])
45
- NamedParamDict = NewType("NamedParamDict", tuple[str, ParamDict])
46
- TestDefinition = NewType("TestDefinition", tuple[str, NamedParamDict, NamedParamDict, str])
47
-
48
- param_types = {
49
- "INT": {"c_type": "int", "ami_type": "Integer", "getter": "get_param_int"},
50
- "FLOAT": {"c_type": "double", "ami_type": "Float", "getter": "get_param_float"},
51
- "TAP": {"c_type": "double", "ami_type": "Tap", "getter": "get_param_float"},
52
- "BOOL": {"c_type": "bool", "ami_type": "Boolean", "getter": "get_param_bool"},
53
- "STRING": {"c_type": "char *", "ami_type": "String", "getter": "get_param_str"},
54
- }
55
-
56
-
57
- def print_param(indent, name, param): # pylint: disable=too-many-branches
58
- """Print AMI parameter specification. Handle nested parameters, via
59
- recursion.
60
-
61
- Args:
62
- indent (str): String containing some number of spaces.
63
- name (str): Parameter name.
64
- param (dict): Dictionary containing parameter definition fields.
65
- """
66
-
67
- print(indent, f"({name}")
68
- if "subs" in param:
69
- for key in param["subs"]:
70
- print_param(indent + " ", key, param["subs"][key])
71
- if "description" in param:
72
- print(indent + " ", f"(Description {param['description']})")
73
- else:
74
- for fld_name, fld_key in [
75
- ("Usage", "usage"),
76
- ("Type", "type"),
77
- ("Format", "format"),
78
- ("Default", "default"),
79
- ("Description", "description"),
80
- ]:
81
- # Trap the special cases.
82
- if fld_name == "Type":
83
- print(indent, " (Type", param_types[param["type"]]["ami_type"], ")")
84
- elif fld_name == "Default":
85
- if param["format"] == "Value":
86
- pass
87
- elif fld_name == "Format":
88
- if param["format"] == "Value":
89
- print(indent, " (Value", param["default"], ")")
90
- elif param["format"] == "List":
91
- print(indent, " (List", end=" ")
92
- for item in param["values"]:
93
- print(item, end=" ")
94
- print(")")
95
- print(indent, " (List_Tip", end=" ")
96
- for item in param["labels"]:
97
- print(item, end=" ")
98
- print(")")
99
- else:
100
- print(indent, f" ({param['format']}", param["default"], param["min"], param["max"], ")")
101
- # Execute the default action.
102
- else:
103
- print(indent, f" ({fld_name}", param[fld_key], ")")
104
- print(indent, ")")
105
-
106
-
107
- def print_code(pname, param):
108
- """Print C++ code needed to query AMI parameter tree for a particular leaf.
109
-
110
- Args:
111
- pname (str): Parameter name.
112
- param (dict): Dictionary containing parameter definition fields.
113
- """
114
-
115
- print(" ", f'node_names.push_back("{pname}");')
116
- if "subs" in param:
117
- for key in param["subs"]:
118
- print_code(key, param["subs"][key])
119
- else:
120
- if param["usage"] == "In" or param["usage"] == "InOut":
121
- ptype = param["type"]
122
- print(f" {param_types[ptype]['c_type']} {pname};")
123
- if ptype == "BOOL":
124
- print(f" {pname} = {param_types[ptype]['getter']}(node_names, {param['default'].lower()});")
125
- else:
126
- print(f" {pname} = {param_types[ptype]['getter']}(node_names, {param['default']});")
127
- print(" ", "node_names.pop_back();")
128
-
129
-
130
- def mk_model(
131
- ibis_params: ParamDict,
132
- ami_params: ParamDict,
133
- model_name: str,
134
- description: str,
135
- out_dir: str = "."
136
- ) -> None:
137
- """
138
- Generate ibis, ami, and cpp files, by merging the
139
- device specific parameterization with the templates.
140
-
141
- Args:
142
- ibis_params: Dictionary of IBIS model parameter definitions.
143
- ami_params: Dictionary of AMI parameter definitions.
144
- model_name: Name given to IBIS model.
145
- description: Model description.
146
-
147
- Keyword Args:
148
- out_dir: Directory in which to place created files.
149
- Default: "."
150
- """
151
-
152
- py_file = (Path(out_dir).resolve() / model_name).with_suffix(".py")
153
- # Configure the model files.
154
- for ext in ["cpp", "ami", "ibs"]:
155
- out_file = py_file.with_suffix(f".{ext}")
156
- if ext == "ami":
157
- em_file = Path(__file__).parent.joinpath("generic.ami.em")
158
- elif ext == "ibs":
159
- em_file = Path(__file__).parent.joinpath("generic.ibs.em")
160
- else:
161
- em_file = out_file.with_suffix(".cpp.em")
162
-
163
- print(f"Building '{out_file}' from '{em_file}'...")
164
- with open(out_file, "w", encoding="utf-8") as o_file:
165
- interpreter = em.Interpreter(
166
- output=o_file,
167
- globals={
168
- "ami_params": ami_params,
169
- "ibis_params": ibis_params,
170
- "param_types": param_types,
171
- "model_name": model_name,
172
- "description": description,
173
- "date": str(date.today()),
174
- },
175
- )
176
- try:
177
- with open(em_file, "rt", encoding="utf-8") as in_file:
178
- interpreter.file(in_file)
179
- finally:
180
- interpreter.shutdown()
181
-
182
-
183
- def ami_config(py_file):
184
- """
185
- Read in ``py_file`` and cpp.em files, then generate: ibis, ami, and cpp files.
186
-
187
- Args:
188
- py_file: name of model configuration file (<stem>.py)
189
-
190
- Notes:
191
- 1. This function is deprecated! Instead, make your model configurator executable
192
- and import what you need from this module. This is much cleaner.
193
- """
194
-
195
- file_base_name = Path(py_file).stem
196
-
197
- # Read model configuration information.
198
- print(f"Reading model configuration information from file: {py_file}.")
199
- spec = importlib.util.spec_from_file_location(file_base_name, py_file)
200
- cfg = importlib.util.module_from_spec(spec)
201
- spec.loader.exec_module(cfg)
202
-
203
- mk_model(cfg.ibis_params, cfg.ami_params, cfg.kFileBaseName, cfg.kDescription, out_dir=Path(py_file).parent)
204
-
205
-
206
- def mk_combs(dict_items: list[tuple[str, Any]]) -> list[list[tuple[str, Any]]]:
207
- """
208
- Make all combinations possible from a list of dictionary items.
209
-
210
- Args:
211
- dict_items: List of dictionary key/value pairs.
212
- The values are lists.
213
-
214
- Return:
215
- List of all possible combinations of key values.
216
- """
217
- if not dict_items:
218
- return [
219
- [],
220
- ]
221
- head, *tail = dict_items
222
- k, vs = head
223
- kvals = [(k, v) for v in vs]
224
- return [[kval] + rest for kval in kvals for rest in mk_combs(tail)]
225
-
226
-
227
- def mk_tests( # pylint: disable=too-many-locals
228
- test_defs: dict[str, TestDefinition],
229
- file_base_name: str,
230
- test_dir: str = "test_runs"
231
- ) -> None:
232
- """
233
- Make the test run configuration files.
234
-
235
- Args:
236
- test_defs: Dictionary of test sweep definitions.
237
- file_base_name: Stem name for test run definition files.
238
-
239
- Keyword Args:
240
- test_dir: Directory in which to place the created test run definition files.
241
- Default: "test_runs/"
242
- """
243
-
244
- pname = Path(test_dir).resolve()
245
- pname.mkdir(exist_ok=True)
246
- pname = (pname / file_base_name).resolve()
247
- pname.mkdir(exist_ok=True)
248
- for fname in test_defs.keys():
249
- desc, ami_defs, sim_defs, ref_fstr = test_defs[fname]
250
- ami_str, ami_dict = ami_defs
251
- sim_str, sim_dict = sim_defs
252
- with open((pname / fname).with_suffix(".run"), "w", encoding="utf-8") as f:
253
- f.write(desc + "\n")
254
- for ami_comb in mk_combs(list(ami_dict.items())):
255
- for sim_comb in mk_combs(list(sim_dict.items())):
256
- pdict = dict(ami_comb)
257
- pdict.update(dict(sim_comb))
258
- f.write(f"\n('{ami_str.format(pdict=pdict)}_{sim_str.format(pdict=pdict)}', \\\n")
259
- f.write(f" ({{'root_name': '{file_base_name}', \\\n")
260
- for k, v in ami_comb:
261
- f.write(f" '{k}': {v}, \\\n")
262
- f.write(" }, \\\n")
263
- if sim_comb:
264
- head, *tail = sim_comb
265
- k, v = head
266
- f.write(f" {{'{k}': {v}, \\\n")
267
- for k, v in tail:
268
- f.write(f" '{k}': {v}, \\\n")
269
- f.write(" } \\\n")
270
- f.write(" ), \\\n")
271
- if ref_fstr:
272
- f.write(f" '{ref_fstr.format(pdict=pdict)}', \\\n")
273
- f.write(")\n")
274
-
275
-
276
- @click.command(context_settings={"help_option_names": ["-h", "--help"]})
277
- @click.argument("py_file", type=click.Path(exists=True, resolve_path=True))
278
- @click.version_option()
279
- def main(py_file):
280
- """
281
- Configure IBIS-AMI model C++ source code, IBIS model, and AMI file.
282
- This command generates three files based off the input config file.
283
- It expects a .cpp.em file to be located in the same directory so that it can
284
- generate a cpp file from the config file and template file.
285
-
286
- Args:
287
- py_file: name of model configuration file (*.py)
288
-
289
- Notes:
290
- 1. This command is deprecated! Instead, make your model configurator executable
291
- and import what you need from this module. This is much cleaner.
292
- """
293
- ami_config(py_file)
294
-
295
-
296
- if __name__ == "__main__":
297
- main() # pylint: disable=no-value-for-parameter
1
+ #! /usr/bin/env python
2
+
3
+ """IBIS-AMI model source code, AMI file, and IBIS file configuration utility.
4
+
5
+ Original author: David Banas
6
+
7
+ Original date: February 26, 2016
8
+
9
+ Copyright (c) 2016 David Banas; all rights reserved World wide.
10
+
11
+ **Note:** The following use model has been deprecated!
12
+ The preferred approach is to make *executable* model configurators,
13
+ which draw what they need from this module.
14
+
15
+ This script gets called from a makefile, when any of the following need rebuilding:
16
+
17
+ * a C++ source code file
18
+ * a ``*.AMI`` file
19
+ * a ``*.IBS`` file
20
+ * a ``*.TST`` file (a dummy place-holder indicating that the test run config. files have been made)
21
+
22
+ All files will be rebuilt.
23
+ (We rebuild all files, because it doesn't take very long, and we can
24
+ ensure consistency this way.)
25
+
26
+ This gets triggered by one of two things:
27
+
28
+ #. The common model configuration information has changed, or
29
+ #. One of the EmPy template files was updated.
30
+
31
+ The idea here is that the ``*.IBS`` file, the ``*.AMI`` file, the C++ source file,
32
+ and the test run configuration files should be configured from a common model
33
+ configuration file, so as to ensure consistency between them all.
34
+ """
35
+
36
+ import importlib.util
37
+ from datetime import date
38
+ from pathlib import Path
39
+ from typing import Any, NewType
40
+
41
+ import click
42
+ import em
43
+
44
+ ParamDict = NewType("ParamDict", dict[str, Any])
45
+ NamedParamDict = NewType("NamedParamDict", tuple[str, ParamDict])
46
+ TestDefinition = NewType("TestDefinition", tuple[str, NamedParamDict, NamedParamDict, str])
47
+
48
+ param_types = {
49
+ "INT": {"c_type": "int", "ami_type": "Integer", "getter": "get_param_int"},
50
+ "FLOAT": {"c_type": "double", "ami_type": "Float", "getter": "get_param_float"},
51
+ "TAP": {"c_type": "double", "ami_type": "Tap", "getter": "get_param_float"},
52
+ "BOOL": {"c_type": "bool", "ami_type": "Boolean", "getter": "get_param_bool"},
53
+ "STRING": {"c_type": "char *", "ami_type": "String", "getter": "get_param_str"},
54
+ }
55
+
56
+
57
+ def print_param(indent, name, param): # pylint: disable=too-many-branches
58
+ """Print AMI parameter specification. Handle nested parameters, via
59
+ recursion.
60
+
61
+ Args:
62
+ indent (str): String containing some number of spaces.
63
+ name (str): Parameter name.
64
+ param (dict): Dictionary containing parameter definition fields.
65
+ """
66
+
67
+ print(indent, f"({name}")
68
+ if "subs" in param:
69
+ for key in param["subs"]:
70
+ print_param(indent + " ", key, param["subs"][key])
71
+ if "description" in param:
72
+ print(indent + " ", f"(Description {param['description']})")
73
+ else:
74
+ for fld_name, fld_key in [
75
+ ("Usage", "usage"),
76
+ ("Type", "type"),
77
+ ("Format", "format"),
78
+ ("Default", "default"),
79
+ ("Description", "description"),
80
+ ]:
81
+ # Trap the special cases.
82
+ if fld_name == "Type":
83
+ print(indent, " (Type", param_types[param["type"]]["ami_type"], ")")
84
+ elif fld_name == "Default":
85
+ if param["format"] == "Value":
86
+ pass
87
+ elif fld_name == "Format":
88
+ if param["format"] == "Value":
89
+ print(indent, " (Value", param["default"], ")")
90
+ elif param["format"] == "List":
91
+ print(indent, " (List", end=" ")
92
+ for item in param["values"]:
93
+ print(item, end=" ")
94
+ print(")")
95
+ print(indent, " (List_Tip", end=" ")
96
+ for item in param["labels"]:
97
+ print(item, end=" ")
98
+ print(")")
99
+ else:
100
+ print(indent, f" ({param['format']}", param["default"], param["min"], param["max"], ")")
101
+ # Execute the default action.
102
+ else:
103
+ print(indent, f" ({fld_name}", param[fld_key], ")")
104
+ print(indent, ")")
105
+
106
+
107
+ def print_code(pname, param):
108
+ """Print C++ code needed to query AMI parameter tree for a particular leaf.
109
+
110
+ Args:
111
+ pname (str): Parameter name.
112
+ param (dict): Dictionary containing parameter definition fields.
113
+ """
114
+
115
+ print(" ", f'node_names.push_back("{pname}");')
116
+ if "subs" in param:
117
+ for key in param["subs"]:
118
+ print_code(key, param["subs"][key])
119
+ else:
120
+ if param["usage"] == "In" or param["usage"] == "InOut":
121
+ ptype = param["type"]
122
+ print(f" {param_types[ptype]['c_type']} {pname};")
123
+ if ptype == "BOOL":
124
+ print(f" {pname} = {param_types[ptype]['getter']}(node_names, {param['default'].lower()});")
125
+ else:
126
+ print(f" {pname} = {param_types[ptype]['getter']}(node_names, {param['default']});")
127
+ print(" ", "node_names.pop_back();")
128
+
129
+
130
+ def mk_model(
131
+ ibis_params: ParamDict,
132
+ ami_params: ParamDict,
133
+ model_name: str,
134
+ description: str,
135
+ out_dir: str = "."
136
+ ) -> None:
137
+ """
138
+ Generate ibis, ami, and cpp files, by merging the
139
+ device specific parameterization with the templates.
140
+
141
+ Args:
142
+ ibis_params: Dictionary of IBIS model parameter definitions.
143
+ ami_params: Dictionary of AMI parameter definitions.
144
+ model_name: Name given to IBIS model.
145
+ description: Model description.
146
+
147
+ Keyword Args:
148
+ out_dir: Directory in which to place created files.
149
+ Default: "."
150
+ """
151
+
152
+ py_file = (Path(out_dir).resolve() / model_name).with_suffix(".py")
153
+ # Configure the model files.
154
+ for ext in ["cpp", "ami", "ibs"]:
155
+ out_file = py_file.with_suffix(f".{ext}")
156
+ if ext == "ami":
157
+ em_file = Path(__file__).parent.joinpath("generic.ami.em")
158
+ elif ext == "ibs":
159
+ em_file = Path(__file__).parent.joinpath("generic.ibs.em")
160
+ else:
161
+ em_file = out_file.with_suffix(".cpp.em")
162
+
163
+ print(f"Building '{out_file}' from '{em_file}'...")
164
+ with open(out_file, "w", encoding="utf-8") as o_file:
165
+ interpreter = em.Interpreter(
166
+ output=o_file,
167
+ globals={
168
+ "ami_params": ami_params,
169
+ "ibis_params": ibis_params,
170
+ "param_types": param_types,
171
+ "model_name": model_name,
172
+ "description": description,
173
+ "date": str(date.today()),
174
+ },
175
+ )
176
+ try:
177
+ with open(em_file, "rt", encoding="utf-8") as in_file:
178
+ interpreter.file(in_file)
179
+ finally:
180
+ interpreter.shutdown()
181
+
182
+
183
+ def ami_config(py_file):
184
+ """
185
+ Read in ``py_file`` and cpp.em files, then generate: ibis, ami, and cpp files.
186
+
187
+ Args:
188
+ py_file: name of model configuration file (<stem>.py)
189
+
190
+ Notes:
191
+ 1. This function is deprecated! Instead, make your model configurator executable
192
+ and import what you need from this module. This is much cleaner.
193
+ """
194
+
195
+ file_base_name = Path(py_file).stem
196
+
197
+ # Read model configuration information.
198
+ print(f"Reading model configuration information from file: {py_file}.")
199
+ spec = importlib.util.spec_from_file_location(file_base_name, py_file)
200
+ cfg = importlib.util.module_from_spec(spec)
201
+ spec.loader.exec_module(cfg)
202
+
203
+ mk_model(cfg.ibis_params, cfg.ami_params, cfg.kFileBaseName, cfg.kDescription, out_dir=Path(py_file).parent)
204
+
205
+
206
+ def mk_combs(dict_items: list[tuple[str, Any]]) -> list[list[tuple[str, Any]]]:
207
+ """
208
+ Make all combinations possible from a list of dictionary items.
209
+
210
+ Args:
211
+ dict_items: List of dictionary key/value pairs.
212
+ The values are lists.
213
+
214
+ Return:
215
+ List of all possible combinations of key values.
216
+ """
217
+ if not dict_items:
218
+ return [
219
+ [],
220
+ ]
221
+ head, *tail = dict_items
222
+ k, vs = head
223
+ kvals = [(k, v) for v in vs]
224
+ return [[kval] + rest for kval in kvals for rest in mk_combs(tail)]
225
+
226
+
227
+ def mk_tests( # pylint: disable=too-many-locals
228
+ test_defs: dict[str, TestDefinition],
229
+ file_base_name: str,
230
+ test_dir: str = "test_runs"
231
+ ) -> None:
232
+ """
233
+ Make the test run configuration files.
234
+
235
+ Args:
236
+ test_defs: Dictionary of test sweep definitions.
237
+ file_base_name: Stem name for test run definition files.
238
+
239
+ Keyword Args:
240
+ test_dir: Directory in which to place the created test run definition files.
241
+ Default: "test_runs/"
242
+ """
243
+
244
+ pname = Path(test_dir).resolve()
245
+ pname.mkdir(exist_ok=True)
246
+ pname = (pname / file_base_name).resolve()
247
+ pname.mkdir(exist_ok=True)
248
+ for fname in test_defs.keys():
249
+ desc, ami_defs, sim_defs, ref_fstr = test_defs[fname]
250
+ ami_str, ami_dict = ami_defs
251
+ sim_str, sim_dict = sim_defs
252
+ with open((pname / fname).with_suffix(".run"), "w", encoding="utf-8") as f:
253
+ f.write(desc + "\n")
254
+ for ami_comb in mk_combs(list(ami_dict.items())):
255
+ for sim_comb in mk_combs(list(sim_dict.items())):
256
+ pdict = dict(ami_comb)
257
+ pdict.update(dict(sim_comb))
258
+ f.write(f"\n('{ami_str.format(pdict=pdict)}_{sim_str.format(pdict=pdict)}', \\\n")
259
+ f.write(f" ({{'root_name': '{file_base_name}', \\\n")
260
+ for k, v in ami_comb:
261
+ f.write(f" '{k}': {v}, \\\n")
262
+ f.write(" }, \\\n")
263
+ if sim_comb:
264
+ head, *tail = sim_comb
265
+ k, v = head
266
+ f.write(f" {{'{k}': {v}, \\\n")
267
+ for k, v in tail:
268
+ f.write(f" '{k}': {v}, \\\n")
269
+ f.write(" } \\\n")
270
+ f.write(" ), \\\n")
271
+ if ref_fstr:
272
+ f.write(f" '{ref_fstr.format(pdict=pdict)}', \\\n")
273
+ f.write(")\n")
274
+
275
+
276
+ @click.command(context_settings={"help_option_names": ["-h", "--help"]})
277
+ @click.argument("py_file", type=click.Path(exists=True, resolve_path=True))
278
+ @click.version_option()
279
+ def main(py_file):
280
+ """
281
+ Configure IBIS-AMI model C++ source code, IBIS model, and AMI file.
282
+ This command generates three files based off the input config file.
283
+ It expects a .cpp.em file to be located in the same directory so that it can
284
+ generate a cpp file from the config file and template file.
285
+
286
+ Args:
287
+ py_file: name of model configuration file (*.py)
288
+
289
+ Notes:
290
+ 1. This command is deprecated! Instead, make your model configurator executable
291
+ and import what you need from this module. This is much cleaner.
292
+ """
293
+ ami_config(py_file)
294
+
295
+
296
+ if __name__ == "__main__":
297
+ main() # pylint: disable=no-value-for-parameter