PyIBIS-AMI 7.2.9__tar.gz → 7.3.1__tar.gz

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 (52) hide show
  1. {pyibis_ami-7.2.9/src/pyibis_ami.egg-info → pyibis_ami-7.3.1}/PKG-INFO +1 -1
  2. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/pyproject.toml +1 -1
  3. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1/src/pyibis_ami.egg-info}/PKG-INFO +1 -1
  4. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/IBIS_AMI_Tester.ipynb +9 -3
  5. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/model.py +13 -3
  6. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/parser.py +46 -10
  7. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ibis/file.py +4 -3
  8. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ibis/parser.py +29 -7
  9. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/tools/run_notebook.py +6 -1
  10. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/LICENSE +0 -0
  11. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/MANIFEST.in +0 -0
  12. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/README.md +0 -0
  13. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/docs/source/ami.rst +0 -0
  14. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/docs/source/conf.py +0 -0
  15. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/docs/source/ibis.rst +0 -0
  16. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/docs/source/index.rst +0 -0
  17. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/docs/source/install.rst +0 -0
  18. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/docs/source/modules.rst +0 -0
  19. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/docs/source/tools.rst +0 -0
  20. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/all_taps.run +0 -0
  21. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/bandwidth.run +0 -0
  22. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/dummy.em +0 -0
  23. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/examples.md +0 -0
  24. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/freq_resp.em +0 -0
  25. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/impulse.em +0 -0
  26. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/impulse_response_8ma.txt +0 -0
  27. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/mode.run +0 -0
  28. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/stratix4_ami_tx_runs/all_taps.run +0 -0
  29. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/stratix4_ami_tx_runs/test_results.xml +0 -0
  30. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/examples/test_results/test_results.xsl +0 -0
  31. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/setup.cfg +0 -0
  32. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibis_ami.egg-info/SOURCES.txt +0 -0
  33. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibis_ami.egg-info/dependency_links.txt +0 -0
  34. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibis_ami.egg-info/entry_points.txt +0 -0
  35. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibis_ami.egg-info/requires.txt +0 -0
  36. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibis_ami.egg-info/top_level.txt +0 -0
  37. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/IBIS_AMI_Checker.ipynb +0 -0
  38. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/__init__.py +0 -0
  39. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/__main__.py +0 -0
  40. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/__init__.py +0 -0
  41. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/config.py +0 -0
  42. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/generic.ami.em +0 -0
  43. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/generic.ibs.em +0 -0
  44. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/parameter.py +0 -0
  45. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ami/reserved_parameter_names.py +0 -0
  46. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/common.py +0 -0
  47. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ibis/__init__.py +0 -0
  48. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/ibis/model.py +0 -0
  49. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/tools/__init__.py +0 -0
  50. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/tools/run_tests.py +0 -0
  51. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/src/pyibisami/tools/test_results.xsl +0 -0
  52. {pyibis_ami-7.2.9 → pyibis_ami-7.3.1}/tests/test_run_tests.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyibis-ami
3
- Version: 7.2.9
3
+ Version: 7.3.1
4
4
  Summary: Facilitates working directly with IBIS-AMI DLLs from the Python command prompt.
5
5
  Author-email: David Banas <capn.freako@gmail.com>
6
6
  Project-URL: Documentation, https://pyibis-ami.readthedocs.io/en/latest/
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "pyibis-ami"
7
7
  description = "Facilitates working directly with IBIS-AMI DLLs from the Python command prompt."
8
- version = "7.2.9"
8
+ version = "7.3.1"
9
9
  authors = [ {name = "David Banas", email = "capn.freako@gmail.com"}
10
10
  ]
11
11
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyibis-ami
3
- Version: 7.2.9
3
+ Version: 7.3.1
4
4
  Summary: Facilitates working directly with IBIS-AMI DLLs from the Python command prompt.
5
5
  Author-email: David Banas <capn.freako@gmail.com>
6
6
  Project-URL: Documentation, https://pyibis-ami.readthedocs.io/en/latest/
