nuspace 0.7.2__tar.gz → 0.7.3__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.
- {nuspace-0.7.2 → nuspace-0.7.3}/CHANGELOG.md +28 -2
- {nuspace-0.7.2 → nuspace-0.7.3}/PKG-INFO +6 -6
- {nuspace-0.7.2 → nuspace-0.7.3}/pyproject.toml +6 -6
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/presets.py +4 -1
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/cell.py +6 -4
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/plane.py +41 -18
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/plane.py +6 -6
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/specs/ops.py +1 -2
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/specs/specs.py +6 -6
- nuspace-0.7.3/src/nuspace/system/init/__init__.py +12 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/init/plane.py +9 -11
- nuspace-0.7.3/src/nuspace/system/init/shapes.py +33 -0
- nuspace-0.7.3/src/nuspace/system/planes.py +94 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/reactions/__init__.py +4 -5
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/reactions/ops.py +3 -3
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/reactions/plane.py +4 -7
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/reactions/shapes.py +7 -7
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/reload/__init__.py +3 -3
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/reload/plane.py +6 -9
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/supervisor/__init__.py +4 -5
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/supervisor/plane.py +9 -13
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/supervisor/shapes.py +11 -8
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/checks.py +20 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/__init__.py +5 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/desks/pruner.py +18 -17
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/desks/ref.py +26 -5
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/device.py +13 -5
- nuspace-0.7.3/src/nuspace/web/here.py +40 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/home/indexer.py +36 -27
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/home/now.py +13 -7
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/home/runs.py +13 -6
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/interactions.py +2 -2
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/ops.py +55 -18
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/planes/__init__.py +25 -50
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/planes/search.py +21 -11
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/ref.py +10 -2
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/shapes.py +14 -5
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/sidebar/feed.py +4 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/sidebar/ref.py +4 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/utils.py +6 -0
- nuspace-0.7.3/src/nuspace/web/viewer/__init__.py +112 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/viewer/feed.py +238 -121
- nuspace-0.7.3/src/nuspace/web/viewer/interactions.py +278 -0
- nuspace-0.7.3/src/nuspace/web/viewer/ref.py +229 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/specs.py +20 -0
- nuspace-0.7.3/tests/_lib/_support/system.py +35 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_host.py +12 -7
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_ops_cell.py +11 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_ops_plane.py +11 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_shapes.py +2 -2
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_specs.py +3 -4
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_system_ops.py +68 -47
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_system_planes.py +20 -6
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_web.py +263 -90
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_web_home.py +43 -12
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_web_indexer.py +28 -22
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_web_ops.py +54 -15
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_web_planes.py +11 -8
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_web_pruner.py +12 -9
- nuspace-0.7.3/tests/nuspace/test_web_scroll.py +124 -0
- nuspace-0.7.2/src/nuspace/system/init/__init__.py +0 -12
- nuspace-0.7.2/src/nuspace/system/init/shapes.py +0 -30
- nuspace-0.7.2/src/nuspace/system/planes.py +0 -103
- nuspace-0.7.2/src/nuspace/web/viewer/__init__.py +0 -72
- nuspace-0.7.2/src/nuspace/web/viewer/interactions.py +0 -186
- nuspace-0.7.2/src/nuspace/web/viewer/ref.py +0 -123
- {nuspace-0.7.2 → nuspace-0.7.3}/.gitignore +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/.pre-commit-config.yaml +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/LICENSE.md +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/Makefile +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/README.md +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/examples/space.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/pkgs/ts/nuspace-ui/python/nuspace_ui/build +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_branding/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_branding/header.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_branding/logo.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_branding/palette.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/__main__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/_installed.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/_meta.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/commands/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/commands/init.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/commands/run.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/commands/telemetry.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/commands/verse.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_cli/main.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_telemetry/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_telemetry/config.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_telemetry/send.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/_telemetry/usage.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/errors.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/devices.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/interactions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/layout.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/lock.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/resources.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/space.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/host/stores.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/backends/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/backends/async_.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/backends/base.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/backends/interactions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/backends/mp.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/backends/pool.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/body.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/close.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/envs.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/interactions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/kernel.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/out.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/reap.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/kernel/records.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/brackets.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/cell_run.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/interactions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/plane_run.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/state.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/ops/worker.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/places.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/cell.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/cell_run.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/content.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/exec.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/plane_run.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/space.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/state.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/store.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/shapes/worker.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/specs/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/specs/registry.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/init/ops.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/system/supervisor/ops.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/interactions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/placement.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/policies.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/reads.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/tree.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/utils/typed.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/desks/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/desks/feed.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/desks/interactions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/desks/model.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/desks/ops.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/env.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/home/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/home/common.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/home/history.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/home/space.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/nav.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/planes/settings.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/session.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/shell.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/sidebar/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/sidebar/interactions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/src/nuspace/web/stores.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_ext/nuspace_testing/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_ext/pyproject.toml +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/__init__.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/actions.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/contents.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/crash_host.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/kernel.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/kernel_envs.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/made.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/_lib/_support/probe.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/conftest.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_brackets.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_cli.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_content.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_errors.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_exports.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_kernel.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_nav.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_ops_cell_run.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_ops_plane_run.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_ops_state.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_ops_worker.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_packaging.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_places.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_session_pipe.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_system_utils.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_telemetry.py +0 -0
- {nuspace-0.7.2 → nuspace-0.7.3}/tests/nuspace/test_web_desks.py +0 -0
|
@@ -2,13 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
## Packages shipped from this repo
|
|
4
4
|
|
|
5
|
-
- **nuspace** (the runtime, the `nuspace` command) — 0.7.
|
|
6
|
-
- **nuspace-ui** (the compiled web bundle) — 0.7.
|
|
5
|
+
- **nuspace** (the runtime, the `nuspace` command) — 0.7.3
|
|
6
|
+
- **nuspace-ui** (the compiled web bundle) — 0.7.3
|
|
7
7
|
|
|
8
8
|
Below is the changelog for **nuspace** - the full commit stream. Newest first.
|
|
9
9
|
The `nuspace-ui` wheel is the same source tree's vite output and is not tracked
|
|
10
10
|
separately here.
|
|
11
11
|
|
|
12
|
+
## 0.7.3 - 2026-11-16
|
|
13
|
+
|
|
14
|
+
- Release nuspace and nuspace-ui 0.7.3
|
|
15
|
+
- Home's Recent timeline shows the last hour, so long runs never hide short ones
|
|
16
|
+
- System planes get minted ids, reserved keys and readable titles, found by key
|
|
17
|
+
- Home execution rows and timeline lanes name their plane without linking to it
|
|
18
|
+
- Sidebar hover buttons shrink to the fold chevron's size, rows and titles alike
|
|
19
|
+
- Boot skeleton gets its top gap back above the title
|
|
20
|
+
|
|
21
|
+
- Drop unused cell and status wire fields; ref classes cover every feed op
|
|
22
|
+
- Cells can make their pane follow the bottom or scroll, for chat style output
|
|
23
|
+
- Opening a deep plane opens its sidebar folders, and only the sidebar reads its tree
|
|
24
|
+
- Each open pane is its own node, so a rename no longer resends its cells
|
|
25
|
+
- Pane menu Width choice now reaches the server and sticks
|
|
26
|
+
- Urls are /p/<plane> and /d/<desk>; old plane links now read page not found
|
|
27
|
+
- Plane and cell ids given from outside must be slugs, so they read cleanly in urls
|
|
28
|
+
- Add plane and / menus fold packages by focus, with flat rows that wrap
|
|
29
|
+
- Pane breadcrumbs come from the server, so they show under collapsed sidebar branches
|
|
30
|
+
- Desk header shows only the desk name and close; items stay in the sidebar
|
|
31
|
+
- Search runs on Enter in any filter, on the new nu input contract
|
|
32
|
+
- Option Cmd click opens a plane to the side; panes get a close button again
|
|
33
|
+
- Desks get a header to switch items and leave; panes close from their menu
|
|
34
|
+
- Sidebar drops say what they do, refuse with a reason, and never shift rows
|
|
35
|
+
- Flat desk shell, one plane frame, and a page, board or full width setting
|
|
36
|
+
- Plane width replaces the compact and full width flags; update specs that set them
|
|
37
|
+
|
|
12
38
|
## 0.7.2 - 2026-11-13
|
|
13
39
|
|
|
14
40
|
- Release nuspace and nuspace-ui 0.7.2
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: nuspace
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.3
|
|
4
4
|
Summary: Computational space for your data and tools.
|
|
5
5
|
Project-URL: Repository, https://github.com/nustackdev/nuspace
|
|
6
6
|
Author-email: Gor Arakelyan <gorarkln@gmail.com>
|
|
@@ -17,16 +17,16 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
17
17
|
Requires-Python: >=3.10
|
|
18
18
|
Requires-Dist: certifi>=2023.7.22
|
|
19
19
|
Requires-Dist: click>=8.0
|
|
20
|
-
Requires-Dist: nucore>=0.7.
|
|
21
|
-
Requires-Dist: nuspace-ui>=0.7.
|
|
22
|
-
Requires-Dist: nustd[kv,mp-pool,proxy,ui,valkey]>=0.7.
|
|
23
|
-
Requires-Dist: nuverse>=0.3.
|
|
20
|
+
Requires-Dist: nucore>=0.7.5
|
|
21
|
+
Requires-Dist: nuspace-ui>=0.7.3
|
|
22
|
+
Requires-Dist: nustd[kv,mp-pool,proxy,ui,valkey]>=0.7.5
|
|
23
|
+
Requires-Dist: nuverse>=0.3.11
|
|
24
24
|
Requires-Dist: rich-click>=1.6
|
|
25
25
|
Requires-Dist: rich>=10.7
|
|
26
26
|
Requires-Dist: typing-extensions>=4.7.0
|
|
27
27
|
Requires-Dist: virtuals-py[redis]>=0.2.2
|
|
28
28
|
Provides-Extra: all
|
|
29
|
-
Requires-Dist: nustd[all]>=0.7.
|
|
29
|
+
Requires-Dist: nustd[all]>=0.7.5; extra == 'all'
|
|
30
30
|
Description-Content-Type: text/markdown
|
|
31
31
|
|
|
32
32
|
<div align="center">
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nuspace"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.3"
|
|
8
8
|
description = "Computational space for your data and tools."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "AGPL-3.0-or-later"
|
|
@@ -14,17 +14,17 @@ dependencies = [
|
|
|
14
14
|
# The fabrics a space runs on, nothing more: kv for the store, valkey for
|
|
15
15
|
# its change notifications, ui for the browser, mp_pool for the workers,
|
|
16
16
|
# proxy (invisibles) for the worker's session.
|
|
17
|
-
"nucore>=0.7.
|
|
18
|
-
"nustd[kv,ui,valkey,mp_pool,proxy]>=0.7.
|
|
17
|
+
"nucore>=0.7.5",
|
|
18
|
+
"nustd[kv,ui,valkey,mp_pool,proxy]>=0.7.5",
|
|
19
19
|
# The store's change notifications run over virtuals' redis backend.
|
|
20
20
|
"virtuals-py[redis]>=0.2.2",
|
|
21
21
|
# The compiled web bundle. A separate distribution only because PyPI caps
|
|
22
22
|
# project size and a SPA rebuilt on every UI tweak would eat the quota --
|
|
23
23
|
# not optional. `pip install nuspace` gives you the browser.
|
|
24
|
-
"nuspace-ui>=0.7.
|
|
24
|
+
"nuspace-ui>=0.7.3",
|
|
25
25
|
# The everyday Planes and Cells. A plugin like any other, found through
|
|
26
26
|
# its entry point, but every space ships with it.
|
|
27
|
-
"nuverse>=0.3.
|
|
27
|
+
"nuverse>=0.3.11",
|
|
28
28
|
"typing-extensions>=4.7.0",
|
|
29
29
|
"click>=8.0",
|
|
30
30
|
"rich>=10.7",
|
|
@@ -55,7 +55,7 @@ classifiers = [
|
|
|
55
55
|
[project.optional-dependencies]
|
|
56
56
|
# Every nustd fabric and kv backend, for cells that reach past the defaults.
|
|
57
57
|
all = [
|
|
58
|
-
"nustd[all]>=0.7.
|
|
58
|
+
"nustd[all]>=0.7.5",
|
|
59
59
|
]
|
|
60
60
|
|
|
61
61
|
[project.urls]
|
|
@@ -102,7 +102,10 @@ def with_plane(
|
|
|
102
102
|
def opened(plane: nu.ObjectRef) -> nu.Nu:
|
|
103
103
|
steps = [_plane_of(found, plane)]
|
|
104
104
|
if web and open_browser:
|
|
105
|
-
url
|
|
105
|
+
# The web device's own url, so the tab opens on the same encoded path a link would.
|
|
106
|
+
from nuspace.web.interactions import Href
|
|
107
|
+
|
|
108
|
+
url = nu.Str(f"http://{host}:{port}") + nu.Str(Href(plane, {}))
|
|
106
109
|
steps.append(Browse(url, host, port))
|
|
107
110
|
return nu.Sequential(*steps, nu.Park())
|
|
108
111
|
|
|
@@ -21,6 +21,7 @@ from nuspace.shapes.space import Space
|
|
|
21
21
|
from nuspace.utils import MintId, Require, anchor_of, place
|
|
22
22
|
from nuspace.utils.checks import (
|
|
23
23
|
anchored,
|
|
24
|
+
id_spelled,
|
|
24
25
|
key_free,
|
|
25
26
|
key_spelled,
|
|
26
27
|
live,
|
|
@@ -91,7 +92,7 @@ def add(
|
|
|
91
92
|
Args:
|
|
92
93
|
plane: The plane it goes on.
|
|
93
94
|
prog: Its source.
|
|
94
|
-
id: Its id. Minted when the op evaluates when absent.
|
|
95
|
+
id: Its id, key chars. Minted when the op evaluates when absent.
|
|
95
96
|
before: A cell of the plane to place it before.
|
|
96
97
|
after: A cell of the plane to place it after. Neither: the end.
|
|
97
98
|
name: Display text only.
|
|
@@ -109,8 +110,8 @@ def add(
|
|
|
109
110
|
Exists: The id or the key is taken.
|
|
110
111
|
Missing: No plane or anchor with that id.
|
|
111
112
|
Removed: The plane or the anchor is removed.
|
|
112
|
-
Refused: An anchor on another plane, a key that is not
|
|
113
|
-
(a literal at build).
|
|
113
|
+
Refused: An anchor on another plane, an id or a key that is not
|
|
114
|
+
key chars (a literal at build).
|
|
114
115
|
TypeError: Both ``before`` and ``after``, at build.
|
|
115
116
|
"""
|
|
116
117
|
anchor = anchor_of(before, after)
|
|
@@ -136,7 +137,8 @@ def add(
|
|
|
136
137
|
)
|
|
137
138
|
|
|
138
139
|
writes = (
|
|
139
|
-
|
|
140
|
+
id_spelled(cid, "cell")
|
|
141
|
+
>> refuse(rows.contains(cid), Exists, "cell ", cid, " exists")
|
|
140
142
|
>> live(Space.planes, plane, "plane")
|
|
141
143
|
>> anchored(listed, rows, anchor, cid, "cell", text("plane ", plane))
|
|
142
144
|
>> spelled
|
|
@@ -25,6 +25,7 @@ from nuspace.shapes.space import Space
|
|
|
25
25
|
from nuspace.utils import MintId, Require, anchor_of, place
|
|
26
26
|
from nuspace.utils.checks import (
|
|
27
27
|
anchored,
|
|
28
|
+
id_spelled,
|
|
28
29
|
key_free,
|
|
29
30
|
key_spelled,
|
|
30
31
|
live,
|
|
@@ -39,6 +40,7 @@ from nuspace.utils.tree import no_cycle, subtree
|
|
|
39
40
|
__all__ = [
|
|
40
41
|
"add",
|
|
41
42
|
"exists",
|
|
43
|
+
"keyed",
|
|
42
44
|
"move",
|
|
43
45
|
"on_change",
|
|
44
46
|
"on_children_change",
|
|
@@ -74,23 +76,34 @@ def _icon_spelled(icon: nu.StrArg) -> None:
|
|
|
74
76
|
raise Refused(msg)
|
|
75
77
|
|
|
76
78
|
|
|
77
|
-
def _reserved(id: nu.StrArg
|
|
78
|
-
"""Refuse an id no
|
|
79
|
+
def _reserved(id: nu.StrArg) -> nu.Nu:
|
|
80
|
+
"""Refuse an id no plane may take: root's or ``""``.
|
|
79
81
|
|
|
80
82
|
Raises:
|
|
81
83
|
Refused: A literal at build, a term at run time.
|
|
82
84
|
"""
|
|
83
85
|
if isinstance(id, str):
|
|
84
|
-
|
|
85
|
-
if id in (ROOT, "") or (user and id in RESERVED):
|
|
86
|
+
if id in (ROOT, ""):
|
|
86
87
|
msg = f"plane id {id!r} is reserved"
|
|
87
88
|
raise Refused(msg)
|
|
88
|
-
|
|
89
|
-
return nu.Noop()
|
|
89
|
+
return nu.Noop()
|
|
90
90
|
pid = nu.Str(id)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
return refuse((pid == ROOT).or_(pid == ""), Refused, "plane id ", id, " is reserved")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _key_reserved(key: nu.StrArg, system: nu.BoolArg) -> nu.Nu:
|
|
95
|
+
"""Refuse a :data:`RESERVED` key for a plane that is not system.
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
Refused: A literal at build, a term at run time.
|
|
99
|
+
"""
|
|
100
|
+
if isinstance(key, str) and isinstance(system, bool):
|
|
101
|
+
if key in RESERVED and not system:
|
|
102
|
+
msg = f"plane key {key!r} is reserved"
|
|
103
|
+
raise Refused(msg)
|
|
104
|
+
return nu.Noop()
|
|
105
|
+
taken = nu.List.of(*sorted(RESERVED)).contains(key).and_(nu.Bool(system).not_())
|
|
106
|
+
return refuse(taken, Refused, "plane key ", key, " is reserved")
|
|
94
107
|
|
|
95
108
|
|
|
96
109
|
def _not_root(id: nu.StrArg, doing: str) -> nu.Nu:
|
|
@@ -134,7 +147,7 @@ def add(
|
|
|
134
147
|
when given. Cost: O(1), about 20 keys.
|
|
135
148
|
|
|
136
149
|
Args:
|
|
137
|
-
id: Its id. Minted when the op evaluates when absent.
|
|
150
|
+
id: Its id, key chars. Minted when the op evaluates when absent.
|
|
138
151
|
parent: The plane it hangs under.
|
|
139
152
|
before: A sibling to place it before.
|
|
140
153
|
after: A sibling to place it after. Neither: the end.
|
|
@@ -143,8 +156,8 @@ def add(
|
|
|
143
156
|
case-sensitive, ``""`` for none.
|
|
144
157
|
icon: ``lucide:<name>`` or ``emoji:<char>``. ``""``: :data:`DEFAULT_ICON`.
|
|
145
158
|
backend: What its runs execute on. ``""``: it does not run.
|
|
146
|
-
system: Protected: ``remove`` refuses it. Only a system plane
|
|
147
|
-
a :data:`~nuspace.shapes.plane.RESERVED`
|
|
159
|
+
system: Protected: ``remove`` refuses it. Only a system plane holds
|
|
160
|
+
a :data:`~nuspace.shapes.plane.RESERVED` key.
|
|
148
161
|
spec: The spec it was made from, ``""`` for none.
|
|
149
162
|
meta: The free dict, for programs. nuspace never reads it.
|
|
150
163
|
into: A ref set to the id in the same commit, for a minted one.
|
|
@@ -153,10 +166,10 @@ def add(
|
|
|
153
166
|
Exists: The id or the key is taken.
|
|
154
167
|
Missing: No parent or anchor with that id.
|
|
155
168
|
Removed: The parent or the anchor is removed.
|
|
156
|
-
Refused: A reserved id (root's
|
|
157
|
-
:data:`~nuspace.shapes.plane.RESERVED` unless ``system
|
|
158
|
-
|
|
159
|
-
icon spelled wrong. A literal at build.
|
|
169
|
+
Refused: A reserved id (root's or ``""``), a
|
|
170
|
+
:data:`~nuspace.shapes.plane.RESERVED` key unless ``system``, an
|
|
171
|
+
id or a key that is not key chars, an anchor that is not a
|
|
172
|
+
sibling, an icon spelled wrong. A literal at build.
|
|
160
173
|
TypeError: Both ``before`` and ``after``, at build.
|
|
161
174
|
"""
|
|
162
175
|
anchor = anchor_of(before, after)
|
|
@@ -186,11 +199,13 @@ def add(
|
|
|
186
199
|
)
|
|
187
200
|
|
|
188
201
|
writes = (
|
|
189
|
-
_reserved(pid
|
|
202
|
+
_reserved(pid)
|
|
203
|
+
>> id_spelled(pid, "plane")
|
|
190
204
|
>> refuse(rows.contains(pid), Exists, "plane ", pid, " exists")
|
|
191
205
|
>> live(rows, parent, "plane")
|
|
192
206
|
>> anchored(siblings, rows, anchor, pid, "plane", text("plane ", parent))
|
|
193
207
|
>> spelled
|
|
208
|
+
>> _key_reserved(key, system)
|
|
194
209
|
>> key_free(Space.indexes.plane_keys, key, None, "plane")
|
|
195
210
|
>> nu.let(nustd.time.time(), made)
|
|
196
211
|
>> place(siblings, pid, before=before, after=after)
|
|
@@ -308,7 +323,9 @@ def set_key(id: nu.StrArg, key: nu.StrArg) -> nu.Nu:
|
|
|
308
323
|
Missing: No plane with that id.
|
|
309
324
|
Removed: It is removed.
|
|
310
325
|
Exists: Another plane holds the key.
|
|
311
|
-
Refused: An empty key, or one not in key chars
|
|
326
|
+
Refused: An empty key, or one not in key chars, a literal at build.
|
|
327
|
+
A :data:`~nuspace.shapes.plane.RESERVED` key on a plane that is
|
|
328
|
+
not system.
|
|
312
329
|
"""
|
|
313
330
|
spelled = key_spelled(key, "plane", empty_ok=False)
|
|
314
331
|
index = Space.indexes.plane_keys
|
|
@@ -317,6 +334,7 @@ def set_key(id: nu.StrArg, key: nu.StrArg) -> nu.Nu:
|
|
|
317
334
|
return (
|
|
318
335
|
spelled
|
|
319
336
|
>> live(Space.planes, id, "plane")
|
|
337
|
+
>> _key_reserved(key, row.system.fallback(False))
|
|
320
338
|
>> key_free(index, key, id, "plane")
|
|
321
339
|
>> nu.IfDo((old != "").and_(old != key), index.del_item(old))
|
|
322
340
|
>> index.set_item(key, id)
|
|
@@ -391,6 +409,11 @@ def exists(id: nu.StrArg, *, removed: bool = False) -> nu.Bool:
|
|
|
391
409
|
return there if removed else there.and_(Space.planes[id].removed_at.exists().not_())
|
|
392
410
|
|
|
393
411
|
|
|
412
|
+
def keyed(key: nu.StrArg) -> nu.Str:
|
|
413
|
+
"""The id of the live plane holding ``key``, ``""`` when none does. A read. Cost: O(1), 1 point read."""
|
|
414
|
+
return nu.Str(Space.indexes.plane_keys.get_item(key, ""))
|
|
415
|
+
|
|
416
|
+
|
|
394
417
|
def title(id: nu.StrArg) -> nu.Str:
|
|
395
418
|
"""What a list or a header shows for a plane: its name, else its id. Cost: O(1), 2 reads.
|
|
396
419
|
|
|
@@ -14,12 +14,12 @@ __all__ = ["RESERVED", "ROOT", "Plane"]
|
|
|
14
14
|
#: remove), has no backend (no run) and no parent of its own (``""``).
|
|
15
15
|
ROOT = "root"
|
|
16
16
|
|
|
17
|
-
#: Plane
|
|
18
|
-
#: unless
|
|
19
|
-
#: web device's (``nuspace.web.planes``): the
|
|
20
|
-
#: home indexer and the desk pruner.
|
|
21
|
-
#:
|
|
22
|
-
#:
|
|
17
|
+
#: Plane keys only nuspace's own planes hold: ``plane.add`` and ``plane.set_key``
|
|
18
|
+
#: refuse them unless the plane is system. The system planes'
|
|
19
|
+
#: (``nuspace.system``), then the web device's (``nuspace.web.planes``): the
|
|
20
|
+
#: searches folder, the home indexer and the desk pruner. Their ids are
|
|
21
|
+
#: minted like any plane's; code finds them by key. Home, search and
|
|
22
|
+
#: settings are found through the web device's roles.
|
|
23
23
|
RESERVED = frozenset(
|
|
24
24
|
{
|
|
25
25
|
"init",
|
|
@@ -129,8 +129,7 @@ def _web_row(pid: nu.Str, spec: PlaneSpec) -> nu.Nu:
|
|
|
129
129
|
return web.add(
|
|
130
130
|
pid,
|
|
131
131
|
editable=flags.editable, # type: ignore[union-attr]
|
|
132
|
-
|
|
133
|
-
compact=flags.compact, # type: ignore[union-attr]
|
|
132
|
+
width=flags.width, # type: ignore[union-attr]
|
|
134
133
|
)
|
|
135
134
|
|
|
136
135
|
|
|
@@ -16,7 +16,7 @@ spec says how a space presents it.
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
18
|
from dataclasses import dataclass, field
|
|
19
|
-
from typing import TYPE_CHECKING, Any
|
|
19
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
20
20
|
|
|
21
21
|
import nu
|
|
22
22
|
import nustd.kv
|
|
@@ -38,13 +38,13 @@ class WebOptions:
|
|
|
38
38
|
|
|
39
39
|
Args:
|
|
40
40
|
editable: Its cells can be edited in the browser.
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
width: How wide its content runs in a pane, at most: ``page`` (the
|
|
42
|
+
reading measure), ``board`` (a dashboard's) or ``full`` (the
|
|
43
|
+
whole pane).
|
|
43
44
|
"""
|
|
44
45
|
|
|
45
46
|
editable: bool = True
|
|
46
|
-
|
|
47
|
-
compact: bool = False
|
|
47
|
+
width: Literal["page", "board", "full"] = "page"
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
class SpecCells(nu.Shape):
|
|
@@ -123,7 +123,7 @@ EMPTY_PLANE = PlaneSpec(
|
|
|
123
123
|
"",
|
|
124
124
|
"Empty",
|
|
125
125
|
description="An empty plane. Add cells with /, or nest planes under it.",
|
|
126
|
-
web=WebOptions(editable=True
|
|
126
|
+
web=WebOptions(editable=True),
|
|
127
127
|
backend="async",
|
|
128
128
|
)
|
|
129
129
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""``nuspace.system.init``: the system plane that starts planes when the space opens.
|
|
2
|
+
|
|
3
|
+
- ops: :func:`boot`, :func:`unboot`, over the boot list (:class:`Boot`).
|
|
4
|
+
- :mod:`.plane`: the plane's cell and its driver.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .ops import boot, unboot
|
|
8
|
+
from .plane import BOOTED, BY, driver
|
|
9
|
+
from .shapes import KEY, Boot, boot_list
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = ["BOOTED", "BY", "KEY", "Boot", "boot", "boot_list", "driver", "unboot"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""The init plane: starts the planes on its boot list when the space opens.
|
|
2
2
|
|
|
3
|
-
One cell,
|
|
3
|
+
One cell, ``main``, runs :func:`driver`. The host asks for init's own
|
|
4
4
|
plane run at open (``nuspace.system.start``); init asks for the rest. A
|
|
5
5
|
plane on the boot list (:class:`~.shapes.Boot`) gets one plane run ``by``
|
|
6
6
|
init in every open, unless it already ran in this open:
|
|
@@ -35,22 +35,20 @@ from nuspace.utils import keys_of
|
|
|
35
35
|
from nuspace.utils.policies import report, restarting
|
|
36
36
|
|
|
37
37
|
from .. import supervisor
|
|
38
|
-
from .shapes import
|
|
38
|
+
from .shapes import KEY, boot_list
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
__all__ = ["BACKEND", "BOOTED", "BY", "
|
|
41
|
+
__all__ = ["BACKEND", "BOOTED", "BY", "PROG", "driver"]
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
#: Its one cell's id, fixed.
|
|
45
|
-
CELL = "init_main"
|
|
46
|
-
|
|
47
44
|
#: What its runs execute on.
|
|
48
45
|
BACKEND = "mp"
|
|
49
46
|
|
|
50
47
|
#: What the plane runs init asks for are recorded as ``by``.
|
|
51
48
|
BY = "init"
|
|
52
49
|
|
|
53
|
-
#: What the boot list starts as, the first time the system planes are made
|
|
50
|
+
#: What the boot list starts as, the first time the system planes are made: plane keys,
|
|
51
|
+
#: written as the ids they find.
|
|
54
52
|
BOOTED = ("supervisor", "reload", "reactions")
|
|
55
53
|
|
|
56
54
|
#: The cell's prog: the driver lives here, the store holds this.
|
|
@@ -69,7 +67,7 @@ def _supervised(plane: nu.Str) -> nu.Bool:
|
|
|
69
67
|
The supervisor plane itself is never skipped: init is what brings it up.
|
|
70
68
|
"""
|
|
71
69
|
policy = supervisor.supervised()[plane].policy
|
|
72
|
-
return policy.exists().and_(plane != supervisor.
|
|
70
|
+
return policy.exists().and_(plane != ops.plane.keyed(supervisor.KEY))
|
|
73
71
|
|
|
74
72
|
|
|
75
73
|
def _due(plane: nu.Str) -> nu.Bool:
|
|
@@ -93,7 +91,7 @@ def _due(plane: nu.Str) -> nu.Bool:
|
|
|
93
91
|
def _up(plane: nu.Str) -> nu.Nu:
|
|
94
92
|
"""One listed plane run if it is due, check and run in one commit. A raise is reported."""
|
|
95
93
|
up = atomic(nu.IfDo(_due(plane), ops.plane_run.add(plane, by=BY)))
|
|
96
|
-
return nu.TryCatch(up, catch=lambda err: report(
|
|
94
|
+
return nu.TryCatch(up, catch=lambda err: report(KEY, plane, err))
|
|
97
95
|
|
|
98
96
|
|
|
99
97
|
def driver() -> nu.Nu:
|
|
@@ -103,7 +101,7 @@ def driver() -> nu.Nu:
|
|
|
103
101
|
raise outside a plane's step (reading the list) is reported and the
|
|
104
102
|
driver runs again (``restarting``).
|
|
105
103
|
"""
|
|
106
|
-
planes = boot_list()
|
|
104
|
+
planes = boot_list(here=True)
|
|
107
105
|
listed = keys_of(planes)
|
|
108
106
|
one_pass = nu.ForEachDo(atomic(listed), lambda p: _up(nu.Str(p)))
|
|
109
107
|
flow = nu.Reconcile(
|
|
@@ -112,4 +110,4 @@ def driver() -> nu.Nu:
|
|
|
112
110
|
after=nu.RECHECK_AFTER,
|
|
113
111
|
every=nu.RECHECK_EVERY,
|
|
114
112
|
)
|
|
115
|
-
return restarting(flow,
|
|
113
|
+
return restarting(flow, KEY)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""init's own state: the plane's key and the boot list, kept in the init plane's state."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import nu
|
|
6
|
+
import nustd.kv
|
|
7
|
+
from nuspace.places import at
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
__all__ = ["KEY", "Boot", "boot_list"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
#: The plane's key. Its id is minted when it is made; code finds it by this.
|
|
14
|
+
KEY = "init"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Boot(nu.Shape):
|
|
18
|
+
"""init's state, in the init plane's state.
|
|
19
|
+
|
|
20
|
+
``planes`` is the boot list: the ids of the planes init runs at every
|
|
21
|
+
open, a set (dict of bool, point add and delete). Reach it through the
|
|
22
|
+
plane's place: ``nuspace.at.plane(init.KEY).state(Boot).planes``.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
planes = nustd.kv.DictRef.slot(bool)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def boot_list(*, here: bool = False) -> nu.Nu:
|
|
29
|
+
"""The boot list's ref, found by key: one index read. ``here``: the running plane's, no read.
|
|
30
|
+
|
|
31
|
+
``here`` is for init's own cell; every other caller finds the plane by key.
|
|
32
|
+
"""
|
|
33
|
+
return (at.plane if here else at.plane(KEY)).state(Boot).planes
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""The system planes as a set: made where missing, and init started. What the host runs at open.
|
|
2
|
+
|
|
3
|
+
Each system plane has a minted id like any plane, a key code finds it by
|
|
4
|
+
(``nuspace.at.plane(KEY)``, ``ops.plane.keyed(KEY)``), a title, is
|
|
5
|
+
``system`` (remove refuses it, only it holds a reserved key) and holds
|
|
6
|
+
cells whose progs are short shims: the code lives in
|
|
7
|
+
``nuspace.system.<plane>``, the store holds the shim. init's boot list
|
|
8
|
+
starts as the other three, so init brings them up:
|
|
9
|
+
|
|
10
|
+
host ensure() >> start()
|
|
11
|
+
init boots supervisor, reload, reactions
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import nu
|
|
17
|
+
from nuspace import ops
|
|
18
|
+
from nuspace.ops.brackets import atomic
|
|
19
|
+
from nuspace.utils import MintId
|
|
20
|
+
|
|
21
|
+
from . import init, reactions, reload, supervisor
|
|
22
|
+
from .init.plane import BACKEND as INIT_BACKEND
|
|
23
|
+
from .init.plane import PROG as INIT_PROG
|
|
24
|
+
from .reactions.plane import BACKEND as REACTIONS_BACKEND
|
|
25
|
+
from .reactions.plane import PARK_PROG
|
|
26
|
+
from .reload.plane import BACKEND as RELOAD_BACKEND
|
|
27
|
+
from .reload.plane import PROG as RELOAD_PROG
|
|
28
|
+
from .supervisor.plane import BACKEND as SUPERVISOR_BACKEND
|
|
29
|
+
from .supervisor.plane import PROG as SUPERVISOR_PROG
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__ = ["BY", "PLANES", "ensure", "start"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
#: Every system plane: ``(key, title, backend, ((cell name, prog), ...))``. init first.
|
|
36
|
+
PLANES = (
|
|
37
|
+
(init.KEY, "Init", INIT_BACKEND, (("main", INIT_PROG),)),
|
|
38
|
+
(supervisor.KEY, "Supervisor", SUPERVISOR_BACKEND, (("main", SUPERVISOR_PROG),)),
|
|
39
|
+
(reload.KEY, "Reload", RELOAD_BACKEND, (("main", RELOAD_PROG),)),
|
|
40
|
+
(reactions.KEY, "Reactions", REACTIONS_BACKEND, (("park", PARK_PROG),)),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
#: What init's own plane run is recorded as ``by`` when :func:`start` asks for it.
|
|
44
|
+
BY = "host"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _made(key: str, title: str, backend: str, cells: tuple[tuple[str, str], ...]) -> nu.Nu:
|
|
48
|
+
"""One system plane and its cells, minted ids, when no plane holds its key. One commit."""
|
|
49
|
+
|
|
50
|
+
def made(minted: nu.ObjectRef) -> nu.Nu:
|
|
51
|
+
plane = nu.Str(minted)
|
|
52
|
+
adds = ops.plane.add(plane, key=key, name=title, backend=backend, system=True)
|
|
53
|
+
for name, prog in cells:
|
|
54
|
+
adds = adds >> ops.cell.add(plane, prog, name=name, fabrics=[])
|
|
55
|
+
return adds
|
|
56
|
+
|
|
57
|
+
return atomic(nu.IfDo(ops.plane.keyed(key) == "", nu.let(MintId("p"), made)))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def ensure() -> nu.Nu:
|
|
61
|
+
"""Every system plane and its cells, then their state's containers, made where missing.
|
|
62
|
+
|
|
63
|
+
Idempotent: a plane is made only when no plane holds its key, and what
|
|
64
|
+
is there is left exactly as it is, init's boot list included (it is data
|
|
65
|
+
somebody may have edited). The boot list starts as the ids of
|
|
66
|
+
:data:`~nuspace.system.init.BOOTED`'s planes the first time. One commit
|
|
67
|
+
per plane, then one State commit.
|
|
68
|
+
"""
|
|
69
|
+
made = nu.Sequential(*(_made(*spec) for spec in PLANES))
|
|
70
|
+
booted = init.boot_list()
|
|
71
|
+
first = nu.Sequential(
|
|
72
|
+
booted.init({}),
|
|
73
|
+
*(booted.set_item(ops.plane.keyed(key), True) for key in init.BOOTED),
|
|
74
|
+
)
|
|
75
|
+
state = (
|
|
76
|
+
nu.IfDo(booted.exists().not_(), first)
|
|
77
|
+
>> supervisor.supervised().init({})
|
|
78
|
+
>> reactions.registry().by_plane.init({})
|
|
79
|
+
)
|
|
80
|
+
return made >> atomic(state)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def start(*, by: nu.StrArg = BY) -> nu.Nu:
|
|
84
|
+
"""A plane run of init asked for, unless it has a live one. One commit. The kernel runs it.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
by: Who asks, what the run is recorded as.
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
Missing: No init plane: :func:`ensure` first.
|
|
91
|
+
"""
|
|
92
|
+
plane = ops.plane.keyed(init.KEY)
|
|
93
|
+
idle = ops.plane_run.any_live(plane).not_()
|
|
94
|
+
return atomic(nu.IfDo(idle, ops.plane_run.add(plane, by=by)))
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
"""``nuspace.system.reactions``: the system plane that runs a plane when something changes.
|
|
2
2
|
|
|
3
3
|
- ops: :func:`add`, :func:`remove`, :func:`clear`; :func:`source`, a reaction's prog.
|
|
4
|
-
- :mod:`.plane`:
|
|
4
|
+
- :mod:`.plane`: its park cell, :func:`react` (a reaction's program) and :func:`up_plane`.
|
|
5
5
|
- shapes: :class:`Registry` (by plane), :class:`Reaction` (a reaction's plane and run).
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from .ops import add, clear, remove, source
|
|
9
|
-
from .plane import
|
|
10
|
-
from .shapes import
|
|
9
|
+
from .plane import react, up_plane
|
|
10
|
+
from .shapes import KEY, Reaction, ReactionIds, Registry, registry
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
__all__ = [
|
|
14
|
-
"
|
|
15
|
-
"PLANE",
|
|
14
|
+
"KEY",
|
|
16
15
|
"Reaction",
|
|
17
16
|
"ReactionIds",
|
|
18
17
|
"Registry",
|
|
@@ -26,7 +26,7 @@ from nuspace.shapes import Space
|
|
|
26
26
|
from nuspace.utils import MintId, keys_of
|
|
27
27
|
from nuspace.utils.checks import live, refuse
|
|
28
28
|
|
|
29
|
-
from .shapes import
|
|
29
|
+
from .shapes import KEY, Reaction, registry
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
if TYPE_CHECKING:
|
|
@@ -127,7 +127,7 @@ def add(
|
|
|
127
127
|
>> at.cell(id=reaction).state(Reaction).plane.set(plane)
|
|
128
128
|
>> registry().by_plane[plane].ids.set_item(reaction, True)
|
|
129
129
|
)
|
|
130
|
-
cell = ops.cell.add(
|
|
130
|
+
cell = ops.cell.add(ops.plane.keyed(KEY), src, id=reaction, name=plane, fabrics=[])
|
|
131
131
|
steps = atomic(kept) >> atomic(cell)
|
|
132
132
|
if into is not None:
|
|
133
133
|
steps = steps >> atomic(into.set(reaction))
|
|
@@ -141,7 +141,7 @@ def add(
|
|
|
141
141
|
def _known(reaction: nu.StrArg) -> nu.Bool:
|
|
142
142
|
"""Whether ``reaction`` is a live reaction: a cell on the reactions plane, not removed, with its plane kept."""
|
|
143
143
|
row = Space.cells[reaction]
|
|
144
|
-
on = row.plane.fallback("") ==
|
|
144
|
+
on = row.plane.fallback("") == ops.plane.keyed(KEY)
|
|
145
145
|
kept = at.cell(id=reaction).state(Reaction).plane.exists()
|
|
146
146
|
return on.and_(row.removed_at.exists().not_()).and_(kept)
|
|
147
147
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""The reactions plane: runs a plane when something changes. No engine of its own.
|
|
2
2
|
|
|
3
3
|
The plane runs its cells like any plane, on the ``async`` backend, and
|
|
4
|
-
init boots it. Its first cell,
|
|
4
|
+
init boots it. Its first cell, ``park``, runs ``nu.Park()``: it never
|
|
5
5
|
ends, so the plane run stays live with no reactions at all, and reload
|
|
6
6
|
gives each new reaction cell its first run in it. Every other cell is a
|
|
7
7
|
reaction (see :mod:`.ops`), whose program is :func:`react`::
|
|
@@ -30,15 +30,12 @@ from nuspace.places import at
|
|
|
30
30
|
from nuspace.shapes import Space
|
|
31
31
|
from nuspace.utils.policies import restarting
|
|
32
32
|
|
|
33
|
-
from .shapes import
|
|
33
|
+
from .shapes import KEY, Reaction
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
__all__ = ["BACKEND", "
|
|
36
|
+
__all__ = ["BACKEND", "PARK_PROG", "react", "up_plane"]
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
#: Its fixed first cell, the one that keeps its run live.
|
|
40
|
-
PARK = "reactions_park"
|
|
41
|
-
|
|
42
39
|
#: What its runs execute on.
|
|
43
40
|
BACKEND = "async"
|
|
44
41
|
|
|
@@ -99,4 +96,4 @@ def react(change: nu.Nu, plane: nu.StrArg, reaction: nu.StrArg) -> nu.Nu:
|
|
|
99
96
|
reaction: The reaction's id.
|
|
100
97
|
"""
|
|
101
98
|
flow = nu.ReactEvery(atomic(change), up_plane(plane, reaction))
|
|
102
|
-
return restarting(flow,
|
|
99
|
+
return restarting(flow, KEY, reaction)
|