collagraph 0.9.2__tar.gz → 0.9.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {collagraph-0.9.2 → collagraph-0.9.3}/.github/workflows/ci.yml +17 -1
- {collagraph-0.9.2 → collagraph-0.9.3}/.gitignore +1 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/PKG-INFO +1 -1
- collagraph-0.9.3/collagraph/__pyinstaller/hook-collagraph.py +126 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/sfc/importer.py +5 -2
- {collagraph-0.9.2 → collagraph-0.9.3}/pyproject.toml +2 -1
- collagraph-0.9.3/tests/pyinstaller/expected_output.json +28 -0
- collagraph-0.9.3/tests/pyinstaller/test_pyinstaller.sh +38 -0
- collagraph-0.9.3/tests/pyinstaller/todo_app/app.py +14 -0
- collagraph-0.9.3/tests/pyinstaller/todo_app/helpers.py +3 -0
- collagraph-0.9.3/tests/pyinstaller/todo_app/todo_item.cgx +11 -0
- collagraph-0.9.3/tests/pyinstaller/todo_app/todo_list.cgx +23 -0
- collagraph-0.9.2/collagraph/__pyinstaller/hook-collagraph.py +0 -58
- {collagraph-0.9.2 → collagraph-0.9.3}/.coveragerc +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/.pre-commit-config.yaml +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/LICENSE +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/README.md +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/__init__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/__main__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/__pyinstaller/__init__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/collagraph.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/component.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/constants.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/fragment.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/hot_reload.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/__init__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/dict_renderer.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pygfx_renderer.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/__init__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/__init__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/combobox.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/dialogbuttonbox.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/dockwidget.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/itemmodel.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/layouts.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/listview.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/menu.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/menubar.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/qobject.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/scrollarea.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/splitter.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/standarditem.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/statusbar.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/tab.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/toolbar.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/treewidget.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/treewidgetitem.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/widget.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/window.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside_renderer.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/sfc/__init__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/sfc/compiler.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/sfc/parser.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/collagraph/weak.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/README.md +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/app_point_cloud.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/button.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/combined-example.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/component-example.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/numberpad.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/point.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/point_cloud.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/pygfx-component.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pygfx/render_widget.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/app.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/big_list.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/cgx_component_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/combobox_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/counter.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/debug_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/dialog_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/dialog_example_window.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/flow_layout.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/item.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/layout_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/list_and_form.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/lists_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/slider_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/tabs_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/template_refs.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/todo_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/todo_list.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/tree_view_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/tree_view_item.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/tree_view_model.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/tree_widget_example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/tree_widget_item.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/examples/pyside/treewidget_selection_demo.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/__init__.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/conftest.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/component/events_child.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/component/events_parent.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/component/provide_child.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/component/provide_parent.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/component/provide_root.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/example.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/file_dunder.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/multiple_classes_right_order.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/multiple_classes_wrong_order.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/multiple_root_elements.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/no_component_class.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/pyside/app.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/pyside/test_pyside_update.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/shadow_imports.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/simple.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/dynamic_component.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/dynamic_for.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/dynamic_for_template.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/dynamic_if.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/dynamic_if_template.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/node.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/simple_tree.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/slots_implicit_default_slot.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/template.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/template_empty.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/template_implicit_default_slot.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/template_implicit_default_slot_name.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/template_partial.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/tree.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/widget_with_slots.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/data/text/expressions.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/conftest.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/lists.cgx +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_pyside_ci.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_pyside_elements.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_pyside_layouts.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_pyside_renderer.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_pyside_resilience.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_pyside_sfc.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_pyside_trigger_signals.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_treewidget_selection.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_update.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/pyside/test_widget.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_anchors.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_attributes_dynamic.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_attributes_static.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_collagraph.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_component.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_component_events.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_component_life_cycle.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_component_provide_inject.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_directive_else.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_directive_else_if.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_directive_for.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_directive_for_keyed.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_directive_if.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_directive_if_no_unnecessary_remount.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_events.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_hot_reload.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_hot_reload_preservation.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_load_string.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_parser.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_pygfx_renderer.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_resolve_names.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_sfc_comments.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_sfc_compilation.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_sfc_import.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_sfc_linting_support.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_sfc_shadowing.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_slots.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_slots_dynamic.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_tag_component.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_tag_dynamic.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_tag_static.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_tag_template.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_template_refs.py +0 -0
- {collagraph-0.9.2 → collagraph-0.9.3}/tests/test_text_expressions.py +0 -0
|
@@ -65,6 +65,22 @@ jobs:
|
|
|
65
65
|
env:
|
|
66
66
|
QT_QPA_PLATFORM: offscreen
|
|
67
67
|
|
|
68
|
+
pyinstaller:
|
|
69
|
+
name: Test PyInstaller hooks
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@v5
|
|
73
|
+
- name: Install uv
|
|
74
|
+
uses: astral-sh/setup-uv@v6
|
|
75
|
+
- name: Set up Python
|
|
76
|
+
uses: actions/setup-python@v5
|
|
77
|
+
with:
|
|
78
|
+
python-version-file: "pyproject.toml"
|
|
79
|
+
- name: Install dependencies
|
|
80
|
+
run: uv sync
|
|
81
|
+
- name: Test PyInstaller hooks
|
|
82
|
+
run: bash tests/pyinstaller/test_pyinstaller.sh
|
|
83
|
+
|
|
68
84
|
build:
|
|
69
85
|
name: Build and test wheel
|
|
70
86
|
runs-on: ubuntu-latest
|
|
@@ -91,7 +107,7 @@ jobs:
|
|
|
91
107
|
publish:
|
|
92
108
|
name: Publish to Github and Pypi
|
|
93
109
|
runs-on: ubuntu-latest
|
|
94
|
-
needs: [lint, test, build]
|
|
110
|
+
needs: [lint, test, build, pyinstaller]
|
|
95
111
|
if: success() && startsWith(github.ref, 'refs/tags/v')
|
|
96
112
|
environment:
|
|
97
113
|
name: pypi
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import atexit
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from PyInstaller.lib.modulegraph.modulegraph import DependencyInfo, MissingModule
|
|
6
|
+
|
|
7
|
+
from collagraph.sfc.compiler import construct_ast, get_script_ast
|
|
8
|
+
from collagraph.sfc.parser import CGXParser
|
|
9
|
+
|
|
10
|
+
# Keep track of generated files so they can be cleaned up
|
|
11
|
+
_generated_files: list[Path] = []
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _cleanup_generated_files():
|
|
15
|
+
for path in _generated_files:
|
|
16
|
+
path.unlink(missing_ok=True)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
atexit.register(_cleanup_generated_files)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def hook(hook_api):
|
|
23
|
+
collagraph_uses = hook_api.analysis.graph.get_code_using("collagraph")
|
|
24
|
+
|
|
25
|
+
hidden_imports = set()
|
|
26
|
+
cgx_modules = set()
|
|
27
|
+
|
|
28
|
+
for package, code in collagraph_uses.items():
|
|
29
|
+
source_dir = Path(code.co_filename).parent
|
|
30
|
+
|
|
31
|
+
# Collect CGX files and their imports from the source directory
|
|
32
|
+
cgx_files = list(source_dir.glob("**/*.cgx"))
|
|
33
|
+
hidden_imports |= collect_hidden_imports(cgx_files)
|
|
34
|
+
|
|
35
|
+
# Pre-compile each CGX file to Python source so that
|
|
36
|
+
# PyInstaller can bundle them as regular Python modules,
|
|
37
|
+
# removing the need to bundle .cgx files and compile them
|
|
38
|
+
# at runtime
|
|
39
|
+
for cgx_path in cgx_files:
|
|
40
|
+
module_name = cgx_path.stem
|
|
41
|
+
tree, _name = construct_ast(cgx_path)
|
|
42
|
+
python_source = ast.unparse(tree)
|
|
43
|
+
|
|
44
|
+
# Write compiled module next to the CGX file so
|
|
45
|
+
# PyInstaller can discover it on its existing search path
|
|
46
|
+
py_path = cgx_path.with_suffix(".py")
|
|
47
|
+
if not py_path.exists():
|
|
48
|
+
py_path.write_text(python_source, encoding="utf-8")
|
|
49
|
+
_generated_files.append(py_path)
|
|
50
|
+
cgx_modules.add(module_name)
|
|
51
|
+
|
|
52
|
+
# Filter out imports that correspond to CGX modules, since
|
|
53
|
+
# they are now available as pre-compiled Python modules
|
|
54
|
+
hidden_imports -= cgx_modules
|
|
55
|
+
|
|
56
|
+
graph = hook_api.analysis.graph
|
|
57
|
+
|
|
58
|
+
# Remove any MissingModule nodes for CGX modules that were
|
|
59
|
+
# already marked as missing during initial analysis (before
|
|
60
|
+
# the compiled .py files existed).
|
|
61
|
+
# removeNode() calls hide_node() which moves the node to
|
|
62
|
+
# hidden_nodes. Graph.add_node() silently ignores nodes in
|
|
63
|
+
# hidden_nodes, so we must also delete from hidden_nodes to
|
|
64
|
+
# allow import_hook to re-add the module as a SourceModule.
|
|
65
|
+
for name in cgx_modules:
|
|
66
|
+
node = graph.find_node(name)
|
|
67
|
+
if isinstance(node, MissingModule):
|
|
68
|
+
graph.removeNode(node)
|
|
69
|
+
if name in graph.graph.hidden_nodes:
|
|
70
|
+
del graph.graph.hidden_nodes[name]
|
|
71
|
+
|
|
72
|
+
# Import CGX modules via the module graph and create edges
|
|
73
|
+
# to the collagraph node so they are included in the bundle.
|
|
74
|
+
collagraph_node = graph.find_node("collagraph")
|
|
75
|
+
for name in cgx_modules:
|
|
76
|
+
try:
|
|
77
|
+
nodes = graph.import_hook(name, collagraph_node)
|
|
78
|
+
for node in nodes:
|
|
79
|
+
graph._updateReference(
|
|
80
|
+
collagraph_node,
|
|
81
|
+
node,
|
|
82
|
+
edge_data=DependencyInfo(
|
|
83
|
+
conditional=False,
|
|
84
|
+
fromlist=False,
|
|
85
|
+
function=False,
|
|
86
|
+
tryexcept=False,
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
except ImportError:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
# Add remaining hidden imports (non-CGX Python modules)
|
|
93
|
+
hook_api.add_imports(*hidden_imports)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def collect_hidden_imports(cgx_files):
|
|
97
|
+
hidden_imports = set()
|
|
98
|
+
for path in cgx_files:
|
|
99
|
+
template = path.read_text(encoding="utf-8")
|
|
100
|
+
# Parse the file component into a tree of Node instances
|
|
101
|
+
parser = CGXParser()
|
|
102
|
+
parser.feed(template)
|
|
103
|
+
|
|
104
|
+
# Get the AST from the script tag
|
|
105
|
+
script_tree = get_script_ast(parser, path)
|
|
106
|
+
|
|
107
|
+
# Find a list of imported module names
|
|
108
|
+
imported_names = ImportsCollector()
|
|
109
|
+
imported_names.visit(script_tree)
|
|
110
|
+
|
|
111
|
+
hidden_imports |= imported_names.names
|
|
112
|
+
|
|
113
|
+
return hidden_imports
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ImportsCollector(ast.NodeVisitor):
|
|
117
|
+
def __init__(self):
|
|
118
|
+
self.names = set()
|
|
119
|
+
|
|
120
|
+
def visit_ImportFrom(self, node):
|
|
121
|
+
if node.module:
|
|
122
|
+
self.names.add(node.module)
|
|
123
|
+
|
|
124
|
+
def visit_Import(self, node):
|
|
125
|
+
for alias in node.names:
|
|
126
|
+
self.names.add(alias.name)
|
|
@@ -66,5 +66,8 @@ class CGXPathFinder(MetaPathFinder):
|
|
|
66
66
|
return spec
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
# Add cgx path finder at the end of the list of finders
|
|
70
|
-
|
|
69
|
+
# Add cgx path finder at the end of the list of finders.
|
|
70
|
+
# Skip when running as a frozen PyInstaller bundle, since CGX files
|
|
71
|
+
# are pre-compiled to Python modules by the PyInstaller hook.
|
|
72
|
+
if not getattr(sys, "frozen", False):
|
|
73
|
+
sys.meta_path.append(CGXPathFinder())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "collagraph"
|
|
3
|
-
version = "0.9.
|
|
3
|
+
version = "0.9.3"
|
|
4
4
|
description = "Reactive user interfaces"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Berend Klein Haneveld", email = "berendkleinhaneveld@gmail.com" },
|
|
@@ -59,6 +59,7 @@ pyside-dev = [
|
|
|
59
59
|
"examples/pygfx/*.py" = ["I001"] # unsorted-imports
|
|
60
60
|
"examples/pyside/flow_layout.py" = ["N802"] # invalid-function-name
|
|
61
61
|
"tests/*" = ["N806", "N802"] # non-lowercase-variable-in-function, invalid-function-name
|
|
62
|
+
"tests/pyinstaller/*" = ["I001", "T20"] # unsorted-imports, flake8-print
|
|
62
63
|
"tests/pyside/test_*.py" = ["E402"] # module-import-not-at-top-of-file
|
|
63
64
|
|
|
64
65
|
[tool.ruff.lint]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "root",
|
|
3
|
+
"children": [
|
|
4
|
+
{
|
|
5
|
+
"type": "list",
|
|
6
|
+
"children": [
|
|
7
|
+
{
|
|
8
|
+
"type": "item",
|
|
9
|
+
"attrs": {
|
|
10
|
+
"label": "[todo] Buy groceries"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "item",
|
|
15
|
+
"attrs": {
|
|
16
|
+
"label": "[done] Write tests"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"type": "item",
|
|
21
|
+
"attrs": {
|
|
22
|
+
"label": "[todo] Deploy app"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
5
|
+
REPO_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
6
|
+
APP_DIR="$SCRIPT_DIR/todo_app"
|
|
7
|
+
EXPECTED="$SCRIPT_DIR/expected_output.json"
|
|
8
|
+
|
|
9
|
+
echo "==> Installing pyinstaller..."
|
|
10
|
+
uv pip install pyinstaller
|
|
11
|
+
|
|
12
|
+
echo "==> Building todo_app with PyInstaller..."
|
|
13
|
+
cd "$APP_DIR"
|
|
14
|
+
uv run pyinstaller \
|
|
15
|
+
--noconfirm \
|
|
16
|
+
--log-level WARN \
|
|
17
|
+
--onefile \
|
|
18
|
+
--name todo_app \
|
|
19
|
+
app.py
|
|
20
|
+
|
|
21
|
+
echo "==> Running bundled application..."
|
|
22
|
+
OUTPUT=$(./dist/todo_app)
|
|
23
|
+
|
|
24
|
+
echo "==> Comparing output..."
|
|
25
|
+
EXPECTED_CONTENT=$(cat "$EXPECTED")
|
|
26
|
+
|
|
27
|
+
if [ "$OUTPUT" = "$EXPECTED_CONTENT" ]; then
|
|
28
|
+
echo "==> PyInstaller test PASSED"
|
|
29
|
+
else
|
|
30
|
+
echo "==> PyInstaller test FAILED"
|
|
31
|
+
echo ""
|
|
32
|
+
echo "Expected:"
|
|
33
|
+
echo "$EXPECTED_CONTENT"
|
|
34
|
+
echo ""
|
|
35
|
+
echo "Got:"
|
|
36
|
+
echo "$OUTPUT"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import collagraph as cg
|
|
4
|
+
|
|
5
|
+
from todo_list import TodoList
|
|
6
|
+
|
|
7
|
+
container = {"type": "root"}
|
|
8
|
+
gui = cg.Collagraph(
|
|
9
|
+
renderer=cg.DictRenderer(),
|
|
10
|
+
event_loop_type=cg.EventLoopType.SYNC,
|
|
11
|
+
)
|
|
12
|
+
gui.render(TodoList, container)
|
|
13
|
+
|
|
14
|
+
print(json.dumps(container, indent=2))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<list>
|
|
2
|
+
<TodoItem
|
|
3
|
+
v-for="todo in state['todos']"
|
|
4
|
+
:done="todo['done']"
|
|
5
|
+
:key="todo['id']"
|
|
6
|
+
:text="todo['text']"
|
|
7
|
+
/>
|
|
8
|
+
</list>
|
|
9
|
+
|
|
10
|
+
<script>
|
|
11
|
+
import collagraph as cg
|
|
12
|
+
from todo_item import TodoItem
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TodoList(cg.Component):
|
|
16
|
+
def init(self):
|
|
17
|
+
self.state["todos"] = [
|
|
18
|
+
{"id": 1, "text": "Buy groceries", "done": False},
|
|
19
|
+
{"id": 2, "text": "Write tests", "done": True},
|
|
20
|
+
{"id": 3, "text": "Deploy app", "done": False},
|
|
21
|
+
]
|
|
22
|
+
</script>
|
|
23
|
+
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import ast
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
from PyInstaller.utils.hooks import collect_data_files
|
|
5
|
-
|
|
6
|
-
from collagraph.sfc.compiler import get_script_ast
|
|
7
|
-
from collagraph.sfc.parser import CGXParser
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def hook(hook_api):
|
|
11
|
-
collagraph_uses = hook_api.analysis.graph.get_code_using("collagraph")
|
|
12
|
-
|
|
13
|
-
hidden_imports = set()
|
|
14
|
-
datas = []
|
|
15
|
-
for package, code in collagraph_uses.items():
|
|
16
|
-
filename = Path(code.co_filename)
|
|
17
|
-
hidden_imports |= collect_hidden_imports(filename.parent)
|
|
18
|
-
datas += collect_data_files(package, includes=["**/*.cgx"])
|
|
19
|
-
|
|
20
|
-
hook_api.add_imports(*hidden_imports)
|
|
21
|
-
hook_api.add_datas(datas)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def collect_hidden_imports(folder):
|
|
25
|
-
folder = Path(folder)
|
|
26
|
-
|
|
27
|
-
hidden_imports = set()
|
|
28
|
-
for path in folder.glob("**/*.cgx"):
|
|
29
|
-
template = path.read_text(encoding="utf-8")
|
|
30
|
-
# Parse the file component into a tree of Node instances
|
|
31
|
-
parser = CGXParser()
|
|
32
|
-
parser.feed(template)
|
|
33
|
-
|
|
34
|
-
# Get the AST from the script tag
|
|
35
|
-
script_tree = get_script_ast(parser, path)
|
|
36
|
-
|
|
37
|
-
# Find a list of imported names (or aliases, if any)
|
|
38
|
-
# Those names don't have to be wrapped by `_lookup`
|
|
39
|
-
imported_names = ImportsCollector()
|
|
40
|
-
imported_names.visit(script_tree)
|
|
41
|
-
|
|
42
|
-
hidden_imports |= imported_names.names
|
|
43
|
-
|
|
44
|
-
return hidden_imports
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class ImportsCollector(ast.NodeVisitor):
|
|
48
|
-
def __init__(self):
|
|
49
|
-
self.names = set()
|
|
50
|
-
|
|
51
|
-
def visit_ImportFrom(self, node):
|
|
52
|
-
for alias in node.names:
|
|
53
|
-
self.names.add(".".join([node.module, alias.name]))
|
|
54
|
-
self.names.add(node.module)
|
|
55
|
-
|
|
56
|
-
def visit_Import(self, node):
|
|
57
|
-
for alias in node.names:
|
|
58
|
-
self.names.add(alias.name)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{collagraph-0.9.2 → collagraph-0.9.3}/collagraph/renderers/pyside/objects/dialogbuttonbox.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{collagraph-0.9.2 → collagraph-0.9.3}/tests/data/slots/template_implicit_default_slot_name.cgx
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|