py2max 0.2.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.
Files changed (184) hide show
  1. py2max-0.2.1/CHANGELOG.md +559 -0
  2. py2max-0.2.1/LICENSE +19 -0
  3. py2max-0.2.1/PKG-INFO +390 -0
  4. py2max-0.2.1/README.md +355 -0
  5. py2max-0.2.1/py2max/__init__.py +67 -0
  6. py2max-0.2.1/py2max/__main__.py +6 -0
  7. py2max-0.2.1/py2max/cli.py +1251 -0
  8. py2max-0.2.1/py2max/core/__init__.py +39 -0
  9. py2max-0.2.1/py2max/core/abstract.py +146 -0
  10. py2max-0.2.1/py2max/core/box.py +231 -0
  11. py2max-0.2.1/py2max/core/common.py +19 -0
  12. py2max-0.2.1/py2max/core/patcher.py +1658 -0
  13. py2max-0.2.1/py2max/core/patchline.py +68 -0
  14. py2max-0.2.1/py2max/exceptions.py +385 -0
  15. py2max-0.2.1/py2max/export/__init__.py +20 -0
  16. py2max-0.2.1/py2max/export/converters.py +345 -0
  17. py2max-0.2.1/py2max/export/svg.py +393 -0
  18. py2max-0.2.1/py2max/layout/__init__.py +26 -0
  19. py2max-0.2.1/py2max/layout/base.py +463 -0
  20. py2max-0.2.1/py2max/layout/flow.py +405 -0
  21. py2max-0.2.1/py2max/layout/grid.py +374 -0
  22. py2max-0.2.1/py2max/layout/matrix.py +628 -0
  23. py2max-0.2.1/py2max/log.py +338 -0
  24. py2max-0.2.1/py2max/maxref/__init__.py +78 -0
  25. py2max-0.2.1/py2max/maxref/category.py +163 -0
  26. py2max-0.2.1/py2max/maxref/db.py +1082 -0
  27. py2max-0.2.1/py2max/maxref/legacy.py +324 -0
  28. py2max-0.2.1/py2max/maxref/parser.py +703 -0
  29. py2max-0.2.1/py2max/py.typed +0 -0
  30. py2max-0.2.1/py2max/server/__init__.py +54 -0
  31. py2max-0.2.1/py2max/server/client.py +295 -0
  32. py2max-0.2.1/py2max/server/inline.py +312 -0
  33. py2max-0.2.1/py2max/server/repl.py +561 -0
  34. py2max-0.2.1/py2max/server/rpc.py +240 -0
  35. py2max-0.2.1/py2max/server/websocket.py +997 -0
  36. py2max-0.2.1/py2max/static/cola.min.js +4 -0
  37. py2max-0.2.1/py2max/static/d3.v7.min.js +2 -0
  38. py2max-0.2.1/py2max/static/dagre-bundle.js +328 -0
  39. py2max-0.2.1/py2max/static/elk.bundled.js +6663 -0
  40. py2max-0.2.1/py2max/static/index.html +168 -0
  41. py2max-0.2.1/py2max/static/interactive.html +589 -0
  42. py2max-0.2.1/py2max/static/interactive.js +2111 -0
  43. py2max-0.2.1/py2max/static/live-preview.js +324 -0
  44. py2max-0.2.1/py2max/static/svg.min.js +13 -0
  45. py2max-0.2.1/py2max/static/svg.min.js.map +1 -0
  46. py2max-0.2.1/py2max/transformers.py +168 -0
  47. py2max-0.2.1/py2max/utils.py +83 -0
  48. py2max-0.2.1/pyproject.toml +77 -0
  49. py2max-0.2.1/tests/__init__.py +0 -0
  50. py2max-0.2.1/tests/data/complex.maxpat +1348 -0
  51. py2max-0.2.1/tests/data/desc.maxpat +136 -0
  52. py2max-0.2.1/tests/data/empty.maxpat +47 -0
  53. py2max-0.2.1/tests/data/nested.maxpat +181 -0
  54. py2max-0.2.1/tests/data/simple.maxpat +86 -0
  55. py2max-0.2.1/tests/data/tabular.maxpat +216 -0
  56. py2max-0.2.1/tests/data/umenu.maxref.xml +1129 -0
  57. py2max-0.2.1/tests/examples/README.md +92 -0
  58. py2max-0.2.1/tests/examples/advanced/connection_patterns.py +128 -0
  59. py2max-0.2.1/tests/examples/advanced/custom_extensions.py +192 -0
  60. py2max-0.2.1/tests/examples/advanced/data_containers.py +140 -0
  61. py2max-0.2.1/tests/examples/advanced/error_handling.py +162 -0
  62. py2max-0.2.1/tests/examples/advanced/performance_optimization.py +131 -0
  63. py2max-0.2.1/tests/examples/advanced/subpatchers.py +90 -0
  64. py2max-0.2.1/tests/examples/api/box_api_examples.py +249 -0
  65. py2max-0.2.1/tests/examples/api/patcher_api_examples.py +225 -0
  66. py2max-0.2.1/tests/examples/auto_layout_demo.py +205 -0
  67. py2max-0.2.1/tests/examples/db/category_db_demo.py +136 -0
  68. py2max-0.2.1/tests/examples/db/maxref_db_demo.py +108 -0
  69. py2max-0.2.1/tests/examples/info_command_demo.py +106 -0
  70. py2max-0.2.1/tests/examples/inline_repl_verification.py +64 -0
  71. py2max-0.2.1/tests/examples/interactive_demo.py +228 -0
  72. py2max-0.2.1/tests/examples/interactive_save_demo.py +164 -0
  73. py2max-0.2.1/tests/examples/layout/columnar_layout_examples.py +169 -0
  74. py2max-0.2.1/tests/examples/layout/flow_layout_examples.py +210 -0
  75. py2max-0.2.1/tests/examples/layout/grid_layout_examples.py +181 -0
  76. py2max-0.2.1/tests/examples/layout/matrix_layout_examples.py +286 -0
  77. py2max-0.2.1/tests/examples/live_preview_demo.py +225 -0
  78. py2max-0.2.1/tests/examples/preview/basic_synth.maxpat +180 -0
  79. py2max-0.2.1/tests/examples/preview/basic_synth.svg +39 -0
  80. py2max-0.2.1/tests/examples/preview/complex_synth.maxpat +379 -0
  81. py2max-0.2.1/tests/examples/preview/complex_synth.svg +71 -0
  82. py2max-0.2.1/tests/examples/preview/flow_layout.maxpat +198 -0
  83. py2max-0.2.1/tests/examples/preview/flow_layout.svg +45 -0
  84. py2max-0.2.1/tests/examples/preview/grid_layout.maxpat +198 -0
  85. py2max-0.2.1/tests/examples/preview/grid_layout.svg +45 -0
  86. py2max-0.2.1/tests/examples/preview/horizontal_layout.maxpat +198 -0
  87. py2max-0.2.1/tests/examples/preview/horizontal_layout.svg +45 -0
  88. py2max-0.2.1/tests/examples/preview/styled_no_ports.svg +22 -0
  89. py2max-0.2.1/tests/examples/preview/styled_no_title.svg +27 -0
  90. py2max-0.2.1/tests/examples/preview/styled_patch.maxpat +105 -0
  91. py2max-0.2.1/tests/examples/preview/styled_with_ports.svg +29 -0
  92. py2max-0.2.1/tests/examples/preview/svg_preview_demo.py +255 -0
  93. py2max-0.2.1/tests/examples/preview/vertical_layout.maxpat +198 -0
  94. py2max-0.2.1/tests/examples/preview/vertical_layout.svg +45 -0
  95. py2max-0.2.1/tests/examples/preview/workflow_demo.maxpat +242 -0
  96. py2max-0.2.1/tests/examples/preview/workflow_demo.svg +50 -0
  97. py2max-0.2.1/tests/examples/quickstart/basic_patch.py +43 -0
  98. py2max-0.2.1/tests/examples/quickstart/layout_examples.py +128 -0
  99. py2max-0.2.1/tests/examples/refresh_function_verification.py +54 -0
  100. py2max-0.2.1/tests/examples/repl_client_server_demo.py +171 -0
  101. py2max-0.2.1/tests/examples/repl_quickstart.py +140 -0
  102. py2max-0.2.1/tests/examples/tutorial/generative_music.py +104 -0
  103. py2max-0.2.1/tests/examples/tutorial/interactive_controller.py +77 -0
  104. py2max-0.2.1/tests/examples/tutorial/signal_processing_chain.py +84 -0
  105. py2max-0.2.1/tests/examples/tutorial/simple_synthesis.py +66 -0
  106. py2max-0.2.1/tests/graphs/random/v30e33.tglf +64 -0
  107. py2max-0.2.1/tests/registry.py +1526 -0
  108. py2max-0.2.1/tests/scratch.py +80 -0
  109. py2max-0.2.1/tests/test_abstract_coverage.py +286 -0
  110. py2max-0.2.1/tests/test_abstraction.py +21 -0
  111. py2max-0.2.1/tests/test_add.py +65 -0
  112. py2max-0.2.1/tests/test_attrui.py +54 -0
  113. py2max-0.2.1/tests/test_basic.py +11 -0
  114. py2max-0.2.1/tests/test_beap.py +9 -0
  115. py2max-0.2.1/tests/test_bpatcher.py +20 -0
  116. py2max-0.2.1/tests/test_cli.py +409 -0
  117. py2max-0.2.1/tests/test_coll.py +16 -0
  118. py2max-0.2.1/tests/test_colors.py +9 -0
  119. py2max-0.2.1/tests/test_comment.py +8 -0
  120. py2max-0.2.1/tests/test_connection_validation.py +182 -0
  121. py2max-0.2.1/tests/test_converters.py +167 -0
  122. py2max-0.2.1/tests/test_core_coverage.py +164 -0
  123. py2max-0.2.1/tests/test_db.py +884 -0
  124. py2max-0.2.1/tests/test_defaults.py +11 -0
  125. py2max-0.2.1/tests/test_dict.py +7 -0
  126. py2max-0.2.1/tests/test_error_handling.py +319 -0
  127. py2max-0.2.1/tests/test_examples.py +473 -0
  128. py2max-0.2.1/tests/test_ezdac.py +10 -0
  129. py2max-0.2.1/tests/test_gen.py +27 -0
  130. py2max-0.2.1/tests/test_group.py +41 -0
  131. py2max-0.2.1/tests/test_itable.py +7 -0
  132. py2max-0.2.1/tests/test_js.py +55 -0
  133. py2max-0.2.1/tests/test_kwds_filter.py +116 -0
  134. py2max-0.2.1/tests/test_layout.py +13 -0
  135. py2max-0.2.1/tests/test_layout_builtins.py +414 -0
  136. py2max-0.2.1/tests/test_layout_coverage.py +233 -0
  137. py2max-0.2.1/tests/test_layout_flow.py +287 -0
  138. py2max-0.2.1/tests/test_layout_graph_layout.py +113 -0
  139. py2max-0.2.1/tests/test_layout_hola1.py +114 -0
  140. py2max-0.2.1/tests/test_layout_hola2.py +100 -0
  141. py2max-0.2.1/tests/test_layout_hola3.py +123 -0
  142. py2max-0.2.1/tests/test_layout_hola_graph.py +124 -0
  143. py2max-0.2.1/tests/test_layout_matrix.py +760 -0
  144. py2max-0.2.1/tests/test_layout_networkx1.py +128 -0
  145. py2max-0.2.1/tests/test_layout_networkx2.py +96 -0
  146. py2max-0.2.1/tests/test_layout_nx_graphviz.py +96 -0
  147. py2max-0.2.1/tests/test_layout_nx_orthogonal.py +120 -0
  148. py2max-0.2.1/tests/test_layout_nx_tsmpy.py +108 -0
  149. py2max-0.2.1/tests/test_layout_vertical.py +43 -0
  150. py2max-0.2.1/tests/test_linking.py +40 -0
  151. py2max-0.2.1/tests/test_maxref.py +470 -0
  152. py2max-0.2.1/tests/test_mc_cycle.py +7 -0
  153. py2max-0.2.1/tests/test_message.py +7 -0
  154. py2max-0.2.1/tests/test_mypatch.py +12 -0
  155. py2max-0.2.1/tests/test_nested.py +18 -0
  156. py2max-0.2.1/tests/test_nested_patchers.py +279 -0
  157. py2max-0.2.1/tests/test_number_tilde.py +52 -0
  158. py2max-0.2.1/tests/test_numbers.py +34 -0
  159. py2max-0.2.1/tests/test_param.py +8 -0
  160. py2max-0.2.1/tests/test_patcher.py +43 -0
  161. py2max-0.2.1/tests/test_pitched_osc.py +15 -0
  162. py2max-0.2.1/tests/test_pydantic.py +160 -0
  163. py2max-0.2.1/tests/test_repl.py +309 -0
  164. py2max-0.2.1/tests/test_repl_client.py +348 -0
  165. py2max-0.2.1/tests/test_repl_inline.py +283 -0
  166. py2max-0.2.1/tests/test_repl_server.py +316 -0
  167. py2max-0.2.1/tests/test_rnbo.py +146 -0
  168. py2max-0.2.1/tests/test_rnbo_subpatcher.py +19 -0
  169. py2max-0.2.1/tests/test_scripting_name.py +7 -0
  170. py2max-0.2.1/tests/test_search.py +166 -0
  171. py2max-0.2.1/tests/test_semantic_ids.py +258 -0
  172. py2max-0.2.1/tests/test_subpatch.py +17 -0
  173. py2max-0.2.1/tests/test_svg.py +331 -0
  174. py2max-0.2.1/tests/test_table.py +68 -0
  175. py2max-0.2.1/tests/test_transformers.py +54 -0
  176. py2max-0.2.1/tests/test_tree.py +74 -0
  177. py2max-0.2.1/tests/test_tree_builder.py +193 -0
  178. py2max-0.2.1/tests/test_tutorial_simple_synthesis.py +44 -0
  179. py2max-0.2.1/tests/test_two_sines.py +47 -0
  180. py2max-0.2.1/tests/test_umenu.py +11 -0
  181. py2max-0.2.1/tests/test_utils.py +18 -0
  182. py2max-0.2.1/tests/test_varname.py +11 -0
  183. py2max-0.2.1/tests/test_websocket.py +232 -0
  184. py2max-0.2.1/tests/test_zl_group.py +11 -0
@@ -0,0 +1,559 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ## [0.2.1] - 2026-01-11
6
+
7
+ ### New: Dagre Layout Algorithm
8
+
9
+ - Added Dagre (Directed Acyclic Graph) as third layout algorithm option alongside WebCola and ELK
10
+ - Integrated `dagre-bundle.js` combining graphlib with require shim for browser compatibility
11
+ - Added Dagre-specific controls: Ranker (network-simplex, longest-path, tight-tree) and Align options
12
+ - Supports all flow directions: top-bottom, bottom-top, left-right, right-left
13
+
14
+ ### Improved: Interactive Editor Visualization
15
+
16
+ - **ViewBox Scaling**: Dynamic padding (10% of content, min 30px, max 100px) with aspect ratio preservation
17
+ - **Port Position Safety**: Added bounds checking with `safeIndex` clamping to prevent invalid port positions
18
+ - **Patchline Animation**: Added `animatePatchlines()` method for smooth patchline transitions during layout
19
+ - **Layout Centering**: Added `centerLayout()` helper method - all three algorithms now center content within canvas
20
+ - **Delta Updates**: Position updates now send only changed box data instead of full patcher state
21
+ - Added `updateBoxPosition()` for efficient single-box DOM updates
22
+ - Added `updateConnectedLines()` to update patchlines without full re-render
23
+ - Significantly reduces bandwidth during drag operations
24
+
25
+ ### Improved: FlowLayoutManager
26
+
27
+ - **Line Crossing Minimization**: Added `_minimize_crossings()` method using barycenter heuristic
28
+ - Objects within each level are reordered based on average position of connected objects in previous level
29
+ - Reduces visual line crossings for cleaner layouts
30
+ - **Negative Position Prevention**: Added bounds clamping and auto-scaling when content exceeds available space
31
+ - **Incremental Layout**: Supports `optimize_layout(changed_objects)` for efficient partial updates
32
+
33
+ ### Improved: GridLayoutManager
34
+
35
+ - Fixed integer division to float division for consistent cluster positioning
36
+ - Now uses consistent float spacing within clusters
37
+ - **Incremental Layout**: Supports `optimize_layout(changed_objects)` for efficient partial updates
38
+
39
+ ### Improved: WebSocket Server Security
40
+
41
+ - **Input Validation**: Added comprehensive schema-based message validation
42
+ - `MESSAGE_SCHEMAS` defines required fields and types for each message type
43
+ - `MAX_STRING_LENGTHS` prevents abuse (256 chars for IDs, 10000 for text, 4096 for filepaths)
44
+ - `COORDINATE_BOUNDS` validates positions (-100000 to 100000)
45
+ - Checks for control characters in strings
46
+ - Validates optional fields (outlet/inlet indices 0-255)
47
+ - Validation errors sent back to client as error messages
48
+
49
+ ### New: Save As Dialog
50
+
51
+ - Added `save_as_required` message type when patcher has no filepath
52
+ - Added `handle_save_as()` handler for saving with specified filepath
53
+ - Added `showSaveAsDialog()` in JavaScript with filename prompt
54
+ - Automatically adds `.maxpat` extension if not provided
55
+
56
+ ### Fixed: ELK Layout
57
+
58
+ - Fixed "Referenced shape does not exist" errors by validating edges before creating ports
59
+ - Ports now created based on actual connections, not just declared counts
60
+
61
+ ### Fixed: Static File Paths
62
+
63
+ - Fixed 404 error for `interactive.html` by correcting static file path resolution
64
+
65
+ ### Improved: Base LayoutManager
66
+
67
+ - Added `prevent_overlaps()` method for iterative overlap prevention
68
+ - **Incremental Layout System**: Added smart layout optimization that only repositions affected objects
69
+ - `optimize_layout(changed_objects)` accepts optional set of changed object IDs
70
+ - `should_use_incremental()` determines when to use incremental vs full layout (30% threshold)
71
+ - `get_affected_objects()` finds changed objects plus their connected neighbors
72
+ - `_incremental_layout()` repositions only affected objects using spiral search
73
+ - `_find_non_overlapping_position()` finds nearby positions that don't overlap with fixed objects
74
+ - `_full_layout()` for complete layout recalculation (subclasses override)
75
+
76
+ ## [0.2.0]
77
+
78
+ ### Updated: Optional Layout Dependencies
79
+
80
+ - Updated `pycola` dependency to `graph-layout` package (<https://github.com/shakfu/graph-layout>)
81
+ - Renamed test file from `test_layout_pycola.py` to `test_layout_graph_layout.py`
82
+ - Updated API to use `ColaLayoutAdapter` from `graph_layout` module
83
+
84
+ - Updated `pyhola` dependency to `hola-graph` package (<https://github.com/shakfu/hola-graph>)
85
+ - Renamed test file from `test_layout_pyhola.py` to `test_layout_hola_graph.py`
86
+ - Updated imports to use `hola_graph._core` module
87
+
88
+ - Fixed `test_layout_networkx2.py` to properly check for `pygraphviz` dependency
89
+ - Test now correctly skips when pygraphviz is not installed
90
+
91
+ ### Simplified: Optional Dependencies
92
+
93
+ - Consolidated optional dependencies in `pyproject.toml` to single `server` option
94
+ - Removed `repl` and `all` options
95
+ - `server` now includes both `websockets` and `ptpython`
96
+ - Install with: `pip install py2max[server]`
97
+
98
+ ### New: Interactive Editor - Advanced Layout with SVG.js, WebCola, and D3.js
99
+
100
+ - Added complete SVG.js (v3.2.5) integration for all SVG manipulation and animation in the interactive editor
101
+
102
+ - Added WebCola constraint-based force-directed graph layout engine with D3.js (v7) integration
103
+
104
+ - Added interactive auto-layout controls panel with real-time parameter adjustment
105
+
106
+ - Added 5 adjustable layout parameters via sliders and controls:
107
+ - **Link Distance** (50-300): Controls spacing between connected objects
108
+ - **Iterations** (10-200): Controls layout quality and convergence
109
+ - **Canvas Width** (400-1600): Adjustable layout area width
110
+ - **Canvas Height** (300-1200): Adjustable layout area height
111
+ - **Avoid Overlaps** (checkbox): Toggle automatic overlap prevention
112
+
113
+ - Added constraint-based layout system with 4 presets:
114
+ - **None**: Natural force-directed layout without alignment constraints
115
+ - **Horizontal Flow**: Aligns objects in horizontal rows (left-to-right signal flow)
116
+ - **Vertical Flow**: Aligns objects in vertical columns (top-to-bottom signal flow)
117
+ - **Grid**: Strict grid alignment with both row and column constraints
118
+
119
+ - Added smooth SVG.js animations (500ms ease-in-out) for layout transitions
120
+
121
+ - Added constraint generation algorithm that analyzes object positions and creates alignment constraints
122
+
123
+ - Added collapsible controls panel with "Apply Layout" and "Hide" buttons
124
+
125
+ - Added visual feedback showing active parameters and constraint count
126
+
127
+ **SVG.js Implementation:**
128
+
129
+ - Refactored all SVG rendering to use SVG.js declarative API instead of native DOM manipulation
130
+ - `initializeSVG()`: Creates SVG canvas and layer groups using SVG.js
131
+ - `createBox()`: Renders boxes with rectangles, text, and clipping paths using SVG.js
132
+ - `createLine()`: Renders connection lines with hitboxes using SVG.js
133
+ - `addPorts()`: Renders inlet/outlet circles using SVG.js
134
+ - `autoLayout()`: Animates box movements using SVG.js transforms
135
+
136
+ **WebCola Integration:**
137
+
138
+ - Force-directed graph layout with configurable parameters
139
+ - Constraint-based positioning using alignment constraints
140
+ - Automatic overlap avoidance with adjustable node dimensions
141
+ - Handles disconnected graph components gracefully
142
+ - Jaccard link lengths for natural connection spacing
143
+
144
+ **Constraint System:**
145
+
146
+ - Automatic constraint generation based on object proximity (50px threshold)
147
+ - Alignment constraints for horizontal rows (Y-axis alignment)
148
+ - Alignment constraints for vertical columns (X-axis alignment)
149
+ - Grid constraints combining both row and column alignment
150
+ - Real-time constraint application with visual feedback
151
+
152
+ **Documentation:**
153
+
154
+ - Added comprehensive `docs/LIBRARIES_INTEGRATION.md` (518 lines)
155
+ - Detailed parameter descriptions and effects
156
+ - Constraint preset usage examples
157
+ - Testing procedures and expected behavior
158
+ - Code examples and API documentation
159
+ - Performance considerations for different patch sizes
160
+
161
+ **Demo Scripts:**
162
+
163
+ - Added `examples/auto_layout_demo.py`: Complex synthesizer with randomized positions (13 objects, 16 connections)
164
+ - Hierarchical layout demo: Tree structure with multiple processing layers (12 objects)
165
+
166
+ **Benefits:**
167
+
168
+ - Professional animated transitions for all layout operations
169
+ - Interactive experimentation with layout parameters
170
+ - Structured layouts matching typical Max patch patterns
171
+ - Clean, maintainable SVG.js codebase
172
+ - Four layout presets for different use cases
173
+ - Real-time visual feedback
174
+ - Minimal overhead (234KB total: D3 + SVG.js + WebCola, minified)
175
+
176
+ **Example Usage:**
177
+
178
+ ```bash
179
+ # Start interactive editor
180
+ py2max serve outputs/auto_layout_demo.maxpat
181
+
182
+ # In browser:
183
+ # 1. Click "Auto-Layout" to show controls
184
+ # 2. Adjust Link Distance slider (50-300)
185
+ # 3. Select Constraint Preset (Grid/Horizontal/Vertical/None)
186
+ # 4. Adjust Iterations for convergence quality
187
+ # 5. Click "Apply Layout" to see smooth animations
188
+ # 6. Experiment with different parameter combinations
189
+ ```
190
+
191
+ ### New: Interactive Editor - Nested Patcher Navigation
192
+
193
+ - Added full nested patcher (subpatcher) navigation support in interactive editor
194
+ - Double-click on subpatcher boxes (blue dashed border) to navigate into them
195
+ - Navigate back using "Parent" button or ESC key
196
+ - Breadcrumb navigation displays current location (e.g., "Main / Oscillator / Envelope")
197
+ - Subpatcher boxes are fully interactive: draggable, connectable, deletable
198
+ - Visual distinction: subpatcher boxes have blue dashed borders and bold blue text
199
+ - Event delegation for reliable double-click detection even with dynamic DOM updates
200
+ - Automatic parent reference restoration when loading patches from files
201
+
202
+ **Server-Side Changes:**
203
+
204
+ - Modified `get_patcher_state_json()` to include `has_subpatcher` flag and `patcher_path` breadcrumb
205
+ - Added `handle_navigate_to_subpatcher()`, `handle_navigate_to_parent()`, `handle_navigate_to_root()` handlers
206
+ - Fixed inlet/outlet count detection to use `numinlets`/`numoutlets` attributes from loaded files
207
+ - Handler now tracks both `root_patcher` (for saving) and `patcher` (current view)
208
+
209
+ **Client-Side Changes:**
210
+
211
+ - Added breadcrumb UI showing patcher hierarchy
212
+ - Implemented event delegation for double-click handling on dynamically created boxes
213
+ - Fixed object positioning by flattening `patching_rect` into `x`, `y`, `width`, `height`
214
+ - CSS styling for subpatcher boxes with distinct visual appearance
215
+ - ESC key navigation support
216
+
217
+ **Core Changes:**
218
+
219
+ - Modified `Patcher.from_dict()` to set `_parent` references for nested subpatchers when loading from files
220
+ - Ensures bidirectional parent-child relationships for proper navigation
221
+
222
+ **Tests:**
223
+
224
+ - Added 14 comprehensive tests in `tests/test_nested_patchers.py`
225
+ - All tests passing (326 passed, 14 skipped)
226
+
227
+ **Demo:**
228
+
229
+ - Added `examples/nested_patcher_demo.py` with three demonstration patches:
230
+ - Synthesizer with nested envelope subpatcher
231
+ - Effects chain with parallel subpatchers
232
+ - Deeply nested hierarchy (6 levels)
233
+
234
+ ### New: SVG Preview Feature
235
+
236
+ - Added `py2max preview` CLI command for offline visual validation of Max patches
237
+
238
+ - Added `py2max.svg` module with complete SVG rendering engine (330 lines)
239
+
240
+ - Added `export_svg()` and `export_svg_string()` functions for programmatic SVG generation
241
+
242
+ - Added SVG rendering for boxes with type-specific styling:
243
+ - Regular objects: Light gray fill
244
+ - Comments: Yellow fill (#ffffd0)
245
+ - Messages: Medium gray fill
246
+
247
+ - Added patchline rendering with correct inlet/outlet connection points
248
+
249
+ - Added optional inlet/outlet port visualization (blue inlets, orange outlets)
250
+
251
+ - Added automatic port detection from MaxRef metadata via `get_inlet_count()` and `get_outlet_count()`
252
+
253
+ - Added support for both Rect objects and list/tuple coordinate formats
254
+
255
+ - Added proper XML text escaping for special characters
256
+
257
+ - Added automatic viewBox calculation with padding
258
+
259
+ - Added browser integration with `--open` flag
260
+
261
+ - Added 17 comprehensive tests covering all SVG functionality
262
+
263
+ - Added `tests/examples/preview/svg_preview_demo.py` demonstration script
264
+
265
+ - Added `docs/SVG_PREVIEW.md` complete documentation
266
+
267
+ **CLI Usage:**
268
+
269
+ ```bash
270
+ # Basic preview (saves to /tmp)
271
+ py2max preview my-patch.maxpat
272
+
273
+ # Specify output path
274
+ py2max preview my-patch.maxpat -o output.svg
275
+
276
+ # Custom title
277
+ py2max preview my-patch.maxpat --title "My Synth"
278
+
279
+ # Hide inlet/outlet ports
280
+ py2max preview my-patch.maxpat --no-ports
281
+
282
+ # Open in browser automatically
283
+ py2max preview my-patch.maxpat --open
284
+
285
+ # Combine options
286
+ py2max preview synth.maxpat -o docs/synth.svg --title "Synth" --open
287
+ ```
288
+
289
+ **Python API:**
290
+
291
+ ```python
292
+ from py2max import Patcher, export_svg, export_svg_string
293
+
294
+ # Create and export
295
+ p = Patcher('synth.maxpat', layout='grid')
296
+ osc = p.add_textbox('cycle~ 440')
297
+ dac = p.add_textbox('ezdac~')
298
+ p.add_line(osc, dac)
299
+ p.optimize_layout()
300
+ export_svg(p, 'synth.svg', title="Simple Synth", show_ports=True)
301
+
302
+ # Export to string
303
+ svg_content = export_svg_string(p, show_ports=True)
304
+ ```
305
+
306
+ **Benefits:**
307
+
308
+ - No Max installation required for visual validation
309
+ - High-quality, scalable vector graphics
310
+ - Works with all py2max layout managers
311
+ - Perfect for CI/CD, documentation, and version control
312
+ - Pure Python implementation with no binary dependencies
313
+ - Viewable in any web browser
314
+
315
+ ### New: SQLite Database Support
316
+
317
+ - Added `py2max.db` module with comprehensive SQLite database support for Max object reference data
318
+
319
+ - Added `MaxRefDB` class for creating, querying, and managing Max object databases
320
+
321
+ - Added 14 normalized database tables: objects, metadata, inlets, outlets, methods, method_args, attributes, attribute_enums, objargs, examples, seealso, misc, palette, parameter
322
+
323
+ - Added support for both in-memory and file-based databases
324
+
325
+ - Added database query API: `search_objects()`, `get_objects_by_category()`, `get_all_categories()`
326
+
327
+ - Added bidirectional conversion: .maxref.xml → SQLite → JSON
328
+
329
+ - Added `export_to_json()` and `import_from_json()` methods for database portability
330
+
331
+ - Added `create_database()` convenience function for database creation and population
332
+
333
+ - Added category-based population methods: `populate_all_objects()`, `populate_all_max_objects()`, `populate_all_jit_objects()`, `populate_all_msp_objects()`, `populate_all_m4l_objects()`
334
+
335
+ - Added maxref category helper functions: `get_all_max_objects()`, `get_all_jit_objects()`, `get_all_msp_objects()`, `get_all_m4l_objects()`, `get_objects_by_category()`
336
+
337
+ - Added category tracking to maxref module (462 Max, 448 MSP, 210 Jitter, 37 M4L objects)
338
+
339
+ - Added complete test suite with 17 test cases
340
+
341
+ - Added `examples/maxref_db_demo.py` demonstration script
342
+
343
+ - Added `examples/category_db_demo.py` category-specific examples
344
+
345
+ - Added `docs/database.md` API documentation
346
+
347
+ ### Improved: MaxRefDB API Enhancements
348
+
349
+ **Python API Improvements:**
350
+
351
+ - Added Pythonic properties: `.count`, `.categories`, `.objects` for cleaner access
352
+ - Added magic methods: `len(db)`, `'obj' in db`, `db['obj']`, `repr(db)` for natural Python usage
353
+ - Added simplified methods: `populate()`, `search()`, `by_category()`, `export()`, `load()` with cleaner naming
354
+ - Added `summary()` method for database statistics with category breakdown
355
+ - Maintained full backward compatibility with deprecated methods
356
+ - All 18 database tests pass
357
+
358
+ **CLI Improvements:**
359
+
360
+ - Added comprehensive `py2max db` subcommand with 7 operations:
361
+ - `db create` - Create new databases with optional category filtering
362
+ - `db populate` - Add objects to existing databases
363
+ - `db info` - Show database information with summary and listing options
364
+ - `db search` - Search objects by text or category with verbose mode
365
+ - `db query` - Get detailed object information (JSON, dict, or human-readable)
366
+ - `db export` - Export database to JSON
367
+ - `db import` - Import JSON data into database
368
+ - Updated `convert maxref-to-sqlite` to use MaxRefDB internally
369
+ - Added 7 new CLI tests covering all db subcommands
370
+ - All 272 tests pass (258 passed, 14 skipped)
371
+
372
+ **Example Usage:**
373
+
374
+ ```python
375
+ # New Pythonic API
376
+ db = MaxRefDB('maxref.db')
377
+ db.populate(category='msp')
378
+ print(len(db)) # Total objects
379
+ if 'cycle~' in db:
380
+ cycle = db['cycle~']
381
+ results = db.search('filter')
382
+ db.export('backup.json')
383
+ ```
384
+
385
+ ```bash
386
+ # New CLI commands
387
+ py2max db create msp.db --category msp
388
+ py2max db info msp.db --summary
389
+ py2max db search msp.db "oscillator" -v
390
+ py2max db query msp.db cycle~ --json
391
+ py2max db export msp.db backup.json
392
+
393
+ # Cache management
394
+ py2max db cache location
395
+ py2max db cache init
396
+ py2max db cache clear
397
+ ```
398
+
399
+ ### New: Automatic Cache System
400
+
401
+ **Platform-Specific Cache:**
402
+
403
+ MaxRefDB now automatically creates and populates a cache database on first use:
404
+
405
+ - **macOS**: `~/Library/Caches/py2max/maxref.db`
406
+ - **Linux**: `~/.cache/py2max/maxref.db`
407
+ - **Windows**: `~/AppData/Local/py2max/Cache/maxref.db`
408
+
409
+ **Benefits:**
410
+
411
+ - One-time population of all 1157 Max objects
412
+ - Instant access on subsequent use
413
+ - No manual setup required
414
+ - Platform-appropriate cache location
415
+
416
+ **New Static Methods:**
417
+
418
+ - `MaxRefDB.get_cache_dir()` - Get platform-specific cache directory
419
+ - `MaxRefDB.get_default_db_path()` - Get default database path
420
+
421
+ **Updated API:**
422
+
423
+ - `MaxRefDB()` - Now uses cache by default
424
+ - `MaxRefDB(db_path, auto_populate=True)` - Control auto-population
425
+ - `MaxRefDB(':memory:')` - In-memory database (no caching)
426
+
427
+ **New CLI Commands:**
428
+
429
+ - `py2max db cache location` - Show cache location and status
430
+ - `py2max db cache init` - Manually initialize cache
431
+ - `py2max db cache clear` - Clear cache database
432
+
433
+ **Example Usage:**
434
+
435
+ ```python
436
+ # Automatic caching (default)
437
+ from py2max.db import MaxRefDB
438
+ db = MaxRefDB() # Auto-populates cache on first use
439
+ print(f"Objects: {len(db)}") # 1157
440
+
441
+ # Get cache location
442
+ print(f"Cache: {MaxRefDB.get_default_db_path()}")
443
+ ```
444
+
445
+ ## [0.1.2]
446
+
447
+ ### Improvements in Type Safety
448
+
449
+ - Added type safety improvements via compliance with `mypy` checks
450
+
451
+ ### Improvements in Layout
452
+
453
+ - Added `optimize_layout()` method for post-connection layout optimization
454
+
455
+ - Added `cluster_connected` parameter to `GridLayoutManager` for connection-aware object clustering
456
+
457
+ - Added `flow_direction` parameter support for both horizontal and vertical layouts in all layout managers
458
+
459
+ - Added backward compatibility for legacy layout manager APIs
460
+
461
+ - Enhanced layout performance with connection-aware clustering algorithms
462
+
463
+ - Improved layout manager consistency with unified `GridLayoutManager` and `FlowLayoutManager` APIs
464
+
465
+ - Added `FlowLayoutManager` with intelligent signal flow analysis and hierarchical positioning
466
+
467
+ - Added `GridLayoutManager` with connection-aware clustering and configurable flow direction
468
+
469
+ ### Improvements in Max Object Introspection
470
+
471
+ - Added optional connection validation system with inlet/outlet validation and `InvalidConnectionError`. This is early stages, and may have some false positives, but planned improvements in handling of excepttions should make this accurate and useful.
472
+
473
+ - Added object introspection methods: `get_inlet_count()`, `get_outlet_count()`, `get_inlet_types()`, `get_outlet_types()`
474
+
475
+ - Added `Box.help()`, `Box.help_text()` and `Box.get_info()` methods for rich object documentation.
476
+
477
+ - Added `maxref` integration system with dynamic help for 1157 Max objects using `.maxref.xml` files
478
+
479
+ ### Bug Fixes
480
+
481
+ - Fixed `maxclass` assignment bug that was preventing patchlines from connecting properly
482
+
483
+ ### Improvements in Project Management
484
+
485
+ - Converted to [uv](https://github.com/astral-sh/uv) for project and dependency management.
486
+
487
+ ## [0.1.1]
488
+
489
+ - Added `Makefile` frontend
490
+
491
+ - Changed package manager to `uv`
492
+
493
+ - Improved compatibility with Python 3.7
494
+
495
+ - Improved core Coverage: 99%
496
+
497
+ - Added clean script: `./scripts/clean.sh`
498
+
499
+ - Added coverage script and reporting: `./scripts/coverage.sh`
500
+
501
+ - Moved `tests` folder from `py2max/py2max/tests` to `py2max/tests`
502
+
503
+ - Added gradual types to `py2max/core`, no errors with `mypy`
504
+
505
+ - Added `number_tilde` test
506
+
507
+ - Fixed `comment` positioning
508
+
509
+ - Added `pyhola` layout.
510
+
511
+ - Added `graphviz` layouts.
512
+
513
+ - Fixed `Adaptagrams` layout.
514
+
515
+ - Added graph layout comparison and additional layouts.
516
+
517
+ - Added vertical layout variant.
518
+
519
+ - Added boolean `tilde` parameter for objects which have a tilde sibling.
520
+
521
+ - Added preliminary support for `rnbo~` include rnbo codebox
522
+
523
+ ## [0.1.0]
524
+
525
+ - Added a generic `.add` method to `Patcher` objects which include some logic to to figure out to which specialized method to dispatch to. See: `tests/test_add.py` for examples of this.
526
+
527
+ - Major refactoring after `test_tree_builder` design experiment, so we have now only one simple extendable Box class, and there is round trip conversion between .maxpat files and patchers.
528
+
529
+ - Added `test_tree_builder.py` which shows that the json tree can be converted to a python object tree which corresponds to it on a one-on-one basis, which itself can be used to generate the json tree for round-trip conversion.
530
+
531
+ - Added `from_file` classmethod to `Patcher` to populate object from `.maxpat` file.
532
+
533
+ - Added `coll`, `dict` and `table` objects and tests
534
+
535
+ - Added some tests which try to use generic layout algorithm in Networkx but the results are quite terrible using builtin algorithms so probably better to try to create something fit-for-purpose.
536
+
537
+ - Added `gen` subpatcher
538
+
539
+ - Moved `varname` to optional kwds instead of being an explicit parameter since it's optional and its inclusion when not populated is sometimes problematic.
540
+
541
+ - Renamed odb to maxclassdb since it only relates to defaults per `maxclass`
542
+
543
+ - Added smarter textbox which uses odb to improve object creation.
544
+
545
+ - Added separate test folder
546
+
547
+ - Added `odb.py` in package with a number of default configs of objects
548
+
549
+ - Converted to package.
550
+
551
+ - Added some notes on graph drawing and layout algorithms
552
+
553
+ - Added comments keyword in box objects + PositionManager for easy documentation
554
+
555
+ - Added Comments objects
556
+
557
+ - Refactor: MaxPatch and Patcher objects are now one.
558
+
559
+ - Initial release
py2max-0.2.1/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2025 Shakeeb Alireza
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.