figpack 0.1.0__tar.gz → 0.1.1__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.
Potentially problematic release.
This version of figpack might be problematic. Click here for more details.
- {figpack-0.1.0 → figpack-0.1.1}/MANIFEST.in +1 -1
- {figpack-0.1.0/figpack.egg-info → figpack-0.1.1}/PKG-INFO +1 -1
- figpack-0.1.1/figpack/core/__init__.py +0 -0
- figpack-0.1.1/figpack/core/_bundle_utils.py +46 -0
- {figpack-0.1.0/figpack → figpack-0.1.1/figpack/core}/_show_view.py +4 -27
- {figpack-0.1.0/figpack → figpack-0.1.1/figpack/core}/_upload_view.py +94 -68
- figpack-0.1.1/figpack/figpack-gui-dist/assets/index-BW-ONVCL.js +65 -0
- {figpack-0.1.0 → figpack-0.1.1}/figpack/figpack-gui-dist/index.html +1 -1
- figpack-0.1.1/figpack/views/Box.py +68 -0
- figpack-0.1.1/figpack/views/LayoutItem.py +55 -0
- figpack-0.1.1/figpack/views/Splitter.py +66 -0
- figpack-0.1.1/figpack/views/TabLayout.py +66 -0
- figpack-0.1.1/figpack/views/TabLayoutItem.py +39 -0
- figpack-0.1.0/figpack/views.py → figpack-0.1.1/figpack/views/TimeseriesGraph.py +5 -1
- figpack-0.1.1/figpack/views/__init__.py +6 -0
- {figpack-0.1.0 → figpack-0.1.1/figpack.egg-info}/PKG-INFO +1 -1
- figpack-0.1.1/figpack.egg-info/SOURCES.txt +26 -0
- {figpack-0.1.0 → figpack-0.1.1}/pyproject.toml +1 -1
- figpack-0.1.0/figpack/figpack-gui-dist/assets/index-BrKvMWud.js +0 -65
- figpack-0.1.0/figpack.egg-info/SOURCES.txt +0 -18
- {figpack-0.1.0 → figpack-0.1.1}/LICENSE +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/README.md +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/figpack/__init__.py +0 -0
- {figpack-0.1.0/figpack → figpack-0.1.1/figpack/core}/figpack_view.py +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/figpack/figpack-gui-dist/assets/index-CeWL3OeJ.css +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/figpack-gui/node_modules/flatted/python/flatted.py +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/figpack.egg-info/dependency_links.txt +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/figpack.egg-info/requires.txt +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/figpack.egg-info/top_level.txt +0 -0
- {figpack-0.1.0 → figpack-0.1.1}/setup.cfg +0 -0
|
File without changes
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pathlib
|
|
3
|
+
import zarr
|
|
4
|
+
from .figpack_view import FigpackView
|
|
5
|
+
|
|
6
|
+
thisdir = pathlib.Path(__file__).parent.resolve()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def prepare_figure_bundle(view: FigpackView, tmpdir: str) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Prepare a figure bundle in the specified temporary directory.
|
|
12
|
+
|
|
13
|
+
This function:
|
|
14
|
+
1. Copies all files from the figpack-gui-dist directory to tmpdir
|
|
15
|
+
2. Writes the view data to a zarr group
|
|
16
|
+
3. Consolidates zarr metadata
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
view: The figpack view to prepare
|
|
20
|
+
tmpdir: The temporary directory to prepare the bundle in
|
|
21
|
+
"""
|
|
22
|
+
html_dir = thisdir / ".." / "figpack-gui-dist"
|
|
23
|
+
if not os.path.exists(html_dir):
|
|
24
|
+
raise SystemExit(f"Error: directory not found: {html_dir}")
|
|
25
|
+
|
|
26
|
+
# Copy all files in html_dir recursively to tmpdir
|
|
27
|
+
for item in html_dir.iterdir():
|
|
28
|
+
if item.is_file():
|
|
29
|
+
target = pathlib.Path(tmpdir) / item.name
|
|
30
|
+
target.write_bytes(item.read_bytes())
|
|
31
|
+
elif item.is_dir():
|
|
32
|
+
target = pathlib.Path(tmpdir) / item.name
|
|
33
|
+
target.mkdir(exist_ok=True)
|
|
34
|
+
for subitem in item.iterdir():
|
|
35
|
+
target_sub = target / subitem.name
|
|
36
|
+
target_sub.write_bytes(subitem.read_bytes())
|
|
37
|
+
|
|
38
|
+
# Write the graph data to the Zarr group
|
|
39
|
+
zarr_group = zarr.open_group(
|
|
40
|
+
pathlib.Path(tmpdir) / "data.zarr",
|
|
41
|
+
mode="w",
|
|
42
|
+
synchronizer=zarr.ThreadSynchronizer(),
|
|
43
|
+
)
|
|
44
|
+
view._write_to_zarr_group(zarr_group)
|
|
45
|
+
|
|
46
|
+
zarr.consolidate_metadata(zarr_group.store)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
3
|
from typing import Union
|
|
4
|
-
import zarr
|
|
5
4
|
import tempfile
|
|
6
5
|
|
|
7
6
|
import webbrowser
|
|
@@ -11,43 +10,21 @@ import pathlib
|
|
|
11
10
|
import threading
|
|
12
11
|
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
|
13
12
|
|
|
14
|
-
from .
|
|
13
|
+
from .figpack_view import FigpackView
|
|
14
|
+
from ._bundle_utils import prepare_figure_bundle
|
|
15
15
|
|
|
16
16
|
thisdir = pathlib.Path(__file__).parent.resolve()
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def _show_view(
|
|
20
|
-
view:
|
|
20
|
+
view: FigpackView,
|
|
21
21
|
*,
|
|
22
22
|
open_in_browser: bool = False,
|
|
23
23
|
port: Union[int, None] = None,
|
|
24
24
|
allow_origin: Union[str, None] = None,
|
|
25
25
|
):
|
|
26
26
|
with tempfile.TemporaryDirectory(prefix="figpack_") as tmpdir:
|
|
27
|
-
|
|
28
|
-
if not os.path.exists(html_dir):
|
|
29
|
-
raise SystemExit(f"Error: directory not found: {html_dir}")
|
|
30
|
-
# copy all files in html_dir recursively to tmpdir
|
|
31
|
-
for item in html_dir.iterdir():
|
|
32
|
-
if item.is_file():
|
|
33
|
-
target = pathlib.Path(tmpdir) / item.name
|
|
34
|
-
target.write_bytes(item.read_bytes())
|
|
35
|
-
elif item.is_dir():
|
|
36
|
-
target = pathlib.Path(tmpdir) / item.name
|
|
37
|
-
target.mkdir(exist_ok=True)
|
|
38
|
-
for subitem in item.iterdir():
|
|
39
|
-
target_sub = target / subitem.name
|
|
40
|
-
target_sub.write_bytes(subitem.read_bytes())
|
|
41
|
-
|
|
42
|
-
# Write the graph data to the Zarr group
|
|
43
|
-
zarr_group = zarr.open_group(
|
|
44
|
-
pathlib.Path(tmpdir) / "data.zarr",
|
|
45
|
-
mode="w",
|
|
46
|
-
synchronizer=zarr.ThreadSynchronizer(),
|
|
47
|
-
)
|
|
48
|
-
view._write_to_zarr_group(zarr_group)
|
|
49
|
-
|
|
50
|
-
zarr.consolidate_metadata(zarr_group.store)
|
|
27
|
+
prepare_figure_bundle(view, tmpdir)
|
|
51
28
|
|
|
52
29
|
serve_files(
|
|
53
30
|
tmpdir,
|
|
@@ -5,11 +5,12 @@ import uuid
|
|
|
5
5
|
import tempfile
|
|
6
6
|
import pathlib
|
|
7
7
|
import requests
|
|
8
|
+
import threading
|
|
9
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
8
10
|
from datetime import datetime, timedelta, timezone
|
|
9
11
|
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
from .views import TimeseriesGraph
|
|
12
|
+
from .figpack_view import FigpackView
|
|
13
|
+
from ._bundle_utils import prepare_figure_bundle
|
|
13
14
|
|
|
14
15
|
thisdir = pathlib.Path(__file__).parent.resolve()
|
|
15
16
|
|
|
@@ -17,7 +18,7 @@ FIGPACK_API_BASE_URL = "https://figpack-api.vercel.app"
|
|
|
17
18
|
TEMPORY_BASE_URL = "https://tempory.net/figpack/figures"
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
def _upload_view(view:
|
|
21
|
+
def _upload_view(view: FigpackView) -> str:
|
|
21
22
|
"""
|
|
22
23
|
Upload a figpack view to the cloud
|
|
23
24
|
|
|
@@ -45,7 +46,7 @@ def _upload_view(view: TimeseriesGraph) -> str:
|
|
|
45
46
|
with tempfile.TemporaryDirectory(prefix="figpack_upload_") as tmpdir:
|
|
46
47
|
# Prepare the figure bundle (reuse logic from _show_view)
|
|
47
48
|
print("Preparing figure bundle...")
|
|
48
|
-
|
|
49
|
+
prepare_figure_bundle(view, tmpdir)
|
|
49
50
|
|
|
50
51
|
# Upload the bundle
|
|
51
52
|
print("Starting upload...")
|
|
@@ -58,40 +59,33 @@ def _upload_view(view: TimeseriesGraph) -> str:
|
|
|
58
59
|
return figure_url
|
|
59
60
|
|
|
60
61
|
|
|
61
|
-
def
|
|
62
|
+
def _upload_single_file(
|
|
63
|
+
figure_id: str, relative_path: str, file_path: pathlib.Path, passcode: str
|
|
64
|
+
) -> str:
|
|
62
65
|
"""
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
Worker function to upload a single file
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
str: The relative path of the uploaded file
|
|
65
70
|
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
target_sub = target / subitem.name
|
|
80
|
-
target_sub.write_bytes(subitem.read_bytes())
|
|
81
|
-
|
|
82
|
-
# Write the graph data to the Zarr group
|
|
83
|
-
zarr_group = zarr.open_group(
|
|
84
|
-
pathlib.Path(tmpdir) / "data.zarr",
|
|
85
|
-
mode="w",
|
|
86
|
-
synchronizer=zarr.ThreadSynchronizer(),
|
|
87
|
-
)
|
|
88
|
-
view._write_to_zarr_group(zarr_group)
|
|
89
|
-
zarr.consolidate_metadata(zarr_group.store)
|
|
71
|
+
file_type = _determine_file_type(relative_path)
|
|
72
|
+
|
|
73
|
+
if file_type == "small":
|
|
74
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
75
|
+
content = f.read()
|
|
76
|
+
_upload_small_file(figure_id, relative_path, content, passcode)
|
|
77
|
+
else: # large file
|
|
78
|
+
_upload_large_file(figure_id, relative_path, file_path, passcode)
|
|
79
|
+
|
|
80
|
+
return relative_path
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
MAX_WORKERS_FOR_UPLOAD = 16
|
|
90
84
|
|
|
91
85
|
|
|
92
86
|
def _upload_bundle(tmpdir: str, figure_id: str, passcode: str) -> None:
|
|
93
87
|
"""
|
|
94
|
-
Upload the prepared bundle to the cloud
|
|
88
|
+
Upload the prepared bundle to the cloud using parallel uploads
|
|
95
89
|
"""
|
|
96
90
|
tmpdir_path = pathlib.Path(tmpdir)
|
|
97
91
|
|
|
@@ -116,42 +110,74 @@ def _upload_bundle(tmpdir: str, figure_id: str, passcode: str) -> None:
|
|
|
116
110
|
|
|
117
111
|
print(f"Found {len(all_files)} files to upload")
|
|
118
112
|
|
|
119
|
-
#
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
uploaded_count
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
113
|
+
# Filter out figpack.json since we already uploaded the initial version
|
|
114
|
+
files_to_upload = [
|
|
115
|
+
(rel_path, file_path)
|
|
116
|
+
for rel_path, file_path in all_files
|
|
117
|
+
if rel_path != "figpack.json"
|
|
118
|
+
]
|
|
119
|
+
total_files_to_upload = len(files_to_upload)
|
|
120
|
+
|
|
121
|
+
if total_files_to_upload == 0:
|
|
122
|
+
print("No additional files to upload")
|
|
123
|
+
else:
|
|
124
|
+
print(
|
|
125
|
+
f"Uploading {total_files_to_upload} files with up to 8 concurrent uploads..."
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Thread-safe progress tracking
|
|
129
|
+
uploaded_count = 0
|
|
130
|
+
count_lock = threading.Lock()
|
|
131
|
+
timer = time.time()
|
|
132
|
+
|
|
133
|
+
# Upload files in parallel with concurrent uploads
|
|
134
|
+
with ThreadPoolExecutor(max_workers=MAX_WORKERS_FOR_UPLOAD) as executor:
|
|
135
|
+
# Submit all upload tasks
|
|
136
|
+
future_to_file = {
|
|
137
|
+
executor.submit(
|
|
138
|
+
_upload_single_file, figure_id, rel_path, file_path, passcode
|
|
139
|
+
): rel_path
|
|
140
|
+
for rel_path, file_path in files_to_upload
|
|
144
141
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
142
|
+
|
|
143
|
+
# Process completed uploads
|
|
144
|
+
for future in as_completed(future_to_file):
|
|
145
|
+
relative_path = future_to_file[future]
|
|
146
|
+
try:
|
|
147
|
+
future.result() # This will raise any exception that occurred during upload
|
|
148
|
+
|
|
149
|
+
# Thread-safe progress update
|
|
150
|
+
with count_lock:
|
|
151
|
+
uploaded_count += 1
|
|
152
|
+
print(
|
|
153
|
+
f"Uploaded {uploaded_count}/{total_files_to_upload}: {relative_path}"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Update progress every 60 seconds
|
|
157
|
+
elapsed_time = time.time() - timer
|
|
158
|
+
if elapsed_time > 60:
|
|
159
|
+
figpack_json = {
|
|
160
|
+
**figpack_json,
|
|
161
|
+
"status": "uploading",
|
|
162
|
+
"upload_progress": f"{uploaded_count}/{total_files_to_upload}",
|
|
163
|
+
"upload_updated": datetime.now(
|
|
164
|
+
timezone.utc
|
|
165
|
+
).isoformat(),
|
|
166
|
+
}
|
|
167
|
+
_upload_small_file(
|
|
168
|
+
figure_id,
|
|
169
|
+
"figpack.json",
|
|
170
|
+
json.dumps(figpack_json, indent=2),
|
|
171
|
+
passcode,
|
|
172
|
+
)
|
|
173
|
+
print(
|
|
174
|
+
f"Updated figpack.json with progress: {uploaded_count}/{total_files_to_upload}"
|
|
175
|
+
)
|
|
176
|
+
timer = time.time()
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
print(f"Failed to upload {relative_path}: {e}")
|
|
180
|
+
raise # Re-raise the exception to stop the upload process
|
|
155
181
|
|
|
156
182
|
# Finally, upload completion status
|
|
157
183
|
print("Uploading completion status...")
|