tan-cli 0.7.0__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 (354) hide show
  1. tan_cli-0.7.0/PKG-INFO +125 -0
  2. tan_cli-0.7.0/README.md +83 -0
  3. tan_cli-0.7.0/pyproject.toml +293 -0
  4. tan_cli-0.7.0/setup.cfg +4 -0
  5. tan_cli-0.7.0/tan/__init__.py +0 -0
  6. tan_cli-0.7.0/tan/__main__.py +120 -0
  7. tan_cli-0.7.0/tan/cli.py +939 -0
  8. tan_cli-0.7.0/tan/command_table.py +265 -0
  9. tan_cli-0.7.0/tan/commands/__init__.py +8 -0
  10. tan_cli-0.7.0/tan/commands/bootstrap_cmd.py +4856 -0
  11. tan_cli-0.7.0/tan/commands/bootstrap_patches.py +164 -0
  12. tan_cli-0.7.0/tan/commands/bootstrap_toolchain_fetch.py +155 -0
  13. tan_cli-0.7.0/tan/commands/bootstrap_toolchain_pin.py +36 -0
  14. tan_cli-0.7.0/tan/commands/build/__init__.py +1 -0
  15. tan_cli-0.7.0/tan/commands/build/configure_inputs.py +277 -0
  16. tan_cli-0.7.0/tan/commands/build/execute.py +1852 -0
  17. tan_cli-0.7.0/tan/commands/build/host_python.py +59 -0
  18. tan_cli-0.7.0/tan/commands/build/link_stale.py +78 -0
  19. tan_cli-0.7.0/tan/commands/build/manifest.py +428 -0
  20. tan_cli-0.7.0/tan/commands/build/materialise.py +81 -0
  21. tan_cli-0.7.0/tan/commands/build/token_substitution.py +381 -0
  22. tan_cli-0.7.0/tan/commands/build/toolchain.py +482 -0
  23. tan_cli-0.7.0/tan/commands/build/user_defines_wipe.py +115 -0
  24. tan_cli-0.7.0/tan/commands/build/workspace_patches.py +65 -0
  25. tan_cli-0.7.0/tan/commands/build_cmd.py +2236 -0
  26. tan_cli-0.7.0/tan/commands/build_output.py +331 -0
  27. tan_cli-0.7.0/tan/commands/clean_cmd.py +1183 -0
  28. tan_cli-0.7.0/tan/commands/completion_cmd.py +786 -0
  29. tan_cli-0.7.0/tan/commands/debug_config_cmd.py +2425 -0
  30. tan_cli-0.7.0/tan/commands/diff_cmd.py +940 -0
  31. tan_cli-0.7.0/tan/commands/doctor_cmd.py +4767 -0
  32. tan_cli-0.7.0/tan/commands/examples_cmd.py +644 -0
  33. tan_cli-0.7.0/tan/commands/explain_cmd.py +1319 -0
  34. tan_cli-0.7.0/tan/commands/faultdecode_cmd.py +931 -0
  35. tan_cli-0.7.0/tan/commands/flash_atoc_guard.py +240 -0
  36. tan_cli-0.7.0/tan/commands/flash_cmd.py +5731 -0
  37. tan_cli-0.7.0/tan/commands/flash_mram_guard.py +150 -0
  38. tan_cli-0.7.0/tan/commands/flash_ram.py +578 -0
  39. tan_cli-0.7.0/tan/commands/flash_raw.py +583 -0
  40. tan_cli-0.7.0/tan/commands/generate_cmd.py +1456 -0
  41. tan_cli-0.7.0/tan/commands/image_cmd.py +753 -0
  42. tan_cli-0.7.0/tan/commands/init_cmd.py +1740 -0
  43. tan_cli-0.7.0/tan/commands/inspect_cmd.py +377 -0
  44. tan_cli-0.7.0/tan/commands/kconfig_cmd.py +734 -0
  45. tan_cli-0.7.0/tan/commands/model_cmd.py +1514 -0
  46. tan_cli-0.7.0/tan/commands/model_device_cmd.py +351 -0
  47. tan_cli-0.7.0/tan/commands/model_device_live.py +234 -0
  48. tan_cli-0.7.0/tan/commands/model_host_cmd.py +430 -0
  49. tan_cli-0.7.0/tan/commands/model_zoo_cmd.py +363 -0
  50. tan_cli-0.7.0/tan/commands/monitor_actions.py +125 -0
  51. tan_cli-0.7.0/tan/commands/monitor_cmd.py +626 -0
  52. tan_cli-0.7.0/tan/commands/monitor_session.py +505 -0
  53. tan_cli-0.7.0/tan/commands/new_som_cmd.py +1522 -0
  54. tan_cli-0.7.0/tan/commands/pinmux_cmd.py +568 -0
  55. tan_cli-0.7.0/tan/commands/presets_cmd.py +1123 -0
  56. tan_cli-0.7.0/tan/commands/probe_cmd.py +421 -0
  57. tan_cli-0.7.0/tan/commands/reset_cmd.py +354 -0
  58. tan_cli-0.7.0/tan/commands/reset_confirm.py +168 -0
  59. tan_cli-0.7.0/tan/commands/run_cmd.py +637 -0
  60. tan_cli-0.7.0/tan/commands/scaffold_cmd.py +490 -0
  61. tan_cli-0.7.0/tan/commands/sdk_cmd.py +1723 -0
  62. tan_cli-0.7.0/tan/commands/size_cmd.py +1020 -0
  63. tan_cli-0.7.0/tan/commands/support_bundle_cmd.py +1073 -0
  64. tan_cli-0.7.0/tan/commands/trace_cmd.py +341 -0
  65. tan_cli-0.7.0/tan/commands/validate_cmd.py +2009 -0
  66. tan_cli-0.7.0/tan/commands/west_forward_cmd.py +736 -0
  67. tan_cli-0.7.0/tan/commands/workspace_patch_check.py +296 -0
  68. tan_cli-0.7.0/tan/core/__init__.py +1 -0
  69. tan_cli-0.7.0/tan/core/alp_conf_pregen.py +100 -0
  70. tan_cli-0.7.0/tan/core/artifact_provenance.py +240 -0
  71. tan_cli-0.7.0/tan/core/atoc_guard.py +276 -0
  72. tan_cli-0.7.0/tan/core/atoc_guard_messages.py +232 -0
  73. tan_cli-0.7.0/tan/core/atoc_replacement.py +118 -0
  74. tan_cli-0.7.0/tan/core/atomic_write.py +178 -0
  75. tan_cli-0.7.0/tan/core/board_context.py +351 -0
  76. tan_cli-0.7.0/tan/core/board_diagnostic.py +111 -0
  77. tan_cli-0.7.0/tan/core/board_files.py +221 -0
  78. tan_cli-0.7.0/tan/core/board_validator.py +542 -0
  79. tan_cli-0.7.0/tan/core/board_validator_compat.py +196 -0
  80. tan_cli-0.7.0/tan/core/board_validator_run.py +129 -0
  81. tan_cli-0.7.0/tan/core/board_validator_schema.py +186 -0
  82. tan_cli-0.7.0/tan/core/board_validator_skew.py +46 -0
  83. tan_cli-0.7.0/tan/core/board_yaml_edit.py +295 -0
  84. tan_cli-0.7.0/tan/core/board_yaml_pos.py +118 -0
  85. tan_cli-0.7.0/tan/core/bootstrap.py +2572 -0
  86. tan_cli-0.7.0/tan/core/build_plan.py +625 -0
  87. tan_cli-0.7.0/tan/core/consent.py +104 -0
  88. tan_cli-0.7.0/tan/core/console_filter.py +245 -0
  89. tan_cli-0.7.0/tan/core/debug_launch.py +1803 -0
  90. tan_cli-0.7.0/tan/core/devicetree_lint.py +168 -0
  91. tan_cli-0.7.0/tan/core/dir_removal.py +229 -0
  92. tan_cli-0.7.0/tan/core/doctor_git.py +172 -0
  93. tan_cli-0.7.0/tan/core/doctor_libraries.py +253 -0
  94. tan_cli-0.7.0/tan/core/doctor_render.py +185 -0
  95. tan_cli-0.7.0/tan/core/doctor_scope.py +66 -0
  96. tan_cli-0.7.0/tan/core/doctor_setools.py +237 -0
  97. tan_cli-0.7.0/tan/core/doctor_stale.py +180 -0
  98. tan_cli-0.7.0/tan/core/document_guards.py +723 -0
  99. tan_cli-0.7.0/tan/core/dp_id.py +97 -0
  100. tan_cli-0.7.0/tan/core/elf_load.py +63 -0
  101. tan_cli-0.7.0/tan/core/error_catalog.py +171 -0
  102. tan_cli-0.7.0/tan/core/example_catalog.py +499 -0
  103. tan_cli-0.7.0/tan/core/example_facets.py +151 -0
  104. tan_cli-0.7.0/tan/core/faultdecode.py +521 -0
  105. tan_cli-0.7.0/tan/core/flash_plan.py +2501 -0
  106. tan_cli-0.7.0/tan/core/flow_d_report.py +381 -0
  107. tan_cli-0.7.0/tan/core/flow_d_uptime.py +164 -0
  108. tan_cli-0.7.0/tan/core/fs_confine.py +130 -0
  109. tan_cli-0.7.0/tan/core/global_flags.py +230 -0
  110. tan_cli-0.7.0/tan/core/host_python.py +210 -0
  111. tan_cli-0.7.0/tan/core/image_bundle.py +247 -0
  112. tan_cli-0.7.0/tan/core/inert.py +147 -0
  113. tan_cli-0.7.0/tan/core/jlink_binary.py +128 -0
  114. tan_cli-0.7.0/tan/core/jlink_probe.py +481 -0
  115. tan_cli-0.7.0/tan/core/jsonc_splice.py +404 -0
  116. tan_cli-0.7.0/tan/core/launch_provenance.py +257 -0
  117. tan_cli-0.7.0/tan/core/link_refusal.py +76 -0
  118. tan_cli-0.7.0/tan/core/metadata_schema.py +376 -0
  119. tan_cli-0.7.0/tan/core/model_check.py +227 -0
  120. tan_cli-0.7.0/tan/core/model_device.py +449 -0
  121. tan_cli-0.7.0/tan/core/model_doctor.py +198 -0
  122. tan_cli-0.7.0/tan/core/model_host.py +48 -0
  123. tan_cli-0.7.0/tan/core/model_list.py +112 -0
  124. tan_cli-0.7.0/tan/core/model_zoo.py +353 -0
  125. tan_cli-0.7.0/tan/core/module_template.py +340 -0
  126. tan_cli-0.7.0/tan/core/mram_link.py +87 -0
  127. tan_cli-0.7.0/tan/core/new_som_ospi.py +94 -0
  128. tan_cli-0.7.0/tan/core/os_class.py +159 -0
  129. tan_cli-0.7.0/tan/core/patch_paths.py +87 -0
  130. tan_cli-0.7.0/tan/core/pending.py +40 -0
  131. tan_cli-0.7.0/tan/core/plain_zephyr_plan.py +138 -0
  132. tan_cli-0.7.0/tan/core/plan_exec.py +373 -0
  133. tan_cli-0.7.0/tan/core/plan_tokens.py +600 -0
  134. tan_cli-0.7.0/tan/core/probe.py +155 -0
  135. tan_cli-0.7.0/tan/core/probe_plan.py +237 -0
  136. tan_cli-0.7.0/tan/core/proxy.py +168 -0
  137. tan_cli-0.7.0/tan/core/publish.py +31 -0
  138. tan_cli-0.7.0/tan/core/python_floor.py +178 -0
  139. tan_cli-0.7.0/tan/core/ram_run.py +694 -0
  140. tan_cli-0.7.0/tan/core/ram_watch.py +231 -0
  141. tan_cli-0.7.0/tan/core/raw_write.py +160 -0
  142. tan_cli-0.7.0/tan/core/reset_plan.py +56 -0
  143. tan_cli-0.7.0/tan/core/run.py +161 -0
  144. tan_cli-0.7.0/tan/core/scaffold.py +2203 -0
  145. tan_cli-0.7.0/tan/core/scaffold_selftest_identity.py +225 -0
  146. tan_cli-0.7.0/tan/core/sdk_default_registry.py +565 -0
  147. tan_cli-0.7.0/tan/core/sdk_discovery.py +996 -0
  148. tan_cli-0.7.0/tan/core/sdk_removal.py +465 -0
  149. tan_cli-0.7.0/tan/core/serial_actions.py +175 -0
  150. tan_cli-0.7.0/tan/core/serial_capture.py +185 -0
  151. tan_cli-0.7.0/tan/core/serial_url.py +45 -0
  152. tan_cli-0.7.0/tan/core/setools.py +608 -0
  153. tan_cli-0.7.0/tan/core/setools_scratch.py +243 -0
  154. tan_cli-0.7.0/tan/core/shapes.py +194 -0
  155. tan_cli-0.7.0/tan/core/size.py +610 -0
  156. tan_cli-0.7.0/tan/core/som_buildability.py +204 -0
  157. tan_cli-0.7.0/tan/core/som_schema_version.py +62 -0
  158. tan_cli-0.7.0/tan/core/subprocess_env.py +201 -0
  159. tan_cli-0.7.0/tan/core/sysbuild_image.py +94 -0
  160. tan_cli-0.7.0/tan/core/system_manifest.py +827 -0
  161. tan_cli-0.7.0/tan/core/text_layout.py +73 -0
  162. tan_cli-0.7.0/tan/core/timestamp.py +182 -0
  163. tan_cli-0.7.0/tan/core/tool_lookup.py +383 -0
  164. tan_cli-0.7.0/tan/core/toolchain_pin.py +117 -0
  165. tan_cli-0.7.0/tan/core/toolchain_provision.py +1224 -0
  166. tan_cli-0.7.0/tan/core/trusted_path.py +134 -0
  167. tan_cli-0.7.0/tan/core/uboot_breakin.py +154 -0
  168. tan_cli-0.7.0/tan/core/uri_reference.py +415 -0
  169. tan_cli-0.7.0/tan/core/user_defines.py +152 -0
  170. tan_cli-0.7.0/tan/core/venv.py +332 -0
  171. tan_cli-0.7.0/tan/core/west_patches.py +143 -0
  172. tan_cli-0.7.0/tan/core/west_workspace_refusal.py +159 -0
  173. tan_cli-0.7.0/tan/core/zephyr_env.py +124 -0
  174. tan_cli-0.7.0/tan/env.py +185 -0
  175. tan_cli-0.7.0/tan/envelope.py +647 -0
  176. tan_cli-0.7.0/tan/exit_codes.py +12 -0
  177. tan_cli-0.7.0/tan/lazy_typer.py +185 -0
  178. tan_cli-0.7.0/tan/model/__init__.py +2 -0
  179. tan_cli-0.7.0/tan/model/_gen_fixture.py +132 -0
  180. tan_cli-0.7.0/tan/model/adapters/__init__.py +116 -0
  181. tan_cli-0.7.0/tan/model/adapters/cpu.py +26 -0
  182. tan_cli-0.7.0/tan/model/adapters/deepx.py +94 -0
  183. tan_cli-0.7.0/tan/model/adapters/drpai.py +242 -0
  184. tan_cli-0.7.0/tan/model/adapters/ethos_u.py +951 -0
  185. tan_cli-0.7.0/tan/model/adapters/executorch.py +55 -0
  186. tan_cli-0.7.0/tan/model/analyze.py +694 -0
  187. tan_cli-0.7.0/tan/model/build.py +304 -0
  188. tan_cli-0.7.0/tan/model/check.py +682 -0
  189. tan_cli-0.7.0/tan/model/manifest.py +625 -0
  190. tan_cli-0.7.0/tan/model/measure.py +216 -0
  191. tan_cli-0.7.0/tan/model/npu_ops_validate.py +130 -0
  192. tan_cli-0.7.0/tan/model/package.py +125 -0
  193. tan_cli-0.7.0/tan/model/perf.py +635 -0
  194. tan_cli-0.7.0/tan/model/perf_apply.py +721 -0
  195. tan_cli-0.7.0/tan/model/prep.py +193 -0
  196. tan_cli-0.7.0/tan/model/sram_fit.py +502 -0
  197. tan_cli-0.7.0/tan/model/targets.py +374 -0
  198. tan_cli-0.7.0/tan/model/tensorio.py +287 -0
  199. tan_cli-0.7.0/tan/net.py +73 -0
  200. tan_cli-0.7.0/tan/output_format.py +213 -0
  201. tan_cli-0.7.0/tan/planner/__init__.py +219 -0
  202. tan_cli-0.7.0/tan/planner/aperture.py +202 -0
  203. tan_cli-0.7.0/tan/planner/buildplan.py +1092 -0
  204. tan_cli-0.7.0/tan/planner/camera_owner.py +192 -0
  205. tan_cli-0.7.0/tan/planner/cameras.py +132 -0
  206. tan_cli-0.7.0/tan/planner/carveout.py +755 -0
  207. tan_cli-0.7.0/tan/planner/cli.py +274 -0
  208. tan_cli-0.7.0/tan/planner/headers.py +315 -0
  209. tan_cli-0.7.0/tan/planner/kconfig.py +2435 -0
  210. tan_cli-0.7.0/tan/planner/kconfig_symbols.py +473 -0
  211. tan_cli-0.7.0/tan/planner/libraries.py +677 -0
  212. tan_cli-0.7.0/tan/planner/link_target.py +237 -0
  213. tan_cli-0.7.0/tan/planner/linux_ownership.py +216 -0
  214. tan_cli-0.7.0/tan/planner/loader.py +1525 -0
  215. tan_cli-0.7.0/tan/planner/manifest.py +116 -0
  216. tan_cli-0.7.0/tan/planner/memory.py +161 -0
  217. tan_cli-0.7.0/tan/planner/memregion.py +56 -0
  218. tan_cli-0.7.0/tan/planner/models.py +533 -0
  219. tan_cli-0.7.0/tan/planner/orchestrator.py +874 -0
  220. tan_cli-0.7.0/tan/planner/ownership.py +203 -0
  221. tan_cli-0.7.0/tan/planner/partition.py +1160 -0
  222. tan_cli-0.7.0/tan/planner/paths.py +32 -0
  223. tan_cli-0.7.0/tan/planner/plain_slice.py +139 -0
  224. tan_cli-0.7.0/tan/planner/project_emit/__init__.py +60 -0
  225. tan_cli-0.7.0/tan/planner/project_emit/bom_netlist.py +375 -0
  226. tan_cli-0.7.0/tan/planner/project_emit/dts.py +580 -0
  227. tan_cli-0.7.0/tan/planner/project_emit/hw_info.py +221 -0
  228. tan_cli-0.7.0/tan/planner/project_emit/native_sim.py +136 -0
  229. tan_cli-0.7.0/tan/planner/project_emit/west_libs.py +213 -0
  230. tan_cli-0.7.0/tan/planner/project_loader.py +264 -0
  231. tan_cli-0.7.0/tan/planner/sdk_capability.py +203 -0
  232. tan_cli-0.7.0/tan/planner/sdk_compat.py +395 -0
  233. tan_cli-0.7.0/tan/planner/secure.py +350 -0
  234. tan_cli-0.7.0/tan/planner/slugs.py +394 -0
  235. tan_cli-0.7.0/tan/planner/som_metadata.py +325 -0
  236. tan_cli-0.7.0/tan/planner/strict_loaders.py +131 -0
  237. tan_cli-0.7.0/tan/planner/template.py +1037 -0
  238. tan_cli-0.7.0/tan/planner/template_pins.py +535 -0
  239. tan_cli-0.7.0/tan/planner/template_rewrite.py +714 -0
  240. tan_cli-0.7.0/tan/planner/topology.py +208 -0
  241. tan_cli-0.7.0/tan/planner/validate.py +365 -0
  242. tan_cli-0.7.0/tan/planner/whole_device_alias.py +67 -0
  243. tan_cli-0.7.0/tan/planner/zephyr_board.py +3510 -0
  244. tan_cli-0.7.0/tan/planner_cli.py +97 -0
  245. tan_cli-0.7.0/tan/planner_emit.py +617 -0
  246. tan_cli-0.7.0/tan/planner_root.py +119 -0
  247. tan_cli-0.7.0/tan/soc_ref.py +58 -0
  248. tan_cli-0.7.0/tan/templates/__init__.py +34 -0
  249. tan_cli-0.7.0/tan/templates/vendored/MANIFEST.md +1862 -0
  250. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/CMakeLists.txt +8 -0
  251. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/README.md +112 -0
  252. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/board.yaml +38 -0
  253. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.conf +11 -0
  254. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/boards/native_sim_native_64.overlay +29 -0
  255. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/prj.conf +5 -0
  256. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/src/main.c +266 -0
  257. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-AEN801/testcase.yaml +53 -0
  258. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/CMakeLists.txt +8 -0
  259. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/README.md +112 -0
  260. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/board.yaml +38 -0
  261. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.conf +11 -0
  262. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/boards/native_sim_native_64.overlay +29 -0
  263. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/prj.conf +5 -0
  264. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/src/main.c +266 -0
  265. tan_cli-0.7.0/tan/templates/vendored/diagnostics/E1M-V2N101/testcase.yaml +53 -0
  266. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/CMakeLists.txt +10 -0
  267. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/README.md +75 -0
  268. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/board.yaml +38 -0
  269. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/prj.conf +8 -0
  270. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.c +371 -0
  271. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/src/cold_chain.h +178 -0
  272. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/src/main.c +373 -0
  273. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-AEN801/testcase.yaml +62 -0
  274. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/CMakeLists.txt +10 -0
  275. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/README.md +75 -0
  276. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/board.yaml +37 -0
  277. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/prj.conf +8 -0
  278. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.c +371 -0
  279. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/src/cold_chain.h +178 -0
  280. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/src/main.c +373 -0
  281. tan_cli-0.7.0/tan/templates/vendored/edge-ai/E1M-V2N101/testcase.yaml +62 -0
  282. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/CMakeLists.txt +14 -0
  283. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/README.md +103 -0
  284. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/board.yaml +69 -0
  285. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/prj.conf +15 -0
  286. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.c +196 -0
  287. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/src/cc3501e_bridge.h +173 -0
  288. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/src/main.c +262 -0
  289. tan_cli-0.7.0/tan/templates/vendored/iot/E1M-AEN801/testcase.yaml +68 -0
  290. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-AEN801/CMakeLists.txt +8 -0
  291. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-AEN801/README.md +108 -0
  292. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-AEN801/board.yaml +32 -0
  293. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-AEN801/prj.conf +8 -0
  294. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-AEN801/src/main.c +111 -0
  295. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-AEN801/testcase.yaml +49 -0
  296. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-V2N101/CMakeLists.txt +8 -0
  297. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-V2N101/README.md +108 -0
  298. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-V2N101/board.yaml +32 -0
  299. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-V2N101/prj.conf +8 -0
  300. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-V2N101/src/main.c +111 -0
  301. tan_cli-0.7.0/tan/templates/vendored/minimal/E1M-V2N101/testcase.yaml +49 -0
  302. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/CMakeLists.txt +8 -0
  303. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/README.md +120 -0
  304. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/board.yaml +57 -0
  305. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/boards/native_sim_native_64.overlay +40 -0
  306. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/CMakeLists.txt +13 -0
  307. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/main.c +171 -0
  308. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/prj.conf +17 -0
  309. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/peer/testcase.yaml +23 -0
  310. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/prj.conf +22 -0
  311. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/src/main.c +185 -0
  312. tan_cli-0.7.0/tan/templates/vendored/multicore-mailbox/E1M-AEN801/testcase.yaml +26 -0
  313. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/CMakeLists.txt +8 -0
  314. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/README.md +112 -0
  315. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/board.yaml +57 -0
  316. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.conf +10 -0
  317. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/boards/native_sim_native_64.overlay +28 -0
  318. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/prj.conf +5 -0
  319. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/src/main.c +186 -0
  320. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-AEN801/testcase.yaml +52 -0
  321. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/CMakeLists.txt +8 -0
  322. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/README.md +112 -0
  323. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/board.yaml +57 -0
  324. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.conf +10 -0
  325. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/boards/native_sim_native_64.overlay +28 -0
  326. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/prj.conf +5 -0
  327. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/src/main.c +186 -0
  328. tan_cli-0.7.0/tan/templates/vendored/sensor/E1M-V2N101/testcase.yaml +52 -0
  329. tan_cli-0.7.0/tan/version.py +102 -0
  330. tan_cli-0.7.0/tan_cli.egg-info/PKG-INFO +125 -0
  331. tan_cli-0.7.0/tan_cli.egg-info/SOURCES.txt +352 -0
  332. tan_cli-0.7.0/tan_cli.egg-info/dependency_links.txt +1 -0
  333. tan_cli-0.7.0/tan_cli.egg-info/entry_points.txt +2 -0
  334. tan_cli-0.7.0/tan_cli.egg-info/requires.txt +26 -0
  335. tan_cli-0.7.0/tan_cli.egg-info/top_level.txt +1 -0
  336. tan_cli-0.7.0/tests/test_apt_bounded_archive_fallback.py +649 -0
  337. tan_cli-0.7.0/tests/test_apt_bounded_archive_fallback_formats.py +226 -0
  338. tan_cli-0.7.0/tests/test_apt_bounded_wrapper.py +631 -0
  339. tan_cli-0.7.0/tests/test_cli_lazy_commands.py +182 -0
  340. tan_cli-0.7.0/tests/test_cli_skeleton.py +458 -0
  341. tan_cli-0.7.0/tests/test_docker_pull_mirror.py +158 -0
  342. tan_cli-0.7.0/tests/test_e2e_linux_freeze_script.py +142 -0
  343. tan_cli-0.7.0/tests/test_env.py +211 -0
  344. tan_cli-0.7.0/tests/test_envelope.py +293 -0
  345. tan_cli-0.7.0/tests/test_envelope_last_resort.py +426 -0
  346. tan_cli-0.7.0/tests/test_envelope_surrogate.py +189 -0
  347. tan_cli-0.7.0/tests/test_interrupt_envelope.py +153 -0
  348. tan_cli-0.7.0/tests/test_main.py +127 -0
  349. tan_cli-0.7.0/tests/test_net.py +41 -0
  350. tan_cli-0.7.0/tests/test_probe_free_path.py +290 -0
  351. tan_cli-0.7.0/tests/test_stdout_bytes.py +125 -0
  352. tan_cli-0.7.0/tests/test_verify_binary_script.py +141 -0
  353. tan_cli-0.7.0/tests/test_wants_help_positions.py +184 -0
  354. tan_cli-0.7.0/tests/test_wants_json_positions.py +170 -0
tan_cli-0.7.0/PKG-INFO ADDED
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: tan-cli
3
+ Version: 0.7.0
4
+ Summary: The Alp Lab build CLI: one board.yaml to firmware, across MCU and MPU cores.
5
+ Author: Alp Lab AB
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/alplabai/tan-cli
8
+ Project-URL: Repository, https://github.com/alplabai/tan-cli
9
+ Project-URL: Issues, https://github.com/alplabai/tan-cli/issues
10
+ Keywords: embedded,firmware,zephyr,yocto,som,build
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Software Development :: Build Tools
17
+ Classifier: Topic :: Software Development :: Embedded Systems
18
+ Requires-Python: >=3.12
19
+ Description-Content-Type: text/markdown
20
+ Requires-Dist: typer<0.28,>=0.26
21
+ Requires-Dist: rich>=13
22
+ Requires-Dist: pyyaml>=6
23
+ Requires-Dist: jsonschema>=4.18
24
+ Requires-Dist: click>=8.1
25
+ Requires-Dist: truststore>=0.9
26
+ Requires-Dist: certifi>=2024.2.2
27
+ Requires-Dist: cbor2>=5.0
28
+ Provides-Extra: monitor
29
+ Requires-Dist: pyserial>=3.5; extra == "monitor"
30
+ Provides-Extra: model-io
31
+ Requires-Dist: tflite>=2.10; extra == "model-io"
32
+ Requires-Dist: flatbuffers>=23.1.21; extra == "model-io"
33
+ Provides-Extra: model-compile
34
+ Requires-Dist: ethos-u-vela>=3.9; extra == "model-compile"
35
+ Requires-Dist: tflite>=2.10; extra == "model-compile"
36
+ Requires-Dist: flatbuffers>=23.1.21; extra == "model-compile"
37
+ Provides-Extra: model
38
+ Requires-Dist: onnxruntime>=1.30.0; extra == "model"
39
+ Requires-Dist: onnx>=1.16.0; extra == "model"
40
+ Requires-Dist: numpy>=1.26; extra == "model"
41
+ Requires-Dist: sympy>=1.12; extra == "model"
42
+
43
+ # tan
44
+
45
+ The Alp Lab build CLI. One `board.yaml` describes a whole module — every core,
46
+ MCU and MPU alike — and `tan` turns it into firmware.
47
+
48
+ ## Install
49
+
50
+ Install from a checkout. `tan` is **not on PyPI yet** — the distribution has
51
+ never been published, so a `pip install` of it answers `ERROR: No matching
52
+ distribution found`. The decision to publish there HAS now been taken
53
+ (tan-cli#1054: PyPI is the sole standalone install channel, and the npm shim is
54
+ retired), and `.github/workflows/release.yml` carries a `publish_pypi` job — but
55
+ it is opt-in and off, waiting on the repository variable `TAN_PYPI_PUBLISH` and
56
+ a pending publisher configured on pypi.org. Until the first final tag uploads
57
+ under that arrangement, a checkout install is the only path.
58
+
59
+ On a PEP 668 host (Debian/Ubuntu, including stock `ubuntu:24.04`), installing
60
+ straight into the system interpreter refuses with
61
+ `error: externally-managed-environment`; install into a virtual environment
62
+ instead. Debian/Ubuntu's `python3` package does not include `venv` either --
63
+ `sudo apt-get install -y python3-venv` first, on those hosts:
64
+
65
+ ```bash
66
+ git clone https://github.com/alplabai/tan-cli && cd tan-cli
67
+ python3 -m venv .venv && source .venv/bin/activate # Linux / macOS
68
+ py -m venv .venv && .venv\Scripts\Activate.ps1 # Windows
69
+ python3 -m pip install ./python # Linux / macOS
70
+ py -m pip install ./python # Windows
71
+ ```
72
+
73
+ ```bash
74
+ tan --version
75
+ tan init # scaffold a project (add --preview to see the plan first)
76
+ tan doctor # is this host able to build and flash?
77
+ tan build # build every core the module declares
78
+ ```
79
+
80
+ Add the `monitor` extra — `pip install "./python[monitor]"` — if you want `tan
81
+ monitor`; it needs pyserial, which a default install leaves out.
82
+
83
+ **Use `-m pip`, not a bare `pip` or `pip3`.** `tan` requires Python **3.12 or
84
+ newer**, and on a machine with several interpreters a bare `pip` can install into
85
+ a different one than the `python3` you will actually build with — on Windows,
86
+ `python3` is frequently the Microsoft Store stub rather than a real interpreter.
87
+ `python3 -m pip` cannot drift from the interpreter that runs it, so the
88
+ `requires-python = ">=3.12"` check either passes honestly or refuses that
89
+ interpreter, instead of installing somewhere you will not find it. (An old
90
+ `setuptools` on the wrong interpreter can fail earlier and for a different
91
+ reason — `project.license` must be valid exactly by one definition, measured
92
+ here on setuptools 68-era metadata handling; that is tan-cli#382, not a version
93
+ mismatch.)
94
+
95
+ **Not building from source?** Every version tag publishes a prebuilt archive per
96
+ platform, and `install.sh` / `install.ps1` fetch and verify one for you — see
97
+ the root [`README.md`](../README.md#install). That is the supported path for
98
+ someone who just wants the command.
99
+
100
+ `tan init` needs no alp-sdk checkout: the scaffold templates ship inside `tan`.
101
+ Most planning/build commands do need a checkout for metadata, schemas, examples,
102
+ and tooling; pass it with `--sdk-root` or place it beside the project.
103
+
104
+ The distribution is not named `tan` because that name is already taken on PyPI
105
+ (an unrelated code formatter); the command you run is still `tan`. Reserving a
106
+ name is not the same as occupying it — nothing is uploaded yet under any of
107
+ them.
108
+
109
+ ## What it does
110
+
111
+ `tan` contains both the relocated planner and the executor. It produces a build
112
+ plan from your `board.yaml` plus alp-sdk metadata, then drives the right tool for
113
+ each core — `west` for Zephyr on Cortex-M, `bitbake` for Yocto on Cortex-A,
114
+ `cmake` for bare metal. You never pick an OS or a toolchain; both are derived
115
+ from each core's architecture.
116
+
117
+ ## Requirements
118
+
119
+ Python 3.12 or newer — the floor Zephyr's own CMake configure enforces. Run
120
+ `tan doctor` to check the rest of the host; it names what is missing and where
121
+ to get it.
122
+
123
+ ## Licence
124
+
125
+ Apache-2.0.
@@ -0,0 +1,83 @@
1
+ # tan
2
+
3
+ The Alp Lab build CLI. One `board.yaml` describes a whole module — every core,
4
+ MCU and MPU alike — and `tan` turns it into firmware.
5
+
6
+ ## Install
7
+
8
+ Install from a checkout. `tan` is **not on PyPI yet** — the distribution has
9
+ never been published, so a `pip install` of it answers `ERROR: No matching
10
+ distribution found`. The decision to publish there HAS now been taken
11
+ (tan-cli#1054: PyPI is the sole standalone install channel, and the npm shim is
12
+ retired), and `.github/workflows/release.yml` carries a `publish_pypi` job — but
13
+ it is opt-in and off, waiting on the repository variable `TAN_PYPI_PUBLISH` and
14
+ a pending publisher configured on pypi.org. Until the first final tag uploads
15
+ under that arrangement, a checkout install is the only path.
16
+
17
+ On a PEP 668 host (Debian/Ubuntu, including stock `ubuntu:24.04`), installing
18
+ straight into the system interpreter refuses with
19
+ `error: externally-managed-environment`; install into a virtual environment
20
+ instead. Debian/Ubuntu's `python3` package does not include `venv` either --
21
+ `sudo apt-get install -y python3-venv` first, on those hosts:
22
+
23
+ ```bash
24
+ git clone https://github.com/alplabai/tan-cli && cd tan-cli
25
+ python3 -m venv .venv && source .venv/bin/activate # Linux / macOS
26
+ py -m venv .venv && .venv\Scripts\Activate.ps1 # Windows
27
+ python3 -m pip install ./python # Linux / macOS
28
+ py -m pip install ./python # Windows
29
+ ```
30
+
31
+ ```bash
32
+ tan --version
33
+ tan init # scaffold a project (add --preview to see the plan first)
34
+ tan doctor # is this host able to build and flash?
35
+ tan build # build every core the module declares
36
+ ```
37
+
38
+ Add the `monitor` extra — `pip install "./python[monitor]"` — if you want `tan
39
+ monitor`; it needs pyserial, which a default install leaves out.
40
+
41
+ **Use `-m pip`, not a bare `pip` or `pip3`.** `tan` requires Python **3.12 or
42
+ newer**, and on a machine with several interpreters a bare `pip` can install into
43
+ a different one than the `python3` you will actually build with — on Windows,
44
+ `python3` is frequently the Microsoft Store stub rather than a real interpreter.
45
+ `python3 -m pip` cannot drift from the interpreter that runs it, so the
46
+ `requires-python = ">=3.12"` check either passes honestly or refuses that
47
+ interpreter, instead of installing somewhere you will not find it. (An old
48
+ `setuptools` on the wrong interpreter can fail earlier and for a different
49
+ reason — `project.license` must be valid exactly by one definition, measured
50
+ here on setuptools 68-era metadata handling; that is tan-cli#382, not a version
51
+ mismatch.)
52
+
53
+ **Not building from source?** Every version tag publishes a prebuilt archive per
54
+ platform, and `install.sh` / `install.ps1` fetch and verify one for you — see
55
+ the root [`README.md`](../README.md#install). That is the supported path for
56
+ someone who just wants the command.
57
+
58
+ `tan init` needs no alp-sdk checkout: the scaffold templates ship inside `tan`.
59
+ Most planning/build commands do need a checkout for metadata, schemas, examples,
60
+ and tooling; pass it with `--sdk-root` or place it beside the project.
61
+
62
+ The distribution is not named `tan` because that name is already taken on PyPI
63
+ (an unrelated code formatter); the command you run is still `tan`. Reserving a
64
+ name is not the same as occupying it — nothing is uploaded yet under any of
65
+ them.
66
+
67
+ ## What it does
68
+
69
+ `tan` contains both the relocated planner and the executor. It produces a build
70
+ plan from your `board.yaml` plus alp-sdk metadata, then drives the right tool for
71
+ each core — `west` for Zephyr on Cortex-M, `bitbake` for Yocto on Cortex-A,
72
+ `cmake` for bare metal. You never pick an OS or a toolchain; both are derived
73
+ from each core's architecture.
74
+
75
+ ## Requirements
76
+
77
+ Python 3.12 or newer — the floor Zephyr's own CMake configure enforces. Run
78
+ `tan doctor` to check the rest of the host; it names what is missing and where
79
+ to get it.
80
+
81
+ ## Licence
82
+
83
+ Apache-2.0.
@@ -0,0 +1,293 @@
1
+ [project]
2
+ # DISTRIBUTION name is `tan-cli`, not `tan`: the name `tan` is already taken on
3
+ # PyPI ("The compromising code formatter", v23.7.0), so `pip install tan` would
4
+ # fetch an unrelated package. The IMPORT package stays `tan` and the console
5
+ # script stays `tan`, so a customer still types `tan build` -- only the install
6
+ # line differs:
7
+ #
8
+ # pip install tan-cli -> tan --version
9
+ #
10
+ # `alp-tan` was the first choice and was also free, preferred at the time
11
+ # because the other Alp Lab artefacts are `alp-`prefixed. Reversed in
12
+ # tan-cli#1054, before anything was ever uploaded under either name: this
13
+ # distribution is published from `github.com/alplabai/tan-cli` and
14
+ # authenticated by Trusted Publishing, which binds the PyPI project to that
15
+ # exact repository. `pypi.org/project/tan-cli` <-> `github.com/alplabai/tan-cli`
16
+ # is one name a reader can follow; `alp-tan` <-> `tan-cli` is two.
17
+ name = "tan-cli"
18
+ # The PEP 440 RENDERING of `python/tan/version.py`'s TAN_VERSION, which is the
19
+ # source of truth -- never edited alone. `0.5.0-rc5.dev0` -> `0.5.0rc5.dev0`
20
+ # (the two spellings are not interchangeable and cannot be string-compared);
21
+ # `python/scripts/version_check.py` owns that mapping and CI runs it.
22
+ version = "0.7.0"
23
+ description = "The Alp Lab build CLI: one board.yaml to firmware, across MCU and MPU cores."
24
+ readme = "README.md"
25
+ # PEP 639 SPDX-expression form, NOT the `{ text = ... }` table -- and it is
26
+ # COUPLED to the `setuptools>=77.0.1` floor in `[build-system]` below, which
27
+ # exists solely to parse this line (tan-cli#382). Changing either without the
28
+ # other is the bug: the table form is what setuptools <77 accepts and what
29
+ # setuptools >=77 deprecates, so there is no spelling that satisfies both.
30
+ license = "Apache-2.0"
31
+ authors = [{ name = "Alp Lab AB" }]
32
+ keywords = ["embedded", "firmware", "zephyr", "yocto", "som", "build"]
33
+ # 3.12, not 3.11: the floor is what the BUILD needs, not what this package's own
34
+ # syntax needs. Zephyr's `cmake/modules/python.cmake` sets
35
+ # `PYTHON_MINIMUM_REQUIRED 3.12`, and `tan build` bakes the interpreter it
36
+ # resolves into every Zephyr slice as `-DPython3_EXECUTABLE` -- so a `tan` frozen
37
+ # against 3.11 hands Zephyr an interpreter its own configure step then rejects,
38
+ # and the customer gets an error naming Zephyr rather than tan. Same effective
39
+ # floor `tan doctor` enforces (`ZEPHYR_PYTHON_FLOOR`, tan/commands/doctor_cmd.py).
40
+ requires-python = ">=3.12"
41
+ # `pyyaml` is load-bearing, not optional: `build/system-manifest.yaml` is the ONLY
42
+ # input `tan image` and `tan size` have, and it is YAML. Without it declared here
43
+ # the PyInstaller build -- which installs exactly this set into a clean venv, see
44
+ # scripts/build_binary.sh -- ships a frozen `tan` whose `size`/`image` can never
45
+ # read a manifest. Both still degrade to a coded `*.manifest-invalid` envelope
46
+ # rather than a traceback if it is somehow absent (`tan.core.system_manifest.
47
+ # load_yaml_document`), but that is a safety net, not the plan. It is now doubly
48
+ # load-bearing: the relocated planner (`tan.planner`) reads every `metadata/**`
49
+ # YAML through it.
50
+ #
51
+ # `jsonschema` arrived WITH the planner and is the fourth runtime dependency.
52
+ # The four-name ceiling (typer, rich, pytest, pyinstaller) was scoped to the
53
+ # executor stage; the planner validates every `board.yaml` against
54
+ # `metadata/schemas/board.schema.json` under Draft 2020-12 before it plans
55
+ # anything (`tan/planner/loader.py`), and that schema is where invariants I-02
56
+ # (no top-level `os:`) and I-03 (`core_entry` is closed) are actually ENFORCED.
57
+ # Reimplementing the validator to save a dependency would move two enforced
58
+ # invariants into hand-written code -- the opposite of consume-what-exists. The
59
+ # planner `sys.exit`s with an install hint if it is absent and `tan build` turns
60
+ # that into a coded `build.plan-unavailable` envelope, never a traceback.
61
+ #
62
+ # `click` is the fifth, and it is declared because `tan/cli.py` and
63
+ # `tan/commands/new_som_cmd.py` IMPORT IT DIRECTLY -- `from click.testing
64
+ # import CliRunner` is how `--help` under `--format json` is captured into one
65
+ # envelope instead of Click printing straight to stdout and calling
66
+ # `ctx.exit(0)` before `emit()` can run (`_emit_help_envelope`). It rode along
67
+ # transitively for years because typer depended on click; starting at **typer
68
+ # 0.26.0** it does not (measured: PyPI `requires_dist` for 0.25.1 still lists
69
+ # `click>=8.2.1`; 0.26.0's does not, and its wheel gained a vendored
70
+ # `typer/_click/` package -- typer's OWN click-alike, not a re-export of the
71
+ # public one). So a clean `pip install tan-cli` produced `ModuleNotFoundError:
72
+ # No module named 'click'` on first run, and every local test suite passed
73
+ # regardless because click was present for other reasons. A package that
74
+ # imports a module must declare it; leaning on someone else's dependency graph
75
+ # is what broke. `tests/gates/test_declared_dependencies.py` fails if any
76
+ # module under `tan/` imports a distribution this list omits. `click` stays
77
+ # required even though typer no longer needs it transitively -- the two direct
78
+ # imports above are real, not incidental.
79
+ #
80
+ # `typer` is capped, not just floored, and the cap is the point of this whole
81
+ # comment. `tan/cli.py:_emit_help_envelope` drives `typer.main.get_command()`'s
82
+ # result -- a `TyperCommand` -- through the PUBLIC `click.testing.CliRunner`.
83
+ # Measured: `type(get_command(app)).__mro__` descends from
84
+ # `typer._click.core.Command`, typer's PRIVATE vendored fork, not from
85
+ # `click.core.Command` -- so this mixes two different click implementations,
86
+ # and it only works because the vendored `UsageError.show()` still exits via
87
+ # `SystemExit`, which `CliRunner` catches generically (see the docstring at
88
+ # that function). That is stable across the vendored-click line -- measured
89
+ # clean (`tests/test_cli_skeleton.py` + `tests/gates`) against both 0.26.0 and
90
+ # 0.27.0, the only two releases of that line so far -- but it is an
91
+ # implementation detail of typer's private fork, not a contract, so nothing
92
+ # says a `0.28` won't change what `get_command()` returns or how its group
93
+ # raises. Uncapped, a resolver is free to pick that day's newest typer for a
94
+ # `pip install ./python` -- the documented path on win32/arm64 and
95
+ # linux/arm64, the two hosts with no frozen asset -- and hand it a CLI built
96
+ # against a private surface that may no longer exist.
97
+ #
98
+ # The floor moved off `>=0.12` for the same "measure, don't guess" reason:
99
+ # `typer==0.12.0` on PyPI is a metapackage stub (`requires_dist` is just
100
+ # `typer-slim[standard]==0.12.0` + `typer-cli==0.12.0`), not a working install
101
+ # of the real `typer` module -- a floor including it was already claiming
102
+ # support that cannot work. `>=0.26` also makes the floor mean something: every
103
+ # version it admits is the SAME vendored-click behaviour this whole comment
104
+ # and `tests/gates/test_typer_click_bound.py` are about, not two different
105
+ # regimes (pre- and post-vendoring) blurred into one range. Pre-0.26 typer may
106
+ # well still work -- it was not the question this port needed answered.
107
+ #
108
+ # `tests/gates/test_typer_click_bound.py` fails if the installed typer drifts
109
+ # outside `<0.28`, or if the private surface this range assumes (`TyperCommand`
110
+ # descending from `typer._click.core.Command`, and a `SystemExit`-raising
111
+ # `UsageError`) goes away from an in-range version -- so a version bump here is
112
+ # a decision, not a drift.
113
+ #
114
+ # `truststore` and `certifi` are REQUIRED, not optional, and both are new
115
+ # (tan-cli#304): a PyInstaller `--onefile` freeze bundles its own `ssl` but no
116
+ # CA bundle and does not fall back to the platform trust store, so a frozen
117
+ # `tan` had ZERO trust anchors -- every `urllib` HTTPS call in `sdk_cmd.py`
118
+ # failed `CERTIFICATE_VERIFY_FAILED` even on a host where `curl`/a browser/
119
+ # system `python3` verified the same endpoint fine. `truststore` is preferred
120
+ # (verifies through the OS's own trust store, so a real corporate CA installed
121
+ # in the machine's keychain still works -- `certifi`'s fixed public-CA list
122
+ # alone would trade that failure for a different one); `certifi`'s bundled
123
+ # `cacert.pem` is the floor `tan/net.py` falls back to if `truststore` is
124
+ # absent or its platform verifier fails. Both are module-scope imports inside
125
+ # `tan/net.py`, so both must be REQUIRED per the reasoning right below this
126
+ # comment.
127
+ # `cbor2` arrived WITH the relocated model engine (ADR-0028 Task 2,
128
+ # `tan/model/manifest.py`): `.alpmodel` is a CBOR container, and
129
+ # `Manifest.to_cbor`/`from_cbor` do a module-scope `import cbor2 as _cbor2` --
130
+ # not lazy, not guarded -- so it is REQUIRED, matching alp-sdk's own
131
+ # classification of the same distribution in its own `pyproject.toml`
132
+ # (`cbor2>=5.0`, alongside PyYAML/jsonschema/click, never under
133
+ # `optional-dependencies`). `tests/gates/test_declared_dependencies.py` fails on
134
+ # this exact shape otherwise -- an eager import of an undeclared distribution.
135
+ dependencies = [
136
+ "typer>=0.26,<0.28",
137
+ "rich>=13",
138
+ "pyyaml>=6",
139
+ "jsonschema>=4.18",
140
+ "click>=8.1",
141
+ "truststore>=0.9",
142
+ "certifi>=2024.2.2",
143
+ "cbor2>=5.0",
144
+ ]
145
+
146
+ # `pyserial` is OPTIONAL, not required: only `tan monitor` needs it, and a serial
147
+ # console is not worth adding to every install of a build tool. `monitor_cmd`
148
+ # imports it lazily inside the two functions that use it and refuses with an
149
+ # actionable message when it is absent, so `tan --version` and every other
150
+ # command still work without it. That laziness is load-bearing, not incidental --
151
+ # a module-scope `import serial` would make the whole CLI unimportable on a clean
152
+ # install the moment `monitor` is registered, so
153
+ # `tests/gates/test_declared_dependencies.py` fails if an extras-only import
154
+ # migrates to module scope.
155
+ classifiers = [
156
+ "Development Status :: 3 - Alpha",
157
+ "Environment :: Console",
158
+ "Intended Audience :: Developers",
159
+ "Programming Language :: Python :: 3.12",
160
+ "Programming Language :: Python :: 3.13",
161
+ "Topic :: Software Development :: Build Tools",
162
+ "Topic :: Software Development :: Embedded Systems",
163
+ ]
164
+
165
+
166
+ # LAST of the `[project]` content on purpose. A table header ends the parent
167
+ # table, so every bare `key = ...` after it belongs to the SUB-table, not to
168
+ # `[project]`. Putting this above `classifiers` silently reparented it into the
169
+ # extras group -- `optional-dependencies` grew a bogus `classifiers` extra,
170
+ # `project.classifiers` vanished from the metadata, and `pip install ./python`
171
+ # failed outright. Keep new `[project]` KEYS above this line and new
172
+ # `[project.*]` TABLES below it.
173
+ [project.optional-dependencies]
174
+ monitor = ["pyserial>=3.5"]
175
+ # Lightweight TFLite read/parse deps for `tan.model.tensorio.extract_io` (tensor
176
+ # I/O extraction from a .tflite flatbuffer) -- pure-Python, no compiler toolchain.
177
+ # `tflite` is a genuinely LAZY, guarded import (`tensorio.py`'s
178
+ # `try: import tflite / except ImportError: return [], []`), so it stays an
179
+ # extra rather than a required dependency -- `extract_io` degrades to "no I/O
180
+ # metadata" rather than failing when it is absent. `flatbuffers` is not imported
181
+ # by name anywhere under `tan/` (so `test_declared_dependencies.py` does not
182
+ # require it), but it is `tflite`'s own declared runtime dependency (measured:
183
+ # `pip show tflite` -> `Requires: flatbuffers, numpy`) -- pinned explicitly here,
184
+ # not left to a transitive resolve, so `pip install tan-cli[model-io]` is a
185
+ # working reader and not just a gate-satisfying stub. Pins mirror alp-sdk's own
186
+ # `model-io` extra exactly (its `pyproject.toml`'s entry, due to be dropped once
187
+ # `scripts/alp_model/` is deleted -- ADR-0028 Task 6) rather than inventing new
188
+ # floors.
189
+ model-io = ["tflite>=2.10", "flatbuffers>=23.1.21"]
190
+
191
+ # Full host model-compile toolchain: adds the Arm Vela compiler `vela` needs
192
+ # for `tan.model.adapters.ethos_u.VelaAdapter.compile()` (`shutil.which("vela")`
193
+ # is the runtime gate; this extra is what puts it on PATH). NOT required for
194
+ # `tan model build` to run -- every vendor adapter shells its compiler as an
195
+ # external binary, never a Python import, so a bare `pip install tan-cli`
196
+ # still works and only that one NPU backend's compile step is unavailable
197
+ # (`is_available()` reports False; `doctor`/`check` explain why). Pins mirror
198
+ # alp-sdk's own `model-compile` extra exactly (due to be dropped from
199
+ # alp-sdk's `pyproject.toml` once `scripts/alp_model/` is deleted -- ADR-0028
200
+ # Task 6) rather than inventing new floors. DEEPX's `dxcom` and DRP-AI's TVM
201
+ # have no such extra on either side -- both are license-gated vendor
202
+ # toolchains with no PyPI wheel to pin.
203
+ model-compile = ["ethos-u-vela>=3.9", "tflite>=2.10", "flatbuffers>=23.1.21"]
204
+
205
+ # Host-tier `tan model prep` / `run` / `ab` (tan-cli#1287): onnxruntime-based INT8
206
+ # quantization and host reference runs. OPTIONAL and deliberately NOT in the
207
+ # frozen release assets (`.[monitor]` only) -- onnxruntime publishes no macOS
208
+ # x86_64 wheel and adds tens of MB for a verb most users never run. Every import
209
+ # is lazy (`tan.model.prep`, `tan.model.measure`); `tan.core.model_host` turns a
210
+ # missing one into the coded `model.model-extra-missing` refusal. `sympy` is
211
+ # onnxruntime's symbolic shape-inference dependency for `quant_pre_process`.
212
+ # Floors: `onnx>=1.16.0` is the release that fixed CVE-2024-27318 (path traversal
213
+ # through external-data locations) -- `tan model prep` loads customer-supplied
214
+ # models. `onnxruntime>=1.30.0` is the version the external-data and corrupt-
215
+ # sample refusal tests were actually run against; a lower floor was not tested.
216
+ model = ["onnxruntime>=1.30.0", "onnx>=1.16.0", "numpy>=1.26", "sympy>=1.12"]
217
+
218
+ [project.urls]
219
+ Homepage = "https://github.com/alplabai/tan-cli"
220
+ Repository = "https://github.com/alplabai/tan-cli"
221
+ Issues = "https://github.com/alplabai/tan-cli/issues"
222
+
223
+ [project.scripts]
224
+ tan = "tan.__main__:main"
225
+
226
+ [build-system]
227
+ # 77.0.1, measured, not guessed (tan-cli#382). `>=68` was a bound nobody had
228
+ # ever built at: PEP 639 support -- the `license = "Apache-2.0"` string form at
229
+ # the top of this file -- landed in the setuptools 77 line, so every version
230
+ # `>=68` admitted below that REJECTS this file's own metadata:
231
+ #
232
+ # pip install setuptools==76.1.0
233
+ # pip wheel --no-deps --no-build-isolation ./python
234
+ # configuration error: `project.license` must be valid exactly by one
235
+ # definition (2 matches found) <- expected `file` or `text`
236
+ #
237
+ # Measured on py3.12.10: 68.1.2 FAIL, 76.1.0 FAIL (the release immediately
238
+ # below the floor), 77.0.1 PASS. Build ISOLATION is what hid it for two years
239
+ # -- pip then downloads the newest setuptools regardless of this line, so every
240
+ # other install path in this repo (`pip install -e ./python` in ci.yml, the
241
+ # venvs in release.yml / python-binaries.yml / clean-host.yml) passes no matter
242
+ # what number is written here. Only a downstream packager pinned to a valid
243
+ # `>=68` environment ever saw it, and they cannot build the distribution at all.
244
+ #
245
+ # 77.0.1 and not `>=77`: setuptools 77.0.0 and 77.0.2 have NO files on PyPI, so
246
+ # `==77` (which PEP 440 zero-pads to 77.0.0) resolves to nothing. 77.0.1 is the
247
+ # first release of that line a resolver can actually install, which makes this
248
+ # bound an exact version the `wheel-floor` job in .github/workflows/ci.yml can
249
+ # pin and build at -- that job derives its pin FROM this string, so a future
250
+ # change here is tested at its own floor with nothing else to update.
251
+ requires = ["setuptools>=77.0.1"]
252
+ build-backend = "setuptools.build_meta"
253
+
254
+ # Explicit, so `tests/` can never be shipped by an auto-discovery change and a
255
+ # new subpackage is never silently omitted from the wheel.
256
+ [tool.setuptools.packages.find]
257
+ where = ["."]
258
+ include = ["tan*"]
259
+
260
+ # `tan init`'s scaffold trees are DATA, not code, so nothing in the import graph
261
+ # pulls them into a wheel on its own -- and without them five of the six
262
+ # templates fail (`init.template-unreadable`). The frozen binary needs the
263
+ # equivalent `--add-data`, see `scripts/build_binary.sh`.
264
+ [tool.setuptools.package-data]
265
+ "tan.templates" = ["vendored/**/*"]
266
+
267
+ [tool.pytest.ini_options]
268
+ pythonpath = ["."]
269
+
270
+ # tan-cli#408. ADVISORY ONLY -- read this before believing it enforces
271
+ # anything. No workflow under `.github/workflows/` runs ruff, so this section
272
+ # changes exactly one thing: an editor with ruff wired in now surfaces the
273
+ # three complexity rules while you type, instead of nothing at all.
274
+ #
275
+ # What actually ENFORCES the size guideline is
276
+ # `tests/gates/test_module_size_budget.py`, a ratchet that runs inside
277
+ # `python -- pytest across python/` -- already a required context on `main`
278
+ # and `dev`, so it gates merges today with no branch-protection change. A new
279
+ # required CI job would have to be added to that list to matter, and adding a
280
+ # required context blocks every open PR until it has run on each of them.
281
+ #
282
+ # `ruff check python/` is red on this tree, deliberately and honestly: 23
283
+ # modules are over 800 lines and 199 functions over 50. The gate records that
284
+ # as a baseline and fails on GROWTH; ruff here reports the standing debt.
285
+ [tool.ruff]
286
+ line-length = 100
287
+ target-version = "py312"
288
+
289
+ [tool.ruff.lint]
290
+ # PLR0911 too-many-return-statements, PLR0912 too-many-branches,
291
+ # PLR0915 too-many-statements -- the three `bootstrap_cmd._run`'s lone
292
+ # `# noqa` names, and the only `noqa: PLR` anywhere under `tan/`.
293
+ extend-select = ["PLR0911", "PLR0912", "PLR0915"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,120 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """The `tan` entrypoint. The command surface itself lives in `tan.cli`.
3
+
4
+ This is the PROCESS BOUNDARY -- the one place both real entrypoints resolve
5
+ to: `pyproject.toml`'s `[project.scripts]` names `tan.__main__:main` (so a
6
+ `pip install`ed console-script calls this module's `main` attribute directly,
7
+ never running the `if __name__ == "__main__"` guard below), and
8
+ `scripts/build_binary.sh` points PyInstaller at this same file. A broken-pipe
9
+ guard sprinkled into each command instead would miss both.
10
+ """
11
+ import errno
12
+ import os
13
+ import sys
14
+
15
+ from tan.cli import main as _cli_main
16
+
17
+
18
+ def _is_broken_pipe(exc: BaseException) -> bool:
19
+ """Is this the OSError a reader closing tan's stdout raises?
20
+
21
+ EPIPE on POSIX. On Windows the same condition surfaces as a plain
22
+ `OSError` with `errno.EINVAL` instead -- CPython's Windows layer maps the
23
+ underlying `ERROR_NO_DATA` to EINVAL, not EPIPE, so `except
24
+ BrokenPipeError` alone (the POSIX-only idiom from the `signal` docs' "Note
25
+ on SIGPIPE") does not catch it there.
26
+
27
+ EINVAL alone is not pipe-specific on Windows -- a plain filesystem error
28
+ (e.g. `open("bad<n.txt")`) raises the same errno. That OSError carries a
29
+ `filename`; the broken-pipe OSError does not (verified against CPython's
30
+ Windows console-write path), so `filename is None` discriminates a closed
31
+ stdout from a real filesystem error without weakening the pipe guard.
32
+ """
33
+ return isinstance(exc, OSError) and (
34
+ exc.errno == errno.EPIPE
35
+ or (sys.platform == "win32" and exc.errno == errno.EINVAL and exc.filename is None)
36
+ )
37
+
38
+
39
+ def _caused_by_broken_pipe(exc: BaseException) -> bool:
40
+ """Was this `SystemExit` raised WHILE a closed stdout was being handled?
41
+
42
+ Nothing reaches this module's `except OSError` arm on POSIX, because two
43
+ layers below it already convert the `BrokenPipeError` into an exit of
44
+ their own and neither is reachable through a public hook:
45
+
46
+ * Rich -- `Console._check_buffer` catches `BrokenPipeError` and calls
47
+ `Console.on_broken_pipe`, which sets `quiet` and raises `SystemExit(1)`.
48
+ This is the one that fires for `tan --help`, since Typer renders every
49
+ `--help` through Rich.
50
+ * Typer/Click -- `typer.core._main` (Click's `BaseCommand.main` shape)
51
+ has `except OSError: if e.errno == errno.EPIPE: ... sys.exit(1)`.
52
+
53
+ Both raise their exit from INSIDE the `except BrokenPipeError`/`except
54
+ OSError` block that caught the pipe, so CPython's implicit chaining leaves
55
+ the original error on `SystemExit.__context__`. Following that chain is
56
+ what identifies the case: `SystemExit(1)` on its own is far too broad to
57
+ remap -- every failed `tan build` raises it -- and the alternatives are
58
+ all private detail of somebody else's library (Click's
59
+ `PacifyFlushWrapper` swap, Rich's `console.quiet`), which an entrypoint
60
+ should not be importing.
61
+ """
62
+ seen: set[int] = set()
63
+ cause: BaseException | None = exc.__cause__ or exc.__context__
64
+ while cause is not None and id(cause) not in seen:
65
+ if _is_broken_pipe(cause):
66
+ return True
67
+ seen.add(id(cause))
68
+ cause = cause.__cause__ or cause.__context__
69
+ return False
70
+
71
+
72
+ def _exit_quietly() -> None:
73
+ """Exit 0 with a stdout that can no longer raise.
74
+
75
+ Redirecting stdout to the null device before returning matters: without
76
+ it, the interpreter's own shutdown-time flush of the now-broken stdout
77
+ raises the same OSError again, straight past any exception handler, and
78
+ prints "Exception ignored in: ..." on stderr regardless.
79
+ """
80
+ try:
81
+ devnull = os.open(os.devnull, os.O_WRONLY)
82
+ os.dup2(devnull, sys.stdout.fileno())
83
+ except OSError:
84
+ pass
85
+ sys.exit(0)
86
+
87
+
88
+ def main() -> None:
89
+ """Run the real CLI, and turn a closed stdout into a quiet exit.
90
+
91
+ `tan generate --help | grep -q x` (or `| head`, any reader that stops
92
+ early) closes tan's stdout mid-write. The Rust oracle exits 0 with empty
93
+ stderr in that situation on BOTH hosts -- measured: `tan.exe generate
94
+ --help | head -n1` on Windows, and tan 0.4.1 linux-musl writing a
95
+ 4327-byte `--help` into a never-read 4 KiB pipe, which is a guaranteed
96
+ EPIPE. This pins the port to the same observable behaviour, and it takes
97
+ two arms because the pipe reaches this frame in two different shapes:
98
+
99
+ * POSIX -- as a `SystemExit(1)` some library layer already raised for it
100
+ (see `_caused_by_broken_pipe`). Left alone, `tan --help | head -n1`
101
+ exited 1 here where the oracle exits 0.
102
+ * Windows -- as the raw `OSError`, because the errno is EINVAL and none of
103
+ those layers recognises it (see `_is_broken_pipe`). Left unhandled,
104
+ Typer's installed pretty-exception hook renders the whole stack as a
105
+ boxed traceback and the process exits non-zero.
106
+ """
107
+ try:
108
+ _cli_main()
109
+ except SystemExit as exc:
110
+ if not _caused_by_broken_pipe(exc):
111
+ raise
112
+ _exit_quietly()
113
+ except OSError as exc:
114
+ if not _is_broken_pipe(exc):
115
+ raise
116
+ _exit_quietly()
117
+
118
+
119
+ if __name__ == "__main__":
120
+ main()