docworkspace 0.2.2__tar.gz → 0.2.4__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.
- {docworkspace-0.2.2 → docworkspace-0.2.4}/PKG-INFO +2 -2
- {docworkspace-0.2.2 → docworkspace-0.2.4}/pyproject.toml +2 -2
- {docworkspace-0.2.2 → docworkspace-0.2.4}/src/docworkspace/workspace/__init__.py +2 -0
- docworkspace-0.2.4/src/docworkspace/workspace/io.py +185 -0
- docworkspace-0.2.4/tests/test_workspace_io_absolute_paths.py +128 -0
- docworkspace-0.2.4/uv.lock +125 -0
- docworkspace-0.2.2/src/docworkspace/workspace/io.py +0 -101
- docworkspace-0.2.2/uv.lock +0 -125
- {docworkspace-0.2.2 → docworkspace-0.2.4}/.github/workflows/ci.yml +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/.github/workflows/release.yml +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/.gitignore +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/PUBLISH.md +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/README.md +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/pytest.ini +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/src/docworkspace/__init__.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/src/docworkspace/node/__init__.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/src/docworkspace/node/core.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/src/docworkspace/node/io.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/src/docworkspace/workspace/analysis.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/src/docworkspace/workspace/core.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/conftest.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/test_fastapi_integration.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/test_node.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/test_node_io.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/test_simple_operations.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/test_workspace.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/test_workspace_serialization_types.py +0 -0
- {docworkspace-0.2.2 → docworkspace-0.2.4}/tests/test_workspace_shim.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docworkspace
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: A workspace library for managing Polars dataframes with parent-child relationships and lazy evaluation
|
|
5
5
|
Requires-Python: >=3.14
|
|
6
|
-
Requires-Dist: polars-text>=0.1.
|
|
6
|
+
Requires-Dist: polars-text>=0.1.3
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
|
|
9
9
|
# DocWorkspace
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "docworkspace"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.4"
|
|
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
|
-
dependencies = ["polars-text>=0.1.
|
|
7
|
+
dependencies = ["polars-text>=0.1.3"]
|
|
8
8
|
|
|
9
9
|
[build-system]
|
|
10
10
|
requires = ["hatchling"]
|
|
@@ -8,9 +8,11 @@ analysis and graph views so internal relative imports
|
|
|
8
8
|
from .analysis import graph_json # noqa: F401
|
|
9
9
|
from .analysis import info_json # noqa: F401
|
|
10
10
|
from .core import Workspace # noqa: F401
|
|
11
|
+
from .io import rebase_workspace_sources # noqa: F401
|
|
11
12
|
|
|
12
13
|
__all__ = [
|
|
13
14
|
"Workspace",
|
|
14
15
|
"info_json",
|
|
15
16
|
"graph_json",
|
|
17
|
+
"rebase_workspace_sources",
|
|
16
18
|
]
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Workspace file persistence helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Dict, Iterable, Union
|
|
8
|
+
|
|
9
|
+
from polars_text import list_source_paths, replace_source_paths
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
12
|
+
from .core import Workspace
|
|
13
|
+
|
|
14
|
+
from ..node.io import NODE_DATA_DIR
|
|
15
|
+
from ..node.io import from_dict as node_from_dict
|
|
16
|
+
from ..node.io import to_dict as node_to_dict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _resolve_metadata_path(path: Path) -> Path:
|
|
20
|
+
if path.is_dir():
|
|
21
|
+
return path / "metadata.json"
|
|
22
|
+
if path.suffix.lower() == ".json":
|
|
23
|
+
return path
|
|
24
|
+
raise ValueError("Workspace path must be a directory or a .json file")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _collect_referenced_sources(plbin_paths: Iterable[Path]) -> set[Path]:
|
|
28
|
+
"""Return the set of absolute source paths referenced by every plbin plan."""
|
|
29
|
+
|
|
30
|
+
referenced: set[Path] = set()
|
|
31
|
+
for plbin in plbin_paths:
|
|
32
|
+
for raw in list_source_paths(plbin):
|
|
33
|
+
referenced.add(Path(raw).resolve())
|
|
34
|
+
return referenced
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _rebase_plan_sources(plbin_path: Path, data_dir: Path) -> None:
|
|
38
|
+
"""Rewrite scan source paths inside ``plbin_path`` to ``data_dir`` by basename.
|
|
39
|
+
|
|
40
|
+
Only paths whose basename exists under ``data_dir`` and whose stored value
|
|
41
|
+
differs from the resolved target are rewritten. Paths that already match
|
|
42
|
+
the current workspace layout are left untouched.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
current_sources = list_source_paths(plbin_path)
|
|
46
|
+
if not current_sources:
|
|
47
|
+
return
|
|
48
|
+
|
|
49
|
+
mapping: dict[str, str] = {}
|
|
50
|
+
for old in current_sources:
|
|
51
|
+
target = (data_dir / Path(old).name).resolve()
|
|
52
|
+
if not target.exists():
|
|
53
|
+
continue
|
|
54
|
+
target_str = str(target)
|
|
55
|
+
if old == target_str:
|
|
56
|
+
continue
|
|
57
|
+
mapping[old] = target_str
|
|
58
|
+
|
|
59
|
+
if mapping:
|
|
60
|
+
replace_source_paths(plbin_path, mapping)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _garbage_collect_workspace_data(
|
|
64
|
+
ws_root_dir: Path, nodes_data: list[dict[str, Any]]
|
|
65
|
+
) -> None:
|
|
66
|
+
"""Remove unreferenced parquet and plbin files from the workspace data dir.
|
|
67
|
+
|
|
68
|
+
* Parquet files not referenced by any registered node's plan are deleted.
|
|
69
|
+
* Plbin files whose name does not match a registered node's ``data_path``
|
|
70
|
+
are deleted (they belong to nodes no longer in the workspace).
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
data_dir = ws_root_dir / NODE_DATA_DIR
|
|
74
|
+
if not data_dir.exists() or not data_dir.is_dir():
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
expected_plbin_names = {
|
|
78
|
+
Path(str(node_payload["data_path"])).name for node_payload in nodes_data
|
|
79
|
+
}
|
|
80
|
+
registered_plbins = [
|
|
81
|
+
data_dir / name for name in expected_plbin_names if (data_dir / name).exists()
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
referenced_sources = _collect_referenced_sources(registered_plbins)
|
|
85
|
+
|
|
86
|
+
for candidate in data_dir.iterdir():
|
|
87
|
+
if not candidate.is_file():
|
|
88
|
+
continue
|
|
89
|
+
suffix = candidate.suffix.lower()
|
|
90
|
+
if suffix == ".plbin":
|
|
91
|
+
if candidate.name not in expected_plbin_names:
|
|
92
|
+
candidate.unlink(missing_ok=True)
|
|
93
|
+
elif suffix == ".parquet":
|
|
94
|
+
if candidate.resolve() not in referenced_sources:
|
|
95
|
+
candidate.unlink(missing_ok=True)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def write_workspace(workspace: "Workspace", path: Union[str, Path]) -> None:
|
|
99
|
+
target = _resolve_metadata_path(Path(path))
|
|
100
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
workspace.ws_root_dir = target.parent
|
|
102
|
+
|
|
103
|
+
description = workspace.description
|
|
104
|
+
created_at = workspace.created_at
|
|
105
|
+
modified_at = workspace.modified_at
|
|
106
|
+
|
|
107
|
+
nodes_data: list[dict[str, Any]] = []
|
|
108
|
+
for node in workspace.nodes.values():
|
|
109
|
+
nodes_data.append(node_to_dict(node))
|
|
110
|
+
|
|
111
|
+
workspace_metadata: Dict[str, Any] = {
|
|
112
|
+
"id": workspace.id,
|
|
113
|
+
"name": workspace.name,
|
|
114
|
+
"version": 2,
|
|
115
|
+
"description": description,
|
|
116
|
+
"created_at": created_at,
|
|
117
|
+
"modified_at": modified_at,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
data = {"workspace_metadata": workspace_metadata, "nodes": nodes_data}
|
|
121
|
+
with target.open("w", encoding="utf-8") as f:
|
|
122
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
123
|
+
|
|
124
|
+
_garbage_collect_workspace_data(target.parent, nodes_data)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def read_workspace_metadata(path: Union[str, Path]) -> Dict[str, Any]:
|
|
128
|
+
"""Load and return the workspace metadata dictionary from metadata.json.
|
|
129
|
+
|
|
130
|
+
This helper only reads/parses the JSON metadata file and does not attempt
|
|
131
|
+
to load any node data payload files.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
target = _resolve_metadata_path(Path(path))
|
|
135
|
+
with target.open("r", encoding="utf-8") as f:
|
|
136
|
+
return json.load(f)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def read_workspace(path: Union[str, Path]) -> "Workspace":
|
|
140
|
+
from .core import Workspace
|
|
141
|
+
|
|
142
|
+
target = _resolve_metadata_path(Path(path))
|
|
143
|
+
data = read_workspace_metadata(path)
|
|
144
|
+
|
|
145
|
+
ws_meta = data.get("workspace_metadata", {})
|
|
146
|
+
workspace = Workspace(
|
|
147
|
+
name=ws_meta.get("name", "restored_workspace"),
|
|
148
|
+
ws_root_dir=target.parent,
|
|
149
|
+
)
|
|
150
|
+
workspace.id = ws_meta.get("id", workspace.id)
|
|
151
|
+
workspace.description = ws_meta.get("description", "") or ""
|
|
152
|
+
workspace.created_at = ws_meta.get("created_at")
|
|
153
|
+
workspace.modified_at = ws_meta.get("modified_at")
|
|
154
|
+
|
|
155
|
+
for node_entry in data.get("nodes", []):
|
|
156
|
+
workspace.add_node(node_from_dict(node_entry, workspace=workspace))
|
|
157
|
+
|
|
158
|
+
return workspace
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def rebase_workspace_sources(path: Union[str, Path]) -> None:
|
|
162
|
+
"""Rewrite stale scan source paths inside every plbin listed in ``metadata.json``.
|
|
163
|
+
|
|
164
|
+
Call this **after** the workspace folder has reached its final location on
|
|
165
|
+
disk (i.e. after any rename / move) but **before** deserializing the
|
|
166
|
+
workspace nodes into memory, so that ``LazyFrame.deserialize`` sees paths
|
|
167
|
+
that match the current filesystem.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
target = _resolve_metadata_path(Path(path))
|
|
171
|
+
data = read_workspace_metadata(path)
|
|
172
|
+
data_dir = (target.parent / NODE_DATA_DIR).resolve()
|
|
173
|
+
|
|
174
|
+
for node_entry in data.get("nodes", []):
|
|
175
|
+
plbin_abs = (target.parent / Path(str(node_entry["data_path"]))).resolve()
|
|
176
|
+
if plbin_abs.exists():
|
|
177
|
+
_rebase_plan_sources(plbin_abs, data_dir)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
__all__ = [
|
|
181
|
+
"write_workspace",
|
|
182
|
+
"read_workspace_metadata",
|
|
183
|
+
"read_workspace",
|
|
184
|
+
"rebase_workspace_sources",
|
|
185
|
+
]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Workspace save-time garbage collection and load-time path rebasing."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import shutil
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import cast
|
|
8
|
+
|
|
9
|
+
import polars as pl
|
|
10
|
+
from polars_text import list_source_paths
|
|
11
|
+
|
|
12
|
+
from docworkspace.node import Node
|
|
13
|
+
from docworkspace.workspace import Workspace
|
|
14
|
+
from docworkspace.workspace.io import rebase_workspace_sources
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _make_parquet(path: Path, df: pl.DataFrame) -> None:
|
|
18
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
df.write_parquet(path)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_save_removes_orphan_parquet_and_plbin(tmp_path: Path):
|
|
23
|
+
ws_root = tmp_path / "ws"
|
|
24
|
+
ws_root.mkdir()
|
|
25
|
+
data_dir = ws_root / "data"
|
|
26
|
+
data_dir.mkdir()
|
|
27
|
+
|
|
28
|
+
kept_parquet = data_dir / "kept.parquet"
|
|
29
|
+
_make_parquet(kept_parquet, pl.DataFrame({"a": [1, 2, 3]}))
|
|
30
|
+
|
|
31
|
+
orphan_parquet = data_dir / "orphan.parquet"
|
|
32
|
+
_make_parquet(orphan_parquet, pl.DataFrame({"b": [9]}))
|
|
33
|
+
|
|
34
|
+
orphan_plbin = data_dir / "ghost-node-id.plbin"
|
|
35
|
+
orphan_plbin.write_bytes(b"not-a-real-plan")
|
|
36
|
+
|
|
37
|
+
ws = Workspace(name="gc_ws", ws_root_dir=ws_root)
|
|
38
|
+
lazy = pl.scan_parquet(kept_parquet.resolve())
|
|
39
|
+
ws.add_node(Node(data=lazy, name="kept"))
|
|
40
|
+
|
|
41
|
+
ws.save(ws_root)
|
|
42
|
+
|
|
43
|
+
assert kept_parquet.exists(), "Referenced parquet must be kept"
|
|
44
|
+
assert not orphan_parquet.exists(), "Unreferenced parquet must be deleted"
|
|
45
|
+
assert not orphan_plbin.exists(), "Unregistered plbin must be deleted"
|
|
46
|
+
|
|
47
|
+
plbin_files = list(data_dir.glob("*.plbin"))
|
|
48
|
+
assert len(plbin_files) == 1
|
|
49
|
+
sources = list_source_paths(plbin_files[0])
|
|
50
|
+
assert any(Path(s) == kept_parquet.resolve() for s in sources)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_rebase_then_load_after_workspace_move(tmp_path: Path):
|
|
54
|
+
"""Simulate the real backend flow: rebase plbin files, then load workspace."""
|
|
55
|
+
|
|
56
|
+
original_root = tmp_path / "original"
|
|
57
|
+
original_root.mkdir()
|
|
58
|
+
data_dir = original_root / "data"
|
|
59
|
+
data_dir.mkdir()
|
|
60
|
+
|
|
61
|
+
parquet_path = data_dir / "input.parquet"
|
|
62
|
+
_make_parquet(parquet_path, pl.DataFrame({"x": [10, 20, 30]}))
|
|
63
|
+
|
|
64
|
+
ws = Workspace(name="move_ws", ws_root_dir=original_root)
|
|
65
|
+
lazy = pl.scan_parquet(parquet_path.resolve())
|
|
66
|
+
ws.add_node(Node(data=lazy, name="input"))
|
|
67
|
+
ws.save(original_root)
|
|
68
|
+
|
|
69
|
+
moved_root = tmp_path / "moved"
|
|
70
|
+
shutil.copytree(original_root, moved_root)
|
|
71
|
+
shutil.rmtree(original_root)
|
|
72
|
+
|
|
73
|
+
# Rebase on disk BEFORE loading (mirrors backend set_current_workspace).
|
|
74
|
+
rebase_workspace_sources(moved_root)
|
|
75
|
+
|
|
76
|
+
ws_reloaded = Workspace.load(moved_root)
|
|
77
|
+
assert len(ws_reloaded.nodes) == 1
|
|
78
|
+
node = next(iter(ws_reloaded.nodes.values()))
|
|
79
|
+
|
|
80
|
+
collected = cast(pl.DataFrame, node.data.collect())
|
|
81
|
+
assert collected.to_series().to_list() == [10, 20, 30]
|
|
82
|
+
|
|
83
|
+
plbin_files = list((moved_root / "data").glob("*.plbin"))
|
|
84
|
+
sources = list_source_paths(plbin_files[0])
|
|
85
|
+
moved_parquet = (moved_root / "data" / "input.parquet").resolve()
|
|
86
|
+
assert all(Path(s) == moved_parquet for s in sources)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_rebase_then_rename_then_save_keeps_parquet(tmp_path: Path):
|
|
90
|
+
"""Repro for the reported bug: rename folder after save, then load + unload.
|
|
91
|
+
|
|
92
|
+
Sequence:
|
|
93
|
+
1. Save workspace in folder A.
|
|
94
|
+
2. Rename folder A → B (simulating user rename).
|
|
95
|
+
3. rebase_workspace_sources(B) → plbin paths point at B/data/…
|
|
96
|
+
4. Load workspace from B.
|
|
97
|
+
5. Save workspace back to B.
|
|
98
|
+
6. Parquet referenced by the node must survive GC.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
folder_a = tmp_path / "Test"
|
|
102
|
+
folder_a.mkdir()
|
|
103
|
+
data_dir = folder_a / "data"
|
|
104
|
+
data_dir.mkdir()
|
|
105
|
+
|
|
106
|
+
parquet_path = data_dir / "my_data.parquet"
|
|
107
|
+
_make_parquet(parquet_path, pl.DataFrame({"v": [100, 200]}))
|
|
108
|
+
|
|
109
|
+
ws = Workspace(name="Test", ws_root_dir=folder_a)
|
|
110
|
+
ws.add_node(Node(data=pl.scan_parquet(parquet_path.resolve()), name="node"))
|
|
111
|
+
ws.save(folder_a)
|
|
112
|
+
|
|
113
|
+
# User renames the folder on disk.
|
|
114
|
+
folder_b = tmp_path / "Test_New"
|
|
115
|
+
folder_a.rename(folder_b)
|
|
116
|
+
|
|
117
|
+
# Backend flow: rebase → load → (later) save.
|
|
118
|
+
rebase_workspace_sources(folder_b)
|
|
119
|
+
ws2 = Workspace.load(folder_b)
|
|
120
|
+
assert len(ws2.nodes) == 1
|
|
121
|
+
|
|
122
|
+
# Verify data is accessible after rename.
|
|
123
|
+
node = next(iter(ws2.nodes.values()))
|
|
124
|
+
assert cast(pl.DataFrame, node.data.collect()).to_series().to_list() == [100, 200]
|
|
125
|
+
|
|
126
|
+
# Save (triggers GC) — the parquet must survive.
|
|
127
|
+
ws2.save(folder_b)
|
|
128
|
+
assert (folder_b / "data" / "my_data.parquet").exists()
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
version = 1
|
|
2
|
+
revision = 3
|
|
3
|
+
requires-python = ">=3.14"
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "colorama"
|
|
7
|
+
version = "0.4.6"
|
|
8
|
+
source = { registry = "https://pypi.org/simple" }
|
|
9
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
10
|
+
wheels = [
|
|
11
|
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "docworkspace"
|
|
16
|
+
version = "0.2.4"
|
|
17
|
+
source = { editable = "." }
|
|
18
|
+
dependencies = [
|
|
19
|
+
{ name = "polars-text" },
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[package.dev-dependencies]
|
|
23
|
+
dev = [
|
|
24
|
+
{ name = "pytest" },
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[package.metadata]
|
|
28
|
+
requires-dist = [{ name = "polars-text", specifier = ">=0.1.3" }]
|
|
29
|
+
|
|
30
|
+
[package.metadata.requires-dev]
|
|
31
|
+
dev = [{ name = "pytest", specifier = ">=8.0.0" }]
|
|
32
|
+
|
|
33
|
+
[[package]]
|
|
34
|
+
name = "iniconfig"
|
|
35
|
+
version = "2.3.0"
|
|
36
|
+
source = { registry = "https://pypi.org/simple" }
|
|
37
|
+
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
|
38
|
+
wheels = [
|
|
39
|
+
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[[package]]
|
|
43
|
+
name = "packaging"
|
|
44
|
+
version = "26.1"
|
|
45
|
+
source = { registry = "https://pypi.org/simple" }
|
|
46
|
+
sdist = { url = "https://files.pythonhosted.org/packages/df/de/0d2b39fb4af88a0258f3bac87dfcbb48e73fbdea4a2ed0e2213f9a4c2f9a/packaging-26.1.tar.gz", hash = "sha256:f042152b681c4bfac5cae2742a55e103d27ab2ec0f3d88037136b6bfe7c9c5de", size = 215519, upload-time = "2026-04-14T21:12:49.362Z" }
|
|
47
|
+
wheels = [
|
|
48
|
+
{ url = "https://files.pythonhosted.org/packages/7a/c2/920ef838e2f0028c8262f16101ec09ebd5969864e5a64c4c05fad0617c56/packaging-26.1-py3-none-any.whl", hash = "sha256:5d9c0669c6285e491e0ced2eee587eaf67b670d94a19e94e3984a481aba6802f", size = 95831, upload-time = "2026-04-14T21:12:47.56Z" },
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[[package]]
|
|
52
|
+
name = "pluggy"
|
|
53
|
+
version = "1.6.0"
|
|
54
|
+
source = { registry = "https://pypi.org/simple" }
|
|
55
|
+
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
|
56
|
+
wheels = [
|
|
57
|
+
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[[package]]
|
|
61
|
+
name = "polars"
|
|
62
|
+
version = "1.40.0"
|
|
63
|
+
source = { registry = "https://pypi.org/simple" }
|
|
64
|
+
dependencies = [
|
|
65
|
+
{ name = "polars-runtime-32" },
|
|
66
|
+
]
|
|
67
|
+
sdist = { url = "https://files.pythonhosted.org/packages/d9/1b/eea7d6fe6daafc1d784cc0f76c729b28051837ccb2d51ae64a0a3f798142/polars-1.40.0.tar.gz", hash = "sha256:711dd50dcbc35ba42a2625fcadc2a1349e2e9abf48e35631bdabafb90d89874b", size = 732943, upload-time = "2026-04-18T05:25:26.077Z" }
|
|
68
|
+
wheels = [
|
|
69
|
+
{ url = "https://files.pythonhosted.org/packages/b4/ad/d5ed79269b7fe59a3dbbfbdbecbe1e59a0b56e38d36491e57d2bfb5846c1/polars-1.40.0-py3-none-any.whl", hash = "sha256:60b1d677ca363e2fc6fdea8c3d16c0653fd52cc37f0249e0f29d9536d5aa45ef", size = 828012, upload-time = "2026-04-18T05:23:39.055Z" },
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[[package]]
|
|
73
|
+
name = "polars-runtime-32"
|
|
74
|
+
version = "1.40.0"
|
|
75
|
+
source = { registry = "https://pypi.org/simple" }
|
|
76
|
+
sdist = { url = "https://files.pythonhosted.org/packages/fb/b2/eae6c1b3d16c7a64ff382f557985ff939cce13455e8c9d056ab8e1e0fc87/polars_runtime_32-1.40.0.tar.gz", hash = "sha256:e31bff8bd37492c714e155e2e1429ac2d9ddf2dd6ec6474cc1cc70ac0b2bd6af", size = 2935285, upload-time = "2026-04-18T05:25:28.038Z" }
|
|
77
|
+
wheels = [
|
|
78
|
+
{ url = "https://files.pythonhosted.org/packages/b0/e4/2325689d2af4f9e70699ff98e8a2543707bebc34af78a5fe0e654107d9ed/polars_runtime_32-1.40.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:cab3ac7ff5bc9e0f4b3b146015569e9417cf0eaff8d3fb71004d73d67b6f09c7", size = 52092528, upload-time = "2026-04-18T05:23:42.341Z" },
|
|
79
|
+
{ url = "https://files.pythonhosted.org/packages/19/a6/82157b19c5c40b2c1ed0493b87b9eaf9b4863cdedca5575ee083488b45ba/polars_runtime_32-1.40.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:d29624c75c4049253300786d00882fce620b3677ce495ebc4199292de8c2ba02", size = 46365073, upload-time = "2026-04-18T05:23:46.7Z" },
|
|
80
|
+
{ url = "https://files.pythonhosted.org/packages/85/b5/5c4f1f2545f56c664cc57bbdd1aa66fcfcb129aa137ed72cc81d58eb480f/polars_runtime_32-1.40.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a034dc0d8481fc1ca0456ab33e98e53a4c6d6cc6a2edb36246cc81c936b925dc", size = 50250561, upload-time = "2026-04-18T05:23:51.316Z" },
|
|
81
|
+
{ url = "https://files.pythonhosted.org/packages/8e/51/cb5eb75394f39c0ec14fddcc9b11adb707e1f28224a552ecbfa72d39b61b/polars_runtime_32-1.40.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70e78c2f13a54a9d92ae30d2625bda759173cc4867ad6a39f85f140058d899c6", size = 56243695, upload-time = "2026-04-18T05:23:55.932Z" },
|
|
82
|
+
{ url = "https://files.pythonhosted.org/packages/16/3a/be1437c0fbecbb07d81b151456089c3cf054eea5a791f849ed39b67611ca/polars_runtime_32-1.40.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1843272c0ef49f4a07435888f0059eca08ec16ab9880219c457195a081df0281", size = 50427843, upload-time = "2026-04-18T05:24:00.159Z" },
|
|
83
|
+
{ url = "https://files.pythonhosted.org/packages/be/c7/ea6449a2161816a13ed1d8aa02177d5a0594e011f0df5ddd2fad8e5bf20e/polars_runtime_32-1.40.0-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:081237dba07f15d61fc151825f203165480e9503ebe72a474a8c99aa78021962", size = 54153077, upload-time = "2026-04-18T05:24:05.066Z" },
|
|
84
|
+
{ url = "https://files.pythonhosted.org/packages/aa/1a/0b239138afe8b80a1a0b4c95db3884e6afbbe82ec3318918ab03bc57f231/polars_runtime_32-1.40.0-cp310-abi3-win_amd64.whl", hash = "sha256:a916040e0b7f461ce987e4551fed9eea5914b4fbb5af907b1d9e80db71fadeb5", size = 51822748, upload-time = "2026-04-18T05:24:09.384Z" },
|
|
85
|
+
{ url = "https://files.pythonhosted.org/packages/06/ce/c16ef8fd3030b7342032b040fab21a42f6fee57e47ee7f41e2f1a1e36f01/polars_runtime_32-1.40.0-cp310-abi3-win_arm64.whl", hash = "sha256:719c64eecde24a95aa3599eb9c8efc98c1499bab7ef9c01cbbe8939cd583e654", size = 45819617, upload-time = "2026-04-18T05:24:13.214Z" },
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
[[package]]
|
|
89
|
+
name = "polars-text"
|
|
90
|
+
version = "0.1.3"
|
|
91
|
+
source = { registry = "https://pypi.org/simple" }
|
|
92
|
+
dependencies = [
|
|
93
|
+
{ name = "polars" },
|
|
94
|
+
]
|
|
95
|
+
sdist = { url = "https://files.pythonhosted.org/packages/fc/36/03bb22e59897e878b9b73cf7f8bb826b587affd42276591619a14b955483/polars_text-0.1.3.tar.gz", hash = "sha256:06b361a607d7a6fa204b040768f159acad88c7f6daf64a213a776f10b7468d92", size = 5357581, upload-time = "2026-04-21T14:03:28.096Z" }
|
|
96
|
+
wheels = [
|
|
97
|
+
{ url = "https://files.pythonhosted.org/packages/5c/54/ec8bb8005b4b2fc70787b6191751d92d2eff3a8c7aa34964ec0aca145451/polars_text-0.1.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e3dad2a26f5d18b5eca8075b97103ad50490a95d735a3d83ddbf805d92f40b4f", size = 16551094, upload-time = "2026-04-21T14:03:18.03Z" },
|
|
98
|
+
{ url = "https://files.pythonhosted.org/packages/a8/da/363f0d519bc0df83e71f2815f8c7018ee4c50876f1f23a2952e1e2739930/polars_text-0.1.3-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:245d3703cce24f5e9afea9ba746eb991c3cc6b06a5a7c5fd6863a22f42172331", size = 20896342, upload-time = "2026-04-21T14:03:21.747Z" },
|
|
99
|
+
{ url = "https://files.pythonhosted.org/packages/ed/4f/9de5690509cea46661e9398290a037a472f43eb935a378d158feeddf4792/polars_text-0.1.3-cp314-cp314-win_amd64.whl", hash = "sha256:0e3f6084581756925867b1c393ab4b6407d4eef05ea7cf46d9c5c4b25b925a74", size = 16329073, upload-time = "2026-04-21T14:03:25.411Z" },
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
[[package]]
|
|
103
|
+
name = "pygments"
|
|
104
|
+
version = "2.20.0"
|
|
105
|
+
source = { registry = "https://pypi.org/simple" }
|
|
106
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
|
107
|
+
wheels = [
|
|
108
|
+
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
[[package]]
|
|
112
|
+
name = "pytest"
|
|
113
|
+
version = "9.0.3"
|
|
114
|
+
source = { registry = "https://pypi.org/simple" }
|
|
115
|
+
dependencies = [
|
|
116
|
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
117
|
+
{ name = "iniconfig" },
|
|
118
|
+
{ name = "packaging" },
|
|
119
|
+
{ name = "pluggy" },
|
|
120
|
+
{ name = "pygments" },
|
|
121
|
+
]
|
|
122
|
+
sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
|
|
123
|
+
wheels = [
|
|
124
|
+
{ url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
|
|
125
|
+
]
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"""Workspace file persistence helpers."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Dict, Union
|
|
8
|
-
|
|
9
|
-
if TYPE_CHECKING: # pragma: no cover
|
|
10
|
-
from .core import Workspace
|
|
11
|
-
|
|
12
|
-
from ..node.io import from_dict as node_from_dict
|
|
13
|
-
from ..node.io import to_dict as node_to_dict
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def _resolve_metadata_path(path: Path) -> Path:
|
|
17
|
-
if path.is_dir():
|
|
18
|
-
return path / "metadata.json"
|
|
19
|
-
if path.suffix.lower() == ".json":
|
|
20
|
-
return path
|
|
21
|
-
raise ValueError("Workspace path must be a directory or a .json file")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def write_workspace(workspace: "Workspace", path: Union[str, Path]) -> None:
|
|
25
|
-
target = _resolve_metadata_path(Path(path))
|
|
26
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
27
|
-
workspace.ws_root_dir = target.parent
|
|
28
|
-
|
|
29
|
-
description = workspace.description
|
|
30
|
-
created_at = workspace.created_at
|
|
31
|
-
modified_at = workspace.modified_at
|
|
32
|
-
|
|
33
|
-
nodes_data: list[dict[str, Any]] = []
|
|
34
|
-
for node in workspace.nodes.values():
|
|
35
|
-
nodes_data.append(node_to_dict(node))
|
|
36
|
-
|
|
37
|
-
workspace_metadata: Dict[str, Any] = {
|
|
38
|
-
"id": workspace.id,
|
|
39
|
-
"name": workspace.name,
|
|
40
|
-
"version": 2,
|
|
41
|
-
"description": description,
|
|
42
|
-
"created_at": created_at,
|
|
43
|
-
"modified_at": modified_at,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
data = {"workspace_metadata": workspace_metadata, "nodes": nodes_data}
|
|
47
|
-
with target.open("w", encoding="utf-8") as f:
|
|
48
|
-
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
49
|
-
|
|
50
|
-
try:
|
|
51
|
-
data_dir = target.parent / "data"
|
|
52
|
-
expected_node_files = {
|
|
53
|
-
Path(str(node_payload["data_path"])).name for node_payload in nodes_data
|
|
54
|
-
}
|
|
55
|
-
if data_dir.exists() and data_dir.is_dir():
|
|
56
|
-
for candidate in data_dir.glob("*.plbin"):
|
|
57
|
-
if candidate.name not in expected_node_files:
|
|
58
|
-
candidate.unlink(missing_ok=True)
|
|
59
|
-
except Exception:
|
|
60
|
-
pass
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def read_workspace_metadata(path: Union[str, Path]) -> Dict[str, Any]:
|
|
64
|
-
"""Load and return the workspace metadata dictionary from metadata.json.
|
|
65
|
-
|
|
66
|
-
This helper only reads/parses the JSON metadata file and does not attempt
|
|
67
|
-
to load any node data payload files.
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
target = _resolve_metadata_path(Path(path))
|
|
71
|
-
with target.open("r", encoding="utf-8") as f:
|
|
72
|
-
return json.load(f)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def read_workspace(path: Union[str, Path]) -> "Workspace":
|
|
76
|
-
from .core import Workspace
|
|
77
|
-
|
|
78
|
-
target = _resolve_metadata_path(Path(path))
|
|
79
|
-
data = read_workspace_metadata(path)
|
|
80
|
-
|
|
81
|
-
ws_meta = data.get("workspace_metadata", {})
|
|
82
|
-
workspace = Workspace(
|
|
83
|
-
name=ws_meta.get("name", "restored_workspace"),
|
|
84
|
-
ws_root_dir=target.parent,
|
|
85
|
-
)
|
|
86
|
-
workspace.id = ws_meta.get("id", workspace.id)
|
|
87
|
-
workspace.description = ws_meta.get("description", "") or ""
|
|
88
|
-
workspace.created_at = ws_meta.get("created_at")
|
|
89
|
-
workspace.modified_at = ws_meta.get("modified_at")
|
|
90
|
-
|
|
91
|
-
for node_entry in data.get("nodes", []):
|
|
92
|
-
workspace.add_node(node_from_dict(node_entry, workspace=workspace))
|
|
93
|
-
|
|
94
|
-
return workspace
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
__all__ = [
|
|
98
|
-
"write_workspace",
|
|
99
|
-
"read_workspace_metadata",
|
|
100
|
-
"read_workspace",
|
|
101
|
-
]
|
docworkspace-0.2.2/uv.lock
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
version = 1
|
|
2
|
-
revision = 3
|
|
3
|
-
requires-python = ">=3.14"
|
|
4
|
-
|
|
5
|
-
[[package]]
|
|
6
|
-
name = "colorama"
|
|
7
|
-
version = "0.4.6"
|
|
8
|
-
source = { registry = "https://pypi.org/simple" }
|
|
9
|
-
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
|
10
|
-
wheels = [
|
|
11
|
-
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
|
12
|
-
]
|
|
13
|
-
|
|
14
|
-
[[package]]
|
|
15
|
-
name = "docworkspace"
|
|
16
|
-
version = "0.2.2"
|
|
17
|
-
source = { editable = "." }
|
|
18
|
-
dependencies = [
|
|
19
|
-
{ name = "polars-text" },
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
[package.dev-dependencies]
|
|
23
|
-
dev = [
|
|
24
|
-
{ name = "pytest" },
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
[package.metadata]
|
|
28
|
-
requires-dist = [{ name = "polars-text", specifier = ">=0.1.2" }]
|
|
29
|
-
|
|
30
|
-
[package.metadata.requires-dev]
|
|
31
|
-
dev = [{ name = "pytest", specifier = ">=8.0.0" }]
|
|
32
|
-
|
|
33
|
-
[[package]]
|
|
34
|
-
name = "iniconfig"
|
|
35
|
-
version = "2.3.0"
|
|
36
|
-
source = { registry = "https://pypi.org/simple" }
|
|
37
|
-
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
|
38
|
-
wheels = [
|
|
39
|
-
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
[[package]]
|
|
43
|
-
name = "packaging"
|
|
44
|
-
version = "26.0"
|
|
45
|
-
source = { registry = "https://pypi.org/simple" }
|
|
46
|
-
sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" }
|
|
47
|
-
wheels = [
|
|
48
|
-
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
|
49
|
-
]
|
|
50
|
-
|
|
51
|
-
[[package]]
|
|
52
|
-
name = "pluggy"
|
|
53
|
-
version = "1.6.0"
|
|
54
|
-
source = { registry = "https://pypi.org/simple" }
|
|
55
|
-
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
|
56
|
-
wheels = [
|
|
57
|
-
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
[[package]]
|
|
61
|
-
name = "polars"
|
|
62
|
-
version = "1.39.3"
|
|
63
|
-
source = { registry = "https://pypi.org/simple" }
|
|
64
|
-
dependencies = [
|
|
65
|
-
{ name = "polars-runtime-32" },
|
|
66
|
-
]
|
|
67
|
-
sdist = { url = "https://files.pythonhosted.org/packages/93/ab/f19e592fce9e000da49c96bf35e77cef67f9cb4b040bfa538a2764c0263e/polars-1.39.3.tar.gz", hash = "sha256:2e016c7f3e8d14fa777ef86fe0477cec6c67023a20ba4c94d6e8431eefe4a63c", size = 728987, upload-time = "2026-03-20T11:16:24.836Z" }
|
|
68
|
-
wheels = [
|
|
69
|
-
{ url = "https://files.pythonhosted.org/packages/b4/db/08f4ca10c5018813e7e0b59e4472302328b3d2ab1512f5a2157a814540e0/polars-1.39.3-py3-none-any.whl", hash = "sha256:c2b955ccc0a08a2bc9259785decf3d5c007b489b523bf2390cf21cec2bb82a56", size = 823985, upload-time = "2026-03-20T11:14:23.619Z" },
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
[[package]]
|
|
73
|
-
name = "polars-runtime-32"
|
|
74
|
-
version = "1.39.3"
|
|
75
|
-
source = { registry = "https://pypi.org/simple" }
|
|
76
|
-
sdist = { url = "https://files.pythonhosted.org/packages/17/39/c8688696bc22b6c501e3b82ef3be10e543c07a785af5660f30997cd22dd2/polars_runtime_32-1.39.3.tar.gz", hash = "sha256:c728e4f469cafab501947585f36311b8fb222d3e934c6209e83791e0df20b29d", size = 2872335, upload-time = "2026-03-20T11:16:26.581Z" }
|
|
77
|
-
wheels = [
|
|
78
|
-
{ url = "https://files.pythonhosted.org/packages/3b/74/1b41205f7368c9375ab1dea91178eaa20435fe3eff036390a53a7660b416/polars_runtime_32-1.39.3-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:425c0b220b573fa097b4042edff73114cc6d23432a21dfd2dc41adf329d7d2e9", size = 45273243, upload-time = "2026-03-20T11:14:26.691Z" },
|
|
79
|
-
{ url = "https://files.pythonhosted.org/packages/90/bf/297716b3095fe719be20fcf7af1d2b6ab069c38199bbace2469608a69b3a/polars_runtime_32-1.39.3-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:ef5884711e3c617d7dc93519a7d038e242f5741cfe5fe9afd32d58845d86c562", size = 40842924, upload-time = "2026-03-20T11:14:31.154Z" },
|
|
80
|
-
{ url = "https://files.pythonhosted.org/packages/3d/3e/e65236d9d0d9babfa0ecba593413c06530fca60a8feb8f66243aa5dba92e/polars_runtime_32-1.39.3-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06b47f535eb1f97a9a1e5b0053ef50db3a4276e241178e37bbb1a38b1fa53b14", size = 43220650, upload-time = "2026-03-20T11:14:35.458Z" },
|
|
81
|
-
{ url = "https://files.pythonhosted.org/packages/b0/15/fc3e43f3fdf3f20b7dfb5abe871ab6162cf8fb4aeabf4cfad822d5dc4c79/polars_runtime_32-1.39.3-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bc9e13dc1d2e828331f2fe8ccbc9757554dc4933a8d3e85e906b988178f95ed", size = 46877498, upload-time = "2026-03-20T11:14:40.14Z" },
|
|
82
|
-
{ url = "https://files.pythonhosted.org/packages/3c/81/bd5f895919e32c6ab0a7786cd0c0ca961cb03152c47c3645808b54383f31/polars_runtime_32-1.39.3-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:363d49e3a3e638fc943e2b9887940300a7d06789930855a178a4727949259dc2", size = 43380176, upload-time = "2026-03-20T11:14:45.566Z" },
|
|
83
|
-
{ url = "https://files.pythonhosted.org/packages/7a/3e/c86433c3b5ec0315bdfc7640d0c15d41f1216c0103a0eab9a9b5147d6c4c/polars_runtime_32-1.39.3-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7c206bdcc7bc62ea038d6adea8e44b02f0e675e0191a54c810703b4895208ea4", size = 46485933, upload-time = "2026-03-20T11:14:51.155Z" },
|
|
84
|
-
{ url = "https://files.pythonhosted.org/packages/54/ce/200b310cf91f98e652eb6ea09fdb3a9718aa0293ebf113dce325797c8572/polars_runtime_32-1.39.3-cp310-abi3-win_amd64.whl", hash = "sha256:d66ca522517554a883446957539c40dc7b75eb0c2220357fb28bc8940d305339", size = 46995458, upload-time = "2026-03-20T11:14:56.074Z" },
|
|
85
|
-
{ url = "https://files.pythonhosted.org/packages/da/76/2d48927e0aa2abbdde08cbf4a2536883b73277d47fbeca95e952de86df34/polars_runtime_32-1.39.3-cp310-abi3-win_arm64.whl", hash = "sha256:f49f51461de63f13e5dd4eb080421c8f23f856945f3f8bd5b2b1f59da52c2860", size = 41857648, upload-time = "2026-03-20T11:15:01.142Z" },
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
[[package]]
|
|
89
|
-
name = "polars-text"
|
|
90
|
-
version = "0.1.2"
|
|
91
|
-
source = { registry = "https://pypi.org/simple" }
|
|
92
|
-
dependencies = [
|
|
93
|
-
{ name = "polars" },
|
|
94
|
-
]
|
|
95
|
-
sdist = { url = "https://files.pythonhosted.org/packages/42/b9/1653c8ac742e3b84ebe328d213b5eb09ee96ce6241c27364911a2e29e2aa/polars_text-0.1.2.tar.gz", hash = "sha256:2a080c8e7e0ecef10b3b431fb14dbb90de6faf552e24ffa30f52f0876c5fe5e8", size = 53365, upload-time = "2026-04-07T23:41:59.225Z" }
|
|
96
|
-
wheels = [
|
|
97
|
-
{ url = "https://files.pythonhosted.org/packages/b4/60/829e2048d45aa63ec9c2634f63bf750b9569aded969920db3240737ea9e9/polars_text-0.1.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7dbd56bc3c90d87defc9e682e816ff7cdf264f19ee458df190322ba92c10c20", size = 7659172, upload-time = "2026-04-07T23:41:53.444Z" },
|
|
98
|
-
{ url = "https://files.pythonhosted.org/packages/a5/60/6417a5e73915e0dbc4c1f0643b41c715428a5350f4b2a97903655b526342/polars_text-0.1.2-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:0283306eb5c185cac89db3abf1ecf877b47c4e18a2afc4ad8892a5ab12116b8f", size = 10981911, upload-time = "2026-04-07T23:41:55.388Z" },
|
|
99
|
-
{ url = "https://files.pythonhosted.org/packages/da/a6/ff1dd58b29c7ac03e7344311e2b82f211d043321d8f9705a9e8e664db900/polars_text-0.1.2-cp314-cp314-win_amd64.whl", hash = "sha256:5b80da5e9902ecaefc4db227a38d20fc6c328ee4254678319329b38248c2ea4e", size = 7771979, upload-time = "2026-04-07T23:41:57.646Z" },
|
|
100
|
-
]
|
|
101
|
-
|
|
102
|
-
[[package]]
|
|
103
|
-
name = "pygments"
|
|
104
|
-
version = "2.20.0"
|
|
105
|
-
source = { registry = "https://pypi.org/simple" }
|
|
106
|
-
sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" }
|
|
107
|
-
wheels = [
|
|
108
|
-
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
[[package]]
|
|
112
|
-
name = "pytest"
|
|
113
|
-
version = "9.0.3"
|
|
114
|
-
source = { registry = "https://pypi.org/simple" }
|
|
115
|
-
dependencies = [
|
|
116
|
-
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
117
|
-
{ name = "iniconfig" },
|
|
118
|
-
{ name = "packaging" },
|
|
119
|
-
{ name = "pluggy" },
|
|
120
|
-
{ name = "pygments" },
|
|
121
|
-
]
|
|
122
|
-
sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" }
|
|
123
|
-
wheels = [
|
|
124
|
-
{ url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" },
|
|
125
|
-
]
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|