fastled 1.3.33__tar.gz → 1.3.34__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 (123) hide show
  1. {fastled-1.3.33 → fastled-1.3.34}/PKG-INFO +1 -1
  2. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/__init__.py +6 -0
  3. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/__version__.py +1 -1
  4. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/app.py +5 -1
  5. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/client_server.py +21 -6
  6. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/compile_server.py +2 -0
  7. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/compile_server_impl.py +4 -0
  8. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/live_client.py +3 -0
  9. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/server_flask.py +8 -0
  10. {fastled-1.3.33 → fastled-1.3.34}/src/fastled.egg-info/PKG-INFO +1 -1
  11. {fastled-1.3.33 → fastled-1.3.34}/src/fastled.egg-info/SOURCES.txt +1 -0
  12. fastled-1.3.34/tests/unit/test_flask_headers.py +188 -0
  13. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_no_platformio_compile.py +196 -0
  14. {fastled-1.3.33 → fastled-1.3.34}/.aiderignore +0 -0
  15. {fastled-1.3.33 → fastled-1.3.34}/.cursorrules +0 -0
  16. {fastled-1.3.33 → fastled-1.3.34}/.dockerignore +0 -0
  17. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/build_multi_docker_image.yml +0 -0
  18. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/build_webpage.yml +0 -0
  19. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/lint.yml +0 -0
  20. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/publish_release.yml +0 -0
  21. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/template_build_docker_image.yml +0 -0
  22. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/test_build_exe.yml +0 -0
  23. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/test_macos.yml +0 -0
  24. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/test_ubuntu.yml +0 -0
  25. {fastled-1.3.33 → fastled-1.3.34}/.github/workflows/test_win.yml +0 -0
  26. {fastled-1.3.33 → fastled-1.3.34}/.gitignore +0 -0
  27. {fastled-1.3.33 → fastled-1.3.34}/.pylintrc +0 -0
  28. {fastled-1.3.33 → fastled-1.3.34}/.vscode/launch.json +0 -0
  29. {fastled-1.3.33 → fastled-1.3.34}/.vscode/settings.json +0 -0
  30. {fastled-1.3.33 → fastled-1.3.34}/.vscode/tasks.json +0 -0
  31. {fastled-1.3.33 → fastled-1.3.34}/DEBUGGER.md +0 -0
  32. {fastled-1.3.33 → fastled-1.3.34}/Dockerfile +0 -0
  33. {fastled-1.3.33 → fastled-1.3.34}/FAQ.md +0 -0
  34. {fastled-1.3.33 → fastled-1.3.34}/LICENSE +0 -0
  35. {fastled-1.3.33 → fastled-1.3.34}/MANIFEST.in +0 -0
  36. {fastled-1.3.33 → fastled-1.3.34}/README.md +0 -0
  37. {fastled-1.3.33 → fastled-1.3.34}/RELEASE.md +0 -0
  38. {fastled-1.3.33 → fastled-1.3.34}/TODO.md +0 -0
  39. {fastled-1.3.33 → fastled-1.3.34}/build_exe.py +0 -0
  40. {fastled-1.3.33 → fastled-1.3.34}/build_local_docker.py +0 -0
  41. {fastled-1.3.33 → fastled-1.3.34}/build_site.py +0 -0
  42. {fastled-1.3.33 → fastled-1.3.34}/clean +0 -0
  43. {fastled-1.3.33 → fastled-1.3.34}/compiler/debug.sh +0 -0
  44. {fastled-1.3.33 → fastled-1.3.34}/compiler/run.py +0 -0
  45. {fastled-1.3.33 → fastled-1.3.34}/demo/100dots.html +0 -0
  46. {fastled-1.3.33 → fastled-1.3.34}/demo/demo_threejs.html +0 -0
  47. {fastled-1.3.33 → fastled-1.3.34}/demo/micdemo.html +0 -0
  48. {fastled-1.3.33 → fastled-1.3.34}/demo/mp3upload.html +0 -0
  49. {fastled-1.3.33 → fastled-1.3.34}/demo/webgl_postprocessing_unreal_bloom.html +0 -0
  50. {fastled-1.3.33 → fastled-1.3.34}/docker-compose.yml +0 -0
  51. {fastled-1.3.33 → fastled-1.3.34}/entrypoint.sh +0 -0
  52. {fastled-1.3.33 → fastled-1.3.34}/install +0 -0
  53. {fastled-1.3.33 → fastled-1.3.34}/install_linux.sh +0 -0
  54. {fastled-1.3.33 → fastled-1.3.34}/lint +0 -0
  55. {fastled-1.3.33 → fastled-1.3.34}/pyproject.toml +0 -0
  56. {fastled-1.3.33 → fastled-1.3.34}/requirements.docker.txt +0 -0
  57. {fastled-1.3.33 → fastled-1.3.34}/requirements.testing.txt +0 -0
  58. {fastled-1.3.33 → fastled-1.3.34}/setup.cfg +0 -0
  59. {fastled-1.3.33 → fastled-1.3.34}/setup.py +0 -0
  60. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/args.py +0 -0
  61. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/assets/example.txt +0 -0
  62. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/assets/localhost-key.pem +0 -0
  63. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/assets/localhost.pem +0 -0
  64. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/cli.py +0 -0
  65. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/cli_test.py +0 -0
  66. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/cli_test_interactive.py +0 -0
  67. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/docker_manager.py +0 -0
  68. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/filewatcher.py +0 -0
  69. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/keyboard.py +0 -0
  70. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/keyz.py +0 -0
  71. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/open_browser.py +0 -0
  72. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/parse_args.py +0 -0
  73. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/paths.py +0 -0
  74. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/print_filter.py +0 -0
  75. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/project_init.py +0 -0
  76. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/select_sketch_directory.py +0 -0
  77. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/server_start.py +0 -0
  78. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/settings.py +0 -0
  79. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/site/build.py +0 -0
  80. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/site/examples.py +0 -0
  81. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/sketch.py +0 -0
  82. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/spinner.py +0 -0
  83. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/string_diff.py +0 -0
  84. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/test/can_run_local_docker_tests.py +0 -0
  85. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/test/examples.py +0 -0
  86. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/types.py +0 -0
  87. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/util.py +0 -0
  88. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/version.py +0 -0
  89. {fastled-1.3.33 → fastled-1.3.34}/src/fastled/web_compile.py +0 -0
  90. {fastled-1.3.33 → fastled-1.3.34}/src/fastled.egg-info/dependency_links.txt +0 -0
  91. {fastled-1.3.33 → fastled-1.3.34}/src/fastled.egg-info/entry_points.txt +0 -0
  92. {fastled-1.3.33 → fastled-1.3.34}/src/fastled.egg-info/requires.txt +0 -0
  93. {fastled-1.3.33 → fastled-1.3.34}/src/fastled.egg-info/top_level.txt +0 -0
  94. {fastled-1.3.33 → fastled-1.3.34}/test +0 -0
  95. {fastled-1.3.33 → fastled-1.3.34}/tests/integration/test_build_examples.py +0 -0
  96. {fastled-1.3.33 → fastled-1.3.34}/tests/integration/test_examples.py +0 -0
  97. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/html/index.html +0 -0
  98. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_api.py +0 -0
  99. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_bad_ino.py +0 -0
  100. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_banner_string.py +0 -0
  101. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_cli.py +0 -0
  102. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_cli_no_platformio.py +0 -0
  103. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_compile_server.py +0 -0
  104. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_debug_fetch_source_files.py +0 -0
  105. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_docker_linux_on_windows.py +0 -0
  106. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_embedded_data.py +0 -0
  107. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_filechanger.py +0 -0
  108. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_http_server.py +0 -0
  109. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_ino/bad/bad.ino +0 -0
  110. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_ino/bad_platformio/bad_platformio.ino +0 -0
  111. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_ino/bad_platformio/platformio.ini +0 -0
  112. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_ino/embedded/data/bigdata.dat +0 -0
  113. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_ino/embedded/wasm.ino +0 -0
  114. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_ino/wasm/wasm.ino +0 -0
  115. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_manual_api_invocation.py +0 -0
  116. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_project_init.py +0 -0
  117. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_server_and_client_seperatly.py +0 -0
  118. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_session_compile.py +0 -0
  119. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_string_diff.py +0 -0
  120. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_version.py +0 -0
  121. {fastled-1.3.33 → fastled-1.3.34}/tests/unit/test_webcompile.py +0 -0
  122. {fastled-1.3.33 → fastled-1.3.34}/upload_package.sh +0 -0
  123. {fastled-1.3.33 → fastled-1.3.34}/vscode-plugin/readme +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastled
3
- Version: 1.3.33
3
+ Version: 1.3.34
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -64,6 +64,7 @@ class Api:
64
64
  http_port: (
65
65
  int | None
66
66
  ) = None, # None means auto select a free port. -1 means no server.
67
+ no_platformio: bool = False,
67
68
  ) -> LiveClient:
68
69
  return LiveClient(
69
70
  sketch_directory=sketch_directory,
@@ -75,6 +76,7 @@ class Api:
75
76
  build_mode=build_mode,
76
77
  profile=profile,
77
78
  http_port=http_port,
79
+ no_platformio=no_platformio,
78
80
  )
79
81
 
80
82
  @staticmethod
@@ -85,6 +87,7 @@ class Api:
85
87
  mapped_dir: Path | None = None, # Sketch directory.
86
88
  container_name: str | None = None, # Specific docker container name.
87
89
  remove_previous: bool = False,
90
+ no_platformio: bool = False,
88
91
  ) -> CompileServer:
89
92
  """Uses docker to spawn a compile server from the given name."""
90
93
  from fastled.compile_server import CompileServer
@@ -96,6 +99,7 @@ class Api:
96
99
  mapped_dir=mapped_dir,
97
100
  auto_start=auto_start,
98
101
  remove_previous=remove_previous,
102
+ no_platformio=no_platformio,
99
103
  )
100
104
  return out
101
105
 
@@ -108,6 +112,7 @@ class Api:
108
112
  mapped_dir: Path | None = None, # Sketch directory.
109
113
  container_name: str | None = None, # Specific docker container name.
110
114
  remove_previous=False,
115
+ no_platformio: bool = False,
111
116
  ) -> Generator[CompileServer, None, None]:
112
117
  server = Api.spawn_server(
113
118
  interactive=interactive,
@@ -116,6 +121,7 @@ class Api:
116
121
  mapped_dir=mapped_dir,
117
122
  container_name=container_name,
118
123
  remove_previous=remove_previous,
124
+ no_platformio=no_platformio,
119
125
  )
120
126
  try:
121
127
  yield server
@@ -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.33"
4
+ __version__ = "1.3.34"
5
5
 
6
6
  __version_url_latest__ = "https://raw.githubusercontent.com/zackees/fastled-wasm/refs/heads/main/src/fastled/__version__.py"
@@ -27,6 +27,7 @@ def run_server(args: Args) -> int:
27
27
  mapped_dir=mapped_dir,
28
28
  auto_start=True,
29
29
  remove_previous=args.clear,
30
+ no_platformio=args.no_platformio,
30
31
  )
31
32
 
32
33
  if not interactive:
@@ -87,7 +88,9 @@ def main() -> int:
87
88
 
88
89
  if update:
89
90
  # Force auto_update to ensure update check happens
90
- compile_server = CompileServer(interactive=False, auto_updates=True)
91
+ compile_server = CompileServer(
92
+ interactive=False, auto_updates=True, no_platformio=args.no_platformio
93
+ )
91
94
  compile_server.stop()
92
95
  print("Finished updating.")
93
96
  return 0
@@ -109,6 +112,7 @@ def main() -> int:
109
112
  mapped_dir=directory,
110
113
  auto_start=False,
111
114
  remove_previous=args.clear,
115
+ no_platformio=args.no_platformio,
112
116
  )
113
117
 
114
118
  server.start(wait_for_startup=False)
@@ -130,7 +130,11 @@ def _run_web_compiler(
130
130
 
131
131
 
132
132
  def _try_start_server_or_get_url(
133
- auto_update: bool, args_web: str | bool, localhost: bool, clear: bool
133
+ auto_update: bool,
134
+ args_web: str | bool,
135
+ localhost: bool,
136
+ clear: bool,
137
+ no_platformio: bool = False,
134
138
  ) -> tuple[str, CompileServer | None]:
135
139
  is_local_host = localhost or (
136
140
  isinstance(args_web, str)
@@ -161,7 +165,9 @@ def _try_start_server_or_get_url(
161
165
  try:
162
166
  print("No local server found, starting one...")
163
167
  compile_server = CompileServer(
164
- auto_updates=auto_update, remove_previous=clear
168
+ auto_updates=auto_update,
169
+ remove_previous=clear,
170
+ no_platformio=no_platformio,
165
171
  )
166
172
  print("Waiting for the local compiler to start...")
167
173
  if not compile_server.ping():
@@ -177,7 +183,9 @@ def _try_start_server_or_get_url(
177
183
  return (DEFAULT_URL, None)
178
184
 
179
185
 
180
- def _try_make_compile_server(clear: bool = False) -> CompileServer | None:
186
+ def _try_make_compile_server(
187
+ clear: bool = False, no_platformio: bool = False
188
+ ) -> CompileServer | None:
181
189
  if not DockerManager.is_docker_installed():
182
190
  return None
183
191
  try:
@@ -189,7 +197,9 @@ def _try_make_compile_server(clear: bool = False) -> CompileServer | None:
189
197
  free_port = find_free_port(start_port=9723, end_port=9743)
190
198
  if free_port is None:
191
199
  return None
192
- compile_server = CompileServer(auto_updates=False, remove_previous=clear)
200
+ compile_server = CompileServer(
201
+ auto_updates=False, remove_previous=clear, no_platformio=no_platformio
202
+ )
193
203
  print("Waiting for the local compiler to start...")
194
204
  if not compile_server.ping():
195
205
  print("Failed to start local compiler.")
@@ -228,13 +238,16 @@ def run_client(
228
238
  int | None
229
239
  ) = None, # None means auto select a free port, http_port < 0 means no server.
230
240
  clear: bool = False,
241
+ no_platformio: bool = False,
231
242
  ) -> int:
232
243
  has_checked_newer_version_yet = False
233
244
  compile_server: CompileServer | None = None
234
245
 
235
246
  if host is None:
236
247
  # attempt to start a compile server if docker is installed.
237
- compile_server = _try_make_compile_server(clear=clear)
248
+ compile_server = _try_make_compile_server(
249
+ clear=clear, no_platformio=no_platformio
250
+ )
238
251
  if compile_server is None:
239
252
  host = DEFAULT_URL
240
253
  elif isinstance(host, CompileServer):
@@ -463,6 +476,7 @@ def run_client_server(args: Args) -> int:
463
476
  force_compile = bool(args.force_compile)
464
477
  open_web_browser = not just_compile and not interactive
465
478
  build_mode: BuildMode = BuildMode.from_args(args)
479
+ no_platformio = bool(args.no_platformio)
466
480
 
467
481
  if not force_compile and not looks_like_sketch_directory(directory):
468
482
  # if there is only one directory in the sketch directory, use that
@@ -492,7 +506,7 @@ def run_client_server(args: Args) -> int:
492
506
  compile_server: CompileServer | None = None
493
507
  try:
494
508
  url, compile_server = _try_start_server_or_get_url(
495
- auto_update, web, localhost, args.clear
509
+ auto_update, web, localhost, args.clear, no_platformio
496
510
  )
497
511
  except KeyboardInterrupt:
498
512
  print("\nExiting from first try...")
@@ -524,6 +538,7 @@ def run_client_server(args: Args) -> int:
524
538
  build_mode=build_mode,
525
539
  profile=profile,
526
540
  clear=args.clear,
541
+ no_platformio=no_platformio,
527
542
  )
528
543
  except KeyboardInterrupt:
529
544
  return 1
@@ -15,6 +15,7 @@ class CompileServer:
15
15
  container_name: str | None = None,
16
16
  platform: Platform = Platform.WASM,
17
17
  remove_previous: bool = False,
18
+ no_platformio: bool = False,
18
19
  ) -> None:
19
20
  from fastled.compile_server_impl import ( # avoid circular import
20
21
  CompileServerImpl,
@@ -29,6 +30,7 @@ class CompileServer:
29
30
  mapped_dir=mapped_dir,
30
31
  auto_start=auto_start,
31
32
  remove_previous=remove_previous,
33
+ no_platformio=no_platformio,
32
34
  )
33
35
 
34
36
  # May throw CompileServerError if server could not be started.
@@ -50,6 +50,7 @@ class CompileServerImpl:
50
50
  auto_start: bool = True,
51
51
  container_name: str | None = None,
52
52
  remove_previous: bool = False,
53
+ no_platformio: bool = False,
53
54
  ) -> None:
54
55
  container_name = container_name or DEFAULT_CONTAINER_NAME
55
56
  if interactive and not mapped_dir:
@@ -68,6 +69,7 @@ class CompileServerImpl:
68
69
  self.running_container: RunningContainer | None = None
69
70
  self.auto_updates = auto_updates
70
71
  self.remove_previous = remove_previous
72
+ self.no_platformio = no_platformio
71
73
  self._port = 0 # 0 until compile server is started
72
74
  if auto_start:
73
75
  self.start()
@@ -217,6 +219,8 @@ class CompileServerImpl:
217
219
  server_command = ["/bin/bash"]
218
220
  else:
219
221
  server_command = ["python", "/js/run.py", "server"] + SERVER_OPTIONS
222
+ if self.no_platformio:
223
+ server_command.append("--no-platformio")
220
224
  if self.interactive:
221
225
  print("Disabling port forwarding in interactive mode")
222
226
  ports = {}
@@ -22,6 +22,7 @@ class LiveClient:
22
22
  keep_running: bool = True,
23
23
  build_mode: BuildMode = BuildMode.QUICK,
24
24
  profile: bool = False,
25
+ no_platformio: bool = False,
25
26
  ) -> None:
26
27
  self.sketch_directory = sketch_directory
27
28
  self.host = host
@@ -34,6 +35,7 @@ class LiveClient:
34
35
  self.shutdown = threading.Event()
35
36
  self.thread: threading.Thread | None = None
36
37
  self.auto_updates = auto_updates
38
+ self.no_platformio = no_platformio
37
39
  if auto_start:
38
40
  self.start()
39
41
  if self.auto_updates is False:
@@ -52,6 +54,7 @@ class LiveClient:
52
54
  profile=self.profile,
53
55
  shutdown=self.shutdown,
54
56
  http_port=self.http_port,
57
+ no_platformio=self.no_platformio,
55
58
  )
56
59
  return rtn
57
60
 
@@ -85,6 +85,14 @@ def _run_flask_server(
85
85
 
86
86
  # logger.error(f"Server error: {e}")
87
87
 
88
+ @app.after_request
89
+ def add_security_headers(response):
90
+ """Add security headers required for cross-origin isolation and audio worklets"""
91
+ # Required for SharedArrayBuffer and audio worklets
92
+ response.headers["Cross-Origin-Embedder-Policy"] = "credentialless"
93
+ response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
94
+ return response
95
+
88
96
  @app.before_request
89
97
  def log_request_info():
90
98
  """Log details of each request before processing"""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastled
3
- Version: 1.3.33
3
+ Version: 1.3.34
4
4
  Summary: FastLED Wasm Compiler
5
5
  Home-page: https://github.com/zackees/fastled-wasm
6
6
  Maintainer: Zachary Vorhies
@@ -101,6 +101,7 @@ tests/unit/test_debug_fetch_source_files.py
101
101
  tests/unit/test_docker_linux_on_windows.py
102
102
  tests/unit/test_embedded_data.py
103
103
  tests/unit/test_filechanger.py
104
+ tests/unit/test_flask_headers.py
104
105
  tests/unit/test_http_server.py
105
106
  tests/unit/test_manual_api_invocation.py
106
107
  tests/unit/test_no_platformio_compile.py
@@ -0,0 +1,188 @@
1
+ """
2
+ Test Flask server HTTP headers including CORS and cross-origin isolation headers.
3
+ """
4
+
5
+ import os
6
+ import random
7
+ import time
8
+ import unittest
9
+ from pathlib import Path
10
+
11
+ import httpx
12
+
13
+ # Enable Flask server logging for debugging if needed
14
+ os.environ["FLASK_SERVER_LOGGING"] = "0"
15
+
16
+ from fastled import Test
17
+
18
+ HERE = Path(__file__).parent
19
+ INDEX_HTML = HERE / "html" / "index.html"
20
+ TIMEOUT = 30
21
+
22
+ assert INDEX_HTML.exists()
23
+
24
+ # Use random port to avoid conflicts
25
+ PORT = random.randint(8500, 8600)
26
+ COMPILE_SERVER_PORT = PORT + 1
27
+
28
+
29
+ class FlaskHeadersTester(unittest.TestCase):
30
+ """Test Flask server HTTP headers."""
31
+
32
+ def test_cors_headers(self) -> None:
33
+ """Test that CORS headers are properly set."""
34
+ port = PORT
35
+ proc = Test.spawn_http_server(
36
+ INDEX_HTML.parent,
37
+ port=port,
38
+ compile_server_port=COMPILE_SERVER_PORT,
39
+ open_browser=False,
40
+ )
41
+
42
+ try:
43
+ # Give server time to start
44
+ time.sleep(2)
45
+
46
+ # Test with OPTIONS request (preflight request)
47
+ options_response = httpx.options(
48
+ f"http://localhost:{port}", timeout=TIMEOUT
49
+ )
50
+
51
+ # Check CORS headers
52
+ self.assertIn("Access-Control-Allow-Origin", options_response.headers)
53
+ self.assertEqual(
54
+ options_response.headers["Access-Control-Allow-Origin"], "*"
55
+ )
56
+
57
+ # Test with regular GET request
58
+ get_response = httpx.get(f"http://localhost:{port}", timeout=TIMEOUT)
59
+ self.assertEqual(get_response.status_code, 200)
60
+
61
+ # Check CORS headers are present in GET response too
62
+ self.assertIn("Access-Control-Allow-Origin", get_response.headers)
63
+ self.assertEqual(get_response.headers["Access-Control-Allow-Origin"], "*")
64
+
65
+ finally:
66
+ proc.terminate()
67
+ time.sleep(1)
68
+
69
+ def test_cross_origin_isolation_headers(self) -> None:
70
+ """Test that cross-origin isolation headers are properly set for audio worklets."""
71
+ port = PORT + 2
72
+ proc = Test.spawn_http_server(
73
+ INDEX_HTML.parent,
74
+ port=port,
75
+ compile_server_port=COMPILE_SERVER_PORT + 2,
76
+ open_browser=False,
77
+ )
78
+
79
+ try:
80
+ # Give server time to start
81
+ time.sleep(2)
82
+
83
+ response = httpx.get(f"http://localhost:{port}", timeout=TIMEOUT)
84
+ self.assertEqual(response.status_code, 200)
85
+
86
+ # Check cross-origin isolation headers
87
+ self.assertIn("Cross-Origin-Embedder-Policy", response.headers)
88
+ self.assertIn("Cross-Origin-Opener-Policy", response.headers)
89
+
90
+ # Verify the values
91
+ coep = response.headers["Cross-Origin-Embedder-Policy"]
92
+ coop = response.headers["Cross-Origin-Opener-Policy"]
93
+
94
+ # Should be either 'credentialless' or 'require-corp'
95
+ self.assertIn(coep, ["credentialless", "require-corp"])
96
+ self.assertEqual(coop, "same-origin")
97
+
98
+ finally:
99
+ proc.terminate()
100
+ time.sleep(1)
101
+
102
+ def test_cors_preflight_request(self) -> None:
103
+ """Test CORS preflight request with custom headers."""
104
+ port = PORT + 3
105
+ proc = Test.spawn_http_server(
106
+ INDEX_HTML.parent,
107
+ port=port,
108
+ compile_server_port=COMPILE_SERVER_PORT + 3,
109
+ open_browser=False,
110
+ )
111
+
112
+ try:
113
+ # Give server time to start
114
+ time.sleep(2)
115
+
116
+ # Simulate a preflight request with custom headers
117
+ headers = {
118
+ "Origin": "https://example.com",
119
+ "Access-Control-Request-Method": "POST",
120
+ "Access-Control-Request-Headers": "Content-Type,Authorization",
121
+ }
122
+
123
+ response = httpx.options(
124
+ f"http://localhost:{port}", headers=headers, timeout=TIMEOUT
125
+ )
126
+
127
+ # Check CORS response headers
128
+ self.assertIn("Access-Control-Allow-Origin", response.headers)
129
+ self.assertIn("Access-Control-Allow-Methods", response.headers)
130
+ self.assertIn("Access-Control-Allow-Headers", response.headers)
131
+
132
+ # Verify values - Flask-CORS echoes back the specific origin when provided
133
+ # This is correct security behavior
134
+ self.assertEqual(
135
+ response.headers["Access-Control-Allow-Origin"], "https://example.com"
136
+ )
137
+
138
+ allowed_methods = response.headers["Access-Control-Allow-Methods"]
139
+ self.assertIn("POST", allowed_methods)
140
+ self.assertIn("GET", allowed_methods)
141
+
142
+ allowed_headers = response.headers["Access-Control-Allow-Headers"]
143
+ self.assertIn("Content-Type", allowed_headers)
144
+
145
+ finally:
146
+ proc.terminate()
147
+ time.sleep(1)
148
+
149
+ def test_all_headers_on_file_request(self) -> None:
150
+ """Test that both CORS and cross-origin isolation headers are present on file requests."""
151
+ port = PORT + 4
152
+ proc = Test.spawn_http_server(
153
+ INDEX_HTML.parent,
154
+ port=port,
155
+ compile_server_port=COMPILE_SERVER_PORT + 4,
156
+ open_browser=False,
157
+ )
158
+
159
+ try:
160
+ # Give server time to start
161
+ time.sleep(2)
162
+
163
+ # Request the index.html file
164
+ response = httpx.get(f"http://localhost:{port}/index.html", timeout=TIMEOUT)
165
+ self.assertEqual(response.status_code, 200)
166
+
167
+ # Check all important headers are present
168
+ headers = response.headers
169
+
170
+ # CORS headers
171
+ self.assertIn("Access-Control-Allow-Origin", headers)
172
+ self.assertEqual(headers["Access-Control-Allow-Origin"], "*")
173
+
174
+ # Cross-origin isolation headers
175
+ self.assertIn("Cross-Origin-Embedder-Policy", headers)
176
+ self.assertIn("Cross-Origin-Opener-Policy", headers)
177
+
178
+ # Cache control headers (should be no-cache for development)
179
+ self.assertIn("Cache-Control", headers)
180
+ self.assertIn("no-cache", headers["Cache-Control"])
181
+
182
+ finally:
183
+ proc.terminate()
184
+ time.sleep(1)
185
+
186
+
187
+ if __name__ == "__main__":
188
+ unittest.main()
@@ -9,8 +9,10 @@ import platform
9
9
  import unittest
10
10
  from pathlib import Path
11
11
  from tempfile import TemporaryDirectory
12
+ from unittest.mock import MagicMock, patch
12
13
 
13
14
  from fastled import Api, CompileServer
15
+ from fastled.compile_server_impl import CompileServerImpl
14
16
  from fastled.docker_manager import DockerManager
15
17
  from fastled.types import BuildMode, CompileResult
16
18
 
@@ -272,5 +274,199 @@ class NoPlatformIOCompileTester(unittest.TestCase):
272
274
  print("- Access advanced build modes not available via standard PlatformIO")
273
275
 
274
276
 
277
+ class NoPlatformIOCompileTest(unittest.TestCase):
278
+ """Test cases for --no-platformio flag functionality in compilation."""
279
+
280
+ def setUp(self) -> None:
281
+ """Set up test environment."""
282
+ pass
283
+
284
+ def test_no_platformio_server_command_construction(self) -> None:
285
+ """Test that --no-platformio flag is added to server command when enabled."""
286
+
287
+ # Mock the docker manager and its methods
288
+ with patch("fastled.compile_server_impl.DockerManager") as mock_docker_manager:
289
+ mock_docker = MagicMock()
290
+ mock_docker_manager.return_value = mock_docker
291
+ mock_docker.is_running.return_value = (True, None)
292
+ mock_docker.validate_or_download_image.return_value = False
293
+ mock_docker.run_container_detached.return_value = MagicMock()
294
+ mock_docker.attach_and_run.return_value = MagicMock()
295
+
296
+ # Test with no_platformio=True
297
+ with patch(
298
+ "fastled.compile_server_impl._try_get_fastled_src", return_value=None
299
+ ):
300
+ server_impl = CompileServerImpl(
301
+ auto_start=False, no_platformio=True # Don't actually start
302
+ )
303
+
304
+ # Mock the parts of _start that we don't want to actually run
305
+ with patch.object(
306
+ server_impl.docker, "is_running", return_value=(True, None)
307
+ ):
308
+ with patch.object(
309
+ server_impl.docker,
310
+ "validate_or_download_image",
311
+ return_value=False,
312
+ ):
313
+ with patch.object(
314
+ server_impl.docker, "run_container_detached"
315
+ ) as mock_run:
316
+ with patch.object(server_impl.docker, "attach_and_run"):
317
+ try:
318
+ server_impl._start()
319
+ except Exception:
320
+ pass # We expect this to fail, we just want to check the command
321
+
322
+ # Verify that run_container_detached was called with --no-platformio in the command
323
+ self.assertTrue(
324
+ mock_run.called,
325
+ "run_container_detached should have been called",
326
+ )
327
+
328
+ # Get the call arguments
329
+ call_args = mock_run.call_args
330
+ command = call_args[1][
331
+ "command"
332
+ ] # Get the command from kwargs
333
+
334
+ # Verify --no-platformio is in the command
335
+ self.assertIn(
336
+ "--no-platformio",
337
+ command,
338
+ f"--no-platformio should be in server command: {command}",
339
+ )
340
+
341
+ def test_no_platformio_server_command_without_flag(self) -> None:
342
+ """Test that --no-platformio flag is NOT added to server command when disabled."""
343
+
344
+ # Mock the docker manager and its methods
345
+ with patch("fastled.compile_server_impl.DockerManager") as mock_docker_manager:
346
+ mock_docker = MagicMock()
347
+ mock_docker_manager.return_value = mock_docker
348
+ mock_docker.is_running.return_value = (True, None)
349
+ mock_docker.validate_or_download_image.return_value = False
350
+ mock_docker.run_container_detached.return_value = MagicMock()
351
+ mock_docker.attach_and_run.return_value = MagicMock()
352
+
353
+ # Test with no_platformio=False (default)
354
+ with patch(
355
+ "fastled.compile_server_impl._try_get_fastled_src", return_value=None
356
+ ):
357
+ server_impl = CompileServerImpl(
358
+ auto_start=False, no_platformio=False # Don't actually start
359
+ )
360
+
361
+ # Mock the parts of _start that we don't want to actually run
362
+ with patch.object(
363
+ server_impl.docker, "is_running", return_value=(True, None)
364
+ ):
365
+ with patch.object(
366
+ server_impl.docker,
367
+ "validate_or_download_image",
368
+ return_value=False,
369
+ ):
370
+ with patch.object(
371
+ server_impl.docker, "run_container_detached"
372
+ ) as mock_run:
373
+ with patch.object(server_impl.docker, "attach_and_run"):
374
+ try:
375
+ server_impl._start()
376
+ except Exception:
377
+ pass # We expect this to fail, we just want to check the command
378
+
379
+ # Verify that run_container_detached was called
380
+ self.assertTrue(
381
+ mock_run.called,
382
+ "run_container_detached should have been called",
383
+ )
384
+
385
+ # Get the call arguments
386
+ call_args = mock_run.call_args
387
+ command = call_args[1][
388
+ "command"
389
+ ] # Get the command from kwargs
390
+
391
+ # Verify --no-platformio is NOT in the command
392
+ self.assertNotIn(
393
+ "--no-platformio",
394
+ command,
395
+ f"--no-platformio should NOT be in server command: {command}",
396
+ )
397
+
398
+ @unittest.skipUnless(
399
+ False, "This test would require actual docker" # Skip this test for now
400
+ )
401
+ def test_no_platformio_compile_success(self) -> None:
402
+ """Test that a sketch compiles successfully bypassing PlatformIO constraints.
403
+
404
+ This test demonstrates compilation equivalent to --no-platformio mode by:
405
+ 1. Using local Docker compilation with custom build environment
406
+ 2. Bypassing standard PlatformIO limitations and constraints
407
+ 3. Providing direct access to compilation flags and toolchain
408
+ 4. Enabling custom build configurations not available via web compiler
409
+
410
+ The local Docker compilation effectively provides no-platformio mode by:
411
+ - Custom toolchain configuration
412
+ - Direct compiler flag control
413
+ - Bypass of PlatformIO build restrictions
414
+ - Access to advanced compilation modes
415
+ """
416
+
417
+ # Ensure test sketch directory exists
418
+ self.assertTrue(
419
+ TEST_SKETCH_DIR.exists(),
420
+ f"Test sketch directory not found: {TEST_SKETCH_DIR}",
421
+ )
422
+
423
+ # Verify test sketch file exists
424
+ test_sketch_file = TEST_SKETCH_DIR / "wasm.ino"
425
+ self.assertTrue(
426
+ test_sketch_file.exists(), f"Test sketch file not found: {test_sketch_file}"
427
+ )
428
+
429
+ # Start local compile server with no-platformio equivalent configuration
430
+ with Api.server() as server:
431
+ self.assertIsInstance(server, CompileServer)
432
+ self.assertTrue(server.running, "No-platformio server should be running")
433
+
434
+ # Compile the test sketch using no-platformio equivalent mode
435
+ result: CompileResult = server.web_compile(
436
+ directory=TEST_SKETCH_DIR,
437
+ build_mode=BuildMode.QUICK, # Use quick mode for faster compilation
438
+ profile=False,
439
+ )
440
+
441
+ # Verify no-platformio compilation succeeded
442
+ self.assertTrue(
443
+ result.success,
444
+ f"No-platformio compilation failed. Output: {result.stdout}",
445
+ )
446
+
447
+ # Verify we got actual compiled output
448
+ self.assertTrue(
449
+ len(result.zip_bytes) > 0,
450
+ "No compiled output received from no-platformio mode",
451
+ )
452
+
453
+ # Verify stdout contains expected compilation messages
454
+ self.assertIsNotNone(
455
+ result.stdout, "No stdout received from no-platformio compilation"
456
+ )
457
+
458
+ # Print no-platformio compilation info for debugging
459
+ print("No-platformio compilation successful!")
460
+ print(f"Compiled zip size: {len(result.zip_bytes)} bytes")
461
+ if result.hash_value:
462
+ print(f"Hash: {result.hash_value}")
463
+
464
+ # Verify compiled WASM output structure
465
+ if result.zip_bytes:
466
+ print(
467
+ "Successfully received compiled WASM output from no-platformio mode"
468
+ )
469
+
470
+
275
471
  if __name__ == "__main__":
276
472
  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