@@ -69,6 +69,9 @@
69
69
  "source": [
70
70
  "%matplotlib inline\n",
71
71
  "\n",
72
+ "import sys\n",
73
+ "import shlex\n",
74
+ "\n",
72
75
  "from matplotlib import pyplot as plt\n",
73
76
  "from matplotlib.figure import Figure\n",
74
77
  "\n",
@@ -161,7 +164,8 @@
161
164
  "f_max = 40e9 # maximum frequency (Hz)\n",
162
165
  "f_step = 10e6 # frequency step (Hz)\n",
163
166
  "fig_x = 10 # Figures x-dimmension (in.)\n",
164
- "fig_y = 3 # Figures y-dimmension (in.)\n"
167
+ "fig_y = 3 # Figures y-dimmension (in.)\n",
168
+ "full_command_line = \"run-notebook\"\n"
165
169
  ]
166
170
  },
167
171
  {
@@ -207,8 +211,10 @@
207
211
  "ts = 0.5 / f_max\n",
208
212
  "t_fft = array([n * ts for n in range(2 * (len(f) - 1))])\n",
209
213
  "\n",
214
+ "print(f\"Full command line: {full_command_line}\")\n",
215
+ "print(f\"Testing model: {ibis_file},\")\n",
210
216
  "param_defs = expand_params(params)\n",
211
- "print(\"Will use the following parameter sweeps:\")\n",
217
+ "print(\"using the following parameter sweeps:\")\n",
212
218
  "for (name, desc, cfgs) in param_defs:\n",
213
219
  " print(f\"\\t{name} ({desc.strip()}): {len(cfgs)} sweeps.\")\n"
214
220
  ]
@@ -1451,7 +1457,7 @@
1451
1457
  "name": "python",
1452
1458
  "nbconvert_exporter": "python",
1453
1459
  "pygments_lexer": "ipython3",
1454
- "version": "3.11.13"
1460
+ "version": "3.10.11"
1455
1461
  }
1456
1462
  },
1457
1463
  "nbformat": 4,
@@ -354,7 +354,9 @@ class AMIModel: # pylint: disable=too-many-instance-attributes
354
354
  return f"({pname} {' '.join(subs)})"
355
355
  return f"({pname} {pval})"
356
356
 
357
- ami_params_in = f"({init_object.ami_params['root_name']} "
357
+ root_name = init_object.ami_params['root_name']
358
+ self._root_name = root_name # pylint: disable=attribute-defined-outside-init
359
+ ami_params_in = f"({root_name} "
358
360
  for item in list(init_object.ami_params.items()):
359
361
  if not item[0] == "root_name":
360
362
  ami_params_in += sexpr(item[0], item[1])
@@ -551,7 +553,7 @@ class AMIModel: # pylint: disable=too-many-instance-attributes
551
553
  H_init *= s_init[-1] / np.abs(H_init[0]) # Normalize for proper d.c.
552
554
  rslt["out_resp_init"] = (t, h_init, s_init, p_init, f, H_init)
553
555
 
554
- if calc_getw and self.info_params["GetWave_Exists"]:
556
+ if calc_getw and self.info_params["GetWave_Exists"].pvalue:
555
557
  # Get model's step response.
556
558
  rng = default_rng()
