fastled 1.3.39__tar.gz → 1.4.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.
- {fastled-1.3.39 → fastled-1.4.1}/PKG-INFO +6 -4
- {fastled-1.3.39 → fastled-1.4.1}/README.md +5 -3
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/__init__.py +4 -1
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/__version__.py +1 -1
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/args.py +5 -10
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/client_server.py +14 -6
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/live_client.py +3 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/open_browser.py +9 -21
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/parse_args.py +8 -18
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/playwright_browser.py +56 -29
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled.egg-info/PKG-INFO +6 -4
- {fastled-1.3.39 → fastled-1.4.1}/tests/integration/test_playwright_integration.py +0 -58
- {fastled-1.3.39 → fastled-1.4.1}/.aiderignore +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.cursorrules +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.dockerignore +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/build_multi_docker_image.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/build_webpage.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/lint.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/publish_release.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/template_build_docker_image.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/test_build_exe.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/test_macos.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/test_ubuntu.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.github/workflows/test_win.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.gitignore +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.pylintrc +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.vscode/launch.json +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.vscode/settings.json +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/.vscode/tasks.json +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/DEBUGGER.md +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/Dockerfile +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/FAQ.md +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/LICENSE +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/MANIFEST.in +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/RELEASE.md +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/TODO.md +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/build_exe.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/build_local_docker.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/build_site.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/clean +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/compiler/debug.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/compiler/run.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/demo/100dots.html +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/demo/demo_threejs.html +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/demo/micdemo.html +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/demo/mp3upload.html +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/docker-compose.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/entrypoint.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/install +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/install_linux.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/lint +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/pyproject.toml +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/requirements.docker.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/requirements.testing.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/setup.cfg +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/setup.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/__main__.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/app.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/assets/example.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/assets/localhost-key.pem +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/assets/localhost.pem +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/cli.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/cli_test.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/cli_test_interactive.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/compile_server.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/compile_server_impl.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/docker_manager.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/filewatcher.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/keyboard.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/keyz.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/paths.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/print_filter.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/project_init.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/select_sketch_directory.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/server_flask.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/server_start.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/settings.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/site/build.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/site/examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/sketch.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/spinner.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/string_diff.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/test/can_run_local_docker_tests.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/test/examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/types.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/util.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/version.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled/web_compile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled.egg-info/SOURCES.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled.egg-info/dependency_links.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled.egg-info/entry_points.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled.egg-info/requires.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/src/fastled.egg-info/top_level.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/test +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/integration/test_build_examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/integration/test_examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/html/index.html +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_api.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_bad_ino.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_banner_string.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_cli.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_cli_no_platformio.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_compile_server.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_debug_fetch_source_files.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_docker_linux_on_windows.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_embedded_data.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_filechanger.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_flask_headers.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_http_server.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_ino/bad/bad.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_ino/embedded/wasm.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_ino/wasm/wasm.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_manual_api_invocation.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_no_platformio_compile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_project_init.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_server_and_client_seperatly.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_session_compile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_string_diff.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_string_diff_comprehensive.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_version.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/tests/unit/test_webcompile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/upload_package.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.1}/vscode-plugin/readme +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fastled
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.4.1
|
4
4
|
Summary: FastLED Wasm Compiler
|
5
5
|
Home-page: https://github.com/zackees/fastled-wasm
|
6
6
|
Maintainer: Zachary Vorhies
|
@@ -81,10 +81,10 @@ For enhanced browser control and automation capabilities, you can install the fu
|
|
81
81
|
$ pip install fastled[full]
|
82
82
|
```
|
83
83
|
|
84
|
-
|
84
|
+
When installed, FastLED will automatically use Playwright to open your compiled sketch in a controlled browser environment instead of your system's default browser:
|
85
85
|
|
86
86
|
```bash
|
87
|
-
$ fastled my_sketch
|
87
|
+
$ fastled my_sketch
|
88
88
|
```
|
89
89
|
|
90
90
|
The Playwright browser provides better automation capabilities and is especially useful for:
|
@@ -94,12 +94,13 @@ The Playwright browser provides better automation capabilities and is especially
|
|
94
94
|
- Persistent browser sessions that stay open until the FastLED process exits
|
95
95
|
|
96
96
|
**Key Benefits:**
|
97
|
+
- Automatically enabled when `fastled[full]` is installed - no additional flags needed
|
97
98
|
- The Playwright browser remains open throughout your development session
|
98
99
|
- Automatic cleanup when the FastLED process exits
|
99
100
|
- Better control over browser behavior and automation capabilities
|
100
101
|
- Consistent behavior across different platforms
|
101
102
|
|
102
|
-
If Playwright is not installed
|
103
|
+
If Playwright is not installed, the system will gracefully fall back to your default browser.
|
103
104
|
|
104
105
|
# Install
|
105
106
|
|
@@ -370,6 +371,7 @@ A: A big chunk of space is being used by unnecessary javascript `emscripten` bun
|
|
370
371
|
|
371
372
|
|
372
373
|
# Revisions
|
374
|
+
* 1.4.00 - Browser now uses playwright when `pip install fastled[full]` is used. Much better app like experience.
|
373
375
|
* 1.2.31 - Bunch of fixes and ease of use while compiling code in the repo.
|
374
376
|
* 1.2.22 - Prefer to use `live-server` from npm. If npm exists on the system then do a background install of `live-server` for next run.
|
375
377
|
* 1.2.20 - Fixed up path issue for web browser launch for hot reload.
|
@@ -51,10 +51,10 @@ For enhanced browser control and automation capabilities, you can install the fu
|
|
51
51
|
$ pip install fastled[full]
|
52
52
|
```
|
53
53
|
|
54
|
-
|
54
|
+
When installed, FastLED will automatically use Playwright to open your compiled sketch in a controlled browser environment instead of your system's default browser:
|
55
55
|
|
56
56
|
```bash
|
57
|
-
$ fastled my_sketch
|
57
|
+
$ fastled my_sketch
|
58
58
|
```
|
59
59
|
|
60
60
|
The Playwright browser provides better automation capabilities and is especially useful for:
|
@@ -64,12 +64,13 @@ The Playwright browser provides better automation capabilities and is especially
|
|
64
64
|
- Persistent browser sessions that stay open until the FastLED process exits
|
65
65
|
|
66
66
|
**Key Benefits:**
|
67
|
+
- Automatically enabled when `fastled[full]` is installed - no additional flags needed
|
67
68
|
- The Playwright browser remains open throughout your development session
|
68
69
|
- Automatic cleanup when the FastLED process exits
|
69
70
|
- Better control over browser behavior and automation capabilities
|
70
71
|
- Consistent behavior across different platforms
|
71
72
|
|
72
|
-
If Playwright is not installed
|
73
|
+
If Playwright is not installed, the system will gracefully fall back to your default browser.
|
73
74
|
|
74
75
|
# Install
|
75
76
|
|
@@ -340,6 +341,7 @@ A: A big chunk of space is being used by unnecessary javascript `emscripten` bun
|
|
340
341
|
|
341
342
|
|
342
343
|
# Revisions
|
344
|
+
* 1.4.00 - Browser now uses playwright when `pip install fastled[full]` is used. Much better app like experience.
|
343
345
|
* 1.2.31 - Bunch of fixes and ease of use while compiling code in the repo.
|
344
346
|
* 1.2.22 - Prefer to use `live-server` from npm. If npm exists on the system then do a background install of `live-server` for next run.
|
345
347
|
* 1.2.20 - Fixed up path issue for web browser launch for hot reload.
|
@@ -70,6 +70,7 @@ class Api:
|
|
70
70
|
int | None
|
71
71
|
) = None, # None means auto select a free port. -1 means no server.
|
72
72
|
no_platformio: bool = False,
|
73
|
+
no_playwright: bool = False,
|
73
74
|
) -> LiveClient:
|
74
75
|
return LiveClient(
|
75
76
|
sketch_directory=sketch_directory,
|
@@ -82,6 +83,7 @@ class Api:
|
|
82
83
|
profile=profile,
|
83
84
|
http_port=http_port,
|
84
85
|
no_platformio=no_platformio,
|
86
|
+
no_playwright=no_playwright,
|
85
87
|
)
|
86
88
|
|
87
89
|
@staticmethod
|
@@ -95,7 +97,6 @@ class Api:
|
|
95
97
|
no_platformio: bool = False,
|
96
98
|
) -> CompileServer:
|
97
99
|
"""Uses docker to spawn a compile server from the given name."""
|
98
|
-
from fastled.compile_server import CompileServer
|
99
100
|
|
100
101
|
out = CompileServer(
|
101
102
|
container_name=container_name,
|
@@ -207,6 +208,7 @@ class Test:
|
|
207
208
|
port: int | None = None,
|
208
209
|
compile_server_port: int | None = None,
|
209
210
|
open_browser: bool = True,
|
211
|
+
no_playwright: bool = False,
|
210
212
|
) -> Process:
|
211
213
|
from fastled.open_browser import spawn_http_server
|
212
214
|
|
@@ -218,6 +220,7 @@ class Test:
|
|
218
220
|
port=port,
|
219
221
|
compile_server_port=compile_server_port,
|
220
222
|
open_browser=open_browser,
|
223
|
+
no_playwright=no_playwright,
|
221
224
|
)
|
222
225
|
return proc
|
223
226
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# IMPORTANT! There's a bug in github which will REJECT any version update
|
2
2
|
# that has any other change in the repo. Please bump the version as the
|
3
3
|
# ONLY change in a commit, or else the pypi update and the release will fail.
|
4
|
-
__version__ = "1.
|
4
|
+
__version__ = "1.4.1"
|
5
5
|
|
6
6
|
__version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
|
@@ -13,6 +13,7 @@ class Args:
|
|
13
13
|
profile: bool
|
14
14
|
force_compile: bool
|
15
15
|
no_platformio: bool
|
16
|
+
no_playwright: bool
|
16
17
|
auto_update: bool | None
|
17
18
|
update: bool
|
18
19
|
localhost: bool
|
@@ -23,8 +24,6 @@ class Args:
|
|
23
24
|
quick: bool
|
24
25
|
release: bool
|
25
26
|
ram_disk_size: str # suffixed liked "25mb" or "1gb"
|
26
|
-
playwright: bool = False # Use Playwright browser instead of system default
|
27
|
-
no_playwright_auto_resize: bool = False # Disable Playwright auto-resize
|
28
27
|
clear = False # Force the last running container to be removed. Useful for benchmarking.
|
29
28
|
|
30
29
|
@staticmethod
|
@@ -53,6 +52,9 @@ class Args:
|
|
53
52
|
assert isinstance(
|
54
53
|
args.no_platformio, bool
|
55
54
|
), f"expected bool, got {type(args.no_platformio)}"
|
55
|
+
assert isinstance(
|
56
|
+
args.no_playwright, bool
|
57
|
+
), f"expected bool, got {type(args.no_playwright)}"
|
56
58
|
assert isinstance(
|
57
59
|
args.no_auto_updates, bool | None
|
58
60
|
), f"expected bool | None, got {type(args.no_auto_updates)}"
|
@@ -68,12 +70,6 @@ class Args:
|
|
68
70
|
assert isinstance(
|
69
71
|
args.release, bool
|
70
72
|
), f"expected bool, got {type(args.release)}"
|
71
|
-
assert isinstance(
|
72
|
-
args.playwright, bool
|
73
|
-
), f"expected bool, got {type(args.playwright)}"
|
74
|
-
assert isinstance(
|
75
|
-
args.no_playwright_auto_resize, bool
|
76
|
-
), f"expected bool, got {type(args.no_playwright_auto_resize)}"
|
77
73
|
|
78
74
|
init: bool | str = False
|
79
75
|
if args.init is None:
|
@@ -91,6 +87,7 @@ class Args:
|
|
91
87
|
profile=args.profile,
|
92
88
|
force_compile=args.force_compile,
|
93
89
|
no_platformio=args.no_platformio,
|
90
|
+
no_playwright=args.no_playwright,
|
94
91
|
auto_update=not args.no_auto_updates,
|
95
92
|
update=args.update,
|
96
93
|
localhost=args.localhost,
|
@@ -101,6 +98,4 @@ class Args:
|
|
101
98
|
quick=args.quick,
|
102
99
|
release=args.release,
|
103
100
|
ram_disk_size=args.ram_disk_size,
|
104
|
-
playwright=args.playwright,
|
105
|
-
no_playwright_auto_resize=args.no_playwright_auto_resize,
|
106
101
|
)
|
@@ -25,6 +25,16 @@ from fastled.web_compile import (
|
|
25
25
|
)
|
26
26
|
|
27
27
|
|
28
|
+
def _always_false() -> bool:
|
29
|
+
return False
|
30
|
+
|
31
|
+
|
32
|
+
try:
|
33
|
+
from fastled.playwright_browser import is_playwright_available
|
34
|
+
except ImportError:
|
35
|
+
is_playwright_available = _always_false
|
36
|
+
|
37
|
+
|
28
38
|
def _create_error_html(error_message: str) -> str:
|
29
39
|
return f"""<!DOCTYPE html>
|
30
40
|
<html>
|
@@ -258,8 +268,7 @@ def run_client(
|
|
258
268
|
) = None, # None means auto select a free port, http_port < 0 means no server.
|
259
269
|
clear: bool = False,
|
260
270
|
no_platformio: bool = False,
|
261
|
-
|
262
|
-
playwright_auto_resize: bool = True,
|
271
|
+
no_playwright: bool = False,
|
263
272
|
) -> int:
|
264
273
|
has_checked_newer_version_yet = False
|
265
274
|
compile_server: CompileServer | None = None
|
@@ -340,8 +349,7 @@ def run_client(
|
|
340
349
|
port=http_port,
|
341
350
|
compile_server_port=port,
|
342
351
|
open_browser=open_web_browser,
|
343
|
-
|
344
|
-
playwright_auto_resize=playwright_auto_resize,
|
352
|
+
no_playwright=no_playwright,
|
345
353
|
)
|
346
354
|
else:
|
347
355
|
print("\nCompilation successful.")
|
@@ -502,6 +510,7 @@ def run_client_server(args: Args) -> int:
|
|
502
510
|
open_web_browser = not just_compile and not interactive
|
503
511
|
build_mode: BuildMode = BuildMode.from_args(args)
|
504
512
|
no_platformio = bool(args.no_platformio)
|
513
|
+
no_playwright = bool(args.no_playwright)
|
505
514
|
|
506
515
|
if not force_compile and not looks_like_sketch_directory(directory):
|
507
516
|
# if there is only one directory in the sketch directory, use that
|
@@ -564,8 +573,7 @@ def run_client_server(args: Args) -> int:
|
|
564
573
|
profile=profile,
|
565
574
|
clear=args.clear,
|
566
575
|
no_platformio=no_platformio,
|
567
|
-
|
568
|
-
playwright_auto_resize=not args.no_playwright_auto_resize,
|
576
|
+
no_playwright=no_playwright,
|
569
577
|
)
|
570
578
|
except KeyboardInterrupt:
|
571
579
|
return 1
|
@@ -23,6 +23,7 @@ class LiveClient:
|
|
23
23
|
build_mode: BuildMode = BuildMode.QUICK,
|
24
24
|
profile: bool = False,
|
25
25
|
no_platformio: bool = False,
|
26
|
+
no_playwright: bool = False,
|
26
27
|
) -> None:
|
27
28
|
self.sketch_directory = sketch_directory
|
28
29
|
self.host = host
|
@@ -36,6 +37,7 @@ class LiveClient:
|
|
36
37
|
self.thread: threading.Thread | None = None
|
37
38
|
self.auto_updates = auto_updates
|
38
39
|
self.no_platformio = no_platformio
|
40
|
+
self.no_playwright = no_playwright
|
39
41
|
if auto_start:
|
40
42
|
self.start()
|
41
43
|
if self.auto_updates is False:
|
@@ -55,6 +57,7 @@ class LiveClient:
|
|
55
57
|
shutdown=self.shutdown,
|
56
58
|
http_port=self.http_port,
|
57
59
|
no_platformio=self.no_platformio,
|
60
|
+
no_playwright=self.no_playwright,
|
58
61
|
)
|
59
62
|
return rtn
|
60
63
|
|
@@ -101,8 +101,7 @@ def spawn_http_server(
|
|
101
101
|
compile_server_port: int,
|
102
102
|
port: int | None = None,
|
103
103
|
open_browser: bool = True,
|
104
|
-
|
105
|
-
playwright_auto_resize: bool = True,
|
104
|
+
no_playwright: bool = False,
|
106
105
|
) -> Process:
|
107
106
|
|
108
107
|
if port is not None and not is_port_free(port):
|
@@ -131,28 +130,17 @@ def spawn_http_server(
|
|
131
130
|
wait_for_server(port)
|
132
131
|
if open_browser:
|
133
132
|
url = f"http://localhost:{port}"
|
134
|
-
if
|
133
|
+
if (
|
134
|
+
PLAYWRIGHT_AVAILABLE
|
135
|
+
and open_with_playwright is not None
|
136
|
+
and not no_playwright
|
137
|
+
):
|
135
138
|
print(f"Opening FastLED sketch in Playwright browser: {url}")
|
136
|
-
if playwright_auto_resize:
|
137
|
-
print(
|
138
|
-
"Auto-resize enabled: Browser window will automatically adjust to content size"
|
139
|
-
)
|
140
|
-
global _playwright_browser_proxy
|
141
|
-
_playwright_browser_proxy = open_with_playwright(
|
142
|
-
url, auto_resize=playwright_auto_resize
|
143
|
-
)
|
144
|
-
elif use_playwright and not PLAYWRIGHT_AVAILABLE:
|
145
139
|
print(
|
146
|
-
"
|
147
|
-
)
|
148
|
-
print(f"Falling back to system browser: {url}")
|
149
|
-
import webbrowser
|
150
|
-
|
151
|
-
webbrowser.open(
|
152
|
-
url=url,
|
153
|
-
new=1,
|
154
|
-
autoraise=True,
|
140
|
+
"Auto-resize enabled: Browser window will automatically adjust to content size"
|
155
141
|
)
|
142
|
+
global _playwright_browser_proxy
|
143
|
+
_playwright_browser_proxy = open_with_playwright(url)
|
156
144
|
else:
|
157
145
|
print(f"Opening browser to {url}")
|
158
146
|
import webbrowser
|
@@ -35,15 +35,12 @@ FastLED WASM Compiler - Useful options:
|
|
35
35
|
--profile Enable profiling the C++ build system
|
36
36
|
--update Update the docker image for the wasm compiler
|
37
37
|
--purge Remove all FastLED containers and images
|
38
|
-
--playwright Use Playwright browser (requires 'pip install fastled[full]')
|
39
|
-
--no-playwright-auto-resize Disable automatic window resizing in Playwright
|
40
38
|
--version Show version information
|
41
39
|
--help Show detailed help
|
42
40
|
Examples:
|
43
41
|
fastled (will auto detect the sketch directory and prompt you)
|
44
42
|
fastled my_sketch
|
45
43
|
fastled my_sketch --web (compiles using the web compiler only)
|
46
|
-
fastled my_sketch --playwright (opens in Playwright browser)
|
47
44
|
fastled --init Blink (initializes a new sketch directory with the Blink example)
|
48
45
|
fastled --server (runs the compiler server in the current directory)
|
49
46
|
|
@@ -85,8 +82,8 @@ def parse_args() -> Args:
|
|
85
82
|
parser.add_argument(
|
86
83
|
"--ram-disk-size",
|
87
84
|
type=str,
|
88
|
-
default="
|
89
|
-
help="
|
85
|
+
default="1gb",
|
86
|
+
help="Size of the RAM disk for compilation (e.g., '1gb', '512mb')",
|
90
87
|
)
|
91
88
|
parser.add_argument(
|
92
89
|
"--web",
|
@@ -116,13 +113,18 @@ def parse_args() -> Args:
|
|
116
113
|
parser.add_argument(
|
117
114
|
"--no-auto-updates",
|
118
115
|
action="store_true",
|
119
|
-
help="Disable automatic updates of the wasm compiler image when using docker.",
|
116
|
+
help="Disable automatic updates of the wasm compiler image when using docker. (Default: False)",
|
120
117
|
)
|
121
118
|
parser.add_argument(
|
122
119
|
"--no-platformio",
|
123
120
|
action="store_true",
|
124
121
|
help="Bypass PlatformIO constraints by using local Docker compilation with custom build environment",
|
125
122
|
)
|
123
|
+
parser.add_argument(
|
124
|
+
"--no-playwright",
|
125
|
+
action="store_true",
|
126
|
+
help="Disable Playwright browser and use default system browser instead",
|
127
|
+
)
|
126
128
|
parser.add_argument(
|
127
129
|
"-u",
|
128
130
|
"--update",
|
@@ -161,18 +163,6 @@ def parse_args() -> Args:
|
|
161
163
|
help="Remove all FastLED containers and images",
|
162
164
|
)
|
163
165
|
|
164
|
-
parser.add_argument(
|
165
|
-
"--playwright",
|
166
|
-
action="store_true",
|
167
|
-
help="Use Playwright browser instead of system default (requires 'pip install fastled[full]')",
|
168
|
-
)
|
169
|
-
|
170
|
-
parser.add_argument(
|
171
|
-
"--no-playwright-auto-resize",
|
172
|
-
action="store_true",
|
173
|
-
help="Disable automatic window resizing in Playwright browser",
|
174
|
-
)
|
175
|
-
|
176
166
|
build_mode = parser.add_mutually_exclusive_group()
|
177
167
|
build_mode.add_argument("--debug", action="store_true", help="Build in debug mode")
|
178
168
|
build_mode.add_argument(
|
@@ -33,26 +33,23 @@ def is_playwright_available() -> bool:
|
|
33
33
|
class PlaywrightBrowser:
|
34
34
|
"""Playwright browser manager for FastLED sketches."""
|
35
35
|
|
36
|
-
def __init__(self, headless: bool = False
|
36
|
+
def __init__(self, headless: bool = False):
|
37
37
|
"""Initialize the Playwright browser manager.
|
38
38
|
|
39
39
|
Args:
|
40
40
|
headless: Whether to run the browser in headless mode
|
41
|
-
auto_resize: Whether to automatically resize the browser window to fit content
|
42
41
|
"""
|
43
42
|
if not PLAYWRIGHT_AVAILABLE:
|
44
43
|
raise ImportError(
|
45
44
|
"Playwright is not installed. Install with: pip install fastled[full]"
|
46
45
|
)
|
47
46
|
|
48
|
-
# debug
|
49
|
-
auto_resize = True
|
50
|
-
|
51
47
|
self.headless = headless
|
52
|
-
self.auto_resize =
|
48
|
+
self.auto_resize = True # Always enable auto-resize
|
53
49
|
self.browser: Any = None
|
54
50
|
self.page: Any = None
|
55
51
|
self.playwright: Any = None
|
52
|
+
self._should_exit = asyncio.Event()
|
56
53
|
|
57
54
|
async def start(self) -> None:
|
58
55
|
"""Start the Playwright browser."""
|
@@ -158,8 +155,9 @@ class PlaywrightBrowser:
|
|
158
155
|
|
159
156
|
# Check if page is still alive
|
160
157
|
if self.page is None or self.page.is_closed():
|
161
|
-
print("[PYTHON] Page closed,
|
162
|
-
|
158
|
+
print("[PYTHON] Page closed, signaling exit")
|
159
|
+
self._should_exit.set()
|
160
|
+
return
|
163
161
|
|
164
162
|
# Get browser window dimensions
|
165
163
|
window_info = await self._get_window_info()
|
@@ -258,15 +256,12 @@ class PlaywrightBrowser:
|
|
258
256
|
self.playwright = None
|
259
257
|
|
260
258
|
|
261
|
-
def run_playwright_browser(
|
262
|
-
url: str, headless: bool = False, auto_resize: bool = True
|
263
|
-
) -> None:
|
259
|
+
def run_playwright_browser(url: str, headless: bool = False) -> None:
|
264
260
|
"""Run Playwright browser in a separate process.
|
265
261
|
|
266
262
|
Args:
|
267
263
|
url: The URL to open
|
268
264
|
headless: Whether to run in headless mode
|
269
|
-
auto_resize: Whether to automatically resize the browser window to fit content
|
270
265
|
"""
|
271
266
|
if not PLAYWRIGHT_AVAILABLE:
|
272
267
|
warnings.warn(
|
@@ -276,7 +271,7 @@ def run_playwright_browser(
|
|
276
271
|
return
|
277
272
|
|
278
273
|
async def main():
|
279
|
-
browser = PlaywrightBrowser(headless=headless
|
274
|
+
browser = PlaywrightBrowser(headless=headless)
|
280
275
|
try:
|
281
276
|
await browser.start()
|
282
277
|
await browser.open_url(url)
|
@@ -309,14 +304,15 @@ class PlaywrightBrowserProxy:
|
|
309
304
|
def __init__(self):
|
310
305
|
self.process = None
|
311
306
|
self.browser_manager = None
|
307
|
+
self.monitor_thread = None
|
308
|
+
self._closing_intentionally = False
|
312
309
|
|
313
|
-
def open(self, url: str, headless: bool = False
|
310
|
+
def open(self, url: str, headless: bool = False) -> None:
|
314
311
|
"""Open URL with Playwright browser and keep it alive.
|
315
312
|
|
316
313
|
Args:
|
317
314
|
url: The URL to open
|
318
315
|
headless: Whether to run in headless mode
|
319
|
-
auto_resize: Whether to automatically resize the browser window to fit content
|
320
316
|
"""
|
321
317
|
if not PLAYWRIGHT_AVAILABLE:
|
322
318
|
warnings.warn(
|
@@ -335,10 +331,13 @@ class PlaywrightBrowserProxy:
|
|
335
331
|
|
336
332
|
self.process = multiprocessing.Process(
|
337
333
|
target=run_playwright_browser_persistent,
|
338
|
-
args=(url, headless
|
334
|
+
args=(url, headless),
|
339
335
|
)
|
340
336
|
self.process.start()
|
341
337
|
|
338
|
+
# Start monitoring thread to exit main process when browser subprocess exits
|
339
|
+
self._start_monitor_thread()
|
340
|
+
|
342
341
|
# Register cleanup
|
343
342
|
import atexit
|
344
343
|
|
@@ -352,10 +351,44 @@ class PlaywrightBrowserProxy:
|
|
352
351
|
|
353
352
|
webbrowser.open(url)
|
354
353
|
|
354
|
+
def _start_monitor_thread(self) -> None:
|
355
|
+
"""Start a thread to monitor the browser process and exit main process when it terminates."""
|
356
|
+
if self.monitor_thread is not None:
|
357
|
+
return
|
358
|
+
|
359
|
+
import os
|
360
|
+
import threading
|
361
|
+
|
362
|
+
def monitor_process():
|
363
|
+
"""Monitor the browser process and exit when it terminates."""
|
364
|
+
if self.process is None:
|
365
|
+
return
|
366
|
+
|
367
|
+
try:
|
368
|
+
# Wait for the process to terminate
|
369
|
+
self.process.join()
|
370
|
+
|
371
|
+
# Check if the process terminated (and we didn't kill it ourselves)
|
372
|
+
if (
|
373
|
+
self.process.exitcode is not None
|
374
|
+
and not self._closing_intentionally
|
375
|
+
):
|
376
|
+
print("[MAIN] Browser closed, exiting main program")
|
377
|
+
# Force exit the entire program
|
378
|
+
os._exit(0)
|
379
|
+
|
380
|
+
except Exception as e:
|
381
|
+
print(f"[MAIN] Error monitoring browser process: {e}")
|
382
|
+
|
383
|
+
self.monitor_thread = threading.Thread(target=monitor_process, daemon=True)
|
384
|
+
self.monitor_thread.start()
|
385
|
+
|
355
386
|
def close(self) -> None:
|
356
387
|
"""Close the Playwright browser."""
|
357
388
|
if self.process and self.process.is_alive():
|
358
389
|
print("Closing Playwright browser...")
|
390
|
+
# Mark that we're intentionally closing to prevent monitor from triggering exit
|
391
|
+
self._closing_intentionally = True
|
359
392
|
self.process.terminate()
|
360
393
|
self.process.join(timeout=5)
|
361
394
|
if self.process.is_alive():
|
@@ -363,21 +396,18 @@ class PlaywrightBrowserProxy:
|
|
363
396
|
self.process = None
|
364
397
|
|
365
398
|
|
366
|
-
def run_playwright_browser_persistent(
|
367
|
-
url: str, headless: bool = False, auto_resize: bool = True
|
368
|
-
) -> None:
|
399
|
+
def run_playwright_browser_persistent(url: str, headless: bool = False) -> None:
|
369
400
|
"""Run Playwright browser in a persistent mode that stays alive until terminated.
|
370
401
|
|
371
402
|
Args:
|
372
403
|
url: The URL to open
|
373
404
|
headless: Whether to run in headless mode
|
374
|
-
auto_resize: Whether to automatically resize the browser window to fit content
|
375
405
|
"""
|
376
406
|
if not PLAYWRIGHT_AVAILABLE:
|
377
407
|
return
|
378
408
|
|
379
409
|
async def main():
|
380
|
-
browser = PlaywrightBrowser(headless=headless
|
410
|
+
browser = PlaywrightBrowser(headless=headless)
|
381
411
|
try:
|
382
412
|
await browser.start()
|
383
413
|
await browser.open_url(url)
|
@@ -386,9 +416,9 @@ def run_playwright_browser_persistent(
|
|
386
416
|
"Playwright browser opened. Browser will remain open until the FastLED process exits."
|
387
417
|
)
|
388
418
|
|
389
|
-
# Keep the browser alive
|
390
|
-
while
|
391
|
-
await asyncio.sleep(1)
|
419
|
+
# Keep the browser alive until exit is signaled
|
420
|
+
while not browser._should_exit.is_set():
|
421
|
+
await asyncio.sleep(0.1)
|
392
422
|
|
393
423
|
except KeyboardInterrupt:
|
394
424
|
print("\nClosing Playwright browser...")
|
@@ -405,9 +435,7 @@ def run_playwright_browser_persistent(
|
|
405
435
|
print(f"Playwright browser failed: {e}")
|
406
436
|
|
407
437
|
|
408
|
-
def open_with_playwright(
|
409
|
-
url: str, headless: bool = False, auto_resize: bool = True
|
410
|
-
) -> PlaywrightBrowserProxy:
|
438
|
+
def open_with_playwright(url: str, headless: bool = False) -> PlaywrightBrowserProxy:
|
411
439
|
"""Open URL with Playwright browser and return a proxy object for lifecycle management.
|
412
440
|
|
413
441
|
This function can be used as a drop-in replacement for webbrowser.open().
|
@@ -415,13 +443,12 @@ def open_with_playwright(
|
|
415
443
|
Args:
|
416
444
|
url: The URL to open
|
417
445
|
headless: Whether to run in headless mode
|
418
|
-
auto_resize: Whether to automatically resize the browser window to fit content
|
419
446
|
|
420
447
|
Returns:
|
421
448
|
PlaywrightBrowserProxy object for managing the browser lifecycle
|
422
449
|
"""
|
423
450
|
proxy = PlaywrightBrowserProxy()
|
424
|
-
proxy.open(url, headless
|
451
|
+
proxy.open(url, headless)
|
425
452
|
return proxy
|
426
453
|
|
427
454
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fastled
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.4.1
|
4
4
|
Summary: FastLED Wasm Compiler
|
5
5
|
Home-page: https://github.com/zackees/fastled-wasm
|
6
6
|
Maintainer: Zachary Vorhies
|
@@ -81,10 +81,10 @@ For enhanced browser control and automation capabilities, you can install the fu
|
|
81
81
|
$ pip install fastled[full]
|
82
82
|
```
|
83
83
|
|
84
|
-
|
84
|
+
When installed, FastLED will automatically use Playwright to open your compiled sketch in a controlled browser environment instead of your system's default browser:
|
85
85
|
|
86
86
|
```bash
|
87
|
-
$ fastled my_sketch
|
87
|
+
$ fastled my_sketch
|
88
88
|
```
|
89
89
|
|
90
90
|
The Playwright browser provides better automation capabilities and is especially useful for:
|
@@ -94,12 +94,13 @@ The Playwright browser provides better automation capabilities and is especially
|
|
94
94
|
- Persistent browser sessions that stay open until the FastLED process exits
|
95
95
|
|
96
96
|
**Key Benefits:**
|
97
|
+
- Automatically enabled when `fastled[full]` is installed - no additional flags needed
|
97
98
|
- The Playwright browser remains open throughout your development session
|
98
99
|
- Automatic cleanup when the FastLED process exits
|
99
100
|
- Better control over browser behavior and automation capabilities
|
100
101
|
- Consistent behavior across different platforms
|
101
102
|
|
102
|
-
If Playwright is not installed
|
103
|
+
If Playwright is not installed, the system will gracefully fall back to your default browser.
|
103
104
|
|
104
105
|
# Install
|
105
106
|
|
@@ -370,6 +371,7 @@ A: A big chunk of space is being used by unnecessary javascript `emscripten` bun
|
|
370
371
|
|
371
372
|
|
372
373
|
# Revisions
|
374
|
+
* 1.4.00 - Browser now uses playwright when `pip install fastled[full]` is used. Much better app like experience.
|
373
375
|
* 1.2.31 - Bunch of fixes and ease of use while compiling code in the repo.
|
374
376
|
* 1.2.22 - Prefer to use `live-server` from npm. If npm exists on the system then do a background install of `live-server` for next run.
|
375
377
|
* 1.2.20 - Fixed up path issue for web browser launch for hot reload.
|
@@ -56,64 +56,6 @@ class PlaywrightIntegrationTester(unittest.TestCase):
|
|
56
56
|
# Test cleanup
|
57
57
|
proxy.close() # Should not raise an exception
|
58
58
|
|
59
|
-
def test_args_integration(self):
|
60
|
-
"""Test that the playwright argument is properly integrated into the Args class."""
|
61
|
-
import argparse
|
62
|
-
|
63
|
-
from fastled.args import Args
|
64
|
-
|
65
|
-
# Create a mock namespace with the playwright argument
|
66
|
-
namespace = argparse.Namespace()
|
67
|
-
namespace.directory = None
|
68
|
-
namespace.init = None
|
69
|
-
namespace.just_compile = False
|
70
|
-
namespace.web = None
|
71
|
-
namespace.interactive = False
|
72
|
-
namespace.profile = False
|
73
|
-
namespace.force_compile = False
|
74
|
-
namespace.no_platformio = False
|
75
|
-
namespace.no_auto_updates = False
|
76
|
-
namespace.update = False
|
77
|
-
namespace.localhost = False
|
78
|
-
namespace.build = False
|
79
|
-
namespace.server = False
|
80
|
-
namespace.purge = False
|
81
|
-
namespace.debug = False
|
82
|
-
namespace.quick = False
|
83
|
-
namespace.release = False
|
84
|
-
namespace.ram_disk_size = "0"
|
85
|
-
namespace.playwright = True
|
86
|
-
|
87
|
-
# Create Args from namespace
|
88
|
-
args = Args.from_namespace(namespace)
|
89
|
-
|
90
|
-
# Verify the playwright flag is set
|
91
|
-
self.assertTrue(args.playwright)
|
92
|
-
|
93
|
-
def test_parse_args_playwright_flag(self):
|
94
|
-
"""Test that the --playwright flag is properly parsed."""
|
95
|
-
import sys
|
96
|
-
|
97
|
-
from fastled.parse_args import parse_args
|
98
|
-
|
99
|
-
# Save original argv
|
100
|
-
original_argv = sys.argv
|
101
|
-
|
102
|
-
try:
|
103
|
-
# Test with --playwright flag
|
104
|
-
sys.argv = ["fastled", "test_dir", "--playwright"]
|
105
|
-
args = parse_args()
|
106
|
-
self.assertTrue(args.playwright)
|
107
|
-
|
108
|
-
# Test without --playwright flag
|
109
|
-
sys.argv = ["fastled", "test_dir"]
|
110
|
-
args = parse_args()
|
111
|
-
self.assertFalse(args.playwright)
|
112
|
-
|
113
|
-
finally:
|
114
|
-
# Restore original argv
|
115
|
-
sys.argv = original_argv
|
116
|
-
|
117
59
|
|
118
60
|
if __name__ == "__main__":
|
119
61
|
unittest.main()
|
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
|
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
|