fastled 1.3.39__tar.gz → 1.4.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.
- {fastled-1.3.39 → fastled-1.4.0}/PKG-INFO +5 -4
- {fastled-1.3.39 → fastled-1.4.0}/README.md +4 -3
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/__init__.py +0 -1
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/__version__.py +1 -1
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/args.py +0 -10
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/client_server.py +10 -6
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/open_browser.py +4 -21
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/parse_args.py +3 -18
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/playwright_browser.py +56 -29
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled.egg-info/PKG-INFO +5 -4
- {fastled-1.3.39 → fastled-1.4.0}/tests/integration/test_playwright_integration.py +0 -58
- {fastled-1.3.39 → fastled-1.4.0}/.aiderignore +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.cursorrules +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.dockerignore +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/build_multi_docker_image.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/build_webpage.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/lint.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/publish_release.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/template_build_docker_image.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/test_build_exe.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/test_macos.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/test_ubuntu.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.github/workflows/test_win.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.gitignore +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.pylintrc +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.vscode/launch.json +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.vscode/settings.json +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/.vscode/tasks.json +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/DEBUGGER.md +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/Dockerfile +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/FAQ.md +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/LICENSE +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/MANIFEST.in +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/RELEASE.md +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/TODO.md +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/build_exe.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/build_local_docker.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/build_site.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/clean +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/compiler/debug.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/compiler/run.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/demo/100dots.html +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/demo/demo_threejs.html +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/demo/micdemo.html +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/demo/mp3upload.html +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/docker-compose.yml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/entrypoint.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/install +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/install_linux.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/lint +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/pyproject.toml +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/requirements.docker.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/requirements.testing.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/setup.cfg +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/setup.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/__main__.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/app.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/assets/example.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/assets/localhost-key.pem +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/assets/localhost.pem +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/cli.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/cli_test.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/cli_test_interactive.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/compile_server.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/compile_server_impl.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/docker_manager.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/filewatcher.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/keyboard.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/keyz.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/live_client.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/paths.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/print_filter.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/project_init.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/select_sketch_directory.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/server_flask.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/server_start.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/settings.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/site/build.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/site/examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/sketch.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/spinner.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/string_diff.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/test/can_run_local_docker_tests.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/test/examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/types.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/util.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/version.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled/web_compile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled.egg-info/SOURCES.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled.egg-info/dependency_links.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled.egg-info/entry_points.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled.egg-info/requires.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/src/fastled.egg-info/top_level.txt +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/test +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/integration/test_build_examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/integration/test_examples.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/html/index.html +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_api.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_bad_ino.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_banner_string.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_cli.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_cli_no_platformio.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_compile_server.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_debug_fetch_source_files.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_docker_linux_on_windows.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_embedded_data.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_filechanger.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_flask_headers.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_http_server.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_ino/bad/bad.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_ino/embedded/wasm.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_ino/wasm/wasm.ino +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_manual_api_invocation.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_no_platformio_compile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_project_init.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_server_and_client_seperatly.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_session_compile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_string_diff.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_string_diff_comprehensive.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_version.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/tests/unit/test_webcompile.py +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/upload_package.sh +0 -0
- {fastled-1.3.39 → fastled-1.4.0}/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.0
|
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
|
|
@@ -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
|
|
@@ -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.0"
|
5
5
|
|
6
6
|
__version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
|
@@ -23,8 +23,6 @@ class Args:
|
|
23
23
|
quick: bool
|
24
24
|
release: bool
|
25
25
|
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
26
|
clear = False # Force the last running container to be removed. Useful for benchmarking.
|
29
27
|
|
30
28
|
@staticmethod
|
@@ -68,12 +66,6 @@ class Args:
|
|
68
66
|
assert isinstance(
|
69
67
|
args.release, bool
|
70
68
|
), 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
69
|
|
78
70
|
init: bool | str = False
|
79
71
|
if args.init is None:
|
@@ -101,6 +93,4 @@ class Args:
|
|
101
93
|
quick=args.quick,
|
102
94
|
release=args.release,
|
103
95
|
ram_disk_size=args.ram_disk_size,
|
104
|
-
playwright=args.playwright,
|
105
|
-
no_playwright_auto_resize=args.no_playwright_auto_resize,
|
106
96
|
)
|
@@ -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,6 @@ 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
|
-
use_playwright: bool = False,
|
262
|
-
playwright_auto_resize: bool = True,
|
263
271
|
) -> int:
|
264
272
|
has_checked_newer_version_yet = False
|
265
273
|
compile_server: CompileServer | None = None
|
@@ -340,8 +348,6 @@ def run_client(
|
|
340
348
|
port=http_port,
|
341
349
|
compile_server_port=port,
|
342
350
|
open_browser=open_web_browser,
|
343
|
-
use_playwright=use_playwright,
|
344
|
-
playwright_auto_resize=playwright_auto_resize,
|
345
351
|
)
|
346
352
|
else:
|
347
353
|
print("\nCompilation successful.")
|
@@ -564,8 +570,6 @@ def run_client_server(args: Args) -> int:
|
|
564
570
|
profile=profile,
|
565
571
|
clear=args.clear,
|
566
572
|
no_platformio=no_platformio,
|
567
|
-
use_playwright=args.playwright,
|
568
|
-
playwright_auto_resize=not args.no_playwright_auto_resize,
|
569
573
|
)
|
570
574
|
except KeyboardInterrupt:
|
571
575
|
return 1
|
@@ -101,8 +101,6 @@ def spawn_http_server(
|
|
101
101
|
compile_server_port: int,
|
102
102
|
port: int | None = None,
|
103
103
|
open_browser: bool = True,
|
104
|
-
use_playwright: bool = False,
|
105
|
-
playwright_auto_resize: bool = True,
|
106
104
|
) -> Process:
|
107
105
|
|
108
106
|
if port is not None and not is_port_free(port):
|
@@ -131,28 +129,13 @@ def spawn_http_server(
|
|
131
129
|
wait_for_server(port)
|
132
130
|
if open_browser:
|
133
131
|
url = f"http://localhost:{port}"
|
134
|
-
if
|
132
|
+
if PLAYWRIGHT_AVAILABLE and open_with_playwright is not None:
|
135
133
|
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
134
|
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,
|
135
|
+
"Auto-resize enabled: Browser window will automatically adjust to content size"
|
155
136
|
)
|
137
|
+
global _playwright_browser_proxy
|
138
|
+
_playwright_browser_proxy = open_with_playwright(url)
|
156
139
|
else:
|
157
140
|
print(f"Opening browser to {url}")
|
158
141
|
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,7 +113,7 @@ 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",
|
@@ -161,18 +158,6 @@ def parse_args() -> Args:
|
|
161
158
|
help="Remove all FastLED containers and images",
|
162
159
|
)
|
163
160
|
|
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
161
|
build_mode = parser.add_mutually_exclusive_group()
|
177
162
|
build_mode.add_argument("--debug", action="store_true", help="Build in debug mode")
|
178
163
|
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.0
|
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
|
|
@@ -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
|
File without changes
|