557
559
  u = np.concatenate(
@@ -581,6 +583,11 @@ class AMIModel: # pylint: disable=too-many-instance-attributes
581
583
 
582
584
  return rslt
583
585
 
586
+ @property
587
+ def root_name(self):
588
+ """AMI parameter tree root name."""
589
+ return self._root_name
590
+
584
591
  def _getInitOut(self):
585
592
  return list(map(float, self._initOut))
586
593
 
@@ -619,7 +626,10 @@ class AMIModel: # pylint: disable=too-many-instance-attributes
619
626
  ami_params_in = property(_getAmiParamsIn, doc="The AMI parameter string passed to AMI_Init() by initialize().")
620
627
 
621
628
  def _getAmiParamsOut(self):
622
- return self._ami_params_out.value
629
+ pout: str = self._ami_params_out.value
630
+ if pout: # pylint: disable=using-constant-test
631
+ return pout.decode() # pylint: disable=no-member
632
+ return f"({self.root_name} )"
623
633
 
624
634
  ami_params_out = property(
625
635
  _getAmiParamsOut, doc="The AMI parameter string returned by either `AMI_Init()` or `AMI_GetWave()`."
@@ -15,7 +15,7 @@ import numpy as np
15
15
  from numpy.typing import NDArray
16
16
  from parsec import ParseError, generate, many, regex, string
17
17
  from traits.api import Bool, Enum, HasTraits, Range, Trait, TraitType
18
- from traitsui.api import Group, HFlow, Item, VGroup, View
18
+ from traitsui.api import Group, HGroup, Item, VGroup, View
19
19
  from traitsui.menu import ModalButtons
20
20
 
21
21
  from .model import AMIModelInitializer
@@ -360,7 +360,8 @@ number = lexeme(regex(r"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?"))
360
360
  integ = lexeme(regex(r"[-+]?[0-9]+"))
361
361
  nat = lexeme(regex(r"[0-9]+"))
362
362
  # tap_ix = (integ << whitespace).parsecmap(int2tap) # Doesn't work!
363
- tap_ix = integ.parsecmap(int2tap)
363
+ # tap_ix = integ.parsecmap(int2tap) # Breaks parsing of node names that begin with a numeral!
364
+ tap_ix = integ.parsecmap(int2tap) << whitespace
364
365
  symbol = lexeme(regex(r"[0-9a-zA-Z_][^\s()]*"))
365
366
  true = lexeme(string("True")).result(True)
366
367
  false = lexeme(string("False")).result(False)
@@ -578,7 +579,7 @@ def parse_ami_param_defs(file_contents: str) -> tuple[ParseErrMsg, dict[str, Any
578
579
  "Model_Specific": model_specific_dict}})
579
580
 
580
581
 
581
- def make_gui(params: ModelSpecificDict) -> tuple[Group, list[TraitType]]:
582
+ def make_gui(params: ModelSpecificDict) -> tuple[Group, list[TraitType]]: # pylint: disable=too-many-locals
582
583
  """
583
584
  Builds top-level ``Group`` and list of ``Trait`` s from AMI parameter dictionary.
584
585
 
@@ -594,18 +595,53 @@ def make_gui(params: ModelSpecificDict) -> tuple[Group, list[TraitType]]:
594
595
  Notes:
595
596
  1. The dictionary passed through ``params`` may have sub-dictionaries.
596
597
  The window layout will reflect this nesting.
598
+ 2. Some AMI files are written to encode the AMI parameter hierarchy
599
+ via some parameter naming scheme. This function makes a primitive attempt
600
+ to decode one particular example of this: ``<grp>_<param>``.
597
601
  """
598
602
 
599
603
  gui_items: list[Item | Group] = []
600
604
  new_traits: list[tuple[str, TraitType]] = []
601
- pnames = list(params.keys())
602
- pnames.sort()
603
- for pname in pnames:
604
- gui_item, new_trait = make_gui_items(pname, params[pname])
605
- gui_items.extend(gui_item)
606
- new_traits.extend(new_trait)
607
605
 
608
- return (HFlow(*gui_items), new_traits)
606
+ # Place parameters with a common prefix in their names,
607
+ # but no pre-existing enclosing group, in a ``VGroup``.
608
+ # - Generate grouped parameter names and list of unique group names.
609
+ pnames = list(params.keys())
610
+ pnames_split = list(map(lambda n: n.split('_'), pnames))
611
+ group_names = list(map(lambda xs: xs[0], pnames_split))
612
+ grouped_pnames = list(zip(pnames, group_names))
613
+ # The following doesn't preserve the parameter ordering of the AMI file!
614
+ # for group_name in set(group_names): # Iterate over unique group names.
615
+ unique_group_names = []
616
+ for group_name in group_names:
617
+ if group_name not in unique_group_names:
618
+ unique_group_names.append(group_name)
619
+ # - Process all parameters, trapping those from a non-explicit group for special processing.
620
+ for group_name in unique_group_names:
621
+ pnames_in_group = [pname for pname, grp_name in grouped_pnames if grp_name == group_name]
622
+ if len(pnames_in_group) > 1:
623
+ _gui_items: list[Item | Group] = []
624
+ for pname in pnames_in_group:
625
+ gui_item, new_trait = make_gui_items(pname, params[pname])
626
+ _gui_items.extend(gui_item)
627
+ new_traits.extend(new_trait)
628
+ gui_items.append(VGroup(*_gui_items, label=group_name, show_border=True))
629
+ else:
630
+ pname = pnames_in_group[0]
631
+ gui_item, new_trait = make_gui_items(pname, params[pname])
632
+ gui_items.extend(gui_item)
633
+ new_traits.extend(new_trait)
634
+
635
+ # Finally, split into two rows if necessary.
636
+ MAX_ITEMS_PER_ROW = 8
637
+ if len(gui_items) > MAX_ITEMS_PER_ROW:
638
+ rslt_grp = VGroup(
639
+ HGroup(*(gui_items[:MAX_ITEMS_PER_ROW])),
640
+ HGroup(*(gui_items[MAX_ITEMS_PER_ROW:])))
641
+ else:
642
+ rslt_grp = HGroup(*gui_items)
643
+
644
+ return (rslt_grp, new_traits)
609
645
 
610
646
 
611
647
  def make_gui_items( # pylint: disable=too-many-locals,too-many-branches
@@ -139,7 +139,7 @@ class IBISModel(HasTraits): # pylint: disable=too-many-instance-attributes
139
139
 
140
140
  # Add Traits for various attributes found in the IBIS file.
141
141
  self.add_trait("comp", Trait(list(components)[0], components)) # Doesn't need a custom mapper, because
142
- self.pins = self.get_pins() # the thing above it (file) can't change.
142
+ self.pins = self.get_pins() # the thing above it (file) can't change.
143
143
  self.add_trait("pin", Enum(self.pins[0], values="pins"))
144
144
  (mname, _) = self.pin_
145
145
  self.models = self.get_models(mname)
@@ -191,7 +191,8 @@ class IBISModel(HasTraits): # pylint: disable=too-many-instance-attributes
191
191
 
192
192
  def __call__(self):
193
193
  """Present a customized GUI to the user, for model selection, etc."""
194
- self.edit_traits(kind="livemodal")
194
+ # self.configure_traits(kind='modal') # Waiting for Enthought/Traits PR1841 to be accepted.
195
+ self.configure_traits()
195
196
 
196
197
  # Logger & Pop-up
197
198
  def log(self, msg, alert=False):
@@ -228,7 +229,7 @@ class IBISModel(HasTraits): # pylint: disable=too-many-instance-attributes
228
229
  resizable=False,
229
230
  buttons=ModalButtons,
230
231
  title="PyBERT IBIS Model Selector",
231
- id="pybert.pybert_ami.model_selector",
232
+ id="pybert_ibis_model_selector",
232
233
  )
233
234
  return view
234
235
 
@@ -91,8 +91,9 @@ def word(p):
91
91
  @generate("remainder of line")
92
92
  def rest_line():
93
93
  "Parse remainder of line."
94
- chars = yield many(none_of("\n\r")) << ignore # So that we still function as a lexeme.
95
- return "".join(chars)
94
+ chars = yield many(none_of("[\n\r")) << ignore # So that we still function as a lexeme.
95
+ rslt = "".join(chars)
96
+ return rslt
96
97
 
97
98
 
98
99
  skip_line = lexeme(rest_line).result("(Skipped.)")
@@ -162,9 +163,6 @@ def ratio():
162
163
  return None
163
164
 
164
165
 
165
- ramp_line = string("dV/dt_") >> ((string("r").result("rising") | string("f").result("falling")) << ignore) + times(
166
- ratio, 1, 3
167
- )
168
166
  ex_line = (
169
167
  word(string("Executable"))
170
168
  >> ( # noqa: W503
@@ -309,11 +307,21 @@ def end():
309
307
 
310
308
 
311
309
  # [Model]
310
+ load_line = string("R_load = ") >> number
311
+
312
+ ramp_line = string("dV/dt_") >> ((string("r").result("rising") | string("f").result("falling")) << ignore) + times(
313
+ ratio, 1, 3
314
+ )
315
+
316
+
312
317
  @generate("[Ramp]")
313
318
  def ramp():
314
319
  "Parse [Ramp]."
320
+ load = yield optional(load_line, 50)
315
321
  lines = yield count(ramp_line, 2).desc("Two ramp_lines")
316
- return dict(lines) # .update(dict(params))
322
+ rslt = dict(lines)
323
+ rslt.update({"load": load})
324
+ return rslt
317
325
 
318
326
 
319
327
  Model_keywords = {
@@ -348,6 +356,17 @@ def model():
348
356
  rlc = lexeme(string("R_pin") | string("L_pin") | string("C_pin"))
349
357
 
350
358
 
359
+ @generate("[Manufacturer]")
360
+ def manufacturer():
361
+ "Parse manufacturer."
362
+ rslt = yield rest_line
363
+ if not rslt:
364
+ rslt = "(n/a)"
365
+ if DEBUG:
366
+ print(f"Manufacturer: {rslt}", flush=True)
367
+ return rslt
368
+
369
+
351
370
  @generate("[Package]")
352
371
  def package():
353
372
  "Parse package RLC values."
@@ -392,7 +411,7 @@ def pins():
392
411
 
393
412
 
394
413
  Component_keywords = {
395
- "manufacturer": rest_line,
414
+ "manufacturer": manufacturer,
396
415
  "package": package,
397
416
  "pin": pins,
398
417
  "diff_pin": skip_keyword,
@@ -495,6 +514,9 @@ def parse_ibis_file(ibis_file_contents_str, debug=False):
495
514
  Dictionary containing keyword definitions (empty upon failure).
496
515
  """
497
516
 
517
+ global DEBUG # pylint: disable=W0603
518
+ DEBUG = debug
519
+
498
520
  try:
499
521
  nodes = ibis_file.parse_strict(ibis_file_contents_str) # Parse must consume the entire file.
500
522
  if debug:
@@ -13,6 +13,8 @@ Copyright (c) 2025 David Banas; all rights reserved World wide.
13
13
  import os
14
14
  from pathlib import Path
15
15
  import subprocess
16
+ import sys
17
+ import shlex
16
18
  from time import time
17
19
  from typing import Any, Optional
18
20
 
@@ -118,10 +120,12 @@ def run_notebook(
118
120
  @click.argument("bit_rate", type=float)
119
121
  @click.version_option(package_name="PyIBIS-AMI")
120
122
  # pylint: disable=too-many-arguments,too-many-positional-arguments
121
- def main(notebook, out_dir, params, ibis_file, bit_rate,
123
+ def main(notebook, out_dir, params, ibis_file, bit_rate, # pylint: disable=too-many-locals
122
124
  debug, is_tx, nspui, no_nspui_swp, nbits,
123
125
  plot_t_max, f_max, f_step, fig_x, fig_y):
124
126
  "Run a *Jupyter* notebook on an IBIS-AMI model file."
127
+ arguments_list = sys.argv
128
+ full_command_line = "run-notebook " + " ".join(shlex.quote(arg) for arg in arguments_list[1:])
125
129
  run_notebook(
126
130
  Path(ibis_file).resolve(), Path(notebook).resolve(),
127
131
  out_dir=Path(out_dir).resolve(),
@@ -140,6 +144,7 @@ def main(notebook, out_dir, params, ibis_file, bit_rate,
140
144
  'fig_y': fig_y,
141
145
  'bit_rate': bit_rate,
142
146
  'params': params,
147
+ 'full_command_line': full_command_line,
143
148
  })
144
149
 
145
150
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes