flograph 0.1.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.
- flograph-0.1.0/.gitignore +10 -0
- flograph-0.1.0/LICENSE +21 -0
- flograph-0.1.0/PKG-INFO +211 -0
- flograph-0.1.0/README.md +172 -0
- flograph-0.1.0/ideas.md +7 -0
- flograph-0.1.0/issues.md +0 -0
- flograph-0.1.0/main.py +5 -0
- flograph-0.1.0/pyproject.toml +57 -0
- flograph-0.1.0/scripts/flopy_to_flograph.py +121 -0
- flograph-0.1.0/src/flograph/__init__.py +0 -0
- flograph-0.1.0/src/flograph/__main__.py +5 -0
- flograph-0.1.0/src/flograph/app.py +43 -0
- flograph-0.1.0/src/flograph/core/__init__.py +26 -0
- flograph-0.1.0/src/flograph/core/datatypes.py +88 -0
- flograph-0.1.0/src/flograph/core/events.py +54 -0
- flograph-0.1.0/src/flograph/core/graph.py +414 -0
- flograph-0.1.0/src/flograph/core/node.py +91 -0
- flograph-0.1.0/src/flograph/core/params.py +69 -0
- flograph-0.1.0/src/flograph/core/ports.py +19 -0
- flograph-0.1.0/src/flograph/core/registry.py +160 -0
- flograph-0.1.0/src/flograph/core/script.py +172 -0
- flograph-0.1.0/src/flograph/core/serialization.py +212 -0
- flograph-0.1.0/src/flograph/core/spec.py +35 -0
- flograph-0.1.0/src/flograph/core/user_nodes.py +201 -0
- flograph-0.1.0/src/flograph/engine/__init__.py +19 -0
- flograph-0.1.0/src/flograph/engine/cache.py +70 -0
- flograph-0.1.0/src/flograph/engine/cache_persistence.py +142 -0
- flograph-0.1.0/src/flograph/engine/context.py +51 -0
- flograph-0.1.0/src/flograph/engine/errors.py +54 -0
- flograph-0.1.0/src/flograph/engine/headless.py +63 -0
- flograph-0.1.0/src/flograph/engine/introspect.py +55 -0
- flograph-0.1.0/src/flograph/engine/scheduler.py +206 -0
- flograph-0.1.0/src/flograph/engine/worker.py +135 -0
- flograph-0.1.0/src/flograph/nodes/__init__.py +0 -0
- flograph-0.1.0/src/flograph/nodes/io/__init__.py +0 -0
- flograph-0.1.0/src/flograph/nodes/io/read_csv.py +31 -0
- flograph-0.1.0/src/flograph/nodes/io/read_excel.py +35 -0
- flograph-0.1.0/src/flograph/nodes/io/read_json.py +33 -0
- flograph-0.1.0/src/flograph/nodes/io/read_parquet.py +30 -0
- flograph-0.1.0/src/flograph/nodes/io/read_sqlite.py +33 -0
- flograph-0.1.0/src/flograph/nodes/io/table.py +68 -0
- flograph-0.1.0/src/flograph/nodes/io/write_csv.py +24 -0
- flograph-0.1.0/src/flograph/nodes/io/write_excel.py +27 -0
- flograph-0.1.0/src/flograph/nodes/io/write_json.py +31 -0
- flograph-0.1.0/src/flograph/nodes/io/write_parquet.py +24 -0
- flograph-0.1.0/src/flograph/nodes/io/write_sqlite.py +35 -0
- flograph-0.1.0/src/flograph/nodes/scripting/__init__.py +0 -0
- flograph-0.1.0/src/flograph/nodes/scripting/node_template.py +68 -0
- flograph-0.1.0/src/flograph/nodes/scripting/python_script.py +22 -0
- flograph-0.1.0/src/flograph/nodes/transform/__init__.py +0 -0
- flograph-0.1.0/src/flograph/nodes/transform/concatenate.py +28 -0
- flograph-0.1.0/src/flograph/nodes/transform/convert_types.py +54 -0
- flograph-0.1.0/src/flograph/nodes/transform/duplicate_filter.py +34 -0
- flograph-0.1.0/src/flograph/nodes/transform/expression.py +29 -0
- flograph-0.1.0/src/flograph/nodes/transform/filter_rows.py +24 -0
- flograph-0.1.0/src/flograph/nodes/transform/group_by.py +46 -0
- flograph-0.1.0/src/flograph/nodes/transform/join.py +31 -0
- flograph-0.1.0/src/flograph/nodes/transform/missing_values.py +63 -0
- flograph-0.1.0/src/flograph/nodes/transform/pivot.py +49 -0
- flograph-0.1.0/src/flograph/nodes/transform/rename_columns.py +35 -0
- flograph-0.1.0/src/flograph/nodes/transform/row_sampling.py +37 -0
- flograph-0.1.0/src/flograph/nodes/transform/select_columns.py +28 -0
- flograph-0.1.0/src/flograph/nodes/transform/sort.py +27 -0
- flograph-0.1.0/src/flograph/nodes/transform/statistics.py +26 -0
- flograph-0.1.0/src/flograph/nodes/transform/string_manipulation.py +52 -0
- flograph-0.1.0/src/flograph/nodes/transform/unpivot.py +40 -0
- flograph-0.1.0/src/flograph/nodes/util/__init__.py +0 -0
- flograph-0.1.0/src/flograph/nodes/util/action_button.py +36 -0
- flograph-0.1.0/src/flograph/nodes/util/constant.py +27 -0
- flograph-0.1.0/src/flograph/nodes/util/note.py +25 -0
- flograph-0.1.0/src/flograph/nodes/util/reroute.py +14 -0
- flograph-0.1.0/src/flograph/nodes/viz/__init__.py +0 -0
- flograph-0.1.0/src/flograph/nodes/viz/card.py +64 -0
- flograph-0.1.0/src/flograph/nodes/viz/show_plot.py +72 -0
- flograph-0.1.0/src/flograph/nodes/viz/show_plotly.py +68 -0
- flograph-0.1.0/src/flograph/nodes/viz/show_table.py +25 -0
- flograph-0.1.0/src/flograph/nodes/viz/slicer.py +61 -0
- flograph-0.1.0/src/flograph/nodes/viz/table_spec.py +26 -0
- flograph-0.1.0/src/flograph/packages.py +89 -0
- flograph-0.1.0/src/flograph/paths.py +31 -0
- flograph-0.1.0/src/flograph/ui/__init__.py +0 -0
- flograph-0.1.0/src/flograph/ui/canvas/__init__.py +13 -0
- flograph-0.1.0/src/flograph/ui/canvas/base_view.py +228 -0
- flograph-0.1.0/src/flograph/ui/canvas/connection_item.py +98 -0
- flograph-0.1.0/src/flograph/ui/canvas/frame_item.py +241 -0
- flograph-0.1.0/src/flograph/ui/canvas/grid.py +49 -0
- flograph-0.1.0/src/flograph/ui/canvas/minimap.py +115 -0
- flograph-0.1.0/src/flograph/ui/canvas/node_item.py +1475 -0
- flograph-0.1.0/src/flograph/ui/canvas/palette.py +228 -0
- flograph-0.1.0/src/flograph/ui/canvas/scene.py +415 -0
- flograph-0.1.0/src/flograph/ui/canvas/view.py +140 -0
- flograph-0.1.0/src/flograph/ui/commands.py +405 -0
- flograph-0.1.0/src/flograph/ui/console/log_dock.py +80 -0
- flograph-0.1.0/src/flograph/ui/dashboard/__init__.py +10 -0
- flograph-0.1.0/src/flograph/ui/dashboard/dashboard_page.py +53 -0
- flograph-0.1.0/src/flograph/ui/dashboard/dashboard_scene.py +147 -0
- flograph-0.1.0/src/flograph/ui/dashboard/dashboard_view.py +56 -0
- flograph-0.1.0/src/flograph/ui/dashboard/page_bar.py +117 -0
- flograph-0.1.0/src/flograph/ui/dashboard/tile_item.py +674 -0
- flograph-0.1.0/src/flograph/ui/dashboard/visuals_list.py +69 -0
- flograph-0.1.0/src/flograph/ui/editor/code_editor.py +213 -0
- flograph-0.1.0/src/flograph/ui/editor/completion.py +183 -0
- flograph-0.1.0/src/flograph/ui/editor/editor_dock.py +188 -0
- flograph-0.1.0/src/flograph/ui/editor/highlighter.py +123 -0
- flograph-0.1.0/src/flograph/ui/editor/save_user_node_dialog.py +64 -0
- flograph-0.1.0/src/flograph/ui/inspector/figure_view.py +194 -0
- flograph-0.1.0/src/flograph/ui/inspector/inspector_dock.py +127 -0
- flograph-0.1.0/src/flograph/ui/inspector/object_view.py +28 -0
- flograph-0.1.0/src/flograph/ui/inspector/pandas_model.py +87 -0
- flograph-0.1.0/src/flograph/ui/inspector/plotly_view.py +91 -0
- flograph-0.1.0/src/flograph/ui/inspector/popup_view.py +76 -0
- flograph-0.1.0/src/flograph/ui/inspector/spec_view.py +26 -0
- flograph-0.1.0/src/flograph/ui/inspector/view_for.py +34 -0
- flograph-0.1.0/src/flograph/ui/mainwindow.py +1240 -0
- flograph-0.1.0/src/flograph/ui/packages_dialog.py +216 -0
- flograph-0.1.0/src/flograph/ui/properties/params_panel.py +286 -0
- flograph-0.1.0/src/flograph/ui/slicer_list.py +86 -0
- flograph-0.1.0/src/flograph/ui/theme.py +85 -0
- flograph-0.1.0/tests/__init__.py +0 -0
- flograph-0.1.0/tests/conftest.py +86 -0
- flograph-0.1.0/tests/test_action_button_node.py +235 -0
- flograph-0.1.0/tests/test_cache_persistence.py +135 -0
- flograph-0.1.0/tests/test_canvas_polish.py +270 -0
- flograph-0.1.0/tests/test_column_suggestions.py +155 -0
- flograph-0.1.0/tests/test_commands.py +166 -0
- flograph-0.1.0/tests/test_dashboard_ui.py +245 -0
- flograph-0.1.0/tests/test_datatypes.py +64 -0
- flograph-0.1.0/tests/test_engine.py +235 -0
- flograph-0.1.0/tests/test_graph.py +160 -0
- flograph-0.1.0/tests/test_graph_pages.py +100 -0
- flograph-0.1.0/tests/test_grid_snap.py +311 -0
- flograph-0.1.0/tests/test_inspector.py +220 -0
- flograph-0.1.0/tests/test_migration_converter.py +102 -0
- flograph-0.1.0/tests/test_no_qt_in_core.py +24 -0
- flograph-0.1.0/tests/test_note_node.py +142 -0
- flograph-0.1.0/tests/test_packages.py +86 -0
- flograph-0.1.0/tests/test_page_commands.py +109 -0
- flograph-0.1.0/tests/test_plotly_node.py +150 -0
- flograph-0.1.0/tests/test_project_lifecycle.py +186 -0
- flograph-0.1.0/tests/test_registry.py +87 -0
- flograph-0.1.0/tests/test_script.py +92 -0
- flograph-0.1.0/tests/test_serialization.py +149 -0
- flograph-0.1.0/tests/test_show_plot_node.py +195 -0
- flograph-0.1.0/tests/test_show_table_node.py +138 -0
- flograph-0.1.0/tests/test_slicer_card_nodes.py +223 -0
- flograph-0.1.0/tests/test_stdlib_nodes.py +512 -0
- flograph-0.1.0/tests/test_table_node.py +157 -0
- flograph-0.1.0/tests/test_ui_editor.py +167 -0
- flograph-0.1.0/tests/test_user_nodes.py +208 -0
- flograph-0.1.0/tests/test_view_keyboard.py +84 -0
- flograph-0.1.0/tests/test_wheel_zoom.py +121 -0
- flograph-0.1.0/uv.lock +952 -0
flograph-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 redthista
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
flograph-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flograph
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Visual node-based Python programming environment (KNIME-style dataflow, Blueprint-style canvas)
|
|
5
|
+
Project-URL: Homepage, https://github.com/redthista/flograph
|
|
6
|
+
Project-URL: Repository, https://github.com/redthista/flograph
|
|
7
|
+
Project-URL: Issues, https://github.com/redthista/flograph/issues
|
|
8
|
+
Author-email: redthista <dconrancpw@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: dataflow,etl,gui,knime,low-code,node-editor,pandas,pyside6,qt,visual-programming
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Environment :: X11 Applications :: Qt
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
22
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
23
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: jedi>=0.19
|
|
26
|
+
Requires-Dist: matplotlib>=3.8
|
|
27
|
+
Requires-Dist: pandas>=2.0
|
|
28
|
+
Requires-Dist: pyside6>=6.7
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest-qt>=4.4; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
32
|
+
Provides-Extra: excel
|
|
33
|
+
Requires-Dist: openpyxl; extra == 'excel'
|
|
34
|
+
Provides-Extra: parquet
|
|
35
|
+
Requires-Dist: pyarrow; extra == 'parquet'
|
|
36
|
+
Provides-Extra: plotly
|
|
37
|
+
Requires-Dist: plotly; extra == 'plotly'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# flograph
|
|
41
|
+
|
|
42
|
+
A visual node-based Python programming environment: KNIME-style dataflow on
|
|
43
|
+
an infinite Blueprint-style canvas, where every node is real, editable Python.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
flograph is a standard pip-installable package (hatchling build backend):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install . # or: uv pip install . / pip install -e .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This puts a `flograph` command on your PATH and makes `python -m flograph`
|
|
56
|
+
work. To build a distributable wheel/sdist instead:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python -m build # or: uv build -> dist/flograph-*.whl
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
> The project was renamed from **flopy** to **flograph** because `flopy` is
|
|
63
|
+
> already taken on PyPI (USGS MODFLOW). To migrate projects saved by the old
|
|
64
|
+
> build, see [Migrating old `.flopy` projects](#migrating-old-flopy-projects).
|
|
65
|
+
|
|
66
|
+
## Run it
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
flograph # console entry point (after install)
|
|
70
|
+
python -m flograph # equivalent module entry point
|
|
71
|
+
python main.py project.flograph # open a project
|
|
72
|
+
python -m flograph.engine.headless project.flograph # run without GUI
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## The idea
|
|
76
|
+
|
|
77
|
+
- **Nodes are Python scripts.** Every node — including the shipped library —
|
|
78
|
+
is a small module: a `NODE` dict declaring typed ports, an optional
|
|
79
|
+
`PARAMS` list that auto-generates its properties form, and a
|
|
80
|
+
`run(ctx, **inputs)` function. Double-click any node to read or fork its
|
|
81
|
+
code in the built-in editor (syntax highlighting, jedi completion,
|
|
82
|
+
error markers on the failing line).
|
|
83
|
+
- **KNIME semantics.** Data flows through typed ports; execution is a
|
|
84
|
+
topological walk of the dirty subgraph; every node's outputs are cached, so
|
|
85
|
+
re-runs only recompute what changed. Status LEDs: gray idle, yellow queued,
|
|
86
|
+
pulsing blue running, green done, red error.
|
|
87
|
+
- **Inspect everything.** Click any node or wire to see the data on it —
|
|
88
|
+
paged table view for DataFrames (millions of rows are fine), matplotlib
|
|
89
|
+
figures with a toolbar, pretty-printed objects. Per-node stdout/logs in the
|
|
90
|
+
console dock.
|
|
91
|
+
|
|
92
|
+
## Canvas
|
|
93
|
+
|
|
94
|
+
| Action | Binding |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| Add node | `Tab` (search palette), right-click, or drag from the library |
|
|
97
|
+
| Connect | drag from a port; drop on empty canvas to pick a compatible node |
|
|
98
|
+
| Reroute dot | double-click a wire |
|
|
99
|
+
| Comment frame | `Ctrl+G` around the selection (frames move their contents) |
|
|
100
|
+
| Run all / selected / cancel | `F5` / `F6` / `Esc` |
|
|
101
|
+
| Pan / zoom | middle-drag or `Space`+drag / wheel |
|
|
102
|
+
| Frame view | `F` |
|
|
103
|
+
| Duplicate / delete | `Ctrl+D` / `Del` |
|
|
104
|
+
| Undo anything | `Ctrl+Z` — every graph mutation is on the undo stack |
|
|
105
|
+
|
|
106
|
+
Projects are plain JSON (`.flograph`); caches are never saved, so a reopened
|
|
107
|
+
project is fully reproducible with one `F5`.
|
|
108
|
+
|
|
109
|
+
### Migrating old `.flopy` projects
|
|
110
|
+
|
|
111
|
+
Projects saved by the old **flopy** build use a `.flopy` extension and embed
|
|
112
|
+
`flopy.*` node type-ids, which this build no longer recognises. Convert them
|
|
113
|
+
in place with the bundled one-shot migrator (stdlib-only, no install needed):
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
python scripts/flopy_to_flograph.py project.flopy # -> project.flograph
|
|
117
|
+
python scripts/flopy_to_flograph.py my/projects --recursive
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
It rewrites builtin `flopy.*` type-ids to `flograph.*` (leaving `user.*`
|
|
121
|
+
nodes alone), renames the file and any `.flopy.cache/` side-car, and by
|
|
122
|
+
default keeps the original (`--delete-original` to remove it).
|
|
123
|
+
|
|
124
|
+
## Node library
|
|
125
|
+
|
|
126
|
+
The shipped library covers the KNIME basics:
|
|
127
|
+
|
|
128
|
+
- **IO** — read/write CSV, Excel, Parquet, JSON (incl. JSONL), SQLite
|
|
129
|
+
(query in, table out), inline Table.
|
|
130
|
+
- **Transform** — Select Columns, Filter Rows, Sort, Join, Group By,
|
|
131
|
+
Expression, Concatenate, Missing Values, Duplicate Row Filter,
|
|
132
|
+
Rename Columns, Pivot, Unpivot, Row Sampling, Convert Types,
|
|
133
|
+
String Manipulation, Statistics.
|
|
134
|
+
- **Viz** — Show Table, Show Plot (live on-canvas cards), Show Plotly
|
|
135
|
+
(fully interactive plotly.js chart embedded on the canvas — hover, zoom
|
|
136
|
+
and pan in place; needs `pip install plotly`, e.g. via
|
|
137
|
+
Tools > Manage Packages).
|
|
138
|
+
- **Scripting / Util** — Python Script, Constant, Reroute, Note,
|
|
139
|
+
Action Button.
|
|
140
|
+
|
|
141
|
+
## Packages
|
|
142
|
+
|
|
143
|
+
**Tools > Manage Packages** installs, upgrades and uninstalls pip packages
|
|
144
|
+
in flograph's own environment (the venv running the app). Nodes execute
|
|
145
|
+
in-process, so anything installed there is immediately importable from a
|
|
146
|
+
node's `run()` — no restart needed for new installs; upgrades of modules
|
|
147
|
+
the app has already imported take effect on the next launch. The dialog
|
|
148
|
+
uses `pip` when the interpreter has it and falls back to `uv pip` (uv-made
|
|
149
|
+
venvs ship without pip); flograph's own core dependencies are protected from
|
|
150
|
+
uninstall.
|
|
151
|
+
|
|
152
|
+
## Writing a node
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
"""My Node
|
|
156
|
+
|
|
157
|
+
Docstring first paragraph shows in the properties panel.
|
|
158
|
+
"""
|
|
159
|
+
NODE = {
|
|
160
|
+
"label": "My Node",
|
|
161
|
+
"category": "Transform",
|
|
162
|
+
"inputs": [("table", "dataframe")],
|
|
163
|
+
"outputs": [("result", "dataframe")],
|
|
164
|
+
}
|
|
165
|
+
PARAMS = [
|
|
166
|
+
{"name": "factor", "type": "float", "default": 1.0},
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
def run(ctx, table):
|
|
170
|
+
ctx.log(f"scaling by {ctx.params['factor']}")
|
|
171
|
+
ctx.check_cancelled() # cooperative cancellation
|
|
172
|
+
return {"result": table * ctx.params["factor"]}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Port types: `any, dataframe, series, number, string, bool, object, figure`.
|
|
176
|
+
`columns`-typed params render with a ▾ picker listing the columns of the
|
|
177
|
+
DataFrames cached on the node's inputs (run upstream once to populate it);
|
|
178
|
+
add `"multi": False` for single-column params so picking replaces instead
|
|
179
|
+
of toggling a comma list.
|
|
180
|
+
Rules: treat inputs as read-only (outputs are cached by reference); heavy
|
|
181
|
+
imports go inside `run()`; matplotlib figures must use the OO API
|
|
182
|
+
(`matplotlib.figure.Figure()`), never pyplot.
|
|
183
|
+
|
|
184
|
+
Drop new `.py` files under `src/flograph/nodes/<category>/` and they appear in
|
|
185
|
+
the library on next launch.
|
|
186
|
+
|
|
187
|
+
## Development
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
uv pip install -p .venv/bin/python -e ".[dev]"
|
|
191
|
+
QT_QPA_PLATFORM=offscreen .venv/bin/python -m pytest tests/
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Architecture (src layout):
|
|
195
|
+
|
|
196
|
+
- `flograph/core` — Qt-free model: graph, typed ports, script contract,
|
|
197
|
+
registry, JSON serialization. Fully unit-testable; a poison test keeps Qt
|
|
198
|
+
and pandas out of its import graph.
|
|
199
|
+
- `flograph/engine` — background execution: plan builder, single-thread pool
|
|
200
|
+
worker, output cache, cancellation, per-node stdout capture, tracebacks
|
|
201
|
+
mapped to node script lines.
|
|
202
|
+
- `flograph/nodes` — the standard library; each node is a script file loaded as
|
|
203
|
+
text through the same contract as user code.
|
|
204
|
+
- `flograph/ui` — canvas (QGraphicsView from scratch), code editor, inspector,
|
|
205
|
+
properties, console. One rule everywhere: **QUndoCommands are the only
|
|
206
|
+
writers to the graph**; items react to graph events.
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
[MIT](LICENSE) — free for commercial and private use, modification, and
|
|
211
|
+
redistribution; just keep the copyright and license notice.
|
flograph-0.1.0/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# flograph
|
|
2
|
+
|
|
3
|
+
A visual node-based Python programming environment: KNIME-style dataflow on
|
|
4
|
+
an infinite Blueprint-style canvas, where every node is real, editable Python.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
flograph is a standard pip-installable package (hatchling build backend):
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install . # or: uv pip install . / pip install -e .
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This puts a `flograph` command on your PATH and makes `python -m flograph`
|
|
17
|
+
work. To build a distributable wheel/sdist instead:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
python -m build # or: uv build -> dist/flograph-*.whl
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> The project was renamed from **flopy** to **flograph** because `flopy` is
|
|
24
|
+
> already taken on PyPI (USGS MODFLOW). To migrate projects saved by the old
|
|
25
|
+
> build, see [Migrating old `.flopy` projects](#migrating-old-flopy-projects).
|
|
26
|
+
|
|
27
|
+
## Run it
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
flograph # console entry point (after install)
|
|
31
|
+
python -m flograph # equivalent module entry point
|
|
32
|
+
python main.py project.flograph # open a project
|
|
33
|
+
python -m flograph.engine.headless project.flograph # run without GUI
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## The idea
|
|
37
|
+
|
|
38
|
+
- **Nodes are Python scripts.** Every node — including the shipped library —
|
|
39
|
+
is a small module: a `NODE` dict declaring typed ports, an optional
|
|
40
|
+
`PARAMS` list that auto-generates its properties form, and a
|
|
41
|
+
`run(ctx, **inputs)` function. Double-click any node to read or fork its
|
|
42
|
+
code in the built-in editor (syntax highlighting, jedi completion,
|
|
43
|
+
error markers on the failing line).
|
|
44
|
+
- **KNIME semantics.** Data flows through typed ports; execution is a
|
|
45
|
+
topological walk of the dirty subgraph; every node's outputs are cached, so
|
|
46
|
+
re-runs only recompute what changed. Status LEDs: gray idle, yellow queued,
|
|
47
|
+
pulsing blue running, green done, red error.
|
|
48
|
+
- **Inspect everything.** Click any node or wire to see the data on it —
|
|
49
|
+
paged table view for DataFrames (millions of rows are fine), matplotlib
|
|
50
|
+
figures with a toolbar, pretty-printed objects. Per-node stdout/logs in the
|
|
51
|
+
console dock.
|
|
52
|
+
|
|
53
|
+
## Canvas
|
|
54
|
+
|
|
55
|
+
| Action | Binding |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| Add node | `Tab` (search palette), right-click, or drag from the library |
|
|
58
|
+
| Connect | drag from a port; drop on empty canvas to pick a compatible node |
|
|
59
|
+
| Reroute dot | double-click a wire |
|
|
60
|
+
| Comment frame | `Ctrl+G` around the selection (frames move their contents) |
|
|
61
|
+
| Run all / selected / cancel | `F5` / `F6` / `Esc` |
|
|
62
|
+
| Pan / zoom | middle-drag or `Space`+drag / wheel |
|
|
63
|
+
| Frame view | `F` |
|
|
64
|
+
| Duplicate / delete | `Ctrl+D` / `Del` |
|
|
65
|
+
| Undo anything | `Ctrl+Z` — every graph mutation is on the undo stack |
|
|
66
|
+
|
|
67
|
+
Projects are plain JSON (`.flograph`); caches are never saved, so a reopened
|
|
68
|
+
project is fully reproducible with one `F5`.
|
|
69
|
+
|
|
70
|
+
### Migrating old `.flopy` projects
|
|
71
|
+
|
|
72
|
+
Projects saved by the old **flopy** build use a `.flopy` extension and embed
|
|
73
|
+
`flopy.*` node type-ids, which this build no longer recognises. Convert them
|
|
74
|
+
in place with the bundled one-shot migrator (stdlib-only, no install needed):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python scripts/flopy_to_flograph.py project.flopy # -> project.flograph
|
|
78
|
+
python scripts/flopy_to_flograph.py my/projects --recursive
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
It rewrites builtin `flopy.*` type-ids to `flograph.*` (leaving `user.*`
|
|
82
|
+
nodes alone), renames the file and any `.flopy.cache/` side-car, and by
|
|
83
|
+
default keeps the original (`--delete-original` to remove it).
|
|
84
|
+
|
|
85
|
+
## Node library
|
|
86
|
+
|
|
87
|
+
The shipped library covers the KNIME basics:
|
|
88
|
+
|
|
89
|
+
- **IO** — read/write CSV, Excel, Parquet, JSON (incl. JSONL), SQLite
|
|
90
|
+
(query in, table out), inline Table.
|
|
91
|
+
- **Transform** — Select Columns, Filter Rows, Sort, Join, Group By,
|
|
92
|
+
Expression, Concatenate, Missing Values, Duplicate Row Filter,
|
|
93
|
+
Rename Columns, Pivot, Unpivot, Row Sampling, Convert Types,
|
|
94
|
+
String Manipulation, Statistics.
|
|
95
|
+
- **Viz** — Show Table, Show Plot (live on-canvas cards), Show Plotly
|
|
96
|
+
(fully interactive plotly.js chart embedded on the canvas — hover, zoom
|
|
97
|
+
and pan in place; needs `pip install plotly`, e.g. via
|
|
98
|
+
Tools > Manage Packages).
|
|
99
|
+
- **Scripting / Util** — Python Script, Constant, Reroute, Note,
|
|
100
|
+
Action Button.
|
|
101
|
+
|
|
102
|
+
## Packages
|
|
103
|
+
|
|
104
|
+
**Tools > Manage Packages** installs, upgrades and uninstalls pip packages
|
|
105
|
+
in flograph's own environment (the venv running the app). Nodes execute
|
|
106
|
+
in-process, so anything installed there is immediately importable from a
|
|
107
|
+
node's `run()` — no restart needed for new installs; upgrades of modules
|
|
108
|
+
the app has already imported take effect on the next launch. The dialog
|
|
109
|
+
uses `pip` when the interpreter has it and falls back to `uv pip` (uv-made
|
|
110
|
+
venvs ship without pip); flograph's own core dependencies are protected from
|
|
111
|
+
uninstall.
|
|
112
|
+
|
|
113
|
+
## Writing a node
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
"""My Node
|
|
117
|
+
|
|
118
|
+
Docstring first paragraph shows in the properties panel.
|
|
119
|
+
"""
|
|
120
|
+
NODE = {
|
|
121
|
+
"label": "My Node",
|
|
122
|
+
"category": "Transform",
|
|
123
|
+
"inputs": [("table", "dataframe")],
|
|
124
|
+
"outputs": [("result", "dataframe")],
|
|
125
|
+
}
|
|
126
|
+
PARAMS = [
|
|
127
|
+
{"name": "factor", "type": "float", "default": 1.0},
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
def run(ctx, table):
|
|
131
|
+
ctx.log(f"scaling by {ctx.params['factor']}")
|
|
132
|
+
ctx.check_cancelled() # cooperative cancellation
|
|
133
|
+
return {"result": table * ctx.params["factor"]}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Port types: `any, dataframe, series, number, string, bool, object, figure`.
|
|
137
|
+
`columns`-typed params render with a ▾ picker listing the columns of the
|
|
138
|
+
DataFrames cached on the node's inputs (run upstream once to populate it);
|
|
139
|
+
add `"multi": False` for single-column params so picking replaces instead
|
|
140
|
+
of toggling a comma list.
|
|
141
|
+
Rules: treat inputs as read-only (outputs are cached by reference); heavy
|
|
142
|
+
imports go inside `run()`; matplotlib figures must use the OO API
|
|
143
|
+
(`matplotlib.figure.Figure()`), never pyplot.
|
|
144
|
+
|
|
145
|
+
Drop new `.py` files under `src/flograph/nodes/<category>/` and they appear in
|
|
146
|
+
the library on next launch.
|
|
147
|
+
|
|
148
|
+
## Development
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
uv pip install -p .venv/bin/python -e ".[dev]"
|
|
152
|
+
QT_QPA_PLATFORM=offscreen .venv/bin/python -m pytest tests/
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Architecture (src layout):
|
|
156
|
+
|
|
157
|
+
- `flograph/core` — Qt-free model: graph, typed ports, script contract,
|
|
158
|
+
registry, JSON serialization. Fully unit-testable; a poison test keeps Qt
|
|
159
|
+
and pandas out of its import graph.
|
|
160
|
+
- `flograph/engine` — background execution: plan builder, single-thread pool
|
|
161
|
+
worker, output cache, cancellation, per-node stdout capture, tracebacks
|
|
162
|
+
mapped to node script lines.
|
|
163
|
+
- `flograph/nodes` — the standard library; each node is a script file loaded as
|
|
164
|
+
text through the same contract as user code.
|
|
165
|
+
- `flograph/ui` — canvas (QGraphicsView from scratch), code editor, inspector,
|
|
166
|
+
properties, console. One rule everywhere: **QUndoCommands are the only
|
|
167
|
+
writers to the graph**; items react to graph events.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
[MIT](LICENSE) — free for commercial and private use, modification, and
|
|
172
|
+
redistribution; just keep the copyright and license notice.
|
flograph-0.1.0/ideas.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
1. flow variables like in knime
|
|
2
|
+
2. Export py script option, that creates a output script mirroring the flow. nice to use when a flograph workflow has matured enough to move the script to its own python script thats stands alone outside of the tool.
|
|
3
|
+
3. moving nodes should happen from their top bar only, make resizing better and esp important on "show *" nodes, as they often need to be resized.
|
|
4
|
+
4. add node: that similar to powerbis "Cards"
|
|
5
|
+
5. add node: a slicer similar to powerbis, maybe it can fit inline and automatically run the visuals that follow?
|
|
6
|
+
6. a way to turn a frame into a new "mega node" that is a node that contains nodes, i can config the initial wiring and end wiring. ie i input a df and it builds the table and graph.
|
|
7
|
+
7.
|
flograph-0.1.0/issues.md
ADDED
|
File without changes
|
flograph-0.1.0/main.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "flograph"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Visual node-based Python programming environment (KNIME-style dataflow, Blueprint-style canvas)"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "redthista", email = "dconrancpw@gmail.com" }]
|
|
10
|
+
keywords = [
|
|
11
|
+
"dataflow", "visual-programming", "node-editor", "etl", "pandas",
|
|
12
|
+
"gui", "pyside6", "qt", "knime", "low-code",
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Environment :: X11 Applications :: Qt",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Visualization",
|
|
25
|
+
"Topic :: Software Development :: User Interfaces",
|
|
26
|
+
"Topic :: Software Development :: Code Generators",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"PySide6>=6.7",
|
|
30
|
+
"pandas>=2.0",
|
|
31
|
+
"matplotlib>=3.8",
|
|
32
|
+
"jedi>=0.19",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/redthista/flograph"
|
|
37
|
+
Repository = "https://github.com/redthista/flograph"
|
|
38
|
+
Issues = "https://github.com/redthista/flograph/issues"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
dev = ["pytest>=8", "pytest-qt>=4.4"]
|
|
42
|
+
excel = ["openpyxl"]
|
|
43
|
+
parquet = ["pyarrow"]
|
|
44
|
+
plotly = ["plotly"]
|
|
45
|
+
|
|
46
|
+
[project.scripts]
|
|
47
|
+
flograph = "flograph.app:main"
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["hatchling"]
|
|
51
|
+
build-backend = "hatchling.build"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.build.targets.wheel]
|
|
54
|
+
packages = ["src/flograph"]
|
|
55
|
+
|
|
56
|
+
[tool.pytest.ini_options]
|
|
57
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Migrate legacy ``.flopy`` project files to the renamed ``.flograph`` format.
|
|
3
|
+
|
|
4
|
+
The project was renamed flopy -> flograph (the name ``flopy`` is taken on PyPI
|
|
5
|
+
by USGS MODFLOW). The rename is a clean break with no in-app backward
|
|
6
|
+
compatibility, so this one-shot tool upgrades any projects saved by the old
|
|
7
|
+
build:
|
|
8
|
+
|
|
9
|
+
* builtin node type-ids ``flopy.<sub>.<name>`` -> ``flograph.<sub>.<name>``
|
|
10
|
+
(``user.*`` and any other prefixes are left untouched);
|
|
11
|
+
* the informational ``flopy_version`` key -> ``flograph_version``;
|
|
12
|
+
* the file itself ``<name>.flopy`` -> ``<name>.flograph``;
|
|
13
|
+
* the side-car cache dir ``<name>.flopy.cache/`` -> ``<name>.flograph.cache/``.
|
|
14
|
+
|
|
15
|
+
Standalone and stdlib-only on purpose: it does not import the ``flograph``
|
|
16
|
+
package, so it runs against old files in any environment.
|
|
17
|
+
|
|
18
|
+
Usage::
|
|
19
|
+
|
|
20
|
+
python scripts/flopy_to_flograph.py project.flopy
|
|
21
|
+
python scripts/flopy_to_flograph.py path/to/dir --recursive
|
|
22
|
+
python scripts/flopy_to_flograph.py project.flopy --delete-original
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import argparse
|
|
27
|
+
import json
|
|
28
|
+
import sys
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
LEGACY_PREFIX = "flopy."
|
|
32
|
+
NEW_PREFIX = "flograph."
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def convert_project_data(data: dict) -> tuple[dict, int]:
|
|
36
|
+
"""Return a rewritten copy of a project dict and the number of builtin
|
|
37
|
+
node type-ids that were re-prefixed. Non-``flopy.*`` type-ids (notably
|
|
38
|
+
``user.*``) are preserved verbatim."""
|
|
39
|
+
rewritten = 0
|
|
40
|
+
if "flopy_version" in data and "flograph_version" not in data:
|
|
41
|
+
data["flograph_version"] = data.pop("flopy_version")
|
|
42
|
+
graph = data.get("graph")
|
|
43
|
+
if isinstance(graph, dict):
|
|
44
|
+
for node in graph.get("nodes", []):
|
|
45
|
+
type_id = node.get("type")
|
|
46
|
+
if isinstance(type_id, str) and type_id.startswith(LEGACY_PREFIX):
|
|
47
|
+
node["type"] = NEW_PREFIX + type_id[len(LEGACY_PREFIX):]
|
|
48
|
+
rewritten += 1
|
|
49
|
+
return data, rewritten
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _new_path(path: Path) -> Path:
|
|
53
|
+
# only the trailing ".flopy" suffix is swapped; the stem is preserved even
|
|
54
|
+
# if it happens to contain the substring "flopy".
|
|
55
|
+
return path.with_name(path.name[: -len(".flopy")] + ".flograph")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def convert_file(path: Path, *, delete_original: bool = False) -> tuple[Path, int]:
|
|
59
|
+
"""Convert one ``.flopy`` file, writing a sibling ``.flograph`` file and
|
|
60
|
+
renaming any ``.flopy.cache`` side-car. Returns (output_path, type_ids
|
|
61
|
+
rewritten)."""
|
|
62
|
+
data = json.loads(path.read_text())
|
|
63
|
+
data, rewritten = convert_project_data(data)
|
|
64
|
+
out_path = _new_path(path)
|
|
65
|
+
out_path.write_text(json.dumps(data, indent=2))
|
|
66
|
+
|
|
67
|
+
old_cache = path.with_name(path.name + ".cache")
|
|
68
|
+
if old_cache.is_dir():
|
|
69
|
+
new_cache = out_path.with_name(out_path.name + ".cache")
|
|
70
|
+
if not new_cache.exists():
|
|
71
|
+
old_cache.rename(new_cache)
|
|
72
|
+
|
|
73
|
+
if delete_original:
|
|
74
|
+
path.unlink()
|
|
75
|
+
|
|
76
|
+
return out_path, rewritten
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _iter_projects(paths: list[Path], recursive: bool):
|
|
80
|
+
for p in paths:
|
|
81
|
+
if p.is_dir():
|
|
82
|
+
yield from sorted(p.rglob("*.flopy") if recursive else p.glob("*.flopy"))
|
|
83
|
+
else:
|
|
84
|
+
yield p
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def main(argv: list[str] | None = None) -> int:
|
|
88
|
+
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
|
89
|
+
parser.add_argument("paths", nargs="+", type=Path,
|
|
90
|
+
help="`.flopy` files and/or directories to convert")
|
|
91
|
+
parser.add_argument("-r", "--recursive", action="store_true",
|
|
92
|
+
help="recurse into directories looking for `.flopy` files")
|
|
93
|
+
parser.add_argument("--delete-original", action="store_true",
|
|
94
|
+
help="delete each source `.flopy` after converting it")
|
|
95
|
+
args = parser.parse_args(argv)
|
|
96
|
+
|
|
97
|
+
files = 0
|
|
98
|
+
total_ids = 0
|
|
99
|
+
errors = 0
|
|
100
|
+
for project in _iter_projects(args.paths, args.recursive):
|
|
101
|
+
if project.suffix != ".flopy":
|
|
102
|
+
print(f"skip (not a .flopy file): {project}", file=sys.stderr)
|
|
103
|
+
continue
|
|
104
|
+
try:
|
|
105
|
+
out_path, rewritten = convert_file(
|
|
106
|
+
project, delete_original=args.delete_original)
|
|
107
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
108
|
+
print(f"error: {project}: {exc}", file=sys.stderr)
|
|
109
|
+
errors += 1
|
|
110
|
+
continue
|
|
111
|
+
files += 1
|
|
112
|
+
total_ids += rewritten
|
|
113
|
+
print(f"converted {project} -> {out_path} ({rewritten} type-ids rewritten)")
|
|
114
|
+
|
|
115
|
+
print(f"\n{files} file(s) converted, {total_ids} type-id(s) rewritten, "
|
|
116
|
+
f"{errors} error(s).")
|
|
117
|
+
return 1 if errors else 0
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if __name__ == "__main__":
|
|
121
|
+
raise SystemExit(main())
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Application entry point: QApplication, theme, registry, main window."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def main(argv: list[str] | None = None) -> int:
|
|
8
|
+
import matplotlib
|
|
9
|
+
matplotlib.use("QtAgg") # before any pyplot import, GUI-safe backend
|
|
10
|
+
|
|
11
|
+
from PySide6.QtCore import Qt
|
|
12
|
+
from PySide6.QtWidgets import QApplication
|
|
13
|
+
|
|
14
|
+
from flograph.core import NodeRegistry
|
|
15
|
+
from flograph.paths import user_nodes_dir
|
|
16
|
+
from flograph.ui.mainwindow import MainWindow
|
|
17
|
+
from flograph.ui.theme import apply_theme
|
|
18
|
+
|
|
19
|
+
# must be set before the QApplication exists: the Show Plotly card embeds
|
|
20
|
+
# Qt WebEngine, which needs shared GL contexts to composite
|
|
21
|
+
QApplication.setAttribute(Qt.AA_ShareOpenGLContexts)
|
|
22
|
+
app = QApplication.instance() or QApplication(sys.argv if argv is None else argv)
|
|
23
|
+
app.setApplicationName("flograph")
|
|
24
|
+
app.setOrganizationName("flograph")
|
|
25
|
+
apply_theme(app)
|
|
26
|
+
|
|
27
|
+
registry = NodeRegistry()
|
|
28
|
+
registry.load_builtins()
|
|
29
|
+
registry.load_user_nodes(user_nodes_dir())
|
|
30
|
+
|
|
31
|
+
window = MainWindow(registry)
|
|
32
|
+
window.resize(1400, 900)
|
|
33
|
+
window.show()
|
|
34
|
+
|
|
35
|
+
args = app.arguments()[1:]
|
|
36
|
+
project = next((a for a in args if a.endswith(".flograph")), None)
|
|
37
|
+
if project:
|
|
38
|
+
window.open_path(project, confirm=False)
|
|
39
|
+
return app.exec()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
raise SystemExit(main())
|