fastled 1.3.29__tar.gz → 1.3.31__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.
Files changed (119) hide show
  1. {fastled-1.3.29 → fastled-1.3.31}/PKG-INFO +5 -1
  2. {fastled-1.3.29 → fastled-1.3.31}/README.md +3 -0
  3. {fastled-1.3.29 → fastled-1.3.31}/pyproject.toml +1 -0
  4. fastled-1.3.31/requirements.docker.txt +1 -0
  5. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/__version__.py +1 -1
  6. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/filewatcher.py +3 -3
  7. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/server_flask.py +17 -0
  8. {fastled-1.3.29 → fastled-1.3.31}/src/fastled.egg-info/PKG-INFO +5 -1
  9. {fastled-1.3.29 → fastled-1.3.31}/src/fastled.egg-info/SOURCES.txt +1 -0
  10. {fastled-1.3.29 → fastled-1.3.31}/src/fastled.egg-info/requires.txt +1 -0
  11. fastled-1.3.31/tests/unit/test_manual_api_invocation.py +368 -0
  12. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_string_diff.py +1 -1
  13. fastled-1.3.29/requirements.docker.txt +0 -1
  14. {fastled-1.3.29 → fastled-1.3.31}/.aiderignore +0 -0
  15. {fastled-1.3.29 → fastled-1.3.31}/.dockerignore +0 -0
  16. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/build_multi_docker_image.yml +0 -0
  17. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/build_webpage.yml +0 -0
  18. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/lint.yml +0 -0
  19. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/publish_release.yml +0 -0
  20. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/template_build_docker_image.yml +0 -0
  21. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/test_build_exe.yml +0 -0
  22. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/test_macos.yml +0 -0
  23. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/test_ubuntu.yml +0 -0
  24. {fastled-1.3.29 → fastled-1.3.31}/.github/workflows/test_win.yml +0 -0
  25. {fastled-1.3.29 → fastled-1.3.31}/.gitignore +0 -0
  26. {fastled-1.3.29 → fastled-1.3.31}/.pylintrc +0 -0
  27. {fastled-1.3.29 → fastled-1.3.31}/.vscode/launch.json +0 -0
  28. {fastled-1.3.29 → fastled-1.3.31}/.vscode/settings.json +0 -0
  29. {fastled-1.3.29 → fastled-1.3.31}/.vscode/tasks.json +0 -0
  30. {fastled-1.3.29 → fastled-1.3.31}/DEBUGGER.md +0 -0
  31. {fastled-1.3.29 → fastled-1.3.31}/Dockerfile +0 -0
  32. {fastled-1.3.29 → fastled-1.3.31}/FAQ.md +0 -0
  33. {fastled-1.3.29 → fastled-1.3.31}/LICENSE +0 -0
  34. {fastled-1.3.29 → fastled-1.3.31}/MANIFEST.in +0 -0
  35. {fastled-1.3.29 → fastled-1.3.31}/RELEASE.md +0 -0
  36. {fastled-1.3.29 → fastled-1.3.31}/TODO.md +0 -0
  37. {fastled-1.3.29 → fastled-1.3.31}/build_exe.py +0 -0
  38. {fastled-1.3.29 → fastled-1.3.31}/build_local_docker.py +0 -0
  39. {fastled-1.3.29 → fastled-1.3.31}/build_site.py +0 -0
  40. {fastled-1.3.29 → fastled-1.3.31}/clean +0 -0
  41. {fastled-1.3.29 → fastled-1.3.31}/compiler/debug.sh +0 -0
  42. {fastled-1.3.29 → fastled-1.3.31}/compiler/run.py +0 -0
  43. {fastled-1.3.29 → fastled-1.3.31}/demo/100dots.html +0 -0
  44. {fastled-1.3.29 → fastled-1.3.31}/demo/demo_threejs.html +0 -0
  45. {fastled-1.3.29 → fastled-1.3.31}/demo/micdemo.html +0 -0
  46. {fastled-1.3.29 → fastled-1.3.31}/demo/mp3upload.html +0 -0
  47. {fastled-1.3.29 → fastled-1.3.31}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
  48. {fastled-1.3.29 → fastled-1.3.31}/docker-compose.yml +0 -0
  49. {fastled-1.3.29 → fastled-1.3.31}/entrypoint.sh +0 -0
  50. {fastled-1.3.29 → fastled-1.3.31}/install +0 -0
  51. {fastled-1.3.29 → fastled-1.3.31}/install_linux.sh +0 -0
  52. {fastled-1.3.29 → fastled-1.3.31}/lint +0 -0
  53. {fastled-1.3.29 → fastled-1.3.31}/requirements.testing.txt +0 -0
  54. {fastled-1.3.29 → fastled-1.3.31}/setup.cfg +0 -0
  55. {fastled-1.3.29 → fastled-1.3.31}/setup.py +0 -0
  56. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/__init__.py +0 -0
  57. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/app.py +0 -0
  58. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/args.py +0 -0
  59. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/assets/example.txt +0 -0
  60. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/assets/localhost-key.pem +0 -0
  61. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/assets/localhost.pem +0 -0
  62. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/cli.py +0 -0
  63. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/cli_test.py +0 -0
  64. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/cli_test_interactive.py +0 -0
  65. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/client_server.py +0 -0
  66. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/compile_server.py +0 -0
  67. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/compile_server_impl.py +0 -0
  68. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/docker_manager.py +0 -0
  69. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/keyboard.py +0 -0
  70. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/keyz.py +0 -0
  71. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/live_client.py +0 -0
  72. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/open_browser.py +0 -0
  73. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/parse_args.py +0 -0
  74. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/paths.py +0 -0
  75. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/print_filter.py +0 -0
  76. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/project_init.py +0 -0
  77. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/select_sketch_directory.py +0 -0
  78. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/server_start.py +0 -0
  79. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/settings.py +0 -0
  80. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/site/build.py +0 -0
  81. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/site/examples.py +0 -0
  82. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/sketch.py +0 -0
  83. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/spinner.py +0 -0
  84. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/string_diff.py +0 -0
  85. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/test/can_run_local_docker_tests.py +0 -0
  86. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/test/examples.py +0 -0
  87. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/types.py +0 -0
  88. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/util.py +0 -0
  89. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/version.py +0 -0
  90. {fastled-1.3.29 → fastled-1.3.31}/src/fastled/web_compile.py +0 -0
  91. {fastled-1.3.29 → fastled-1.3.31}/src/fastled.egg-info/dependency_links.txt +0 -0
  92. {fastled-1.3.29 → fastled-1.3.31}/src/fastled.egg-info/entry_points.txt +0 -0
  93. {fastled-1.3.29 → fastled-1.3.31}/src/fastled.egg-info/top_level.txt +0 -0
  94. {fastled-1.3.29 → fastled-1.3.31}/test +0 -0
  95. {fastled-1.3.29 → fastled-1.3.31}/tests/integration/test_build_examples.py +0 -0
  96. {fastled-1.3.29 → fastled-1.3.31}/tests/integration/test_examples.py +0 -0
  97. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/html/index.html +0 -0
  98. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_api.py +0 -0
  99. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_bad_ino.py +0 -0
  100. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_banner_string.py +0 -0
  101. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_cli.py +0 -0
  102. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_compile_server.py +0 -0
  103. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_debug_fetch_source_files.py +0 -0
  104. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_docker_linux_on_windows.py +0 -0
  105. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_embedded_data.py +0 -0
  106. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_filechanger.py +0 -0
  107. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_http_server.py +0 -0
  108. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_ino/bad/bad.ino +0 -0
  109. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
  110. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
  111. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
  112. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_ino/embedded/wasm.ino +0 -0
  113. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_ino/wasm/wasm.ino +0 -0
  114. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_project_init.py +0 -0
  115. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_server_and_client_seperatly.py +0 -0
  116. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_version.py +0 -0
  117. {fastled-1.3.29 → fastled-1.3.31}/tests/unit/test_webcompile.py +0 -0
  118. {fastled-1.3.29 → fastled-1.3.31}/upload_package.sh +0 -0
  119. {fastled-1.3.29 → fastled-1.3.31}/vscode-plugin/readme +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastled
3
- Version: 1.3.29
3
+ Version: 1.3.31
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -19,6 +19,7 @@ Requires-Dist: rapidfuzz>=3.10.1
19
19
  Requires-Dist: progress>=1.6
20
20
  Requires-Dist: watchfiles>=1.0.5
21
21
  Requires-Dist: Flask>=3.0.0
22
+ Requires-Dist: flask-cors>=4.0.0
22
23
  Requires-Dist: livereload
23
24
  Requires-Dist: disklru>=2.0.4
24
25
  Dynamic: home-page
@@ -55,8 +56,10 @@ Compile times are extremely fast, thanks to aggressive object caching for C++ an
55
56
 
56
57
  If you have docker installed, the compiler will download the docker image and run a private local server on your machine. If you don't have Docker installed then the app will fall back to using the public web compiler.
57
58
 
59
+
58
60
  In every conceivable way, the local compiler will be much faster than the web version.
59
61
 
62
+
60
63
  # Run
61
64
 
62
65
  Once `fastled` is installed you'll just navigate to your sketch directory and run it.
@@ -69,6 +72,7 @@ $ fastled
69
72
  ```
70
73
 
71
74
 
75
+
72
76
  # Install
73
77
 
74
78
  This is a python app, so any python package manager will work. We also provide python compiled binaries for Windows, MacOS, and Linux.
@@ -28,8 +28,10 @@ Compile times are extremely fast, thanks to aggressive object caching for C++ an
28
28
 
29
29
  If you have docker installed, the compiler will download the docker image and run a private local server on your machine. If you don't have Docker installed then the app will fall back to using the public web compiler.
30
30
 
31
+
31
32
  In every conceivable way, the local compiler will be much faster than the web version.
32
33
 
34
+
33
35
  # Run
34
36
 
35
37
  Once `fastled` is installed you'll just navigate to your sketch directory and run it.
@@ -42,6 +44,7 @@ $ fastled
42
44
  ```
43
45
 
44
46
 
47
+
45
48
  # Install
46
49
 
47
50
  This is a python app, so any python package manager will work. We also provide python compiled binaries for Windows, MacOS, and Linux.
@@ -22,6 +22,7 @@ dependencies = [
22
22
  ########## End Docker Manager Dependencies
23
23
  "watchfiles>=1.0.5",
24
24
  "Flask>=3.0.0",
25
+ "flask-cors>=4.0.0",
25
26
  "livereload",
26
27
  "disklru>=2.0.4",
27
28
  ]
@@ -0,0 +1 @@
1
+ fastled-wasm-server>=1.0.92
@@ -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.3.29"
4
+ __version__ = "1.3.31"
5
5
 
6
6
  __version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
@@ -22,8 +22,8 @@ _WATCHER_TIMEOUT = 0.1
22
22
 
23
23
 
24
24
  def file_watcher_enabled() -> bool:
25
- """Check if watchdog is disabled"""
26
- return os.getenv("NO_FILE_WATCHING", "0") == "1"
25
+ """Check if watchdog is enabled"""
26
+ return os.getenv("NO_FILE_WATCHING", "0") != "1"
27
27
 
28
28
 
29
29
  def file_watcher_set(enabled: bool) -> None:
@@ -134,7 +134,7 @@ class FileChangedNotifier(threading.Thread):
134
134
  Returns:
135
135
  Changed filepath or None if no change within timeout
136
136
  """
137
- if file_watcher_enabled():
137
+ if not file_watcher_enabled():
138
138
  time.sleep(timeout)
139
139
  return None
140
140
  try:
@@ -60,9 +60,26 @@ def _run_flask_server(
60
60
  """
61
61
  try:
62
62
  from flask import Flask, Response, request, send_from_directory
63
+ from flask_cors import CORS
63
64
 
64
65
  app = Flask(__name__)
65
66
 
67
+ # Enable CORS for all domains on all routes
68
+ CORS(
69
+ app,
70
+ resources={
71
+ r"/*": {
72
+ "origins": "*",
73
+ "methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
74
+ "allow_headers": [
75
+ "Content-Type",
76
+ "Authorization",
77
+ "X-Requested-With",
78
+ ],
79
+ }
80
+ },
81
+ )
82
+
66
83
  # Must be a full path or flask will fail to find the file.
67
84
  fastled_js = fastled_js.resolve()
68
85
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastled
3
- Version: 1.3.29
3
+ Version: 1.3.31
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -19,6 +19,7 @@ Requires-Dist: rapidfuzz>=3.10.1
19
19
  Requires-Dist: progress>=1.6
20
20
  Requires-Dist: watchfiles>=1.0.5
21
21
  Requires-Dist: Flask>=3.0.0
22
+ Requires-Dist: flask-cors>=4.0.0
22
23
  Requires-Dist: livereload
23
24
  Requires-Dist: disklru>=2.0.4
24
25
  Dynamic: home-page
@@ -55,8 +56,10 @@ Compile times are extremely fast, thanks to aggressive object caching for C++ an
55
56
 
56
57
  If you have docker installed, the compiler will download the docker image and run a private local server on your machine. If you don't have Docker installed then the app will fall back to using the public web compiler.
57
58
 
59
+
58
60
  In every conceivable way, the local compiler will be much faster than the web version.
59
61
 
62
+
60
63
  # Run
61
64
 
62
65
  Once `fastled` is installed you'll just navigate to your sketch directory and run it.
@@ -69,6 +72,7 @@ $ fastled
69
72
  ```
70
73
 
71
74
 
75
+
72
76
  # Install
73
77
 
74
78
  This is a python app, so any python package manager will work. We also provide python compiled binaries for Windows, MacOS, and Linux.
@@ -100,6 +100,7 @@ tests/unit/test_docker_linux_on_windows.py
100
100
  tests/unit/test_embedded_data.py
101
101
  tests/unit/test_filechanger.py
102
102
  tests/unit/test_http_server.py
103
+ tests/unit/test_manual_api_invocation.py
103
104
  tests/unit/test_project_init.py
104
105
  tests/unit/test_server_and_client_seperatly.py
105
106
  tests/unit/test_string_diff.py
@@ -7,5 +7,6 @@ rapidfuzz>=3.10.1
7
7
  progress>=1.6
8
8
  watchfiles>=1.0.5
9
9
  Flask>=3.0.0
10
+ flask-cors>=4.0.0
10
11
  livereload
11
12
  disklru>=2.0.4
@@ -0,0 +1,368 @@
1
+ """
2
+ Unit test file demonstrating manual API invocation of fastled-wasm-server.
3
+
4
+ This test file shows how to manually invoke the fastled-wasm-server API endpoints
5
+ using raw HTTP requests, bypassing the high-level Python API wrapper.
6
+ """
7
+
8
+ import io
9
+ import tempfile
10
+ import time
11
+ import unittest
12
+ import zipfile
13
+ from pathlib import Path
14
+
15
+ import httpx
16
+
17
+ from fastled import Api
18
+ from fastled.settings import DEFAULT_URL
19
+ from fastled.types import BuildMode
20
+
21
+
22
+ class TestManualApiInvocation(unittest.TestCase):
23
+ """Test manual invocation of fastled-wasm-server API endpoints."""
24
+
25
+ # Class-level variables for shared server instance
26
+ server = None
27
+ base_url = None
28
+
29
+ @classmethod
30
+ def setUpClass(cls):
31
+ """Set up test environment once for all tests."""
32
+ cls.test_dir = Path(__file__).parent / "unit" / "test_ino" / "wasm"
33
+ cls.timeout = 30
34
+
35
+ # Check if we can run local docker tests
36
+ if cls._enabled():
37
+ print("\n🚀 Starting local FastLED WASM server for manual API tests...")
38
+ cls.server = Api.spawn_server()
39
+ cls.base_url = cls.server.url()
40
+ print(f"✅ Server started at: {cls.base_url}")
41
+ else:
42
+ print("\n🌐 Using web server for manual API tests...")
43
+ cls.server = None
44
+ cls.base_url = DEFAULT_URL
45
+ print(f"✅ Using web server: {cls.base_url}")
46
+
47
+ @classmethod
48
+ def tearDownClass(cls):
49
+ """Clean up server after all tests."""
50
+ if cls.server is not None:
51
+ print("\n🛑 Stopping local FastLED WASM server...")
52
+ cls.server.stop()
53
+ print("✅ Server stopped")
54
+
55
+ @classmethod
56
+ def _enabled(cls) -> bool:
57
+ """Check if this system can run the tests."""
58
+ from fastled import Test
59
+
60
+ return Test.can_run_local_docker_tests()
61
+
62
+ def _create_test_sketch_zip(self) -> bytes:
63
+ """Create a test sketch zip file for upload."""
64
+ # Create in-memory zip file with test sketch
65
+ zip_buffer = io.BytesIO()
66
+ with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zip_file:
67
+ # Add the main sketch file
68
+ sketch_content = """#include <FastLED.h>
69
+
70
+ #define LED_PIN 3
71
+ #define NUM_LEDS 100
72
+
73
+ CRGB leds[NUM_LEDS];
74
+
75
+ void setup() {
76
+ FastLED.addLeds<WS2812, LED_PIN>(leds, NUM_LEDS);
77
+ }
78
+
79
+ void loop() {
80
+ fill_rainbow(leds, NUM_LEDS, 0, 7);
81
+ FastLED.show();
82
+ delay(30);
83
+ }"""
84
+ zip_file.writestr("wasm/wasm.ino", sketch_content)
85
+ # Add build mode identifier
86
+ zip_file.writestr("wasm/build_mode.txt", BuildMode.QUICK.value)
87
+
88
+ return zip_buffer.getvalue()
89
+
90
+ @unittest.skipUnless(True, "Test manual API invocation")
91
+ def test_info_endpoint_manual(self) -> None:
92
+ """Test the /info endpoint to get available examples using manual HTTP requests."""
93
+ # Test /info endpoint manually
94
+ info_url = f"{self.base_url}/info"
95
+ print(f"\nTesting INFO endpoint manually: {info_url}")
96
+
97
+ response = httpx.get(info_url, timeout=self.timeout)
98
+
99
+ self.assertEqual(response.status_code, 200)
100
+ data = response.json()
101
+ self.assertIn("examples", data)
102
+ self.assertIsInstance(data["examples"], list)
103
+ self.assertGreater(len(data["examples"]), 0)
104
+
105
+ print(f"✅ Found {len(data['examples'])} examples: {data['examples']}")
106
+
107
+ @unittest.skipUnless(True, "Test manual API invocation")
108
+ def test_healthz_endpoint_manual(self) -> None:
109
+ """Test the /healthz endpoint for health check using manual HTTP requests."""
110
+ # Test /healthz endpoint manually
111
+ healthz_url = f"{self.base_url}/healthz"
112
+ print(f"\nTesting HEALTHZ endpoint manually: {healthz_url}")
113
+
114
+ response = httpx.get(healthz_url, timeout=self.timeout)
115
+
116
+ self.assertEqual(response.status_code, 200)
117
+ print(f"✅ Health check successful: {response.text}")
118
+
119
+ @unittest.skipUnless(True, "Test manual API invocation")
120
+ def test_compile_wasm_endpoint_manual(self) -> None:
121
+ """Test manual invocation of /compile/wasm endpoint using raw HTTP requests.
122
+
123
+ This test demonstrates how to manually call the FastLED WASM compilation API
124
+ without using the high-level Python wrapper functions.
125
+ """
126
+ # Create test sketch zip
127
+ zip_bytes = self._create_test_sketch_zip()
128
+
129
+ # Test /compile/wasm endpoint manually
130
+ compile_url = f"{self.base_url}/compile/wasm"
131
+ print(f"\nTesting COMPILE/WASM endpoint manually: {compile_url}")
132
+ print(f"📦 Upload size: {len(zip_bytes)} bytes")
133
+
134
+ # Prepare headers (exactly as the internal API does)
135
+ headers = {
136
+ "accept": "application/json",
137
+ "authorization": "oBOT5jbsO4ztgrpNsQwlmFLIKB", # Default auth token
138
+ "build": BuildMode.QUICK.value.lower(),
139
+ "profile": "false",
140
+ }
141
+
142
+ # Prepare files for upload
143
+ files = {"file": ("wasm.zip", zip_bytes, "application/x-zip-compressed")}
144
+
145
+ # Make the request manually
146
+ start_time = time.time()
147
+
148
+ with httpx.Client(timeout=60 * 2) as client: # 2 minute timeout
149
+ response = client.post(
150
+ compile_url, files=files, headers=headers, follow_redirects=True
151
+ )
152
+
153
+ compile_time = time.time() - start_time
154
+ print(f"⏱️ Compilation took: {compile_time:.2f} seconds")
155
+
156
+ # Verify response
157
+ print(f"📋 Response status: {response.status_code}")
158
+ if response.status_code != 200:
159
+ print(f"❌ Response content: {response.text}")
160
+
161
+ self.assertEqual(response.status_code, 200)
162
+
163
+ # Verify we got a zip file back
164
+ self.assertGreater(len(response.content), 0)
165
+ print(f"📥 Response zip size: {len(response.content)} bytes")
166
+
167
+ # Try to extract and verify the response contains expected files
168
+ with tempfile.TemporaryDirectory() as temp_dir:
169
+ temp_path = Path(temp_dir)
170
+ zip_path = temp_path / "response.zip"
171
+ zip_path.write_bytes(response.content)
172
+
173
+ # Extract and check contents
174
+ import shutil
175
+
176
+ shutil.unpack_archive(zip_path, temp_path, "zip")
177
+
178
+ # Look for expected output files
179
+ js_files = list(temp_path.glob("**/*.js"))
180
+ wasm_files = list(temp_path.glob("**/*.wasm"))
181
+
182
+ print(f"🔍 Found JS files: {[f.name for f in js_files]}")
183
+ print(f"🔍 Found WASM files: {[f.name for f in wasm_files]}")
184
+
185
+ self.assertGreater(len(js_files), 0, "Expected to find .js files")
186
+ self.assertGreater(len(wasm_files), 0, "Expected to find .wasm files")
187
+
188
+ # Verify file sizes are reasonable
189
+ for js_file in js_files:
190
+ size = js_file.stat().st_size
191
+ self.assertGreater(
192
+ size, 1000, f"JS file {js_file.name} too small: {size} bytes"
193
+ )
194
+ print(f"📄 {js_file.name}: {size:,} bytes")
195
+
196
+ for wasm_file in wasm_files:
197
+ size = wasm_file.stat().st_size
198
+ self.assertGreater(
199
+ size, 1000, f"WASM file {wasm_file.name} too small: {size} bytes"
200
+ )
201
+ print(f"⚙️ {wasm_file.name}: {size:,} bytes")
202
+
203
+ @unittest.skipUnless(True, "Test manual API invocation")
204
+ def test_compile_libfastled_endpoint_manual(self) -> None:
205
+ """Test manual invocation of /compile/libfastled endpoint using raw HTTP requests.
206
+
207
+ This test demonstrates how to manually call the FastLED library compilation API
208
+ which compiles just the FastLED library without a sketch.
209
+ """
210
+ # Test /compile/libfastled endpoint manually
211
+ compile_url = f"{self.base_url}/compile/libfastled"
212
+ print(f"\nTesting COMPILE/LIBFASTLED endpoint manually: {compile_url}")
213
+
214
+ # Prepare headers for libfastled compilation
215
+ headers = {
216
+ "accept": "application/json",
217
+ "authorization": "oBOT5jbsO4ztgrpNsQwlmFLIKB", # Default auth token
218
+ "build": BuildMode.QUICK.value.lower(),
219
+ }
220
+
221
+ print(f"🔧 Build mode: {headers['build']}")
222
+
223
+ # Make the request manually (no file upload needed for library compilation)
224
+ start_time = time.time()
225
+
226
+ with httpx.Client(
227
+ timeout=60 * 3
228
+ ) as client: # 3 minute timeout for library compilation
229
+ response = client.post(compile_url, headers=headers, follow_redirects=True)
230
+
231
+ compile_time = time.time() - start_time
232
+ print(f"⏱️ Library compilation took: {compile_time:.2f} seconds")
233
+
234
+ # Verify response
235
+ print(f"📋 Response status: {response.status_code}")
236
+ if response.status_code != 200:
237
+ print(f"❌ Response content: {response.text}")
238
+
239
+ self.assertEqual(response.status_code, 200)
240
+
241
+ # Verify we got some content back (streaming response)
242
+ self.assertGreater(len(response.content), 0)
243
+ print(f"📥 Response size: {len(response.content)} bytes")
244
+
245
+ # Check if it's a zip file or other binary content
246
+ if response.content.startswith(b"PK"): # ZIP file magic bytes
247
+ print("📦 Response appears to be a ZIP file")
248
+ # Try to extract and verify the response contains expected library files
249
+ with tempfile.TemporaryDirectory() as temp_dir:
250
+ temp_path = Path(temp_dir)
251
+ zip_path = temp_path / "libfastled.zip"
252
+ zip_path.write_bytes(response.content)
253
+
254
+ # Extract and check contents
255
+ import shutil
256
+
257
+ shutil.unpack_archive(zip_path, temp_path, "zip")
258
+
259
+ # Look for expected library files
260
+ lib_files = list(temp_path.glob("**/*.a")) + list(
261
+ temp_path.glob("**/*.so")
262
+ )
263
+ header_files = list(temp_path.glob("**/*.h")) + list(
264
+ temp_path.glob("**/*.hpp")
265
+ )
266
+
267
+ print(f"🔍 Found library files: {[f.name for f in lib_files]}")
268
+ print(f"🔍 Found header files: {[f.name for f in header_files]}")
269
+
270
+ # We expect at least some library or header files
271
+ self.assertGreater(
272
+ len(lib_files) + len(header_files),
273
+ 0,
274
+ "Expected to find library or header files",
275
+ )
276
+ else:
277
+ print("📄 Response appears to be text/binary data")
278
+ # Could be a streaming response with compilation logs
279
+ try:
280
+ text_content = response.content.decode("utf-8")
281
+ print(f"📝 Response preview: {text_content[:200]}...")
282
+ except UnicodeDecodeError:
283
+ print("🔧 Response contains binary data")
284
+
285
+ @unittest.skipUnless(True, "Test manual API invocation")
286
+ def test_project_init_endpoint_manual(self) -> None:
287
+ """Test the /project/init endpoint to initialize a project using manual HTTP requests."""
288
+ # Test /project/init endpoint manually
289
+ init_url = f"{self.base_url}/project/init"
290
+ print(f"\nTesting PROJECT/INIT endpoint manually: {init_url}")
291
+
292
+ # Request a basic example project
293
+ example_name = "wasm" # This should be a basic available example
294
+
295
+ response = httpx.post(
296
+ init_url,
297
+ json=example_name,
298
+ headers={"accept": "application/json"},
299
+ timeout=self.timeout,
300
+ )
301
+
302
+ self.assertEqual(response.status_code, 200)
303
+
304
+ # Verify we got a zip file back
305
+ self.assertGreater(len(response.content), 0)
306
+ print(f"📦 Project init zip size: {len(response.content)} bytes")
307
+
308
+ # Verify the zip contains expected files
309
+ with tempfile.TemporaryDirectory() as temp_dir:
310
+ temp_path = Path(temp_dir)
311
+ zip_path = temp_path / "project.zip"
312
+ zip_path.write_bytes(response.content)
313
+
314
+ # Extract and check contents
315
+ import shutil
316
+
317
+ shutil.unpack_archive(zip_path, temp_path, "zip")
318
+
319
+ # Look for .ino files
320
+ ino_files = list(temp_path.glob("**/*.ino"))
321
+ print(f"📄 Found .ino files: {[f.name for f in ino_files]}")
322
+
323
+ self.assertGreater(len(ino_files), 0, "Expected to find .ino files")
324
+
325
+ @unittest.skipUnless(True, "Test manual API invocation")
326
+ def test_docs_endpoint_manual(self) -> None:
327
+ """Test that the /docs endpoint exists (FastAPI documentation) using manual HTTP requests."""
328
+ if not self._enabled():
329
+ self.skipTest("Local server not available for /docs test")
330
+
331
+ # Test /docs endpoint manually
332
+ docs_url = f"{self.base_url}/docs"
333
+ print(f"\nTesting DOCS endpoint manually: {docs_url}")
334
+
335
+ response = httpx.get(docs_url, timeout=self.timeout)
336
+
337
+ # Should return HTML documentation
338
+ self.assertEqual(response.status_code, 200)
339
+ self.assertIn("text/html", response.headers.get("content-type", "").lower())
340
+ print("✅ FastAPI docs endpoint accessible")
341
+
342
+ def test_api_endpoints_summary(self) -> None:
343
+ """Test that demonstrates all available API endpoints and their usage.
344
+
345
+ This is a comprehensive test showing what endpoints exist and how to use them manually.
346
+ """
347
+ print("\n" + "=" * 70)
348
+ print("📋 FASTLED WASM SERVER API ENDPOINTS SUMMARY")
349
+ print("=" * 70)
350
+ print("Available endpoints:")
351
+ print(" • /compile/wasm - Main compilation endpoint (POST)")
352
+ print(" • /compile/libfastled - FastLED library compilation (POST)")
353
+ print(" • /info - Get available examples (GET)")
354
+ print(" • /project/init - Initialize project from example (POST)")
355
+ print(" • /healthz - Health check (GET)")
356
+ print(" • /docs - FastAPI documentation (GET)")
357
+ print(" • /dwarfsource - Debug source files (POST)")
358
+ print(" • /sourcefiles/* - Source file serving (GET)")
359
+ print("\n✅ NEW: /compile/libfastled endpoint found!")
360
+ print(" Compiles the FastLED library without requiring a sketch")
361
+ print("=" * 70)
362
+
363
+ # This test always passes - it's just for documentation
364
+ self.assertTrue(True, "API endpoints summary displayed")
365
+
366
+
367
+ if __name__ == "__main__":
368
+ unittest.main()
@@ -4,6 +4,7 @@ from fastled.string_diff import is_in_order_match, string_diff
4
4
 
5
5
  _HAYSTACK: list[str] = [
6
6
  "examples\\AnalogOutput",
7
+ "examples\\Animartrix",
7
8
  "examples\\Apa102",
8
9
  "examples\\Apa102HD",
9
10
  "examples\\Apa102HDOverride",
@@ -24,7 +25,6 @@ _HAYSTACK: list[str] = [
24
25
  "examples\\FireCylinder",
25
26
  "examples\\FireMatrix",
26
27
  "examples\\FirstLight",
27
- "examples\\FxAnimartrix",
28
28
  "examples\\FxCylon",
29
29
  "examples\\FxDemoReel100",
30
30
  "examples\\FxEngine",
@@ -1 +0,0 @@
1
- fastled-wasm-server>=1.0.80
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