fastled 1.4.9__py3-none-any.whl → 1.4.10__py3-none-any.whl
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/__version__.py +1 -1
- fastled/interruptible_http.py +148 -0
- fastled/open_browser.py +4 -2
- fastled/{playwright_browser.py → playwright/playwright_browser.py} +2 -2
- fastled/web_compile.py +42 -45
- {fastled-1.4.9.dist-info → fastled-1.4.10.dist-info}/METADATA +1 -1
- {fastled-1.4.9.dist-info → fastled-1.4.10.dist-info}/RECORD +12 -11
- /fastled/{chrome_extension_downloader.py → playwright/chrome_extension_downloader.py} +0 -0
- {fastled-1.4.9.dist-info → fastled-1.4.10.dist-info}/WHEEL +0 -0
- {fastled-1.4.9.dist-info → fastled-1.4.10.dist-info}/entry_points.txt +0 -0
- {fastled-1.4.9.dist-info → fastled-1.4.10.dist-info}/licenses/LICENSE +0 -0
- {fastled-1.4.9.dist-info → fastled-1.4.10.dist-info}/top_level.txt +0 -0
fastled/__version__.py
CHANGED
@@ -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.
|
4
|
+
__version__ = "1.4.10"
|
5
5
|
|
6
6
|
__version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
|
@@ -0,0 +1,148 @@
|
|
1
|
+
"""
|
2
|
+
Interruptible HTTP requests that can be cancelled with Ctrl+C.
|
3
|
+
|
4
|
+
This module provides cross-platform HTTP request functionality that can be
|
5
|
+
interrupted with Ctrl+C by using asyncio cancellation and periodic checks.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
|
10
|
+
import httpx
|
11
|
+
|
12
|
+
|
13
|
+
class InterruptibleHTTPRequest:
|
14
|
+
"""A wrapper for making HTTP requests that can be interrupted by Ctrl+C."""
|
15
|
+
|
16
|
+
def __init__(self):
|
17
|
+
self.cancelled = False
|
18
|
+
|
19
|
+
async def _make_request_async(
|
20
|
+
self,
|
21
|
+
url: str,
|
22
|
+
files: dict,
|
23
|
+
headers: dict,
|
24
|
+
transport: httpx.HTTPTransport | None = None,
|
25
|
+
timeout: float = 240,
|
26
|
+
follow_redirects: bool = True,
|
27
|
+
) -> httpx.Response:
|
28
|
+
"""Make an async HTTP request."""
|
29
|
+
# Convert sync transport to async transport if provided
|
30
|
+
async_transport = None
|
31
|
+
if transport is not None:
|
32
|
+
# For IPv4 connections, create async transport with local address
|
33
|
+
async_transport = httpx.AsyncHTTPTransport(local_address="0.0.0.0")
|
34
|
+
|
35
|
+
async with httpx.AsyncClient(
|
36
|
+
transport=async_transport,
|
37
|
+
timeout=timeout,
|
38
|
+
) as client:
|
39
|
+
response = await client.post(
|
40
|
+
url,
|
41
|
+
follow_redirects=follow_redirects,
|
42
|
+
files=files,
|
43
|
+
headers=headers,
|
44
|
+
)
|
45
|
+
return response
|
46
|
+
|
47
|
+
def make_request_interruptible(
|
48
|
+
self,
|
49
|
+
url: str,
|
50
|
+
files: dict,
|
51
|
+
headers: dict,
|
52
|
+
transport: httpx.HTTPTransport | None = None,
|
53
|
+
timeout: float = 240,
|
54
|
+
follow_redirects: bool = True,
|
55
|
+
) -> httpx.Response:
|
56
|
+
"""Make an HTTP request that can be interrupted by Ctrl+C."""
|
57
|
+
try:
|
58
|
+
# Create a new event loop if we're not in one
|
59
|
+
try:
|
60
|
+
loop = asyncio.get_running_loop()
|
61
|
+
# We're already in an event loop, use run_in_executor
|
62
|
+
return asyncio.run_coroutine_threadsafe(
|
63
|
+
self._run_with_keyboard_check(
|
64
|
+
url, files, headers, transport, timeout, follow_redirects
|
65
|
+
),
|
66
|
+
loop,
|
67
|
+
).result()
|
68
|
+
except RuntimeError:
|
69
|
+
# No running loop, create one
|
70
|
+
return asyncio.run(
|
71
|
+
self._run_with_keyboard_check(
|
72
|
+
url, files, headers, transport, timeout, follow_redirects
|
73
|
+
)
|
74
|
+
)
|
75
|
+
except KeyboardInterrupt:
|
76
|
+
print("\nHTTP request cancelled by user")
|
77
|
+
raise
|
78
|
+
|
79
|
+
async def _run_with_keyboard_check(
|
80
|
+
self,
|
81
|
+
url: str,
|
82
|
+
files: dict,
|
83
|
+
headers: dict,
|
84
|
+
transport: httpx.HTTPTransport | None = None,
|
85
|
+
timeout: float = 240,
|
86
|
+
follow_redirects: bool = True,
|
87
|
+
) -> httpx.Response:
|
88
|
+
"""Run the request with periodic keyboard interrupt checks."""
|
89
|
+
task = asyncio.create_task(
|
90
|
+
self._make_request_async(
|
91
|
+
url, files, headers, transport, timeout, follow_redirects
|
92
|
+
)
|
93
|
+
)
|
94
|
+
|
95
|
+
# Poll for keyboard interrupt while waiting for the request
|
96
|
+
# This approach allows the task to be cancelled when KeyboardInterrupt
|
97
|
+
# is raised in the calling thread
|
98
|
+
while not task.done():
|
99
|
+
try:
|
100
|
+
# Wait for either completion or a short timeout
|
101
|
+
response = await asyncio.wait_for(asyncio.shield(task), timeout=0.1)
|
102
|
+
return response
|
103
|
+
except asyncio.TimeoutError:
|
104
|
+
# Continue waiting - the short timeout allows for more responsive
|
105
|
+
# cancellation when KeyboardInterrupt is raised
|
106
|
+
continue
|
107
|
+
except KeyboardInterrupt:
|
108
|
+
task.cancel()
|
109
|
+
print("\nHTTP request cancelled by user")
|
110
|
+
raise
|
111
|
+
|
112
|
+
return await task
|
113
|
+
|
114
|
+
|
115
|
+
def make_interruptible_post_request(
|
116
|
+
url: str,
|
117
|
+
files: dict | None = None,
|
118
|
+
headers: dict | None = None,
|
119
|
+
transport: httpx.HTTPTransport | None = None,
|
120
|
+
timeout: float = 240,
|
121
|
+
follow_redirects: bool = True,
|
122
|
+
) -> httpx.Response:
|
123
|
+
"""
|
124
|
+
Convenience function to make an interruptible POST request.
|
125
|
+
|
126
|
+
Args:
|
127
|
+
url: The URL to make the request to
|
128
|
+
files: Files to upload (optional)
|
129
|
+
headers: HTTP headers (optional)
|
130
|
+
transport: HTTP transport to use (optional)
|
131
|
+
timeout: Request timeout in seconds
|
132
|
+
follow_redirects: Whether to follow redirects
|
133
|
+
|
134
|
+
Returns:
|
135
|
+
The HTTP response
|
136
|
+
|
137
|
+
Raises:
|
138
|
+
KeyboardInterrupt: If the request was cancelled by Ctrl+C
|
139
|
+
"""
|
140
|
+
request_handler = InterruptibleHTTPRequest()
|
141
|
+
return request_handler.make_request_interruptible(
|
142
|
+
url=url,
|
143
|
+
files=files or {},
|
144
|
+
headers=headers or {},
|
145
|
+
transport=transport,
|
146
|
+
timeout=timeout,
|
147
|
+
follow_redirects=follow_redirects,
|
148
|
+
)
|
fastled/open_browser.py
CHANGED
@@ -6,7 +6,7 @@ import weakref
|
|
6
6
|
from multiprocessing import Process
|
7
7
|
from pathlib import Path
|
8
8
|
|
9
|
-
from fastled.playwright_browser import open_with_playwright
|
9
|
+
from fastled.playwright.playwright_browser import open_with_playwright
|
10
10
|
from fastled.server_flask import run_flask_in_thread
|
11
11
|
|
12
12
|
# Global reference to keep Playwright browser alive
|
@@ -128,7 +128,9 @@ def spawn_http_server(
|
|
128
128
|
if should_use_playwright:
|
129
129
|
if app:
|
130
130
|
# For --app mode, try to install browsers if needed
|
131
|
-
from fastled.playwright_browser import
|
131
|
+
from fastled.playwright.playwright_browser import (
|
132
|
+
install_playwright_browsers,
|
133
|
+
)
|
132
134
|
|
133
135
|
install_playwright_browsers()
|
134
136
|
|
@@ -77,7 +77,7 @@ class PlaywrightBrowser:
|
|
77
77
|
def _setup_extensions(self) -> None:
|
78
78
|
"""Setup Chrome extensions for enhanced debugging."""
|
79
79
|
try:
|
80
|
-
from fastled.chrome_extension_downloader import (
|
80
|
+
from fastled.playwright.chrome_extension_downloader import (
|
81
81
|
download_cpp_devtools_extension,
|
82
82
|
)
|
83
83
|
|
@@ -706,7 +706,7 @@ def install_playwright_browsers() -> bool:
|
|
706
706
|
|
707
707
|
# Also download the C++ DevTools Support extension
|
708
708
|
try:
|
709
|
-
from fastled.chrome_extension_downloader import (
|
709
|
+
from fastled.playwright.chrome_extension_downloader import (
|
710
710
|
download_cpp_devtools_extension,
|
711
711
|
)
|
712
712
|
|
fastled/web_compile.py
CHANGED
@@ -9,13 +9,14 @@ from pathlib import Path
|
|
9
9
|
import httpx
|
10
10
|
|
11
11
|
from fastled.find_good_connection import find_good_connection
|
12
|
+
from fastled.interruptible_http import make_interruptible_post_request
|
12
13
|
from fastled.settings import SERVER_PORT
|
13
14
|
from fastled.types import BuildMode, CompileResult
|
14
15
|
from fastled.zip_files import ZipResult, zip_files
|
15
16
|
|
16
17
|
DEFAULT_HOST = "https://fastled.onrender.com"
|
17
18
|
ENDPOINT_COMPILED_WASM = "compile/wasm"
|
18
|
-
_TIMEOUT = 60 * 4 #
|
19
|
+
_TIMEOUT = 60 * 4 # 4 mins timeout
|
19
20
|
_AUTH_TOKEN = "oBOT5jbsO4ztgrpNsQwlmFLIKB"
|
20
21
|
|
21
22
|
|
@@ -83,25 +84,26 @@ def _compile_libfastled(
|
|
83
84
|
httpx.HTTPTransport(local_address="0.0.0.0") if connection_result.ipv4 else None
|
84
85
|
)
|
85
86
|
|
86
|
-
|
87
|
+
headers = {
|
88
|
+
"accept": "application/json",
|
89
|
+
"authorization": auth_token,
|
90
|
+
"build": build_mode.value.lower(),
|
91
|
+
}
|
92
|
+
|
93
|
+
url = f"{connection_result.host}/compile/libfastled"
|
94
|
+
print(f"Compiling libfastled on {url} via {ipv4_stmt}")
|
95
|
+
|
96
|
+
# Use interruptible HTTP request
|
97
|
+
response = make_interruptible_post_request(
|
98
|
+
url=url,
|
99
|
+
files={}, # No files for libfastled compilation
|
100
|
+
headers=headers,
|
87
101
|
transport=transport,
|
88
102
|
timeout=_TIMEOUT * 2, # Give more time for library compilation
|
89
|
-
|
90
|
-
|
91
|
-
"accept": "application/json",
|
92
|
-
"authorization": auth_token,
|
93
|
-
"build": build_mode.value.lower(),
|
94
|
-
}
|
95
|
-
|
96
|
-
url = f"{connection_result.host}/compile/libfastled"
|
97
|
-
print(f"Compiling libfastled on {url} via {ipv4_stmt}")
|
98
|
-
response = client.post(
|
99
|
-
url,
|
100
|
-
headers=headers,
|
101
|
-
timeout=_TIMEOUT * 2,
|
102
|
-
)
|
103
|
+
follow_redirects=False,
|
104
|
+
)
|
103
105
|
|
104
|
-
|
106
|
+
return response
|
105
107
|
|
106
108
|
|
107
109
|
def _send_compile_request(
|
@@ -131,37 +133,32 @@ def _send_compile_request(
|
|
131
133
|
|
132
134
|
archive_size = len(zip_bytes)
|
133
135
|
|
134
|
-
|
136
|
+
headers = {
|
137
|
+
"accept": "application/json",
|
138
|
+
"authorization": auth_token,
|
139
|
+
"build": (
|
140
|
+
build_mode.value.lower() if build_mode else BuildMode.QUICK.value.lower()
|
141
|
+
),
|
142
|
+
"profile": "true" if profile else "false",
|
143
|
+
"no-platformio": "true" if no_platformio else "false",
|
144
|
+
"allow-libcompile": "false", # Always false since we handle it manually
|
145
|
+
}
|
146
|
+
|
147
|
+
url = f"{connection_result.host}/{ENDPOINT_COMPILED_WASM}"
|
148
|
+
print(f"Compiling sketch on {url} via {ipv4_stmt}. Zip size: {archive_size} bytes")
|
149
|
+
files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
|
150
|
+
|
151
|
+
# Use interruptible HTTP request
|
152
|
+
response = make_interruptible_post_request(
|
153
|
+
url=url,
|
154
|
+
files=files,
|
155
|
+
headers=headers,
|
135
156
|
transport=transport,
|
136
157
|
timeout=_TIMEOUT,
|
137
|
-
|
138
|
-
|
139
|
-
"accept": "application/json",
|
140
|
-
"authorization": auth_token,
|
141
|
-
"build": (
|
142
|
-
build_mode.value.lower()
|
143
|
-
if build_mode
|
144
|
-
else BuildMode.QUICK.value.lower()
|
145
|
-
),
|
146
|
-
"profile": "true" if profile else "false",
|
147
|
-
"no-platformio": "true" if no_platformio else "false",
|
148
|
-
"allow-libcompile": "false", # Always false since we handle it manually
|
149
|
-
}
|
150
|
-
|
151
|
-
url = f"{connection_result.host}/{ENDPOINT_COMPILED_WASM}"
|
152
|
-
print(
|
153
|
-
f"Compiling sketch on {url} via {ipv4_stmt}. Zip size: {archive_size} bytes"
|
154
|
-
)
|
155
|
-
files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
|
156
|
-
response = client.post(
|
157
|
-
url,
|
158
|
-
follow_redirects=True,
|
159
|
-
files=files,
|
160
|
-
headers=headers,
|
161
|
-
timeout=_TIMEOUT,
|
162
|
-
)
|
158
|
+
follow_redirects=True,
|
159
|
+
)
|
163
160
|
|
164
|
-
|
161
|
+
return response
|
165
162
|
|
166
163
|
|
167
164
|
def _process_compile_response(
|
@@ -1,9 +1,8 @@
|
|
1
1
|
fastled/__init__.py,sha256=dahiY41HLLotTjqmpVJmXSwUEp8NKqoZ57jt55hBLa4,7667
|
2
2
|
fastled/__main__.py,sha256=OcKv2ER1_iQAsZzLIUb3C8hRC9L2clNOhCrjpshrlf4,336
|
3
|
-
fastled/__version__.py,sha256=
|
3
|
+
fastled/__version__.py,sha256=79y56vY5gQySq33JTd8MFfXtNmylXNSfvohTya9mP_M,373
|
4
4
|
fastled/app.py,sha256=6XOuObi72AUnZXASDOVbcSflr4He0xnIDk5P8nVmVus,6131
|
5
5
|
fastled/args.py,sha256=d8Afa7NMcNLMIQqIBX_ZOL5JOyeJ7XCch4LdkhFNChk,3671
|
6
|
-
fastled/chrome_extension_downloader.py,sha256=48YyQrsuK1TVXPuAvRGzqkQJnx0991Ka6OVUo1A58zU,7079
|
7
6
|
fastled/cli.py,sha256=drgR2AOxVrj3QEz58iiKscYAumbbin2vIV-k91VCOAA,561
|
8
7
|
fastled/cli_test.py,sha256=W-1nODZrip_JU6BEbYhxOa4ckxduOsiX8zIoRkTyxv4,550
|
9
8
|
fastled/cli_test_interactive.py,sha256=BjNhveZOk5aCffHbcrxPQQjWmAuj4ClVKKcKX5eY6yM,542
|
@@ -13,13 +12,13 @@ fastled/compile_server_impl.py,sha256=iCwNCs7YxypUuVPmY4979mOgoH9OiuAJa1a1bmpG1c
|
|
13
12
|
fastled/docker_manager.py,sha256=rkq39ZKrU6NHIyDa3mzs0Unb6o9oMeAwxhqiuHJU_RY,40291
|
14
13
|
fastled/filewatcher.py,sha256=gEcJJHTDJ1X3gKJzltmEBhixWGbZj2eJD7a4vwSvITQ,10036
|
15
14
|
fastled/find_good_connection.py,sha256=xnrJjrbwNZUkvSQRn_ZTMoVh5GBWTbO-lEsr_L95xq8,3372
|
15
|
+
fastled/interruptible_http.py,sha256=2QwUsRNJ1qawf_-Lp1l0dBady3TK0SrBFhmnWgM7oqg,4888
|
16
16
|
fastled/keyboard.py,sha256=UTAsqCn1UMYnB8YDzENiLTj4GeL45tYfEcO7_5fLFEg,3556
|
17
17
|
fastled/keyz.py,sha256=LO-8m_7CpNDiZLM-FXhQ30f9gN1bUYz5lOsUPTIbI-c,4020
|
18
18
|
fastled/live_client.py,sha256=yp_ujG92EHYpSedGOUteuG2nQvMKbp1GbUpgQ6nU4Dc,3083
|
19
|
-
fastled/open_browser.py,sha256=
|
19
|
+
fastled/open_browser.py,sha256=N0d_D87sSBOUbBUl7gktJufdyM1laEKIERCXnEYCyu4,5086
|
20
20
|
fastled/parse_args.py,sha256=UiGgFoR_7ZCVC26rxE4FpxpmPu9xBhiiCD4pwmY_gLw,11520
|
21
21
|
fastled/paths.py,sha256=VsPmgu0lNSCFOoEC0BsTYzDygXqy15AHUfN-tTuzDZA,99
|
22
|
-
fastled/playwright_browser.py,sha256=qsPQiwamSOSBuXPoqgr1ybIRZbjJH5MeoMNLjpR4aTg,26776
|
23
22
|
fastled/print_filter.py,sha256=nc_rqYYdCUPinFycaK7fiQF5PG1up51pmJptR__QyAs,1499
|
24
23
|
fastled/project_init.py,sha256=bBt4DwmW5hZkm9ICt9Qk-0Nr_0JQM7icCgH5Iv-bCQs,3984
|
25
24
|
fastled/select_sketch_directory.py,sha256=-eudwCns3AKj4HuHtSkZAFwbnf005SNL07pOzs9VxnE,1383
|
@@ -32,18 +31,20 @@ fastled/string_diff.py,sha256=oTncu0qYdLlLUtYLLDB4bzdQ2OfzegAR6XNAzwE9fIs,6002
|
|
32
31
|
fastled/types.py,sha256=ZDf1TbTT4XgA_pKIwr4JbkDB38_29ogSdDORjoT-zuY,1803
|
33
32
|
fastled/util.py,sha256=TjhXbUNh4p2BGhNAldSeL68B7BBOjsWAXji5gy-vDEQ,1440
|
34
33
|
fastled/version.py,sha256=TpBMiEVdO3_sUZEu6wmwN8Q4AgX2BiCxStCsnPKh6E0,1209
|
35
|
-
fastled/web_compile.py,sha256=
|
34
|
+
fastled/web_compile.py,sha256=8wJ6EK01hHsQLfeon4_TQaEDQZjsHHPidPPIzjMYUuM,9960
|
36
35
|
fastled/zip_files.py,sha256=BgHFjaLJ7wF6mnzjqOgn76VcKDwhwc_-w_qyUG_-aNs,2815
|
37
36
|
fastled/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
|
38
37
|
fastled/assets/localhost-key.pem,sha256=Q-CNO_UoOd8fFNN4ljcnqwUeCMhzTplRjLO2x0pYRlU,1704
|
39
38
|
fastled/assets/localhost.pem,sha256=QTwUtTwjYWbm9m3pHW2IlK2nFZJ8b0pppxPjhgVZqQo,1619
|
39
|
+
fastled/playwright/chrome_extension_downloader.py,sha256=48YyQrsuK1TVXPuAvRGzqkQJnx0991Ka6OVUo1A58zU,7079
|
40
|
+
fastled/playwright/playwright_browser.py,sha256=5cx80kEV72CPlBT9fIcJNc9z40EFSOfXchBKBE9R4sE,26798
|
40
41
|
fastled/site/build.py,sha256=2YKU_UWKlJdGnjdbAbaL0co6kceFMSTVYwH1KCmgPZA,13987
|
41
42
|
fastled/site/examples.py,sha256=s6vj2zJc6BfKlnbwXr1QWY1mzuDBMt6j5MEBOWjO_U8,155
|
42
43
|
fastled/test/can_run_local_docker_tests.py,sha256=LEuUbHctRhNNFWcvnz2kEGmjDJeXO4c3kNpizm3yVJs,400
|
43
44
|
fastled/test/examples.py,sha256=GfaHeY1E8izBl6ZqDVjz--RHLyVR4NRnQ5pBesCFJFY,1673
|
44
|
-
fastled-1.4.
|
45
|
-
fastled-1.4.
|
46
|
-
fastled-1.4.
|
47
|
-
fastled-1.4.
|
48
|
-
fastled-1.4.
|
49
|
-
fastled-1.4.
|
45
|
+
fastled-1.4.10.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
|
46
|
+
fastled-1.4.10.dist-info/METADATA,sha256=ZUfEDRHSSsMmIZSZ4j3FCypY9lIZ4Yxuloo4HfU9QIc,31910
|
47
|
+
fastled-1.4.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
48
|
+
fastled-1.4.10.dist-info/entry_points.txt,sha256=RCwmzCSOS4-C2i9EziANq7Z2Zb4KFnEMR1FQC0bBwAw,101
|
49
|
+
fastled-1.4.10.dist-info/top_level.txt,sha256=Bbv5kpJpZhWNCvDF4K0VcvtBSDMa8B7PTOrZa9CezHY,8
|
50
|
+
fastled-1.4.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|