fastled 1.4.37__py3-none-any.whl → 1.4.38__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.37"
4
+ __version__ = "1.4.38"
5
5
 
6
6
  __version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
fastled/compile_server.py CHANGED
@@ -101,3 +101,9 @@ class CompileServer:
101
101
 
102
102
  def process_running(self) -> bool:
103
103
  return self.impl.process_running()
104
+
105
+ def get_emsdk_headers(self, filepath: Path) -> None:
106
+ """Get EMSDK headers ZIP data from the server and save to filepath."""
107
+ if not str(filepath).endswith(".zip"):
108
+ raise ValueError("Filepath must end with .zip")
109
+ return self.impl.get_emsdk_headers(filepath)
@@ -338,3 +338,14 @@ class CompileServerImpl:
338
338
  self.docker.suspend_container(self.container_name)
339
339
  self._port = 0
340
340
  print("Compile server stopped")
341
+
342
+ def get_emsdk_headers(self, filepath: Path) -> None:
343
+ """Get EMSDK headers ZIP data from the server and save to filepath."""
344
+ from fastled.util import download_emsdk_headers
345
+
346
+ if not self._port:
347
+ raise RuntimeError("Server has not been started yet")
348
+ if not self.ping():
349
+ raise RuntimeError("Server is not running")
350
+
351
+ download_emsdk_headers(self.url(), filepath)
fastled/header_dump.py ADDED
@@ -0,0 +1,63 @@
1
+ """Header dump functionality for EMSDK headers export."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+
6
+
7
+ def dump_emsdk_headers(output_path: Path | str, server_url: str | None = None) -> None:
8
+ """
9
+ Dump EMSDK headers to a specified path.
10
+
11
+ Args:
12
+ output_path: Path where to save the headers ZIP file
13
+ server_url: URL of the server. If None, tries to create local server first,
14
+ then falls back to remote server if local fails.
15
+ """
16
+ from fastled import Api
17
+ from fastled.settings import DEFAULT_URL
18
+ from fastled.util import download_emsdk_headers
19
+
20
+ # Convert to Path if string
21
+ if isinstance(output_path, str):
22
+ output_path = Path(output_path)
23
+
24
+ ends_with_zip = output_path.suffix == ".zip"
25
+ if not ends_with_zip:
26
+ raise ValueError(f"{output_path} must end with .zip")
27
+
28
+ try:
29
+ if server_url is not None:
30
+ # Use the provided server URL
31
+ download_emsdk_headers(server_url, output_path)
32
+ print(f"SUCCESS: EMSDK headers exported to {output_path}")
33
+ else:
34
+ # Try to create local server first
35
+ try:
36
+ with Api.server() as server:
37
+ base_url = server.url()
38
+ download_emsdk_headers(base_url, output_path)
39
+ print(
40
+ f"SUCCESS: EMSDK headers exported to {output_path} (using local server)"
41
+ )
42
+ except Exception as local_error:
43
+ print(
44
+ f"WARNING: Local server failed ({local_error}), falling back to remote server"
45
+ )
46
+ # Fall back to remote server
47
+ download_emsdk_headers(DEFAULT_URL, output_path)
48
+ print(
49
+ f"SUCCESS: EMSDK headers exported to {output_path} (using remote server)"
50
+ )
51
+
52
+ except Exception as e:
53
+ print(f"ERROR: Exception during header dump: {e}")
54
+ sys.exit(1)
55
+
56
+
57
+ if __name__ == "__main__":
58
+ if len(sys.argv) != 2:
59
+ print("Usage: python -m fastled.header_dump <output_path>")
60
+ sys.exit(1)
61
+
62
+ output_path = sys.argv[1]
63
+ dump_emsdk_headers(output_path)
fastled/live_client.py CHANGED
@@ -99,3 +99,15 @@ class LiveClient:
99
99
 
100
100
  def __exit__(self, exc_type, exc_value, traceback) -> None:
101
101
  self.finalize()
102
+
103
+ def get_emsdk_headers(self, filepath: Path) -> None:
104
+ """Get EMSDK headers ZIP data from the server and save to filepath."""
105
+ if isinstance(self.host, CompileServer):
106
+ self.host.get_emsdk_headers(filepath)
107
+ else:
108
+ # Handle string host or None case by using web_compile approach
109
+ from fastled.settings import DEFAULT_URL
110
+ from fastled.util import download_emsdk_headers
111
+
112
+ base_url = self.host if isinstance(self.host, str) else DEFAULT_URL
113
+ download_emsdk_headers(base_url, filepath)
fastled/parse_args.py CHANGED
@@ -212,32 +212,11 @@ def parse_args() -> Args:
212
212
 
213
213
  # Handle --emsdk-headers early before other processing
214
214
  if args.emsdk_headers:
215
- import httpx
215
+ from fastled.header_dump import dump_emsdk_headers
216
216
 
217
217
  out_path = args.emsdk_headers
218
- base_url = args.web if isinstance(args.web, str) else DEFAULT_URL
219
- try:
220
- timeout = httpx.Timeout(
221
- 30.0, read=30.0
222
- ) # 30 second timeout for read operations
223
- with httpx.stream(
224
- "GET", f"{base_url}/headers/emsdk", timeout=timeout
225
- ) as response:
226
- if response.status_code == 200:
227
- Path(out_path).parent.mkdir(parents=True, exist_ok=True)
228
- with open(out_path, "wb") as f:
229
- for chunk in response.iter_bytes(chunk_size=512000):
230
- f.write(chunk)
231
- print(f"SUCCESS: EMSDK headers exported to {out_path}")
232
- sys.exit(0)
233
- else:
234
- print(
235
- f"ERROR: Failed to export EMSDK headers: HTTP {response.status_code}"
236
- )
237
- sys.exit(1)
238
- except Exception as e:
239
- print(f"ERROR: Exception: {e}")
240
- sys.exit(1)
218
+ dump_emsdk_headers(out_path)
219
+ sys.exit(0)
241
220
 
242
221
  # Auto-enable app mode if debug is used and Playwright cache exists
243
222
  if args.debug and not args.app:
fastled/print_filter.py CHANGED
@@ -1,52 +1,52 @@
1
- import re
2
- from abc import ABC, abstractmethod
3
- from enum import Enum
4
-
5
-
6
- class PrintFilter(ABC):
7
- """Abstract base class for filtering text output."""
8
-
9
- def __init__(self, echo: bool = True) -> None:
10
- self.echo = echo
11
-
12
- @abstractmethod
13
- def filter(self, text: str) -> str:
14
- """Filter the text according to implementation-specific rules."""
15
- pass
16
-
17
- def print(self, text: str | bytes) -> str:
18
- """Prints the text to the console after filtering."""
19
- if isinstance(text, bytes):
20
- text = text.decode("utf-8")
21
- text = self.filter(text)
22
- if self.echo:
23
- print(text, end="")
24
- return text
25
-
26
-
27
- def _handle_ino_cpp(line: str) -> str:
28
- if ".ino.cpp" in line[0:30]:
29
- # Extract the filename without path and extension
30
- match = re.search(r"src/([^/]+)\.ino\.cpp", line)
31
- if match:
32
- filename = match.group(1)
33
- # Replace with examples/Filename/Filename.ino format
34
- line = line.replace(
35
- f"src/{filename}.ino.cpp", f"examples/{filename}/{filename}.ino"
36
- )
37
- else:
38
- # Fall back to simple extension replacement if regex doesn't match
39
- line = line.replace(".ino.cpp", ".ino")
40
- return line
41
-
42
-
43
- class PrintFilterDefault(PrintFilter):
44
- """Provides default filtering for FastLED output."""
45
-
46
- def filter(self, text: str) -> str:
47
- return text
48
-
49
-
50
- class CompileOrLink(Enum):
51
- COMPILE = "compile"
52
- LINK = "link"
1
+ import re
2
+ from abc import ABC, abstractmethod
3
+ from enum import Enum
4
+
5
+
6
+ class PrintFilter(ABC):
7
+ """Abstract base class for filtering text output."""
8
+
9
+ def __init__(self, echo: bool = True) -> None:
10
+ self.echo = echo
11
+
12
+ @abstractmethod
13
+ def filter(self, text: str) -> str:
14
+ """Filter the text according to implementation-specific rules."""
15
+ pass
16
+
17
+ def print(self, text: str | bytes) -> str:
18
+ """Prints the text to the console after filtering."""
19
+ if isinstance(text, bytes):
20
+ text = text.decode("utf-8")
21
+ text = self.filter(text)
22
+ if self.echo:
23
+ print(text, end="")
24
+ return text
25
+
26
+
27
+ def _handle_ino_cpp(line: str) -> str:
28
+ if ".ino.cpp" in line[0:30]:
29
+ # Extract the filename without path and extension
30
+ match = re.search(r"src/([^/]+)\.ino\.cpp", line)
31
+ if match:
32
+ filename = match.group(1)
33
+ # Replace with examples/Filename/Filename.ino format
34
+ line = line.replace(
35
+ f"src/{filename}.ino.cpp", f"examples/{filename}/{filename}.ino"
36
+ )
37
+ else:
38
+ # Fall back to simple extension replacement if regex doesn't match
39
+ line = line.replace(".ino.cpp", ".ino")
40
+ return line
41
+
42
+
43
+ class PrintFilterDefault(PrintFilter):
44
+ """Provides default filtering for FastLED output."""
45
+
46
+ def filter(self, text: str) -> str:
47
+ return text
48
+
49
+
50
+ class CompileOrLink(Enum):
51
+ COMPILE = "compile"
52
+ LINK = "link"
fastled/util.py CHANGED
@@ -52,3 +52,37 @@ def find_free_port(start_port: int, end_port: int) -> int | None:
52
52
  f"No free port found in the range {start_port}-{end_port}. Using {start_port}."
53
53
  )
54
54
  return None
55
+
56
+
57
+ def download_emsdk_headers(base_url: str, filepath: Path) -> None:
58
+ """Download EMSDK headers from the specified URL and save to filepath.
59
+
60
+ Args:
61
+ base_url: Base URL of the server (e.g., 'http://localhost:8080')
62
+ filepath: Path where to save the headers ZIP file (must end with .zip)
63
+
64
+ Raises:
65
+ ValueError: If filepath doesn't end with .zip
66
+ RuntimeError: If download fails or server returns error
67
+ """
68
+ if not str(filepath).endswith(".zip"):
69
+ raise ValueError("Filepath must end with .zip")
70
+
71
+ import httpx
72
+
73
+ try:
74
+ timeout = httpx.Timeout(30.0, read=30.0)
75
+ with httpx.stream(
76
+ "GET", f"{base_url}/headers/emsdk", timeout=timeout
77
+ ) as response:
78
+ if response.status_code == 200:
79
+ filepath.parent.mkdir(parents=True, exist_ok=True)
80
+ with open(filepath, "wb") as f:
81
+ for chunk in response.iter_bytes(chunk_size=512000):
82
+ f.write(chunk)
83
+ else:
84
+ raise RuntimeError(
85
+ f"Failed to get EMSDK headers: HTTP {response.status_code}"
86
+ )
87
+ except Exception as e:
88
+ raise RuntimeError(f"Error downloading EMSDK headers: {e}") from e
fastled/version.py CHANGED
@@ -1,41 +1,41 @@
1
- from concurrent.futures import Future, ThreadPoolExecutor
2
-
3
- import httpx
4
-
5
- from fastled.__version__ import __version_url_latest__
6
-
7
-
8
- def _fetch_version() -> str | Exception:
9
- """
10
- Helper function to fetch the latest version from the GitHub repository.
11
- """
12
- try:
13
- response = httpx.get(__version_url_latest__)
14
- response.raise_for_status()
15
- # Extract the version string from the response text
16
- version_line = response.text.split("__version__ = ")[1].split('"')[1]
17
- return version_line
18
- except Exception as e:
19
- return e
20
-
21
-
22
- def get_latest_version() -> Future[str | Exception]:
23
- """
24
- Fetch the latest version from the GitHub repository.
25
- Returns a future that will resolve with the version string or an exception.
26
- """
27
- executor = ThreadPoolExecutor()
28
- return executor.submit(_fetch_version)
29
-
30
-
31
- def unit_test() -> None:
32
- future = get_latest_version()
33
- latest_version = future.result() # Wait for the future to complete
34
- if isinstance(latest_version, Exception):
35
- print(f"Error fetching latest version: {latest_version}")
36
- else:
37
- print(f"Latest version: {latest_version}")
38
-
39
-
40
- if __name__ == "__main__":
41
- unit_test()
1
+ from concurrent.futures import Future, ThreadPoolExecutor
2
+
3
+ import httpx
4
+
5
+ from fastled.__version__ import __version_url_latest__
6
+
7
+
8
+ def _fetch_version() -> str | Exception:
9
+ """
10
+ Helper function to fetch the latest version from the GitHub repository.
11
+ """
12
+ try:
13
+ response = httpx.get(__version_url_latest__)
14
+ response.raise_for_status()
15
+ # Extract the version string from the response text
16
+ version_line = response.text.split("__version__ = ")[1].split('"')[1]
17
+ return version_line
18
+ except Exception as e:
19
+ return e
20
+
21
+
22
+ def get_latest_version() -> Future[str | Exception]:
23
+ """
24
+ Fetch the latest version from the GitHub repository.
25
+ Returns a future that will resolve with the version string or an exception.
26
+ """
27
+ executor = ThreadPoolExecutor()
28
+ return executor.submit(_fetch_version)
29
+
30
+
31
+ def unit_test() -> None:
32
+ future = get_latest_version()
33
+ latest_version = future.result() # Wait for the future to complete
34
+ if isinstance(latest_version, Exception):
35
+ print(f"Error fetching latest version: {latest_version}")
36
+ else:
37
+ print(f"Latest version: {latest_version}")
38
+
39
+
40
+ if __name__ == "__main__":
41
+ unit_test()