session-py 0.231.0__tar.gz → 0.232.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. {session_py-0.231.0 → session_py-0.232.0}/PKG-INFO +3 -1
  2. {session_py-0.231.0 → session_py-0.232.0}/README.md +2 -0
  3. session_py-0.232.0/docs/history.md +99 -0
  4. {session_py-0.231.0 → session_py-0.232.0}/pyproject.toml +1 -1
  5. {session_py-0.231.0 → session_py-0.232.0}/.github/FUNDING.yml +0 -0
  6. {session_py-0.231.0 → session_py-0.232.0}/.github/workflows/publish.yml +0 -0
  7. {session_py-0.231.0 → session_py-0.232.0}/.github/workflows/test.yml +0 -0
  8. {session_py-0.231.0 → session_py-0.232.0}/.gitignore +0 -0
  9. {session_py-0.231.0 → session_py-0.232.0}/.gitmodules +0 -0
  10. {session_py-0.231.0 → session_py-0.232.0}/AGENTS.md +0 -0
  11. {session_py-0.231.0 → session_py-0.232.0}/CLAUDE.md +0 -0
  12. {session_py-0.231.0 → session_py-0.232.0}/conftest.py +0 -0
  13. {session_py-0.231.0 → session_py-0.232.0}/examples/bench.py +0 -0
  14. {session_py-0.231.0 → session_py-0.232.0}/examples/bvh_demo.py +0 -0
  15. {session_py-0.231.0 → session_py-0.232.0}/examples/loft_holes.py +0 -0
  16. {session_py-0.231.0 → session_py-0.232.0}/examples/nurbsurface.py +0 -0
  17. {session_py-0.231.0 → session_py-0.232.0}/serialization/.gitkeep +0 -0
  18. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/__init__.py +0 -0
  19. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/aabb.py +0 -0
  20. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/aabb_test.py +0 -0
  21. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/boolean_polyline.py +0 -0
  22. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/boolean_polyline_test.py +0 -0
  23. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/brep.py +0 -0
  24. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/brep_test.py +0 -0
  25. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/closest.py +0 -0
  26. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/closest_test.py +0 -0
  27. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/collection.py +0 -0
  28. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/collection_test.py +0 -0
  29. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/color.py +0 -0
  30. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/color_test.py +0 -0
  31. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/convex_hull.py +0 -0
  32. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/convex_hull_test.py +0 -0
  33. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/element.py +0 -0
  34. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/element_test.py +0 -0
  35. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/file_encoders.py +0 -0
  36. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/file_encoders_test.py +0 -0
  37. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/file_obj.py +0 -0
  38. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/file_obj_test.py +0 -0
  39. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/file_step.py +0 -0
  40. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/file_step_test.py +0 -0
  41. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/graph.py +0 -0
  42. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/graph_test.py +0 -0
  43. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/history.py +0 -0
  44. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/history_test.py +0 -0
  45. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/instance_ref.py +0 -0
  46. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/instance_ref_test.py +0 -0
  47. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/interaction.py +0 -0
  48. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/interaction_test.py +0 -0
  49. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/intersection.py +0 -0
  50. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/intersection_test.py +0 -0
  51. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/io_xyz.py +0 -0
  52. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/io_xyz_test.py +0 -0
  53. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/line.py +0 -0
  54. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/line_test.py +0 -0
  55. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/matrix.py +0 -0
  56. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/matrix_test.py +0 -0
  57. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/mesh.py +0 -0
  58. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/mesh_offset.py +0 -0
  59. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/mesh_offset_test.py +0 -0
  60. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/mesh_test.py +0 -0
  61. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/mini_test.py +0 -0
  62. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbscurve.py +0 -0
  63. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbscurve_test.py +0 -0
  64. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbsknot.py +0 -0
  65. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbsknot_test.py +0 -0
  66. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbssurface.py +0 -0
  67. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbssurface_test.py +0 -0
  68. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbssurface_trimmed.py +0 -0
  69. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/nurbssurface_trimmed_test.py +0 -0
  70. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/obb.py +0 -0
  71. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/obb_test.py +0 -0
  72. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/objects.py +0 -0
  73. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/objects_test.py +0 -0
  74. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/plane.py +0 -0
  75. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/plane_test.py +0 -0
  76. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/point.py +0 -0
  77. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/point_test.py +0 -0
  78. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/pointcloud.py +0 -0
  79. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/pointcloud_test.py +0 -0
  80. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/polyline.py +0 -0
  81. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/polyline_test.py +0 -0
  82. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/primitives.py +0 -0
  83. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/primitives_test.py +0 -0
  84. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/.gitattributes +0 -0
  85. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/__init__.py +0 -0
  86. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/boundingbox_pb2.py +0 -0
  87. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/brep_pb2.py +0 -0
  88. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/color_pb2.py +0 -0
  89. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/element_pb2.py +0 -0
  90. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/file_encoders_pb2.py +0 -0
  91. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/graph_edge_pb2.py +0 -0
  92. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/graph_pb2.py +0 -0
  93. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/graph_vertex_pb2.py +0 -0
  94. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/instance_ref_pb2.py +0 -0
  95. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/interaction_pb2.py +0 -0
  96. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/line_pb2.py +0 -0
  97. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/matrix_pb2.py +0 -0
  98. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/mesh_pb2.py +0 -0
  99. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/nurbscurve_pb2.py +0 -0
  100. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/nurbssurface_pb2.py +0 -0
  101. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/nurbssurface_trimmed_pb2.py +0 -0
  102. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/objects_pb2.py +0 -0
  103. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/plane_pb2.py +0 -0
  104. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/point_pb2.py +0 -0
  105. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/pointcloud_pb2.py +0 -0
  106. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/polyline_pb2.py +0 -0
  107. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/quaternion_pb2.py +0 -0
  108. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/session_pb2.py +0 -0
  109. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/sheet_pb2.py +0 -0
  110. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/tolerance_pb2.py +0 -0
  111. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/tree_pb2.py +0 -0
  112. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/treenode_pb2.py +0 -0
  113. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/vector_pb2.py +0 -0
  114. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/proto/xform_pb2.py +0 -0
  115. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/py.typed +0 -0
  116. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/quaternion.py +0 -0
  117. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/quaternion_test.py +0 -0
  118. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/reload.py +0 -0
  119. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/remesh_cdt.py +0 -0
  120. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/remesh_cdt_test.py +0 -0
  121. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/remesh_nurbssurface_adaptive.py +0 -0
  122. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/remesh_nurbssurface_adaptive_test.py +0 -0
  123. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/remesh_nurbssurface_grid.py +0 -0
  124. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/remesh_nurbssurface_grid_test.py +0 -0
  125. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/session.py +0 -0
  126. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/session_config.py +0 -0
  127. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/session_config_test.py +0 -0
  128. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/session_test.py +0 -0
  129. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/simple_split.py +0 -0
  130. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/simple_split_test.py +0 -0
  131. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_aabbtree.py +0 -0
  132. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_aabbtree_test.py +0 -0
  133. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_bvh.py +0 -0
  134. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_bvh_test.py +0 -0
  135. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_kdtree.py +0 -0
  136. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_kdtree_test.py +0 -0
  137. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_octree.py +0 -0
  138. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_octree_test.py +0 -0
  139. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_rtree.py +0 -0
  140. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/spatial_rtree_test.py +0 -0
  141. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/tolerance.py +0 -0
  142. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/tolerance_test.py +0 -0
  143. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/tree.py +0 -0
  144. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/tree_test.py +0 -0
  145. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/vector.py +0 -0
  146. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/vector_test.py +0 -0
  147. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/xform.py +0 -0
  148. {session_py-0.231.0 → session_py-0.232.0}/src/session_py/xform_test.py +0 -0
  149. {session_py-0.231.0 → session_py-0.232.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: session_py
3
- Version: 0.231.0
3
+ Version: 0.232.0
4
4
  Summary: A minimal Python geometry library
5
5
  Project-URL: Homepage, https://github.com/petrasvestartas/session_py
6
6
  Project-URL: Repository, https://github.com/petrasvestartas/session_py
@@ -26,6 +26,8 @@ Description-Content-Type: text/markdown
26
26
 
27
27
  Python geometry kernel. Published to [PyPI](https://pypi.org/project/session-py/) automatically on every push to main.
28
28
 
29
+ Undo, history and purge: [docs/history.md](docs/history.md).
30
+
29
31
  ## Install
30
32
 
31
33
  ```bash
@@ -2,6 +2,8 @@
2
2
 
3
3
  Python geometry kernel. Published to [PyPI](https://pypi.org/project/session-py/) automatically on every push to main.
4
4
 
5
+ Undo, history and purge: [docs/history.md](docs/history.md).
6
+
5
7
  ## Install
6
8
 
7
9
  ```bash
@@ -0,0 +1,99 @@
1
+ # Undo, history and purge
2
+
3
+ How `Session` deletes, undoes, redoes and saves. The code is in `src/session_py/session.py`, `history.py`, `collection.py`, `tree.py` and `graph.py`.
4
+
5
+ ## A delete is a flag, not a copy
6
+
7
+ `remove_object(guid)` does not erase anything. It marks the object dead in place: its slot in the typed list, its tree node, its transform, its graph vertex and edges, and the interactions on those edges.
8
+
9
+ A dead entry is still in memory but hidden from every public view.
10
+
11
+ A tomb is the small record that remembers where a dead object lives (its list, its slot, its node) and holds what it parked while dead (transform, vertex, edges, interactions).
12
+
13
+ History keeps the same Python object the session held, never a copy. Undo flips the tomb back to live, so the object returns as the same object (`is` holds), in the same slot, under the same tree node. Redo flips it dead again. Both are O(1) plus the object's edges.
14
+
15
+ Tree nodes work the same way: a dead node hides itself and its subtree, and a node moved to a new parent leaves a dead ghost in its old place.
16
+
17
+ ## Collection
18
+
19
+ Every typed list in `Objects` (`points`, `meshes`, `breps`, ...) is a `Collection`: a list of slots where each slot can be live or dead.
20
+
21
+ The public views see live entries only, in slot order:
22
+
23
+ - `len(c)` and `bool(c)` count live entries.
24
+ - `for item in c` skips dead slots.
25
+ - `c[i]` returns the i-th live entry, and a slice returns a list of live entries.
26
+ - `item in c` and `==` compare live entries only.
27
+
28
+ The raw slot API is for `Session`, `History` and the purge, not for user code: `get_slot`, `get_item`, `set_item`, `is_dead`, `set_dead`, `get_tomb`, `set_tomb`, `number_of_dead`, `number_of_slots`, `is_compacting`, `compact_step` and `compact`.
29
+
30
+ `copy.deepcopy` of a collection copies its live entries only, already compacted.
31
+
32
+ ## History is bounded by bytes
33
+
34
+ Every record carries a weight: an estimate of the bytes it keeps alive. A record costs `RECORD` (256 bytes) plus the weight of the object it holds; a removed object also adds 128 bytes per graph edge.
35
+
36
+ For a mesh with V vertices and F faces the weight is `128 + 768·V + 192·F`. A mesh of 10,000 vertices and 20,000 faces weighs about 11.5 MB.
37
+
38
+ When the undo and redo stacks together pass `history.budget` (`BUDGET`, 256 MB by default), the oldest step is dropped. Steps are also capped at `CAPACITY` (64), but for real models the byte budget is the limit that bites. The newest step is always kept.
39
+
40
+ A new step clears the redo stack.
41
+
42
+ ## Purge
43
+
44
+ A dead slot stays until a purge frees it. A purge only frees what no history record can still reach.
45
+
46
+ - `purge()` clears the history, then compacts everything: every list, every tree node, and dense graph indices. It is O(n + N + V log V + E log E).
47
+ - `pb_dumps`, `pb_dump`, `file_json_dumps` and `file_json_dump` call `purge()` first, so undo cannot cross a save. `to_proto` and `__jsondump__` write live entries and keep the history.
48
+ - `purge_step(work)` does at most `work` units of the purge and returns `True` while it is unfinished. Call it on idle frames with `PURGE_WORK` from `session_py.session` (1024 units, about 2 ms in Python). It only runs when dropped history left something to free (`purge_due()`).
49
+ - `checkpoint(work)` writes the live session as protobuf bytes, `work` units per call, and returns them once done, `None` until then. It keeps the history, so it is the call for autosave.
50
+
51
+ Both are resumable cursors and never block an edit. A compaction picks up where it stopped. A checkpoint started before an edit is thrown away and restarts from the new state.
52
+
53
+ ## Twins
54
+
55
+ A twin is a second entry with a guid that is already live.
56
+
57
+ `add_*` refuses a guid that is already live anywhere in the session, as an object, component, instance or definition. It adds nothing and returns `None` or the node that guid already has.
58
+
59
+ Ownership is judged session-wide: when undo or redo would revive a tomb whose guid another live entry now owns, the tomb stays dead and the live entry keeps the guid, its node, transform and edges.
60
+
61
+ ## Interactions
62
+
63
+ `interactions` maps an edge guid to that edge's list of interactions. A delete parks each incident edge's list in the tomb under the edge guid. Undo puts the edges back and returns each list only when the restored edge has the same guid. Redo parks them again.
64
+
65
+ ## Graph: take_node and put_node
66
+
67
+ - `take_node(key)` removes a vertex and its incident edges without renumbering the others, and returns `(vertex, edges)`; `None` when the key is missing.
68
+ - `put_node(vertex, edges)` puts them back. It adopts a bare vertex `add_edge` created meanwhile, and skips an edge whose other end is gone or whose place a newer edge took.
69
+
70
+ Both are O(d) for a vertex of degree d. Indices become dense again at the next `purge()`, which calls `renumber()`.
71
+
72
+ ## Example
73
+
74
+ ```python
75
+ from session_py import Point
76
+ from session_py import Session
77
+ from session_py.session import PURGE_WORK
78
+
79
+ session = Session()
80
+ node = session.add_point(Point(1.0, 2.0, 3.0))
81
+ guid = node.name
82
+
83
+ session.begin("delete")
84
+ session.remove_object(guid)
85
+ session.commit()
86
+ # len(session.objects.points) == 0, number_of_slots() == 1: the slot is dead, not gone.
87
+
88
+ session.undo() # The same object is live again in the same slot.
89
+ session.redo() # Dead again.
90
+
91
+ session.pb_dump("scene.pb") # Purges: history cleared, the dead slot freed.
92
+ # session.undo() now returns False.
93
+
94
+ # On an idle frame:
95
+ session.purge_step(PURGE_WORK)
96
+
97
+ # Autosave, one call per frame until the bytes arrive:
98
+ data = session.checkpoint(PURGE_WORK)
99
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "session_py"
7
- version = "0.231.0"
7
+ version = "0.232.0"
8
8
  description = "A minimal Python geometry library"
9
9
  authors = [{name = "Petras Vestartas", email = "petrasvestartas@gmail.com"}]
10
10
  license = {text = "MIT"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes