picolet 0.0.1__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 (167) hide show
  1. picolet-0.0.1/.gitignore +34 -0
  2. picolet-0.0.1/PKG-INFO +250 -0
  3. picolet-0.0.1/README.md +224 -0
  4. picolet-0.0.1/hatch_build.py +77 -0
  5. picolet-0.0.1/picolet/__init__.py +26 -0
  6. picolet-0.0.1/picolet/__main__.py +125 -0
  7. picolet-0.0.1/picolet/_bridge/__init__.py +0 -0
  8. picolet-0.0.1/picolet/_bridge/picolet-bridge.js +1 -0
  9. picolet-0.0.1/picolet/_runtime_data/RUNTIME_TAG +1 -0
  10. picolet-0.0.1/picolet/_runtime_data/__init__.py +0 -0
  11. picolet-0.0.1/picolet/_runtime_data/mbm.toml +71 -0
  12. picolet-0.0.1/picolet/_runtime_data/sbom/__init__.py +0 -0
  13. picolet-0.0.1/picolet/_runtime_data/sbom/runtime.toml +288 -0
  14. picolet-0.0.1/picolet/cli/RUNTIME_TAG +1 -0
  15. picolet-0.0.1/picolet/cli/__init__.py +0 -0
  16. picolet-0.0.1/picolet/cli/_paths.py +144 -0
  17. picolet-0.0.1/picolet/cli/_targets.py +92 -0
  18. picolet-0.0.1/picolet/cli/_trailer.py +56 -0
  19. picolet-0.0.1/picolet/cli/build_cmd.py +981 -0
  20. picolet-0.0.1/picolet/cli/dev_cmd.py +324 -0
  21. picolet-0.0.1/picolet/cli/init_cmd.py +225 -0
  22. picolet-0.0.1/picolet/cli/run_cmd.py +129 -0
  23. picolet-0.0.1/picolet/cli/runtime_resolver.py +810 -0
  24. picolet-0.0.1/picolet/cli/sbom_gen.py +873 -0
  25. picolet-0.0.1/picolet/cli/test_cmd.py +640 -0
  26. picolet-0.0.1/picolet/cli/validate_cmd.py +61 -0
  27. picolet-0.0.1/picolet/cli/validator.py +469 -0
  28. picolet-0.0.1/picolet/templates/__init__.py +0 -0
  29. picolet-0.0.1/picolet/templates/config-editor/package.json +22 -0
  30. picolet-0.0.1/picolet/templates/config-editor/picolet.toml +20 -0
  31. picolet-0.0.1/picolet/templates/config-editor/src/config_store.py +302 -0
  32. picolet-0.0.1/picolet/templates/config-editor/src/config_validator.py +148 -0
  33. picolet-0.0.1/picolet/templates/config-editor/src/difflib.py +171 -0
  34. picolet-0.0.1/picolet/templates/config-editor/src/main.py +74 -0
  35. picolet-0.0.1/picolet/templates/config-editor/src/micro_yaml.py +265 -0
  36. picolet-0.0.1/picolet/templates/config-editor/src/tomllib.py +490 -0
  37. picolet-0.0.1/picolet/templates/config-editor/tsconfig.json +19 -0
  38. picolet-0.0.1/picolet/templates/config-editor/tsconfig.node.json +10 -0
  39. picolet-0.0.1/picolet/templates/config-editor/ui/index.html +12 -0
  40. picolet-0.0.1/picolet/templates/config-editor/ui/public/fonts/JetBrainsMono-Regular.woff2 +0 -0
  41. picolet-0.0.1/picolet/templates/config-editor/ui/src/App.vue +27 -0
  42. picolet-0.0.1/picolet/templates/config-editor/ui/src/assets/fonts.css +12 -0
  43. picolet-0.0.1/picolet/templates/config-editor/ui/src/assets/main.css +367 -0
  44. picolet-0.0.1/picolet/templates/config-editor/ui/src/env.d.ts +2 -0
  45. picolet-0.0.1/picolet/templates/config-editor/ui/src/main.ts +7 -0
  46. picolet-0.0.1/picolet/templates/config-editor/ui/src/picolet.d.ts +26 -0
  47. picolet-0.0.1/picolet/templates/config-editor/ui/src/router/index.ts +17 -0
  48. picolet-0.0.1/picolet/templates/config-editor/ui/src/store.ts +46 -0
  49. picolet-0.0.1/picolet/templates/config-editor/ui/src/views/DiffView.vue +78 -0
  50. picolet-0.0.1/picolet/templates/config-editor/ui/src/views/EditView.vue +409 -0
  51. picolet-0.0.1/picolet/templates/config-editor/ui/src/views/PickerView.vue +234 -0
  52. picolet-0.0.1/picolet/templates/config-editor/vite.config.ts +18 -0
  53. picolet-0.0.1/picolet/templates/dashboard/package.json +22 -0
  54. picolet-0.0.1/picolet/templates/dashboard/picolet.toml +20 -0
  55. picolet-0.0.1/picolet/templates/dashboard/src/main.py +71 -0
  56. picolet-0.0.1/picolet/templates/dashboard/src/metrics_reader.py +463 -0
  57. picolet-0.0.1/picolet/templates/dashboard/tsconfig.json +19 -0
  58. picolet-0.0.1/picolet/templates/dashboard/tsconfig.node.json +10 -0
  59. picolet-0.0.1/picolet/templates/dashboard/ui/index.html +12 -0
  60. picolet-0.0.1/picolet/templates/dashboard/ui/public/fonts/Antonio-Bold.woff2 +0 -0
  61. picolet-0.0.1/picolet/templates/dashboard/ui/public/fonts/Antonio-Regular.woff2 +0 -0
  62. picolet-0.0.1/picolet/templates/dashboard/ui/public/fonts/DMSans-Medium.woff2 +0 -0
  63. picolet-0.0.1/picolet/templates/dashboard/ui/public/fonts/DMSans-Regular.woff2 +0 -0
  64. picolet-0.0.1/picolet/templates/dashboard/ui/public/fonts/JetBrainsMono-Regular.woff2 +0 -0
  65. picolet-0.0.1/picolet/templates/dashboard/ui/src/App.vue +55 -0
  66. picolet-0.0.1/picolet/templates/dashboard/ui/src/assets/fonts.css +43 -0
  67. picolet-0.0.1/picolet/templates/dashboard/ui/src/assets/main.css +401 -0
  68. picolet-0.0.1/picolet/templates/dashboard/ui/src/components/CpuChart.vue +87 -0
  69. picolet-0.0.1/picolet/templates/dashboard/ui/src/components/DiskChart.vue +91 -0
  70. picolet-0.0.1/picolet/templates/dashboard/ui/src/components/MemoryGauge.vue +96 -0
  71. picolet-0.0.1/picolet/templates/dashboard/ui/src/components/NetworkChart.vue +91 -0
  72. picolet-0.0.1/picolet/templates/dashboard/ui/src/components/ProcessList.vue +53 -0
  73. picolet-0.0.1/picolet/templates/dashboard/ui/src/components/SparklineStrip.vue +81 -0
  74. picolet-0.0.1/picolet/templates/dashboard/ui/src/components/TopStrip.vue +33 -0
  75. picolet-0.0.1/picolet/templates/dashboard/ui/src/env.d.ts +2 -0
  76. picolet-0.0.1/picolet/templates/dashboard/ui/src/main.ts +7 -0
  77. picolet-0.0.1/picolet/templates/dashboard/ui/src/picolet.d.ts +25 -0
  78. picolet-0.0.1/picolet/templates/dashboard/ui/src/router/index.ts +13 -0
  79. picolet-0.0.1/picolet/templates/dashboard/ui/src/store.ts +45 -0
  80. picolet-0.0.1/picolet/templates/dashboard/ui/src/utils/format.ts +51 -0
  81. picolet-0.0.1/picolet/templates/dashboard/ui/src/utils/svg.ts +84 -0
  82. picolet-0.0.1/picolet/templates/dashboard/ui/src/views/DashboardView.vue +56 -0
  83. picolet-0.0.1/picolet/templates/dashboard/vite.config.ts +18 -0
  84. picolet-0.0.1/picolet/templates/hello-cli/picolet.toml +4 -0
  85. picolet-0.0.1/picolet/templates/hello-cli/src/main.py +19 -0
  86. picolet-0.0.1/picolet/templates/hello-lvgl/picolet.toml +15 -0
  87. picolet-0.0.1/picolet/templates/hello-lvgl/src/main.py +52 -0
  88. picolet-0.0.1/picolet/templates/hello-vue/package.json +21 -0
  89. picolet-0.0.1/picolet/templates/hello-vue/picolet.toml +20 -0
  90. picolet-0.0.1/picolet/templates/hello-vue/src/main.py +40 -0
  91. picolet-0.0.1/picolet/templates/hello-vue/tsconfig.json +19 -0
  92. picolet-0.0.1/picolet/templates/hello-vue/tsconfig.node.json +10 -0
  93. picolet-0.0.1/picolet/templates/hello-vue/ui/index.html +12 -0
  94. picolet-0.0.1/picolet/templates/hello-vue/ui/src/App.vue +127 -0
  95. picolet-0.0.1/picolet/templates/hello-vue/ui/src/env.d.ts +2 -0
  96. picolet-0.0.1/picolet/templates/hello-vue/ui/src/main.ts +4 -0
  97. picolet-0.0.1/picolet/templates/hello-vue/ui/src/picolet.d.ts +28 -0
  98. picolet-0.0.1/picolet/templates/hello-vue/vite.config.ts +17 -0
  99. picolet-0.0.1/picolet/templates/hello-webview/picolet.toml +17 -0
  100. picolet-0.0.1/picolet/templates/hello-webview/src/main.py +22 -0
  101. picolet-0.0.1/picolet/templates/hello-webview/ui/app.js +24 -0
  102. picolet-0.0.1/picolet/templates/hello-webview/ui/index.html +17 -0
  103. picolet-0.0.1/picolet/templates/hello-webview/ui/style.css +15 -0
  104. picolet-0.0.1/picolet/templates/notes/package.json +23 -0
  105. picolet-0.0.1/picolet/templates/notes/picolet.toml +20 -0
  106. picolet-0.0.1/picolet/templates/notes/src/main.py +70 -0
  107. picolet-0.0.1/picolet/templates/notes/src/notes_store.py +178 -0
  108. picolet-0.0.1/picolet/templates/notes/tsconfig.json +19 -0
  109. picolet-0.0.1/picolet/templates/notes/tsconfig.node.json +10 -0
  110. picolet-0.0.1/picolet/templates/notes/ui/index.html +12 -0
  111. picolet-0.0.1/picolet/templates/notes/ui/public/fonts/source-sans-3.woff2 +0 -0
  112. picolet-0.0.1/picolet/templates/notes/ui/public/fonts/source-serif-4-italic.woff2 +0 -0
  113. picolet-0.0.1/picolet/templates/notes/ui/public/fonts/source-serif-4-roman.woff2 +0 -0
  114. picolet-0.0.1/picolet/templates/notes/ui/src/App.vue +15 -0
  115. picolet-0.0.1/picolet/templates/notes/ui/src/assets/fonts.css +34 -0
  116. picolet-0.0.1/picolet/templates/notes/ui/src/assets/main.css +459 -0
  117. picolet-0.0.1/picolet/templates/notes/ui/src/env.d.ts +2 -0
  118. picolet-0.0.1/picolet/templates/notes/ui/src/main.ts +7 -0
  119. picolet-0.0.1/picolet/templates/notes/ui/src/picolet.d.ts +25 -0
  120. picolet-0.0.1/picolet/templates/notes/ui/src/router/index.ts +17 -0
  121. picolet-0.0.1/picolet/templates/notes/ui/src/views/AboutView.vue +25 -0
  122. picolet-0.0.1/picolet/templates/notes/ui/src/views/EditView.vue +173 -0
  123. picolet-0.0.1/picolet/templates/notes/ui/src/views/ListView.vue +108 -0
  124. picolet-0.0.1/picolet/templates/notes/vite.config.ts +18 -0
  125. picolet-0.0.1/picolet/templates/pydfu/README.md +109 -0
  126. picolet-0.0.1/picolet/templates/pydfu/package.json +22 -0
  127. picolet-0.0.1/picolet/templates/pydfu/picolet.toml +29 -0
  128. picolet-0.0.1/picolet/templates/pydfu/src/_crc32.py +28 -0
  129. picolet-0.0.1/picolet/templates/pydfu/src/_dfu_file.py +79 -0
  130. picolet-0.0.1/picolet/templates/pydfu/src/_pydfu/__init__.py +2 -0
  131. picolet-0.0.1/picolet/templates/pydfu/src/_pydfu/pydfu.py +462 -0
  132. picolet-0.0.1/picolet/templates/pydfu/src/_usb/__init__.py +2 -0
  133. picolet-0.0.1/picolet/templates/pydfu/src/_usb/control.py +10 -0
  134. picolet-0.0.1/picolet/templates/pydfu/src/_usb/core.py +339 -0
  135. picolet-0.0.1/picolet/templates/pydfu/src/_usb/libusb-1.0.dll +0 -0
  136. picolet-0.0.1/picolet/templates/pydfu/src/_usb/util.py +21 -0
  137. picolet-0.0.1/picolet/templates/pydfu/src/main.py +379 -0
  138. picolet-0.0.1/picolet/templates/pydfu/src/pydfu_adapter.py +190 -0
  139. picolet-0.0.1/picolet/templates/pydfu/src/pydfu_mock.py +51 -0
  140. picolet-0.0.1/picolet/templates/pydfu/tsconfig.json +19 -0
  141. picolet-0.0.1/picolet/templates/pydfu/tsconfig.node.json +10 -0
  142. picolet-0.0.1/picolet/templates/pydfu/ui/index.html +12 -0
  143. picolet-0.0.1/picolet/templates/pydfu/ui/public/fonts/IBMPlexSans-Regular.woff2 +0 -0
  144. picolet-0.0.1/picolet/templates/pydfu/ui/public/fonts/IBMPlexSans-SemiBold.woff2 +0 -0
  145. picolet-0.0.1/picolet/templates/pydfu/ui/public/fonts/MonaspaceNeon-Bold.woff2 +0 -0
  146. picolet-0.0.1/picolet/templates/pydfu/ui/public/fonts/MonaspaceNeon-Regular.woff2 +0 -0
  147. picolet-0.0.1/picolet/templates/pydfu/ui/src/App.vue +111 -0
  148. picolet-0.0.1/picolet/templates/pydfu/ui/src/assets/fonts.css +27 -0
  149. picolet-0.0.1/picolet/templates/pydfu/ui/src/assets/main.css +156 -0
  150. picolet-0.0.1/picolet/templates/pydfu/ui/src/components/AuditStrip.vue +114 -0
  151. picolet-0.0.1/picolet/templates/pydfu/ui/src/components/DeviceDetail.vue +202 -0
  152. picolet-0.0.1/picolet/templates/pydfu/ui/src/components/DeviceList.vue +181 -0
  153. picolet-0.0.1/picolet/templates/pydfu/ui/src/components/HeaderRail.vue +131 -0
  154. picolet-0.0.1/picolet/templates/pydfu/ui/src/components/LedDot.vue +54 -0
  155. picolet-0.0.1/picolet/templates/pydfu/ui/src/env.d.ts +2 -0
  156. picolet-0.0.1/picolet/templates/pydfu/ui/src/main.ts +7 -0
  157. picolet-0.0.1/picolet/templates/pydfu/ui/src/picolet.d.ts +24 -0
  158. picolet-0.0.1/picolet/templates/pydfu/ui/src/router/index.ts +17 -0
  159. picolet-0.0.1/picolet/templates/pydfu/ui/src/views/FlashView.vue +429 -0
  160. picolet-0.0.1/picolet/templates/pydfu/ui/src/views/HomeView.vue +29 -0
  161. picolet-0.0.1/picolet/templates/pydfu/ui/src/views/LogView.vue +68 -0
  162. picolet-0.0.1/picolet/templates/pydfu/vite.config.ts +18 -0
  163. picolet-0.0.1/picolet/testing/__init__.py +17 -0
  164. picolet-0.0.1/picolet/testing/_chromium.py +90 -0
  165. picolet-0.0.1/picolet/testing/_harness.py +651 -0
  166. picolet-0.0.1/picolet/testing/_webkit.py +314 -0
  167. picolet-0.0.1/pyproject.toml +66 -0
@@ -0,0 +1,34 @@
1
+ # Build output
2
+ target/
3
+ build/
4
+ build-*/
5
+ *.exe
6
+ *.pyc
7
+ __pycache__/
8
+
9
+ # Frontend build outputs (Vite dist/) inside examples/
10
+ examples/*/dist/
11
+
12
+ # Cached runtime artifacts downloaded by `picolet build`
13
+ .picolet-cache/
14
+
15
+ # Dependencies / caches
16
+ node_modules/
17
+ .venv/
18
+ .uv-cache/
19
+
20
+ # Editor
21
+ .vscode/
22
+ .idea/
23
+ *.swp
24
+
25
+ # OS
26
+ .DS_Store
27
+ Thumbs.db
28
+
29
+ # Build-hook materialised resources (hatch_build.py copies these in
30
+ # from sibling workspace packages; checked-in copies would drift).
31
+ packages/picolet/picolet/_bridge/picolet-bridge.js
32
+ packages/picolet/picolet/_runtime_data/sbom/runtime.toml
33
+ packages/picolet/picolet/_runtime_data/mbm.toml
34
+ packages/picolet/picolet/_runtime_data/RUNTIME_TAG
picolet-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.4
2
+ Name: picolet
3
+ Version: 0.0.1
4
+ Summary: Compile Python programs to small self-contained native binaries via MicroPython
5
+ Project-URL: Homepage, https://github.com/andrewleech/picolet
6
+ Project-URL: Source, https://github.com/andrewleech/picolet
7
+ Project-URL: Issues, https://github.com/andrewleech/picolet/issues
8
+ Author-email: Andrew Leech <andrew@alelec.net>
9
+ License: MIT
10
+ Keywords: binary,bundler,freeze,lvgl,micropython,webview
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Build Tools
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: mpremote
21
+ Provides-Extra: testing
22
+ Requires-Dist: pillow>=10.0; extra == 'testing'
23
+ Requires-Dist: playwright>=1.40; extra == 'testing'
24
+ Requires-Dist: websockets>=12.0; extra == 'testing'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # Picolet
28
+
29
+ Compile a Python program into a small self-contained native executable. Like PyInstaller, but the binary is hundreds of kilobytes rather than tens of megabytes, starts in milliseconds, and has no runtime Python dependency on the host.
30
+
31
+ ## The shape of it
32
+
33
+ A Picolet binary is one file. Inside:
34
+
35
+ - A trimmed MicroPython interpreter (~410–650 KB depending on renderer).
36
+ - Your application's `.py` code, compiled to bytecode and frozen into the binary.
37
+ - Optional bundled assets (HTML, fonts, images, schemas) as a read-only ROM filesystem appended to the executable.
38
+ - Optionally: a GUI renderer (system webview or native LVGL) for HTML/JS or native UIs.
39
+
40
+ The result runs on any matching-OS/arch machine without installing Python.
41
+
42
+ ## Three ways to use it
43
+
44
+ ### 1. Bundle a single CLI script
45
+
46
+ The simplest case:
47
+
48
+ ```bash
49
+ picolet build hello.py
50
+ ./hello # Linux ≈ 647 KB
51
+ ./hello.exe # Windows ≈ 409 KB
52
+ ```
53
+
54
+ `hello.py` becomes a self-contained executable. Sub-second startup. No `python` interpreter needed on the host machine. Roughly 20–50× smaller than the equivalent PyInstaller bundle, with no first-launch unpacking delay.
55
+
56
+ ### 2. Manifest-driven build
57
+
58
+ For multi-module apps, drive the build from a MicroPython `manifest.py`:
59
+
60
+ ```python
61
+ # manifest.py
62
+ require("argparse") # frozen micropython-lib module
63
+ require("typing")
64
+ freeze("./src", "main.py") # your entry
65
+ freeze("./src/lib", "utils.py") # additional modules
66
+ freeze("./src/lib", "data_model.py")
67
+ ```
68
+
69
+ ```bash
70
+ picolet build --manifest manifest.py
71
+ ```
72
+
73
+ The manifest is the canonical MicroPython mechanism for declaring what's frozen into a build. Picolet uses it directly — everything declared is included.
74
+
75
+ Medium-term: romfs contents (HTML, fonts, etc.) declared in the same manifest, per upstream evolution.
76
+
77
+ ### 3. GUI application
78
+
79
+ Add a `picolet.toml` to pick a renderer and bundle UI assets:
80
+
81
+ ```toml
82
+ [app]
83
+ name = "my-app"
84
+ entry = "src/main.py"
85
+
86
+ [ui]
87
+ renderer = "webview" # or "lvgl" for native
88
+ root = "ui"
89
+
90
+ [window]
91
+ title = "My App"
92
+ size = [900, 600]
93
+
94
+ [romfs]
95
+ include = ["ui", "assets"]
96
+ ```
97
+
98
+ ```bash
99
+ picolet build
100
+ ```
101
+
102
+ For Vue or other JS framework frontends:
103
+
104
+ ```toml
105
+ [ui.frontend]
106
+ framework = "vue" # builds Vite output into romfs automatically
107
+ ```
108
+
109
+ The IPC bridge is set up automatically:
110
+
111
+ ```javascript
112
+ // JS side
113
+ await window.picolet.invoke('list_items', { filter: 'active' });
114
+ window.picolet.on('progress', e => bar.update(e.pct));
115
+ ```
116
+
117
+ ```python
118
+ # Python side
119
+ @picolet.command
120
+ async def list_items(args):
121
+ return [...]
122
+ ```
123
+
124
+ Four worked examples under `examples/` (`pydfu`, `notes`, `config-editor`, `dashboard`) demonstrate the patterns end-to-end, each with a distinct visual aesthetic.
125
+
126
+ ## Caveats
127
+
128
+ Read these before adopting.
129
+
130
+ - **MicroPython, not CPython.** The standard library subset is smaller. Pure-Python code using `os`, `sys`, `json`, `re`, `time`, `asyncio`, `struct`, `io` etc. typically works. Code that depends on C extensions (numpy, pandas, Pillow, lxml, etc.) does not. Picolet cannot make a CPython library "just work" — it would have to be ported or replaced with a MicroPython equivalent.
131
+
132
+ - **`micropython-lib` fills most stdlib gaps.** Modules like `argparse`, `pathlib`, `dataclasses`, `typing`, `unittest` are available via [micropython-lib](https://github.com/micropython/micropython-lib) and are declared with `require("name")` in the manifest.
133
+
134
+ - **Custom C modules are straightforward.** A Picolet binary is a MicroPython build under the hood, so any C module written against the standard MicroPython API works. Drop a directory under `user_c_modules/` and reference it in the manifest. Once [upstream PR #18229](https://github.com/micropython/micropython/pull/18229) lands in the fork, `c_module("./path/to/mymodule")` can declare it directly in the manifest.
135
+
136
+ - **Python C-API extensions (CPython `.so`/`.pyd`) do NOT work.** MicroPython's runtime is binary-incompatible with CPython. Write a MicroPython C module instead.
137
+
138
+ - **Async semantics differ slightly.** MicroPython's `asyncio` is a subset of CPython's. Coroutines, tasks, queues, locks, `gather`, `wait_for` work; `asyncio.run` with policies, debug mode, the `loop.add_signal_handler` interface, and some niche APIs don't. Most app code is unaffected.
139
+
140
+ - **First-class platform support is Linux x64 and Windows x64.** macOS (Intel + Apple Silicon) is source-complete but requires GitHub Actions CI for native builds — local cross-compile from Linux is not supported. ARM Linux and mobile platforms are on the backlog.
141
+
142
+ See [docs/caveats.md](docs/caveats.md) for a full catalogue.
143
+
144
+ ## Toolchain expectations
145
+
146
+ - The `picolet` CLI runs on Linux, macOS, or Windows (host).
147
+ - Building Windows binaries from Linux uses [`dockcross`](https://github.com/dockcross/dockcross); Docker is required for that path.
148
+ - Building macOS binaries uses GitHub Actions runners (`macos-13` Intel, `macos-14` Apple Silicon).
149
+ - Node.js + npm are required only when building Vue/React frontends.
150
+
151
+ ## Getting started
152
+
153
+ Install the CLI. `uv tool install` is the recommended path (no separate
154
+ package manager needed if you already use `uv`); `pipx` is the fallback
155
+ for environments without `uv`. Plain `pip install` is deliberately not
156
+ listed — most modern distros (PEP 668) block it system-wide.
157
+
158
+ ```bash
159
+ uv tool install picolet-cli # recommended
160
+ # or:
161
+ pipx install picolet-cli # fallback
162
+
163
+ picolet init my-app --template hello-cli # see --list-templates for the full set
164
+ cd my-app
165
+ picolet dev # live rebuild on file changes
166
+ picolet build # produce target/<os-arch>/my-app[.exe]
167
+ ```
168
+
169
+ Templates: `hello-cli`, `hello-webview`, `hello-lvgl`, `hello-vue`, `pydfu`, `notes`, `config-editor`, `dashboard`.
170
+
171
+ ## Examples gallery
172
+
173
+ <table>
174
+ <tr>
175
+ <td align="center">
176
+ <a href="examples/pydfu/">
177
+ <img src="examples/pydfu/screenshots/device-list-populated.png" alt="pydfu screenshot" />
178
+ </a>
179
+ <br>
180
+ <strong>pydfu</strong><br>
181
+ DFU firmware flasher (industrial control-panel aesthetic)
182
+ </td>
183
+ <td align="center">
184
+ <a href="examples/notes/">
185
+ <img src="examples/notes/screenshots/list-populated.png" alt="notes screenshot" />
186
+ </a>
187
+ <br>
188
+ <strong>notes</strong><br>
189
+ Markdown notes (editorial / refined)
190
+ </td>
191
+ </tr>
192
+ <tr>
193
+ <td align="center">
194
+ <a href="examples/config-editor/">
195
+ <img src="examples/config-editor/screenshots/edit-toml.png" alt="config-editor screenshot" />
196
+ </a>
197
+ <br>
198
+ <strong>config-editor</strong><br>
199
+ Schema-driven TOML/YAML/JSON editor (brutalist terminal)
200
+ </td>
201
+ <td align="center">
202
+ <a href="examples/dashboard/">
203
+ <img src="examples/dashboard/screenshots/full-dashboard.png" alt="dashboard screenshot" />
204
+ </a>
205
+ <br>
206
+ <strong>dashboard</strong><br>
207
+ Live system metrics (data-dense)
208
+ </td>
209
+ </tr>
210
+ </table>
211
+
212
+ See [docs/examples.md](docs/examples.md) for a longer tour of each.
213
+
214
+ ## Renderers
215
+
216
+ | Renderer | Backed by | Use case | Binary size (typical) |
217
+ |---|---|---|---|
218
+ | (none) | — | CLI tool, no UI | ~647 KB Linux / ~409 KB Windows |
219
+ | `webview` | WebKitGTK 4.1 (Linux), WebView2 (Windows), WKWebView (macOS) | HTML/CSS/JS frontend | ~710 KB Linux / ~525 KB Windows |
220
+ | `lvgl` | [`lv_binding_micropython`](https://github.com/lvgl/lv_binding_micropython) + SDL2 | Native widgets, zero system UI deps | ~1.84 MB Linux / ~2.05 MB Windows |
221
+
222
+ ## Repository layout
223
+
224
+ ```
225
+ picolet/
226
+ ├── packages/
227
+ │ ├── picolet-cli/ # picolet init|dev|build|run|test
228
+ │ ├── picolet-runtime/ # the MicroPython runtime + variants + user_c_modules
229
+ │ ├── picolet-bridge-js/ # JS shim: window.picolet.invoke(...)
230
+ │ ├── picolet-templates/ # `picolet init --template <name>` starter packs
231
+ │ └── picolet-testing/ # AppHarness for autonomous test/screenshot
232
+ ├── examples/ # four worked example apps
233
+ ├── tests/ # per-phase test suites
234
+ └── docs/ # architecture, caveats, examples, CLI reference
235
+ ```
236
+
237
+ ## More
238
+
239
+ - [Getting started](docs/getting-started.md) — step-by-step tutorial
240
+ - [`manifest.py` guide](docs/manifest.md) — declaring frozen modules + `require()` from `micropython-lib` and community packages
241
+ - [Architecture](docs/architecture.md) — design decisions
242
+ - [Caveats](docs/caveats.md) — MicroPython compatibility reference
243
+ - [Examples tour](docs/examples.md) — what each example app demonstrates
244
+ - [CLI reference](docs/cli-reference.md) — every `picolet` subcommand
245
+ - [SBOM](docs/sbom.md) — supply-chain documentation
246
+ - [History](docs/history/) — phase artefacts and version-specific specs/plans/audits
247
+
248
+ ## License
249
+
250
+ MIT throughout. See [LICENSE](LICENSE).
@@ -0,0 +1,224 @@
1
+ # Picolet
2
+
3
+ Compile a Python program into a small self-contained native executable. Like PyInstaller, but the binary is hundreds of kilobytes rather than tens of megabytes, starts in milliseconds, and has no runtime Python dependency on the host.
4
+
5
+ ## The shape of it
6
+
7
+ A Picolet binary is one file. Inside:
8
+
9
+ - A trimmed MicroPython interpreter (~410–650 KB depending on renderer).
10
+ - Your application's `.py` code, compiled to bytecode and frozen into the binary.
11
+ - Optional bundled assets (HTML, fonts, images, schemas) as a read-only ROM filesystem appended to the executable.
12
+ - Optionally: a GUI renderer (system webview or native LVGL) for HTML/JS or native UIs.
13
+
14
+ The result runs on any matching-OS/arch machine without installing Python.
15
+
16
+ ## Three ways to use it
17
+
18
+ ### 1. Bundle a single CLI script
19
+
20
+ The simplest case:
21
+
22
+ ```bash
23
+ picolet build hello.py
24
+ ./hello # Linux ≈ 647 KB
25
+ ./hello.exe # Windows ≈ 409 KB
26
+ ```
27
+
28
+ `hello.py` becomes a self-contained executable. Sub-second startup. No `python` interpreter needed on the host machine. Roughly 20–50× smaller than the equivalent PyInstaller bundle, with no first-launch unpacking delay.
29
+
30
+ ### 2. Manifest-driven build
31
+
32
+ For multi-module apps, drive the build from a MicroPython `manifest.py`:
33
+
34
+ ```python
35
+ # manifest.py
36
+ require("argparse") # frozen micropython-lib module
37
+ require("typing")
38
+ freeze("./src", "main.py") # your entry
39
+ freeze("./src/lib", "utils.py") # additional modules
40
+ freeze("./src/lib", "data_model.py")
41
+ ```
42
+
43
+ ```bash
44
+ picolet build --manifest manifest.py
45
+ ```
46
+
47
+ The manifest is the canonical MicroPython mechanism for declaring what's frozen into a build. Picolet uses it directly — everything declared is included.
48
+
49
+ Medium-term: romfs contents (HTML, fonts, etc.) declared in the same manifest, per upstream evolution.
50
+
51
+ ### 3. GUI application
52
+
53
+ Add a `picolet.toml` to pick a renderer and bundle UI assets:
54
+
55
+ ```toml
56
+ [app]
57
+ name = "my-app"
58
+ entry = "src/main.py"
59
+
60
+ [ui]
61
+ renderer = "webview" # or "lvgl" for native
62
+ root = "ui"
63
+
64
+ [window]
65
+ title = "My App"
66
+ size = [900, 600]
67
+
68
+ [romfs]
69
+ include = ["ui", "assets"]
70
+ ```
71
+
72
+ ```bash
73
+ picolet build
74
+ ```
75
+
76
+ For Vue or other JS framework frontends:
77
+
78
+ ```toml
79
+ [ui.frontend]
80
+ framework = "vue" # builds Vite output into romfs automatically
81
+ ```
82
+
83
+ The IPC bridge is set up automatically:
84
+
85
+ ```javascript
86
+ // JS side
87
+ await window.picolet.invoke('list_items', { filter: 'active' });
88
+ window.picolet.on('progress', e => bar.update(e.pct));
89
+ ```
90
+
91
+ ```python
92
+ # Python side
93
+ @picolet.command
94
+ async def list_items(args):
95
+ return [...]
96
+ ```
97
+
98
+ Four worked examples under `examples/` (`pydfu`, `notes`, `config-editor`, `dashboard`) demonstrate the patterns end-to-end, each with a distinct visual aesthetic.
99
+
100
+ ## Caveats
101
+
102
+ Read these before adopting.
103
+
104
+ - **MicroPython, not CPython.** The standard library subset is smaller. Pure-Python code using `os`, `sys`, `json`, `re`, `time`, `asyncio`, `struct`, `io` etc. typically works. Code that depends on C extensions (numpy, pandas, Pillow, lxml, etc.) does not. Picolet cannot make a CPython library "just work" — it would have to be ported or replaced with a MicroPython equivalent.
105
+
106
+ - **`micropython-lib` fills most stdlib gaps.** Modules like `argparse`, `pathlib`, `dataclasses`, `typing`, `unittest` are available via [micropython-lib](https://github.com/micropython/micropython-lib) and are declared with `require("name")` in the manifest.
107
+
108
+ - **Custom C modules are straightforward.** A Picolet binary is a MicroPython build under the hood, so any C module written against the standard MicroPython API works. Drop a directory under `user_c_modules/` and reference it in the manifest. Once [upstream PR #18229](https://github.com/micropython/micropython/pull/18229) lands in the fork, `c_module("./path/to/mymodule")` can declare it directly in the manifest.
109
+
110
+ - **Python C-API extensions (CPython `.so`/`.pyd`) do NOT work.** MicroPython's runtime is binary-incompatible with CPython. Write a MicroPython C module instead.
111
+
112
+ - **Async semantics differ slightly.** MicroPython's `asyncio` is a subset of CPython's. Coroutines, tasks, queues, locks, `gather`, `wait_for` work; `asyncio.run` with policies, debug mode, the `loop.add_signal_handler` interface, and some niche APIs don't. Most app code is unaffected.
113
+
114
+ - **First-class platform support is Linux x64 and Windows x64.** macOS (Intel + Apple Silicon) is source-complete but requires GitHub Actions CI for native builds — local cross-compile from Linux is not supported. ARM Linux and mobile platforms are on the backlog.
115
+
116
+ See [docs/caveats.md](docs/caveats.md) for a full catalogue.
117
+
118
+ ## Toolchain expectations
119
+
120
+ - The `picolet` CLI runs on Linux, macOS, or Windows (host).
121
+ - Building Windows binaries from Linux uses [`dockcross`](https://github.com/dockcross/dockcross); Docker is required for that path.
122
+ - Building macOS binaries uses GitHub Actions runners (`macos-13` Intel, `macos-14` Apple Silicon).
123
+ - Node.js + npm are required only when building Vue/React frontends.
124
+
125
+ ## Getting started
126
+
127
+ Install the CLI. `uv tool install` is the recommended path (no separate
128
+ package manager needed if you already use `uv`); `pipx` is the fallback
129
+ for environments without `uv`. Plain `pip install` is deliberately not
130
+ listed — most modern distros (PEP 668) block it system-wide.
131
+
132
+ ```bash
133
+ uv tool install picolet-cli # recommended
134
+ # or:
135
+ pipx install picolet-cli # fallback
136
+
137
+ picolet init my-app --template hello-cli # see --list-templates for the full set
138
+ cd my-app
139
+ picolet dev # live rebuild on file changes
140
+ picolet build # produce target/<os-arch>/my-app[.exe]
141
+ ```
142
+
143
+ Templates: `hello-cli`, `hello-webview`, `hello-lvgl`, `hello-vue`, `pydfu`, `notes`, `config-editor`, `dashboard`.
144
+
145
+ ## Examples gallery
146
+
147
+ <table>
148
+ <tr>
149
+ <td align="center">
150
+ <a href="examples/pydfu/">
151
+ <img src="examples/pydfu/screenshots/device-list-populated.png" alt="pydfu screenshot" />
152
+ </a>
153
+ <br>
154
+ <strong>pydfu</strong><br>
155
+ DFU firmware flasher (industrial control-panel aesthetic)
156
+ </td>
157
+ <td align="center">
158
+ <a href="examples/notes/">
159
+ <img src="examples/notes/screenshots/list-populated.png" alt="notes screenshot" />
160
+ </a>
161
+ <br>
162
+ <strong>notes</strong><br>
163
+ Markdown notes (editorial / refined)
164
+ </td>
165
+ </tr>
166
+ <tr>
167
+ <td align="center">
168
+ <a href="examples/config-editor/">
169
+ <img src="examples/config-editor/screenshots/edit-toml.png" alt="config-editor screenshot" />
170
+ </a>
171
+ <br>
172
+ <strong>config-editor</strong><br>
173
+ Schema-driven TOML/YAML/JSON editor (brutalist terminal)
174
+ </td>
175
+ <td align="center">
176
+ <a href="examples/dashboard/">
177
+ <img src="examples/dashboard/screenshots/full-dashboard.png" alt="dashboard screenshot" />
178
+ </a>
179
+ <br>
180
+ <strong>dashboard</strong><br>
181
+ Live system metrics (data-dense)
182
+ </td>
183
+ </tr>
184
+ </table>
185
+
186
+ See [docs/examples.md](docs/examples.md) for a longer tour of each.
187
+
188
+ ## Renderers
189
+
190
+ | Renderer | Backed by | Use case | Binary size (typical) |
191
+ |---|---|---|---|
192
+ | (none) | — | CLI tool, no UI | ~647 KB Linux / ~409 KB Windows |
193
+ | `webview` | WebKitGTK 4.1 (Linux), WebView2 (Windows), WKWebView (macOS) | HTML/CSS/JS frontend | ~710 KB Linux / ~525 KB Windows |
194
+ | `lvgl` | [`lv_binding_micropython`](https://github.com/lvgl/lv_binding_micropython) + SDL2 | Native widgets, zero system UI deps | ~1.84 MB Linux / ~2.05 MB Windows |
195
+
196
+ ## Repository layout
197
+
198
+ ```
199
+ picolet/
200
+ ├── packages/
201
+ │ ├── picolet-cli/ # picolet init|dev|build|run|test
202
+ │ ├── picolet-runtime/ # the MicroPython runtime + variants + user_c_modules
203
+ │ ├── picolet-bridge-js/ # JS shim: window.picolet.invoke(...)
204
+ │ ├── picolet-templates/ # `picolet init --template <name>` starter packs
205
+ │ └── picolet-testing/ # AppHarness for autonomous test/screenshot
206
+ ├── examples/ # four worked example apps
207
+ ├── tests/ # per-phase test suites
208
+ └── docs/ # architecture, caveats, examples, CLI reference
209
+ ```
210
+
211
+ ## More
212
+
213
+ - [Getting started](docs/getting-started.md) — step-by-step tutorial
214
+ - [`manifest.py` guide](docs/manifest.md) — declaring frozen modules + `require()` from `micropython-lib` and community packages
215
+ - [Architecture](docs/architecture.md) — design decisions
216
+ - [Caveats](docs/caveats.md) — MicroPython compatibility reference
217
+ - [Examples tour](docs/examples.md) — what each example app demonstrates
218
+ - [CLI reference](docs/cli-reference.md) — every `picolet` subcommand
219
+ - [SBOM](docs/sbom.md) — supply-chain documentation
220
+ - [History](docs/history/) — phase artefacts and version-specific specs/plans/audits
221
+
222
+ ## License
223
+
224
+ MIT throughout. See [LICENSE](LICENSE).
@@ -0,0 +1,77 @@
1
+ """Hatch build hook: materialize sibling-package resources into picolet/.
2
+
3
+ The picolet wheel ships three pieces of data that live in sibling workspace
4
+ packages outside packages/picolet/:
5
+
6
+ packages/picolet-bridge-js/dist/picolet-bridge.js
7
+ packages/picolet-runtime/sbom/runtime.toml
8
+ packages/picolet-runtime/mbm.toml
9
+ packages/picolet-runtime/RUNTIME_TAG
10
+
11
+ A ``[tool.hatch.build.targets.wheel.force-include]`` rule with ``../`` paths
12
+ *almost* works — it does when hatch is building directly from the source
13
+ workspace. It fails when uv (or pip) builds the wheel from an extracted
14
+ sdist, because the extracted sdist root has no siblings.
15
+
16
+ This hook runs in ``initialize`` (before file enumeration) and copies the
17
+ sibling files into the picolet/ package tree at:
18
+
19
+ picolet/_bridge/picolet-bridge.js
20
+ picolet/_runtime_data/sbom/runtime.toml
21
+ picolet/_runtime_data/mbm.toml
22
+ picolet/_runtime_data/RUNTIME_TAG
23
+
24
+ Once present in the tree they get enumerated as ordinary package files for
25
+ both sdist and wheel. The sdist therefore contains them, so a downstream
26
+ ``pip wheel`` from the sdist works without needing the workspace.
27
+
28
+ The destination files are git-ignored in the repo so they don't drift
29
+ between dev builds and CI rebuilds.
30
+
31
+ When the hook can't find the source files (the workspace root has no
32
+ siblings — e.g. an extracted sdist), it skips silently; the assumption is
33
+ that the files are already in the package tree because the sdist build hook
34
+ already put them there.
35
+ """
36
+ from __future__ import annotations
37
+
38
+ import shutil
39
+ from pathlib import Path
40
+
41
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
42
+
43
+
44
+ # (workspace-relative source, package-relative destination)
45
+ _FILE_MAP = (
46
+ ("packages/picolet-bridge-js/dist/picolet-bridge.js",
47
+ "picolet/_bridge/picolet-bridge.js"),
48
+ ("packages/picolet-runtime/sbom/runtime.toml",
49
+ "picolet/_runtime_data/sbom/runtime.toml"),
50
+ ("packages/picolet-runtime/mbm.toml",
51
+ "picolet/_runtime_data/mbm.toml"),
52
+ ("packages/picolet-runtime/RUNTIME_TAG",
53
+ "picolet/_runtime_data/RUNTIME_TAG"),
54
+ )
55
+
56
+
57
+ class CustomBuildHook(BuildHookInterface):
58
+ PLUGIN_NAME = "picolet-resources"
59
+
60
+ def initialize(self, version, build_data):
61
+ pkg_root = Path(self.root) # packages/picolet/
62
+ # workspace root: parent.parent from packages/picolet/ → repo root
63
+ repo_root = pkg_root.parent.parent
64
+
65
+ for src_rel, dst_rel in _FILE_MAP:
66
+ src = repo_root / src_rel
67
+ dst = pkg_root / dst_rel
68
+
69
+ if not src.is_file():
70
+ # Likely building from an extracted sdist where siblings
71
+ # don't exist. The sdist build hook should have already
72
+ # placed the file at dst; if it's missing too the build
73
+ # will fail later with a clearer error.
74
+ continue
75
+
76
+ dst.parent.mkdir(parents=True, exist_ok=True)
77
+ shutil.copy2(src, dst)
@@ -0,0 +1,26 @@
1
+ """Picolet — compile Python programs to small self-contained native binaries.
2
+
3
+ Public surface from the host-installed CLI:
4
+
5
+ picolet.cli — command implementations (build, dev, init, run, test, ...)
6
+ picolet.testing — AppHarness + webview/CDP drivers for autonomous testing
7
+ (requires the [testing] extra: ``pip install picolet[testing]``)
8
+ picolet.templates — starter-app templates discoverable via importlib.resources
9
+
10
+ The ``picolet`` CLI command is exposed via the entry point declared in
11
+ pyproject.toml; ``python -m picolet`` invokes the same main().
12
+
13
+ Note: the in-binary ``import picolet`` inside a compiled MicroPython runtime
14
+ refers to a separate set of frozen modules (the dispatcher, IPC transport,
15
+ system event facade, etc.) that live under packages/picolet-runtime/python/
16
+ and never ship in this wheel.
17
+ """
18
+
19
+ try:
20
+ from importlib.metadata import PackageNotFoundError, version as _pkg_version
21
+
22
+ __version__ = _pkg_version("picolet")
23
+ except Exception:
24
+ __version__ = "0.0.0-dev"
25
+
26
+ __all__ = ("__version__",)