scistackplotdb 0.1.31__tar.gz → 0.1.33__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: scistackplotdb
3
- Version: 0.1.31
3
+ Version: 0.1.33
4
4
  Summary: scidb-backed plotting: load variables into long tables and plot them with scistackplot
5
5
  Author: SciStack Contributors
6
6
  License-Expression: MIT
@@ -17,8 +17,10 @@ Classifier: Programming Language :: Python :: 3.13
17
17
  Classifier: Topic :: Scientific/Engineering :: Visualization
18
18
  Classifier: Typing :: Typed
19
19
  Requires-Python: >=3.10
20
- Requires-Dist: scistack-db>=0.1.0
21
- Requires-Dist: scistackplot>=0.1.0
20
+ Requires-Dist: sciduckdb==0.1.33
21
+ Requires-Dist: scistack-db==0.1.33
22
+ Requires-Dist: scistacklog==0.1.33
23
+ Requires-Dist: scistackplot==0.1.33
22
24
  Provides-Extra: dev
23
25
  Requires-Dist: matplotlib>=3.6; extra == 'dev'
24
26
  Requires-Dist: pytest-cov>=4.0; extra == 'dev'
@@ -1,14 +1,22 @@
1
1
  [build-system]
2
- requires = ["hatchling", "hatch-vcs"]
2
+ requires = ["hatchling", "hatch-vcs", "hatch-dependency-coversion==0.0.1a4"]
3
3
  build-backend = "hatchling.build"
4
4
 
5
5
  [tool.hatch.version]
6
6
  source = "vcs"
7
7
  raw-options = { search_parent_directories = true, local_scheme = "no-local-version" }
8
8
 
9
+ # Sibling SciStack packages are pinned to EXACTLY this build's version at build
10
+ # time (lockstep releases), so [project] dependencies lists them unversioned. The
11
+ # extra "dynamic" entry is what makes hatchling run the hook. Every sibling in
12
+ # dependencies must be named here: CI's build job fails a wheel whose internal
13
+ # dependency is not "==<its own version>".
14
+ [tool.hatch.metadata.hooks.dependency-coversion]
15
+ override-versions-of = ["scistackplot", "scistack-db", "sciduckdb", "scistacklog"]
16
+
9
17
  [project]
10
18
  name = "scistackplotdb"
11
- dynamic = ["version"]
19
+ dynamic = ["version", "dependency-coversioning"]
12
20
  description = "scidb-backed plotting: load variables into long tables and plot them with scistackplot"
13
21
  readme = "README.md"
14
22
  license = "MIT"
@@ -37,8 +45,10 @@ classifiers = [
37
45
  "Typing :: Typed",
38
46
  ]
39
47
  dependencies = [
40
- "scistackplot>=0.1.0",
41
- "scistack-db>=0.1.0",
48
+ "scistackplot",
49
+ "scistack-db",
50
+ "sciduckdb",
51
+ "scistacklog",
42
52
  ]
43
53
 
44
54
  [project.optional-dependencies]
@@ -352,3 +352,41 @@ class VersionedStore:
352
352
  )
353
353
  return {}
354
354
  return envelope
