fastled 1.4.34__py3-none-any.whl → 1.4.36__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 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.34"
4
+ __version__ = "1.4.36"
5
5
 
6
6
  __version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
fastled/app.py CHANGED
@@ -12,6 +12,7 @@ from fastled.compile_server import CompileServer
12
12
  from fastled.emoji_util import EMO
13
13
  from fastled.filewatcher import file_watcher_set
14
14
  from fastled.parse_args import Args, parse_args
15
+ from fastled.settings import DEFAULT_URL
15
16
  from fastled.sketch import find_sketch_directories, looks_like_fastled_repo
16
17
 
17
18
 
@@ -53,6 +54,31 @@ def main() -> int:
53
54
 
54
55
  args = parse_args()
55
56
 
57
+ if args.emsdk_headers:
58
+ import httpx
59
+
60
+ out_path = args.emsdk_headers
61
+ base_url = args.web if isinstance(args.web, str) else DEFAULT_URL
62
+ try:
63
+ response = httpx.get(f"{base_url}/headers/emsdk")
64
+ if response.status_code == 200:
65
+ Path(out_path).parent.mkdir(parents=True, exist_ok=True)
66
+ with open(out_path, "wb") as f:
67
+ f.write(response.content)
68
+ print(f"{EMO('✅','SUCCESS:')} EMSDK headers exported to {out_path}")
69
+ return 0
70
+ else:
71
+ print(
72
+ f"{EMO('❌','ERROR:')} Failed to export EMSDK headers: HTTP {response.status_code}"
73
+ )
74
+ return 1
75
+ except KeyboardInterrupt:
76
+ print("\nExiting from main...")
77
+ return 1
78
+ except Exception as e:
79
+ print(f"{EMO('❌','ERROR:')} Exception: {e}")
80
+ return 1
81
+
56
82
  # Handle --install command early
57
83
  if args.install:
58
84
  from fastled.install.main import fastled_install
fastled/args.py CHANGED
@@ -29,6 +29,7 @@ class Args:
29
29
  install: bool = False # Install FastLED development environment
30
30
  dry_run: bool = False # Dry run mode for testing
31
31
  no_interactive: bool = False # Non-interactive mode
32
+ emsdk_headers: str | None = None # Path to export EMSDK headers ZIP
32
33
 
33
34
  @staticmethod
34
35
  def from_namespace(args: argparse.Namespace) -> "Args":
@@ -84,6 +85,9 @@ class Args:
84
85
  assert isinstance(
85
86
  args.no_interactive, bool
86
87
  ), f"expected bool, got {type(args.no_interactive)}"
88
+ assert isinstance(
89
+ args.emsdk_headers, str | None
90
+ ), f"expected str | None, got {type(args.emsdk_headers)}"
87
91
 
88
92
  init: bool | str = False
89
93
  if args.init is None:
@@ -115,5 +119,6 @@ class Args:
115
119
  ram_disk_size=args.ram_disk_size,
116
120
  install=args.install,
117
121
  dry_run=args.dry_run,
122
+ emsdk_headers=args.emsdk_headers,
118
123
  no_interactive=args.no_interactive,
119
124
  )
