docworkspace 0.2.8__tar.gz → 0.2.9__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 (26) hide show
  1. {docworkspace-0.2.8 → docworkspace-0.2.9}/PKG-INFO +1 -1
  2. {docworkspace-0.2.8 → docworkspace-0.2.9}/pyproject.toml +1 -1
  3. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/__init__.py +1 -1
  4. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/workspace/analysis.py +14 -1
  5. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_workspace.py +32 -0
  6. {docworkspace-0.2.8 → docworkspace-0.2.9}/uv.lock +1 -1
  7. {docworkspace-0.2.8 → docworkspace-0.2.9}/.github/workflows/ci.yml +0 -0
  8. {docworkspace-0.2.8 → docworkspace-0.2.9}/.github/workflows/release.yml +0 -0
  9. {docworkspace-0.2.8 → docworkspace-0.2.9}/.gitignore +0 -0
  10. {docworkspace-0.2.8 → docworkspace-0.2.9}/PUBLISH.md +0 -0
  11. {docworkspace-0.2.8 → docworkspace-0.2.9}/README.md +0 -0
  12. {docworkspace-0.2.8 → docworkspace-0.2.9}/pytest.ini +0 -0
  13. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/node/__init__.py +0 -0
  14. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/node/core.py +0 -0
  15. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/node/io.py +0 -0
  16. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/workspace/__init__.py +0 -0
  17. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/workspace/core.py +0 -0
  18. {docworkspace-0.2.8 → docworkspace-0.2.9}/src/docworkspace/workspace/io.py +0 -0
  19. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/conftest.py +0 -0
  20. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_fastapi_integration.py +0 -0
  21. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_node.py +0 -0
  22. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_node_io.py +0 -0
  23. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_simple_operations.py +0 -0
  24. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_workspace_io_absolute_paths.py +0 -0
  25. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_workspace_serialization_types.py +0 -0
  26. {docworkspace-0.2.8 → docworkspace-0.2.9}/tests/test_workspace_shim.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docworkspace
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: A workspace library for managing Polars dataframes with parent-child relationships and lazy evaluation
5
5
  Requires-Python: >=3.14
6
6
  Requires-Dist: polars-text>=0.1.6
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "docworkspace"
3
- version = "0.2.8"
3
+ version = "0.2.9"
4
4
  description = "A workspace library for managing Polars dataframes with parent-child relationships and lazy evaluation"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.14"
@@ -7,5 +7,5 @@ serialization, analysis, and graph helpers in dedicated submodules.
7
7
  from .node import DerivedColumnMeta, Node # package exposing Node
8
8
  from .workspace import Workspace # shim -> workspace.core.Workspace
9
9
 
10
- __version__ = "0.2.8"
10
+ __version__ = "0.2.9"
11
11
  __all__ = ["Workspace", "Node", "DerivedColumnMeta"]
@@ -34,7 +34,20 @@ def graph_json(workspace: "Workspace") -> Dict[str, object]:
34
34
  edges_payload: List[Dict[str, str]] = []
35
35
 
36
36
  for node in workspace.nodes.values():
37
- nodes_payload.append(node.info())
37
+ try:
38
+ nodes_payload.append(node.info())
39
+ except Exception as exc:
40
+ # Per-node fallback: one broken node (e.g. missing source file,
41
+ # undeserializable lazy plan) must not take down the whole graph.
42
+ nodes_payload.append(
43
+ {
44
+ "id": node.id,
45
+ "name": getattr(node, "name", node.id),
46
+ "operation": getattr(node, "operation", "unknown"),
47
+ "child_ids": [c.id for c in getattr(node, "children", [])],
48
+ "error": f"{type(exc).__name__}: {exc}",
49
+ }
50
+ )
38
51
 
39
52
  for child in node.children:
40
53
  edges_payload.append({"source": node.id, "target": child.id})
@@ -431,6 +431,38 @@ class TestWorkspaceGraphOperations:
431
431
  for field in required_fields:
432
432
  assert field in node_data
433
433
 
434
+ def test_workspace_graph_survives_broken_node_info(self):
435
+ """One node failing `info()` must not break the whole graph payload."""
436
+ workspace = Workspace("graph_resilience")
437
+ good_node = Node(
438
+ data=pl.DataFrame({"x": [1, 2, 3]}).lazy(),
439
+ name="good",
440
+ workspace=workspace,
441
+ )
442
+ bad_node = Node(
443
+ data=pl.DataFrame({"y": [4, 5]}).lazy(),
444
+ name="bad",
445
+ workspace=workspace,
446
+ )
447
+
448
+ # Simulate a broken lazy plan / missing source file: info() raises.
449
+ def _boom() -> dict:
450
+ raise RuntimeError("source parquet missing")
451
+
452
+ bad_node.info = _boom # type: ignore[method-assign]
453
+
454
+ graph_data = workspace.graph_json()
455
+
456
+ nodes_by_id = {n["id"]: n for n in graph_data["nodes"]}
457
+ assert good_node.id in nodes_by_id
458
+ assert bad_node.id in nodes_by_id
459
+ # Healthy node still carries its real info.
460
+ assert "shape" in nodes_by_id[good_node.id]
461
+ # Broken node carries an error envelope plus identity fields.
462
+ assert nodes_by_id[bad_node.id]["name"] == "bad"
463
+ assert "error" in nodes_by_id[bad_node.id]
464
+ assert "RuntimeError" in nodes_by_id[bad_node.id]["error"]
465
+
434
466
  def test_workspace_with_initial_data_loading(self):
435
467
  """Test explicit initial data loading after creating an empty workspace."""
436
468
  # Test with DataFrame converted to LazyFrame before creating a Node.
@@ -13,7 +13,7 @@ wheels = [
13
13
 
14
14
  [[package]]
15
15
  name = "docworkspace"
16
- version = "0.2.8"
16
+ version = "0.2.9"
17
17
  source = { editable = "." }
18
18
  dependencies = [
19
19
  { name = "polars-text" },
File without changes
File without changes
File without changes
File without changes