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.
- {cicwave-0.7.1/src/cicwave.egg-info → cicwave-0.7.2}/PKG-INFO +1 -1
- {cicwave-0.7.1 → cicwave-0.7.2}/pyproject.toml +1 -1
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/cli.py +14 -3
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/wave_pg.py +53 -7
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/wavefiles.py +12 -0
- {cicwave-0.7.1 → cicwave-0.7.2/src/cicwave.egg-info}/PKG-INFO +1 -1
- {cicwave-0.7.1 → cicwave-0.7.2}/LICENSE +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/README.md +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/setup.cfg +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/__init__.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/analysis.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/apisource.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/command.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/mcp_server.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/ngraw.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/pivot.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/stdf.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave/theme.py +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/SOURCES.txt +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/dependency_links.txt +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/entry_points.txt +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/requires.txt +0 -0
- {cicwave-0.7.1 → cicwave-0.7.2}/src/cicwave.egg-info/top_level.txt +0 -0
|
@@ -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=
|
|
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=
|
|
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),
|
|
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
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
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
|
|
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
|
|
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=
|
|
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
|
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|