fastled/client_server.py CHANGED
@@ -276,28 +276,30 @@ def _try_make_compile_server(
276
276
 
277
277
 
278
278
  def _background_update_docker_image() -> None:
279
- """Perform docker image update in the background."""
279
+ """Perform docker image update in the background silently."""
280
280
  try:
281
- print("\n🔄 Starting background update of docker image...")
281
+ # Only attempt update if Docker is installed and running
282
+ if not DockerManager.is_docker_installed():
283
+ return
284
+
282
285
  docker_manager = DockerManager()
283
- updated = docker_manager.validate_or_download_image(
286
+ docker_running, _ = docker_manager.is_running()
287
+ if not docker_running:
288
+ return
289
+
290
+ # Silently update the docker image
291
+ docker_manager.validate_or_download_image(
284
292
  image_name=IMAGE_NAME, tag="latest", upgrade=True
285
293
  )
286
- if updated:
287
- print(
288
- f"{EMO('✅', 'SUCCESS:')} Background docker image update completed successfully."
289
- )
290
- else:
291
- print(f"{EMO('ℹ️', 'INFO:')} Docker image was already up to date.")
292
294
  except KeyboardInterrupt:
293
- print(
294
- f"{EMO('⚠️', 'WARNING:')} Background docker image update interrupted by user."
295
- )
296
295
  import _thread
297
296
 
298
297
  _thread.interrupt_main()
299
298
  except Exception as e:
300
- print(f"{EMO('⚠️', 'WARNING:')} Background docker image update failed: {e}")
299
+ # Log warning but don't disrupt user experience
300
+ import warnings
301
+
302
+ warnings.warn(f"Background docker image update failed: {e}")
301
303
 
302
304
 
303
305
  def _is_local_host(url: str) -> bool:
@@ -370,7 +372,7 @@ def run_client(
370
372
  # Auto-detect libcompile capability on first call
371
373
  from fastled.sketch import looks_like_fastled_repo
372
374
 
373
- allow_libcompile = looks_like_fastled_repo(Path(".").resolve())
375
+ allow_libcompile = is_local_host and looks_like_fastled_repo(Path(".").resolve())
374
376
 
375
377
  try:
376
378
 
@@ -416,11 +418,14 @@ def run_client(
416
418
  app=app,
417
419
  )
418
420
  else:
419
- print("\nCompilation successful.")
421
+ if result.success:
422
+ print("\nCompilation successful.")
423
+ else:
424
+ print("\nCompilation failed.")
420
425
  if compile_server:
421
426
  print("Shutting down compile server...")
422
427
  compile_server.stop()
423
- return 0
428
+ return 0 if result.success else 1
424
429
 
425
430
  if not keep_running or shutdown.is_set():
426
431
  if http_proc:
fastled/docker_manager.py CHANGED
@@ -509,9 +509,12 @@ class DockerManager:
509
509
  # Quick check for latest version
510
510
  with Spinner(f"Pulling newer version of {image_name}:{tag}..."):
511
511
  cmd_list = ["docker", "pull", f"{image_name}:{tag}"]
512
- cmd_str = subprocess.list2cmdline(cmd_list)
513
- print(f"Running command: {cmd_str}")
514
- subprocess.run(cmd_list, check=True)
512
+ subprocess.run(
513
+ cmd_list,
514
+ check=True,
515
+ stdout=subprocess.DEVNULL,
516
+ stderr=subprocess.DEVNULL,
517
+ )
515
518
  print(f"Updated to newer version of {image_name}:{tag}")
516
519
  local_image_hash = self.client.images.get(f"{image_name}:{tag}").id
517
520
  assert local_image_hash is not None
@@ -524,9 +527,12 @@ class DockerManager:
524
527
  with Spinner("Loading "):
525
528
  # We use docker cli here because it shows the download.
526
529
  cmd_list = ["docker", "pull", f"{image_name}:{tag}"]
527
- cmd_str = subprocess.list2cmdline(cmd_list)
528
- print(f"Running command: {cmd_str}")
529
- subprocess.run(cmd_list, check=True)
530
+ subprocess.run(
531
+ cmd_list,
532
+ check=True,
533
+ stdout=subprocess.DEVNULL,
534
+ stderr=subprocess.DEVNULL,
535
+ )
530
536
  try:
531
537
  local_image = self.client.images.get(f"{image_name}:{tag}")
532
538
  local_image_hash = local_image.id
fastled/emoji_util.py CHANGED
@@ -13,3 +13,15 @@ def EMO(emoji: str, fallback: str) -> str:
13
13
  return emoji
14
14
  except (UnicodeEncodeError, AttributeError):
15
15
  return fallback
16
+
17
+
18
+ def safe_print(text: str) -> None:
19
+ """Print text safely, handling Unicode/emoji encoding issues on Windows cmd.exe"""
20
+ try:
21
+ print(text)
22
+ except UnicodeEncodeError:
23
+ # Replace problematic characters with safe alternatives
24
+ safe_text = text.encode(
25
+ sys.stdout.encoding or "utf-8", errors="replace"
26
+ ).decode(sys.stdout.encoding or "utf-8")
27
+ print(safe_text)
@@ -130,20 +130,195 @@ def update_vscode_settings_for_fastled() -> None:
130
130
  return
131
131
  settings_json_path = Path.cwd() / ".vscode" / "settings.json"
132
132
 
133
- # FastLED repository-specific settings
133
+ # FastLED repository-specific settings - updated to match the official FastLED repo
134
134
  fastled_settings = {
135
+ # Terminal configuration
136
+ "terminal.integrated.defaultProfile.windows": "Git Bash",
137
+ "terminal.integrated.shellIntegration.enabled": False,
138
+ "terminal.integrated.profiles.windows": {
139
+ "Command Prompt": {"path": "C:\\Windows\\System32\\cmd.exe"},
140
+ "Git Bash": {
141
+ "path": "C:\\Program Files\\Git\\bin\\bash.exe",
142
+ "args": ["--cd=."],
143
+ },
144
+ },
145
+ # File settings
146
+ "files.eol": "\n", # Unix line endings
147
+ "files.autoDetectEol": False, # Prevent VS Code from auto-detecting and changing EOL
148
+ "files.insertFinalNewline": True, # Ensure files end with a newline
149
+ "files.trimFinalNewlines": True, # Remove extra newlines at the end
150
+ "editor.tabSize": 4,
151
+ "editor.insertSpaces": True,
152
+ "editor.detectIndentation": True,
153
+ "editor.formatOnSave": False, # Disabled to prevent conflicts
154
+ # Debugger defaults - ensure C++ debugger is used for C++ files
155
+ "debug.defaultDebuggerType": "cppdbg",
156
+ "debug.toolBarLocation": "docked",
157
+ "debug.console.fontSize": 14,
158
+ "debug.console.lineHeight": 19,
159
+ # Python configuration (using uv as per project rules)
160
+ "python.defaultInterpreterPath": "uv",
161
+ "python.debugger": "debugpy",
162
+ # File associations for debugger
163
+ "[cpp]": {
164
+ "editor.defaultFormatter": "llvm-vs-code-extensions.vscode-clangd",
165
+ "debug.defaultDebuggerType": "cppdbg",
166
+ },
167
+ "[c]": {
168
+ "editor.defaultFormatter": "ms-vscode.cpptools",
169
+ "debug.defaultDebuggerType": "cppdbg",
170
+ },
171
+ "[ino]": {
172
+ "editor.defaultFormatter": "ms-vscode.cpptools",
173
+ "debug.defaultDebuggerType": "cppdbg",
174
+ },
175
+ # clangd configuration - enhanced
135
176
  "clangd.arguments": [
136
- "--compile-commands-dir=${workspaceFolder}/compile_commands",
137
- "--header-insertion=never",
177
+ "--compile-commands-dir=${workspaceFolder}",
138
178
  "--clang-tidy",
179
+ "--header-insertion=never",
180
+ "--completion-style=detailed",
181
+ "--function-arg-placeholders=false",
139
182
  "--background-index",
183
+ "--pch-storage=memory",
184
+ ],
185
+ "clangd.fallbackFlags": [
186
+ "-std=c++17",
187
+ "-I${workspaceFolder}/src",
188
+ "-I${workspaceFolder}/tests",
189
+ "-Wno-global-constructors",
140
190
  ],
191
+ # Disable conflicting IntelliSense to let clangd handle C++ analysis
141
192
  "C_Cpp.intelliSenseEngine": "disabled",
142
- "files.associations": {"*.ino": "cpp", "*.h": "cpp", "*.cpp": "cpp"},
143
- "editor.formatOnSave": True,
144
- "editor.formatOnType": True,
145
- "editor.tabSize": 4,
146
- "editor.insertSpaces": True,
193
+ "C_Cpp.autocomplete": "disabled",
194
+ "C_Cpp.errorSquiggles": "disabled",
195
+ "C_Cpp.suggestSnippets": False,
196
+ "C_Cpp.intelliSenseEngineFallback": "disabled",
197
+ "C_Cpp.autocompleteAddParentheses": False,
198
+ "C_Cpp.formatting": "disabled",
199
+ "C_Cpp.vcpkg.enabled": False,
200
+ "C_Cpp.configurationWarnings": "disabled",
201
+ "C_Cpp.intelliSenseCachePath": "",
202
+ "C_Cpp.intelliSenseCacheSize": 0,
203
+ "C_Cpp.intelliSenseUpdateDelay": 0,
204
+ "C_Cpp.workspaceParsingPriority": "lowest",
205
+ "C_Cpp.disabled": True,
206
+ # File associations - comprehensive
207
+ "files.associations": {
208
+ "*.ino": "cpp",
209
+ "*.h": "cpp",
210
+ "*.hpp": "cpp",
211
+ "*.cpp": "cpp",
212
+ "*.c": "c",
213
+ "*.inc": "cpp",
214
+ "*.tcc": "cpp",
215
+ "*.embeddedhtml": "html",
216
+ # Core C++ standard library files
217
+ "compare": "cpp",
218
+ "type_traits": "cpp",
219
+ "cmath": "cpp",
220
+ "limits": "cpp",
221
+ "iostream": "cpp",
222
+ "random": "cpp",
223
+ "functional": "cpp",
224
+ "bit": "cpp",
225
+ "vector": "cpp",
226
+ "array": "cpp",
227
+ "string": "cpp",
228
+ "memory": "cpp",
229
+ "algorithm": "cpp",
230
+ "iterator": "cpp",
231
+ "utility": "cpp",
232
+ "optional": "cpp",
233
+ "variant": "cpp",
234
+ "numeric": "cpp",
235
+ "chrono": "cpp",
236
+ "thread": "cpp",
237
+ "mutex": "cpp",
238
+ "atomic": "cpp",
239
+ "future": "cpp",
240
+ "condition_variable": "cpp",
241
+ },
242
+ # Disable Java language support and popups
243
+ "java.enabled": False,
244
+ "java.jdt.ls.enabled": False,
245
+ "java.compile.nullAnalysis.mode": "disabled",
246
+ "java.configuration.checkProjectSettingsExclusions": False,
247
+ "java.import.gradle.enabled": False,
248
+ "java.import.maven.enabled": False,
249
+ "java.autobuild.enabled": False,
250
+ "java.maxConcurrentBuilds": 0,
251
+ "java.recommendations.enabled": False,
252
+ "java.help.showReleaseNotes": False,
253
+ "redhat.telemetry.enabled": False,
254
+ # Java exclusions
255
+ "java.project.sourcePaths": [],
256
+ "java.project.referencedLibraries": [],
257
+ "files.exclude": {
258
+ "**/.classpath": True,
259
+ "**/.project": True,
260
+ "**/.factorypath": True,
261
+ },
262
+ # Disable PlatformIO auto-detection for .ino files in FastLED project
263
+ "platformio.disableToolchainAutoInstaller": True,
264
+ "platformio-ide.autoRebuildAutocompleteIndex": False,
265
+ "platformio-ide.activateProjectOnTextEditorChange": False,
266
+ "platformio-ide.autoOpenPlatformIOIniFile": False,
267
+ "platformio-ide.autoPreloadEnvTasks": False,
268
+ "platformio-ide.autoCloseSerialMonitor": False,
269
+ "platformio-ide.disablePIOHomeStartup": True,
270
+ # Disable conflicting extensions
271
+ "extensions.ignoreRecommendations": True,
272
+ # Semantic token color customizations for better C++ development
273
+ "editor.semanticTokenColorCustomizations": {
274
+ "rules": {
275
+ # Types (classes, structs, enums) - Teal/Cyan
276
+ "class": "#4EC9B0",
277
+ "struct": "#4EC9B0",
278
+ "type": "#4EC9B0",
279
+ "enum": "#4EC9B0",
280
+ "enumMember": "#B5CEA8",
281
+ "typedef": "#4EC9B0",
282
+ # Variables - Almost pure white for maximum readability
283
+ "variable": "#FAFAFA",
284
+ "variable.local": "#FAFAFA",
285
+ # Parameters - Orange for clear distinction
286
+ "parameter": "#FF8C42",
287
+ "variable.parameter": "#FF8C42",
288
+ # Properties - Light purple/pink
289
+ "property": "#D197D9",
290
+ # Functions and methods - Yellow
291
+ "function": "#DCDCAA",
292
+ "method": "#DCDCAA",
293
+ "function.declaration": "#DCDCAA",
294
+ "method.declaration": "#DCDCAA",
295
+ # Namespaces - Soft blue
296
+ "namespace": "#86C5F7",
297
+ # Constants and readonly - Light green with italic
298
+ "variable.readonly": {"foreground": "#B5CEA8", "fontStyle": "italic"},
299
+ "variable.defaultLibrary": "#B5CEA8",
300
+ # Macros and defines - Muted red/salmon
301
+ "macro": "#E06C75",
302
+ # String literals - Peach/salmon
303
+ "string": "#CE9178",
304
+ # Numbers - Light green
305
+ "number": "#B5CEA8",
306
+ # Keywords - Pink/magenta
307
+ "keyword": "#C586C0",
308
+ # Storage specifiers - Bright magenta/pink
309
+ "keyword.storage": "#FF79C6",
310
+ "storageClass": "#FF79C6",
311
+ # Built-in types - Different from user-defined types
312
+ "type.builtin": "#569CD6",
313
+ "keyword.type": "#569CD6",
314
+ # Comments - Green
315
+ "comment": "#6A9955",
316
+ "comment.documentation": "#6A9955",
317
+ }
318
+ },
319
+ # Inlay hints - Brighter gray for better visibility
320
+ "editor.inlayHints.fontColor": "#808080",
321
+ "editor.inlayHints.background": "#3C3C3C20",
147
322
  }
148
323
 
149
324
  if settings_json_path.exists():
@@ -164,4 +339,6 @@ def update_vscode_settings_for_fastled() -> None:
164
339
  with open(settings_json_path, "w") as f:
165
340
  json.dump(data, f, indent=4)
166
341
 
167
- print(f"✅ Updated {settings_json_path} with FastLED development settings")
342
+ print(
343
+ f"✅ Updated {settings_json_path} with comprehensive FastLED development settings"
344
+ )
fastled/parse_args.py CHANGED
@@ -187,6 +187,12 @@ def parse_args() -> Args:
187
187
  action="store_true",
188
188
  help="Run in non-interactive mode (fail instead of prompting for input)",
189
189
  )
190
+ parser.add_argument(
191
+ "--emsdk-headers",
192
+ type=str,
193
+ default=None,
194
+ help="Export EMSDK headers ZIP to specified path",
195
+ )
190
196
 
191
197
  build_mode = parser.add_mutually_exclusive_group()
192
198
  build_mode.add_argument("--debug", action="store_true", help="Build in debug mode")
@@ -207,8 +213,10 @@ def parse_args() -> Args:
207
213
  if args.debug and not args.app:
208
214
  playwright_dir = Path.home() / ".fastled" / "playwright"
209
215
  if playwright_dir.exists() and any(playwright_dir.iterdir()):
216
+ from fastled.emoji_util import EMO
217
+
210
218
  print(
211
- "🎭 Detected Playwright cache - automatically enabling app mode for debug"
219
+ f"{EMO('⚠️', 'WARNING:')} Debug mode detected with Playwright installed - automatically enabling app mode"
212
220
  )
213
221
  args.app = True
214
222
  elif not args.no_interactive:
@@ -1,10 +1,12 @@
1
1
  from pathlib import Path
2
2
 
3
+ from rapidfuzz import fuzz
4
+
3
5
  from fastled.string_diff import string_diff_paths
4
6
 
5
7
 
6
8
  def select_sketch_directory(
7
- sketch_directories: list[Path], cwd_is_fastled: bool
9
+ sketch_directories: list[Path], cwd_is_fastled: bool, is_followup: bool = False
8
10
  ) -> str | None:
9
11
  if cwd_is_fastled:
10
12
  exclude = ["src", "dev", "tests"]
@@ -28,10 +30,38 @@ def select_sketch_directory(
28
30
  return str(sketch_directories[index])
29
31
  except (ValueError, IndexError):
30
32
  inputs = [p for p in sketch_directories]
31
- top_hits: list[tuple[float, Path]] = string_diff_paths(which, inputs)
32
- if len(top_hits) == 1:
33
- example = top_hits[0][1]
34
- return str(example)
33
+
34
+ if is_followup:
35
+ # On follow-up, find the closest match by fuzzy distance
36
+ distances = []
37
+ for path in inputs:
38
+ path_str = str(path).replace("\\", "/")
39
+ dist = fuzz.token_sort_ratio(which.lower(), path_str.lower())
40
+ distances.append((dist, path))
41
+
42
+ # Get the best distance and return the closest match(es)
43
+ best_distance = max(distances, key=lambda x: x[0])[0]
44
+ best_matches = [
45
+ path for dist, path in distances if dist == best_distance
46
+ ]
47
+
48
+ if len(best_matches) == 1:
49
+ example = best_matches[0]
50
+ return str(example)
51
+ else:
52
+ # If still multiple matches with same distance, recurse again
53
+ return select_sketch_directory(
54
+ best_matches, cwd_is_fastled, is_followup=True
55
+ )
35
56
  else:
36
- return select_sketch_directory([p for _, p in top_hits], cwd_is_fastled)
57
+ # First call - use original fuzzy matching (allows ambiguity)
58
+ top_hits: list[tuple[float, Path]] = string_diff_paths(which, inputs)
59
+ if len(top_hits) == 1:
60
+ example = top_hits[0][1]
61
+ return str(example)
62
+ else:
63
+ # Recursive call with is_followup=True for more precise matching
64
+ return select_sketch_directory(
65
+ [p for _, p in top_hits], cwd_is_fastled, is_followup=True
66
+ )
37
67
  return None
fastled/test/examples.py CHANGED
@@ -2,6 +2,8 @@ from tempfile import TemporaryDirectory
2
2
  from time import time
3
3
  from warnings import warn
4
4
 
5
+ from fastled.emoji_util import safe_print
6
+
5
7
  _FILTER = True
6
8
 
7
9
 
@@ -18,21 +20,21 @@ def test_examples(
18
20
  examples.remove("LuminescentGrand")
19
21
  with TemporaryDirectory() as tmpdir:
20
22
  for example in examples:
21
- print(f"Initializing example: {example}")
23
+ safe_print(f"Initializing example: {example}")
22
24
  try:
23
25
  sketch_dir = Api.project_init(example, outputdir=tmpdir, host=host)
24
26
  except Exception as e:
25
27
  warn(f"Failed to initialize example: {example}, error: {e}")
26
28
  out[example] = e
27
29
  continue
28
- print(f"Project initialized at: {sketch_dir}")
30
+ safe_print(f"Project initialized at: {sketch_dir}")
29
31
  start = time()
30
- print(f"Compiling example: {example}")
32
+ safe_print(f"Compiling example: {example}")
31
33
  diff = time() - start
32
- print(f"Compilation took: {diff:.2f} seconds")
34
+ safe_print(f"Compilation took: {diff:.2f} seconds")
33
35
  result = Api.web_compile(sketch_dir, host=host)
34
36
  if not result.success:
35
- print(f"Compilation failed for {example}: {result.stdout}")
37
+ safe_print(f"Compilation failed for {example}: {result.stdout}")
36
38
  out[example] = Exception(result.stdout)
37
39
  return out
38
40
 
fastled/web_compile.py CHANGED
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
 
9
9
  import httpx
10
10
 
11
+ from fastled.emoji_util import EMO, safe_print
11
12
  from fastled.find_good_connection import find_good_connection
12
13
  from fastled.interruptible_http import make_interruptible_post_request
13
14
  from fastled.settings import AUTH_TOKEN, SERVER_PORT
@@ -89,7 +90,7 @@ def _banner(msg: str) -> str:
89
90
 
90
91
 
91
92
  def _print_banner(msg: str) -> None:
92
- print(_banner(msg))
93
+ safe_print(_banner(msg))
93
94
 
94
95
 
95
96
  def _compile_libfastled(
@@ -144,7 +145,6 @@ def _send_compile_request(
144
145
  build_mode: BuildMode,
145
146
  profile: bool,
146
147
  no_platformio: bool,
147
- allow_libcompile: bool,
148
148
  ) -> httpx.Response:
149
149
  """Send the compile request to the server and return the response."""
150
150
  host = _sanitize_host(host)
@@ -293,6 +293,11 @@ def _process_compile_response(
293
293
  )
294
294
 
295
295
 
296
+ def _libcompiled_is_allowed(host: str) -> bool:
297
+ """Check if libcompiled is allowed for the given host."""
298
+ return "localhost" in host or "127.0.0.1" in host or "0.0.0.0" in host
299
+
300
+
296
301
  def web_compile(
297
302
  directory: Path | str,
298
303
  host: str | None = None,
@@ -312,6 +317,12 @@ def web_compile(
312
317
  if not directory.exists():
313
318
  raise FileNotFoundError(f"Directory not found: {directory}")
314
319
 
320
+ if allow_libcompile and not _libcompiled_is_allowed(host):
321
+ print(
322
+ f"{EMO('🚫', '[ERROR]')} libcompile is not allowed for host {host}, disabling."
323
+ )
324
+ allow_libcompile = False
325
+
315
326
  # Time the zip creation
316
327
  zip_start_time = time.time()
317
328
  zip_result: ZipResult | Exception = zip_files(directory, build_mode=build_mode)
@@ -419,7 +430,6 @@ def web_compile(
419
430
  build_mode,
420
431
  profile,
421
432
  no_platformio,
422
- False, # allow_libcompile is always False since we handle it manually
423
433
  )
424
434
  sketch_time = time.time() - sketch_start_time
425
435
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastled
3
- Version: 1.4.34
3
+ Version: 1.4.36
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -23,6 +23,7 @@ Requires-Dist: flask-cors>=4.0.0
23
23
  Requires-Dist: livereload
24
24
  Requires-Dist: disklru>=2.0.4
25
25
  Requires-Dist: playwright>=1.40.0
26
+ Requires-Dist: websockify>=0.13.0
26
27
  Dynamic: home-page
27
28
  Dynamic: license-file
28
29
  Dynamic: maintainer
@@ -1,16 +1,16 @@
1
1
  fastled/__init__.py,sha256=LlLu9fO3O4FeB5-wt2wHGIFJW76H9FlhdABytEqg8A4,7717
2
2
  fastled/__main__.py,sha256=OcKv2ER1_iQAsZzLIUb3C8hRC9L2clNOhCrjpshrlf4,336
3
- fastled/__version__.py,sha256=JS27XS6R4UvWw9SBgOKxvu_FFX7El2hKH1MP1Y8nc_E,373
4
- fastled/app.py,sha256=7LmwXW1j6fePakOENVB4P52NIlUFCcyw-leRhN7by3A,6539
5
- fastled/args.py,sha256=LtYgskJjy1k47nrTBJ-5rXrNelO4TbexT92o3sR0dlk,4531
3
+ fastled/__version__.py,sha256=X18yBR3A2-maAsqadc1UyBbvqCZB-ZSj09nuElN84MY,373
4
+ fastled/app.py,sha256=fWOH2SA4rxW8BPNgBrKs4xsWvUEMX6RzMWPKyyjBoVM,7539
5
+ fastled/args.py,sha256=Xa7AYnoMcsuSVQUyM6M2P_8liQtQFJzuuBdPbfw9U-g,4786
6
6
  fastled/cli.py,sha256=drgR2AOxVrj3QEz58iiKscYAumbbin2vIV-k91VCOAA,561
7
7
  fastled/cli_test.py,sha256=W-1nODZrip_JU6BEbYhxOa4ckxduOsiX8zIoRkTyxv4,550
8
8
  fastled/cli_test_interactive.py,sha256=BjNhveZOk5aCffHbcrxPQQjWmAuj4ClVKKcKX5eY6yM,542
9
- fastled/client_server.py,sha256=h4ocBUffYtZSZTJpGqE96L4bcEwr3OrYzzbqvsivKnQ,24683
9
+ fastled/client_server.py,sha256=RnxVnQSFZ4B6xqDHkde6uu9bB6xpPsH5k39m77yrCZc,24730
10
10
  fastled/compile_server.py,sha256=iGUjteXKp5Dlp7mxAE4eD4s0NWgApRIp4ZjtcAN2iZY,3124
11
11
  fastled/compile_server_impl.py,sha256=jBvLH6Di3y_dKsmStw0JSl30u0esHXtVno-r9-Vr1HA,12624
12
- fastled/docker_manager.py,sha256=c0-DBA4_YtCl2XgtohL6uKtW0TK6vkHO0o2vympZShg,41089
13
- fastled/emoji_util.py,sha256=grWwm-UgquR8lvJpSnEfJ2D1hEdByRT4U_GdedI5BzI,433
12
+ fastled/docker_manager.py,sha256=_C-H3_gvT43TTT9yraCXBJmwweBmSe3o_YZOTI_7sfc,41205
13
+ fastled/emoji_util.py,sha256=z3lROwgfCxpqIIJFzQxehH8gcTwGdf4VLPsUgcbcFBM,849
14
14
  fastled/filewatcher.py,sha256=1EFeOLPEA_aN_V_tzgixS3mDhfleh0arTGUy0vWq6Is,10101
15
15
  fastled/find_good_connection.py,sha256=xnrJjrbwNZUkvSQRn_ZTMoVh5GBWTbO-lEsr_L95xq8,3372
16
16
  fastled/interruptible_http.py,sha256=2QwUsRNJ1qawf_-Lp1l0dBady3TK0SrBFhmnWgM7oqg,4888
@@ -18,11 +18,11 @@ fastled/keyboard.py,sha256=UTAsqCn1UMYnB8YDzENiLTj4GeL45tYfEcO7_5fLFEg,3556
18
18
  fastled/keyz.py,sha256=LO-8m_7CpNDiZLM-FXhQ30f9gN1bUYz5lOsUPTIbI-c,4020
19
19
  fastled/live_client.py,sha256=GPQf6Vj8mneEs4kc_nrfPlw-OmMMuDiIe2iWrP7FeeQ,3143
20
20
  fastled/open_browser.py,sha256=YgfSd6GRCXzOyMsJ5jV1Zx6dKY7622hZrqs_RWx9H1k,5146
21
- fastled/parse_args.py,sha256=y7wZOewxx5x0m6366yuaJn1H0fTqWgS8kt7DNIyFvV0,13561
21
+ fastled/parse_args.py,sha256=QYZLjqGu6j7xtPYwohDN-WpaNwIuhsKXBnGc1V3XUxI,13800
22
22
  fastled/paths.py,sha256=VsPmgu0lNSCFOoEC0BsTYzDygXqy15AHUfN-tTuzDZA,99
23
23
  fastled/print_filter.py,sha256=nc_rqYYdCUPinFycaK7fiQF5PG1up51pmJptR__QyAs,1499
24
24
  fastled/project_init.py,sha256=bBt4DwmW5hZkm9ICt9Qk-0Nr_0JQM7icCgH5Iv-bCQs,3984
25
- fastled/select_sketch_directory.py,sha256=-eudwCns3AKj4HuHtSkZAFwbnf005SNL07pOzs9VxnE,1383
25
+ fastled/select_sketch_directory.py,sha256=K7erbgU7pRppGNKyOoOUhNXaWp2qAzyl_EOb7Ai1Yxo,2721
26
26
  fastled/server_flask.py,sha256=HA0Pqkrr7OZn5TgMjykskXYrB-ACFd9sw7ND1L4RW-Y,17132
27
27
  fastled/server_start.py,sha256=W9yKStkRlRNuXeV6j_6O7HjjFPyVLBHMcF9Uy2QjDWQ,479
28
28
  fastled/settings.py,sha256=8RLN3S0ZK4DMphr0gKPfwPKfwIzOtHiQsqMTpGnX7Xg,1842
@@ -32,7 +32,7 @@ fastled/string_diff.py,sha256=oTncu0qYdLlLUtYLLDB4bzdQ2OfzegAR6XNAzwE9fIs,6002
32
32
  fastled/types.py,sha256=tBikcoKjbBcCTi36MMCz_TjMEBoa-FppRL-yKAVwXFc,1909
33
33
  fastled/util.py,sha256=TjhXbUNh4p2BGhNAldSeL68B7BBOjsWAXji5gy-vDEQ,1440
34
34
  fastled/version.py,sha256=TpBMiEVdO3_sUZEu6wmwN8Q4AgX2BiCxStCsnPKh6E0,1209
35
- fastled/web_compile.py,sha256=th_uswHLNsoSMKZS4PjowR7lc1moDkPpe63lhMC3YM4,16479
35
+ fastled/web_compile.py,sha256=VDUTsc6EKc_Ty2KkVddTR6ENaj3renZs66Q1rV_jGsc,16823
36
36
  fastled/zip_files.py,sha256=BgHFjaLJ7wF6mnzjqOgn76VcKDwhwc_-w_qyUG_-aNs,2815
37
37
  fastled/assets/example.txt,sha256=lTBovRjiz0_TgtAtbA1C5hNi2ffbqnNPqkKg6UiKCT8,54
38
38
  fastled/assets/localhost-key.pem,sha256=Q-CNO_UoOd8fFNN4ljcnqwUeCMhzTplRjLO2x0pYRlU,1704
@@ -43,17 +43,17 @@ fastled/install/extension_manager.py,sha256=uaK5wLrfz3Vsrmr9gm7aEumaQtE2vFKV6RvD
43
43
  fastled/install/main.py,sha256=7a4L082wVB3lT6DEc-YILQwFMGyw4mWqRPViFYmG6DI,5212
44
44
  fastled/install/project_detection.py,sha256=hv9wgBAvSEJ0X8ghrcbP1gRc1AWP72XMHxGQac6Jl5k,4877
45
45
  fastled/install/test_install.py,sha256=_wDPkhk6jCNLTxS1IIRS3CyDFKFm3RAQLGaG2las-Zg,13502
46
- fastled/install/vscode_config.py,sha256=9gRQ6QrtIQ6NNJ9rR6-aSlI-bgByqnqeE-CGoK5w8GE,5273
46
+ fastled/install/vscode_config.py,sha256=8z3w0sXqUpuOT0PxTukqRCsTFzTr6WQ8-mPv50XTPHI,12693
47
47
  fastled/playwright/chrome_extension_downloader.py,sha256=48YyQrsuK1TVXPuAvRGzqkQJnx0991Ka6OVUo1A58zU,7079
48
48
  fastled/playwright/playwright_browser.py,sha256=F58BVDJGlFqxOjakT0wGI3hKwxjwrrM1BlUDd1uT-u8,29449
49
49
  fastled/playwright/resize_tracking.py,sha256=frJOFKTcGOn--lQH_adXhcPc7BNek2hPYVLAAk8QI1o,4500
50
50
  fastled/site/build.py,sha256=2YKU_UWKlJdGnjdbAbaL0co6kceFMSTVYwH1KCmgPZA,13987
51
51
  fastled/site/examples.py,sha256=s6vj2zJc6BfKlnbwXr1QWY1mzuDBMt6j5MEBOWjO_U8,155
52
52
  fastled/test/can_run_local_docker_tests.py,sha256=LEuUbHctRhNNFWcvnz2kEGmjDJeXO4c3kNpizm3yVJs,400
53
- fastled/test/examples.py,sha256=GfaHeY1E8izBl6ZqDVjz--RHLyVR4NRnQ5pBesCFJFY,1673
54
- fastled-1.4.34.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
55
- fastled-1.4.34.dist-info/METADATA,sha256=twGbF7An9oQ0-pgSCrZeJJzzQEpncTU4tLjGXYzbQC8,31910
56
- fastled-1.4.34.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
- fastled-1.4.34.dist-info/entry_points.txt,sha256=RCwmzCSOS4-C2i9EziANq7Z2Zb4KFnEMR1FQC0bBwAw,101
58
- fastled-1.4.34.dist-info/top_level.txt,sha256=Bbv5kpJpZhWNCvDF4K0VcvtBSDMa8B7PTOrZa9CezHY,8
59
- fastled-1.4.34.dist-info/RECORD,,
53
+ fastled/test/examples.py,sha256=M0o-5NIhCuwcUHo7CPQw5llLd3OU3FfPgussVScd8Fs,1741
54
+ fastled-1.4.36.dist-info/licenses/LICENSE,sha256=b6pOoifSXiUaz_lDS84vWlG3fr4yUKwB8fzkrH9R8bQ,1064
55
+ fastled-1.4.36.dist-info/METADATA,sha256=nhygXwjdC3xbHrks0x5lXSlyxzvndtqx46LL5E4kz6A,31944
56
+ fastled-1.4.36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
57
+ fastled-1.4.36.dist-info/entry_points.txt,sha256=RCwmzCSOS4-C2i9EziANq7Z2Zb4KFnEMR1FQC0bBwAw,101
58
+ fastled-1.4.36.dist-info/top_level.txt,sha256=Bbv5kpJpZhWNCvDF4K0VcvtBSDMa8B7PTOrZa9CezHY,8
59
+ fastled-1.4.36.dist-info/RECORD,,