355
+
356
+ # ---- copying a whole store (project bundles) ------------------------
357
+
358
+ def _all_columns(self) -> list[str]:
359
+ scope = [self.scope_column] if self.scope_column else []
360
+ return [self.id_column, *scope, "name", "version", "saved_at", "hidden", "envelope_json"]
361
+
362
+ def dump_rows(self, db) -> list[dict]:
363
+ """Every row, every version, hidden ones too, as plain dicts: what a
364
+ project bundle carries (``scistackplotdb.bundle_section``). Nothing
365
+ is filtered -- a copy keeps the history the original kept."""
366
+ if not self.table_exists(db):
367
+ return []
368
+ cols = self._all_columns()
369
+ rows = db._duck._fetchall(
370
+ f"SELECT {', '.join(cols)} FROM {self.table} ORDER BY {self.id_column}, version"
371
+ )
372
+ Log.info("[%s] dump_rows: %d row(s)", self.tag, len(rows), layer=LAYER)
373
+ return [dict(zip(cols, row)) for row in rows]
374
+
375
+ def load_rows(self, db, rows: list[dict]) -> int:
376
+ """Insert *rows* (from :meth:`dump_rows`) verbatim, ids and versions
377
+ kept; a row already present is left as it is. Returns rows inserted."""
378
+ if not rows:
379
+ return 0
380
+ self.ensure_table(db)
381
+ cols = self._all_columns()
382
+ before = db._duck._fetchone(f"SELECT count(*) FROM {self.table}")[0]
383
+ for row in rows:
384
+ db._duck._execute(
385
+ f"INSERT INTO {self.table} ({', '.join(cols)}) "
386
+ f"VALUES ({', '.join('?' for _ in cols)}) ON CONFLICT DO NOTHING",
387
+ [row.get(c) for c in cols],
388
+ )
389
+ after = db._duck._fetchone(f"SELECT count(*) FROM {self.table}")[0]
390
+ Log.info("[%s] load_rows: %d of %d row(s) inserted", self.tag, after - before,
391
+ len(rows), layer=LAYER)
392
+ return after - before
@@ -0,0 +1,59 @@
1
+ """
2
+ The ``plots`` section of a project bundle (``scidb.bundle``): saved plots and
3
+ plot presets, copied row for row.
4
+
5
+ Both stores key nothing by canvas ids or database record ids -- a saved plot
6
+ is named per VARIABLE, a preset per project -- so a verbatim copy into the
7
+ new project is the whole story: ids, versions and hidden rows kept, exactly
8
+ as the exporting project had them (``VersionedStore.dump_rows`` /
9
+ ``load_rows``, the one owner of the table's columns).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+
16
+ from scistacklog import Log
17
+
18
+ from . import presets, saved
19
+
20
+ LAYER = "scistackplotdb"
21
+
22
+ _STORES = {"saved_plots.json": saved.STORE, "presets.json": presets.STORE}
23
+
24
+
25
+ class PlotsSection:
26
+ name = "plots"
27
+
28
+ def export(self, ctx) -> "dict[str, bytes]":
29
+ files: dict[str, bytes] = {}
30
+ for filename, store in _STORES.items():
31
+ rows = store.dump_rows(ctx.db)
32
+ if rows:
33
+ files[filename] = json.dumps(rows, indent=2, default=str).encode("utf-8")
34
+ Log.info("[bundle_section] plots export: %s", sorted(files), layer=LAYER)
35
+ return files
36
+
37
+ def import_(self, ctx, files: "dict[str, bytes]") -> dict:
38
+ report = {}
39
+ key_map = getattr(ctx, "key_map", None)
40
+ for filename, store in _STORES.items():
41
+ if filename in files:
42
+ rows = json.loads(files[filename].decode("utf-8"))
43
+ if key_map is not None and not key_map.is_identity:
44
+ rows = [_remap_row(row, store, key_map, ctx.map_report) for row in rows]
45
+ report[store.table] = store.load_rows(ctx.db, rows)
46
+ Log.info("[bundle_section] plots import: %s", report, layer=LAYER)
47
+ return report
48
+
49
+
50
+ def _remap_row(row: dict, store, key_map, map_report) -> dict:
51
+ """A saved plot or preset carried into another schema (portability Stage
52
+ 6). A spec names factors in many fields (roles, groups, facets, colours,
53
+ filters, difference bars, ...), so every string EQUAL to an exporter key
54
+ is renamed (``KeyMap.exact_strings``) and the item is flagged for review
55
+ -- a factor that merely equals a key name cannot be told apart."""
56
+ envelope = json.loads(row["envelope_json"])
57
+ where = f"{store.noun} {row.get('name')!r}"
58
+ mapped = key_map.exact_strings(envelope, where, map_report)
59
+ return {**row, "envelope_json": json.dumps(mapped)}