cicwave 0.7.1__tar.gz → 0.7.2__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 (23) hide show
  1. {cicwave-0.7.1/src/cicwave.egg-info → cicwave-0.7.2}/PKG-INFO +1 -1
  2. {cicwave-0.7.1 → cicwave-0.7.2}/pyproject.toml +1 -1
  3. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/cli.py +14 -3
  4. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/wave_pg.py +53 -7
  5. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/wavefiles.py +12 -0
  6. {cicwave-0.7.1 → cicwave-0.7.2/src/cicwave.egg-info}/PKG-INFO +1 -1
  7. {cicwave-0.7.1 → cicwave-0.7.2}/LICENSE +0 -0
  8. {cicwave-0.7.1 → cicwave-0.7.2}/README.md +0 -0
  9. {cicwave-0.7.1 → cicwave-0.7.2}/setup.cfg +0 -0
  10. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/__init__.py +0 -0
  11. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/analysis.py +0 -0
  12. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/apisource.py +0 -0
  13. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/command.py +0 -0
  14. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/mcp_server.py +0 -0
  15. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/ngraw.py +0 -0
  16. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/pivot.py +0 -0
  17. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/stdf.py +0 -0
  18. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/theme.py +0 -0
  19. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/SOURCES.txt +0 -0
  20. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/dependency_links.txt +0 -0
  21. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/entry_points.txt +0 -0
  22. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/requires.txt +0 -0
  23. {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cicwave
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: Advanced waveform viewer with PyQtGraph backend
5
5
  Author-email: Carsten Wulff <carsten@wulff.no>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cicwave"
7
- version = "0.7.1"
7
+ version = "0.7.2"
8
8
  authors = [
9
9
  { name="Carsten Wulff", email="carsten@wulff.no" },
10
10
  ]
@@ -119,6 +119,16 @@ def _spec_path_of(path):
119
119
  return path.lower()
120
120
 
121
121
 
122
+ def _spec_ref(path):
123
+ """How a spec is recorded for a session: absolute path, or URL as-is.
124
+
125
+ ``os.path.abspath`` on an ``http://`` URL yields a local path that
126
+ names nothing, so a session written from a URL spec could not be
127
+ read back. Mirrors what ``PgWaveWindow.openSourceSpec`` does.
128
+ """
129
+ return path if _URL_RE.match(path) else os.path.abspath(path)
130
+
131
+
122
132
  def _is_source_spec_file(path):
123
133
  """True for a YAML/JSON pivot spec that fetches its own data.
124
134
 
@@ -210,7 +220,7 @@ def _run_catalog_spec(pivot_spec, spec, x, pivot_info_flag,
210
220
  c.win.applySession(session_path)
211
221
  c.win.browser.openLazyFrame(
212
222
  os.path.basename(pivot_spec), groups, catalog.load_group,
213
- pivot_spec_path=os.path.abspath(pivot_spec))
223
+ pivot_spec_path=_spec_ref(pivot_spec))
214
224
  c.run()
215
225
 
216
226
 
@@ -320,7 +330,7 @@ def _run_wave_pg(files, x, sheet, pivot_spec=None,
320
330
  name = "pivot(%s)" % os.path.basename(f)
321
331
  c.openDataFrame(
322
332
  pivoted, name,
323
- pivot_spec_path=os.path.abspath(pivot_spec),
333
+ pivot_spec_path=_spec_ref(pivot_spec),
324
334
  original_path=(
325
335
  f if _URL_RE.match(f) else os.path.abspath(f)),
326
336
  source_spec=from_source)
@@ -393,7 +403,8 @@ def main(files, globs, x, sheet, fmt, pivot, pivot_info, session, export,
393
403
  advanced visualization of simulation data.
394
404
 
395
405
  Supports: .raw, .csv, .tsv, .xlsx, .json, .parquet, .feather, .npz,
396
- .h5, .pkl, .vcd (digital), .iqvsa (LitePoint), .stdf (ATE), and more.
406
+ .h5, .pkl, .vcd (digital), .iqvsa (LitePoint), .stdf (ATE),
407
+ .u32 (raw counter captures), and more.
397
408
 
398
409
  \b
399
410
  URL sources:
@@ -4021,6 +4021,14 @@ class PgWaveWindow(QMainWindow):
4021
4021
  if getattr(wave, 'show_as_digital', False):
4022
4022
  wave_dict['digital'] = True
4023
4023
  wave_dict['digital_format'] = wave.digital_format
4024
+ #- A catalog's waves exist only once their group has been
4025
+ #- fetched, so the session has to say which one to ask
4026
+ #- for; without it the wave is simply not found on load.
4027
+ group = None
4028
+ if hasattr(wave.wfile, 'groupOf'):
4029
+ group = wave.wfile.groupOf(wave.key)
4030
+ if group is not None:
4031
+ wave_dict['group'] = group
4024
4032
  waves.append(wave_dict)
4025
4033
  plot_dict = {'name': tab_name, 'waves': waves}
4026
4034
  if widget.custom_xlabel:
@@ -4067,11 +4075,18 @@ class PgWaveWindow(QMainWindow):
4067
4075
  return
4068
4076
  session = self._build_session()
4069
4077
  session_dir = os.path.dirname(os.path.abspath(fname))
4078
+
4079
+ def _portable(ref):
4080
+ #- A URL is already portable; only a local path is worth
4081
+ #- rewriting relative to where the session is being saved.
4082
+ return ref if _is_url(ref) else os.path.relpath(ref, session_dir)
4083
+
4070
4084
  for fe in session.get('files', []):
4071
- if not _is_url(fe['path']):
4072
- fe['path'] = os.path.relpath(fe['path'], session_dir)
4073
- if 'pivot' in fe:
4074
- fe['pivot'] = os.path.relpath(fe['pivot'], session_dir)
4085
+ #- A spec that fetches its own data is stored as 'source'
4086
+ #- and has no 'path' at all, so key by what is there.
4087
+ for key in ('path', 'source', 'pivot'):
4088
+ if key in fe:
4089
+ fe[key] = _portable(fe[key])
4075
4090
 
4076
4091
  with open(fname, 'w') as fh:
4077
4092
  yaml.dump(session, fh, default_flow_style=False, sort_keys=False)
@@ -4101,15 +4116,29 @@ class PgWaveWindow(QMainWindow):
4101
4116
  fpath = os.path.normpath(os.path.join(session_dir, fpath))
4102
4117
  fmt = fe.get('format')
4103
4118
  pivot_path = fpath if from_source else fe.get('pivot')
4104
- if pivot_path and not os.path.isabs(pivot_path):
4119
+ if (pivot_path and not _is_url(pivot_path)
4120
+ and not os.path.isabs(pivot_path)):
4105
4121
  pivot_path = os.path.normpath(
4106
4122
  os.path.join(session_dir, pivot_path))
4107
4123
 
4108
4124
  try:
4109
4125
  if pivot_path:
4110
- from .apisource import load_flat_frame
4126
+ from .apisource import (
4127
+ LazyCatalog, has_catalog, load_flat_frame)
4111
4128
  from .pivot import load_spec, apply_pivot
4112
4129
  spec = load_spec(pivot_path)
4130
+ spec_ref = (pivot_path if _is_url(pivot_path)
4131
+ else os.path.abspath(pivot_path))
4132
+ if from_source and has_catalog(spec):
4133
+ #- Same as opening the spec directly: the groups
4134
+ #- are named now and each is fetched when it is
4135
+ #- plotted. Fetching the lot is what a catalog
4136
+ #- exists to avoid, session or not.
4137
+ catalog = LazyCatalog(spec)
4138
+ self.browser.openLazyFrame(
4139
+ os.path.basename(fpath), catalog.load(),
4140
+ catalog.load_group, pivot_spec_path=spec_ref)
4141
+ continue
4113
4142
  xaxis = self.browser.xaxis or spec.get('columns', '')
4114
4143
  if not self.browser.xaxis and spec.get('columns'):
4115
4144
  self.browser.xaxis = spec['columns']
@@ -4120,7 +4149,7 @@ class PgWaveWindow(QMainWindow):
4120
4149
  name = "pivot(%s)" % os.path.basename(fpath)
4121
4150
  self.browser.openDataFrame(
4122
4151
  pivoted, name,
4123
- pivot_spec_path=os.path.abspath(pivot_path),
4152
+ pivot_spec_path=spec_ref,
4124
4153
  original_path=(fpath if _is_url(fpath)
4125
4154
  else os.path.abspath(fpath)),
4126
4155
  source_spec=from_source)
@@ -4145,6 +4174,10 @@ class PgWaveWindow(QMainWindow):
4145
4174
  for wd in pd.get('waves', []):
4146
4175
  wave_name = wd.get('name')
4147
4176
  style = wd.get('style', 'Lines')
4177
+ #- A wave from a catalog group is not there until that
4178
+ #- group is fetched; one request, not the whole catalog.
4179
+ if wd.get('group'):
4180
+ self._fetch_session_group(wd['group'])
4148
4181
  wave = self._find_wave(wave_name)
4149
4182
  if wave:
4150
4183
  bits = wd.get('twos_complement_bits')
@@ -4193,6 +4226,19 @@ class PgWaveWindow(QMainWindow):
4193
4226
  xv = math.log10(xv)
4194
4227
  p._set_cursor(which[-1], xv)
4195
4228
 
4229
+ def _fetch_session_group(self, group):
4230
+ """Fetch a catalog group a session's plot needs, if still pending."""
4231
+ for wf in self.browser.files.values():
4232
+ if hasattr(wf, 'isPendingGroup') and wf.isPendingGroup(group):
4233
+ try:
4234
+ wf.loadGroup(group)
4235
+ except Exception as e:
4236
+ QMessageBox.critical(
4237
+ self, "Fetch",
4238
+ "Failed to fetch %s:\n%s" % (group, e))
4239
+ self.browser._fill_waves()
4240
+ return
4241
+
4196
4242
  def _find_wave(self, name):
4197
4243
  """Look up a PgWave by column name across all loaded files."""
4198
4244
  for fkey, wf in self.browser.files.items():
@@ -470,6 +470,9 @@ class WaveFile():
470
470
  self._group_loader = group_loader
471
471
  self._pending_groups = list(groups)
472
472
  self._loaded_groups = set()
473
+ #- Which group produced each wave, so a session can name the one
474
+ #- group it has to fetch to get a plotted wave back.
475
+ self._group_of = dict()
473
476
  self._remote = (not self._virtual) and _is_url(fname)
474
477
  self._remote_bytes = None
475
478
  self._remote_content_type = None
@@ -1056,10 +1059,19 @@ class WaveFile():
1056
1059
  if c not in x_columns
1057
1060
  and (self._df is None or c not in self._df.columns)]
1058
1061
  self._merge_group_frame(frame)
1062
+ #- Every column the fetch brought in, not just the plottable
1063
+ #- ones: a session may name the group's x column too, and it is
1064
+ #- just as absent until the group is fetched.
1065
+ for c in frame.columns:
1066
+ self._group_of.setdefault(c, name)
1059
1067
  for wave in list(self.waves.values()):
1060
1068
  wave.reload()
1061
1069
  return added
1062
1070
 
1071
+ def groupOf(self, name):
1072
+ """The catalog group *name* came from, or None if it stands alone."""
1073
+ return self._group_of.get(name)
1074
+
1063
1075
  def _merge_group_frame(self, frame):
1064
1076
  """Append a fetched group's rows, widening the frame as needed.
1065
1077
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cicwave
3
- Version: 0.7.1
3
+ Version: 0.7.2
4
4
  Summary: Advanced waveform viewer with PyQtGraph backend
5
5
  Author-email: Carsten Wulff <carsten@wulff.no>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes