machineconfig 8.14__py3-none-any.whl → 8.50__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of machineconfig might be problematic. Click here for more details.

Files changed (273) hide show
  1. machineconfig/cluster/remote/run_cluster.py +1 -1
  2. machineconfig/cluster/remote/run_remote.py +1 -1
  3. machineconfig/cluster/sessions_managers/utils/maker.py +10 -8
  4. machineconfig/cluster/sessions_managers/wt_local.py +1 -1
  5. machineconfig/cluster/sessions_managers/wt_local_manager.py +1 -1
  6. machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
  7. machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
  8. machineconfig/jobs/installer/checks/check_installations.py +133 -0
  9. machineconfig/jobs/installer/checks/install_utils.py +132 -0
  10. machineconfig/jobs/installer/checks/report_utils.py +39 -0
  11. machineconfig/jobs/installer/checks/vt_utils.py +89 -0
  12. machineconfig/jobs/installer/installer_data.json +225 -140
  13. machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
  14. machineconfig/jobs/installer/package_groups.py +10 -9
  15. machineconfig/jobs/installer/python_scripts/boxes.py +1 -2
  16. machineconfig/jobs/installer/python_scripts/code.py +10 -8
  17. machineconfig/jobs/installer/python_scripts/hx.py +30 -13
  18. machineconfig/jobs/installer/python_scripts/nerfont_windows_helper.py +6 -5
  19. machineconfig/jobs/installer/python_scripts/sysabc.py +25 -19
  20. machineconfig/jobs/installer/python_scripts/yazi.py +33 -17
  21. machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
  22. machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +1 -1
  23. machineconfig/jobs/scripts_dynamic/a.py +413 -10
  24. machineconfig/profile/create_links.py +77 -20
  25. machineconfig/profile/create_links_export.py +63 -58
  26. machineconfig/profile/mapper_data.toml +30 -0
  27. machineconfig/profile/mapper_dotfiles.toml +253 -0
  28. machineconfig/scripts/python/agents.py +70 -172
  29. machineconfig/scripts/python/ai/initai.py +3 -1
  30. machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
  31. machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
  32. machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +7 -5
  33. machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
  34. machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
  35. machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
  36. machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
  37. machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
  38. machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
  39. machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
  40. machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
  41. machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
  42. machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
  43. machineconfig/scripts/python/cloud.py +58 -11
  44. machineconfig/scripts/python/croshell.py +4 -156
  45. machineconfig/scripts/python/devops.py +57 -40
  46. machineconfig/scripts/python/devops_navigator.py +17 -3
  47. machineconfig/scripts/python/fire_jobs.py +8 -207
  48. machineconfig/scripts/python/ftpx.py +5 -225
  49. machineconfig/scripts/python/graph/cli_graph.json +8743 -0
  50. machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
  51. machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
  52. machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
  53. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
  54. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
  55. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
  56. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
  57. machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
  58. machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +5 -5
  59. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
  60. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
  61. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +3 -3
  62. machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
  63. machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
  64. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
  65. machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
  66. machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
  67. machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +267 -0
  68. machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
  69. machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
  70. machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +76 -0
  71. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_nw.py +52 -72
  72. machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
  73. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +40 -23
  74. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
  75. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
  76. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_terminal.py +12 -6
  77. machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
  78. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +12 -6
  79. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
  80. machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +68 -52
  81. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/run_script.py +75 -58
  82. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
  83. machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
  84. machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
  85. machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
  86. machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
  87. machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
  88. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
  89. machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
  90. machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +1 -1
  91. machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
  92. machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
  93. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
  94. machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
  95. machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
  96. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
  97. machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
  98. machineconfig/scripts/python/helpers/helpers_network/__init__.py +0 -0
  99. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +15 -17
  100. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address_switch.py +1 -1
  101. machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
  102. machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_ssh.py +2 -2
  103. machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
  104. machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
  105. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
  106. machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
  107. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
  108. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
  109. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +117 -33
  110. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
  111. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
  112. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
  113. machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
  114. machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
  115. machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
  116. machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +186 -0
  117. machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -1
  118. machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
  119. machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
  120. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
  121. machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/python.py +47 -26
  122. machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
  123. machineconfig/scripts/python/mcfg_entry.py +133 -48
  124. machineconfig/scripts/python/msearch.py +15 -61
  125. machineconfig/scripts/python/sessions.py +59 -194
  126. machineconfig/scripts/python/terminal.py +18 -96
  127. machineconfig/scripts/python/utils.py +101 -20
  128. machineconfig/settings/atuin/config.toml +294 -0
  129. machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
  130. machineconfig/settings/linters/.ruff.toml +1 -0
  131. machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
  132. machineconfig/settings/shells/bash/init.sh +6 -3
  133. machineconfig/settings/shells/pwsh/init.ps1 +69 -1
  134. machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
  135. machineconfig/settings/shells/wezterm/wezterm.lua +4 -1
  136. machineconfig/settings/shells/wt/settings.json +20 -7
  137. machineconfig/settings/shells/zsh/init.sh +25 -4
  138. machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
  139. machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
  140. machineconfig/settings/tv/config.toml +234 -0
  141. machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
  142. machineconfig/settings/wsl/.wslconfig +5 -30
  143. machineconfig/settings/yazi/yazi_linux.toml +18 -8
  144. machineconfig/settings/zellij/layouts/st.kdl +2 -2
  145. machineconfig/settings/zellij/layouts/st2.kdl +1 -1
  146. machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
  147. machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
  148. machineconfig/setup_mac/__init__.py +0 -2
  149. machineconfig/setup_windows/__init__.py +0 -1
  150. machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
  151. machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
  152. machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
  153. machineconfig/type_hinting/sql/__init__.py +1 -0
  154. machineconfig/type_hinting/sql/base.py +216 -0
  155. machineconfig/type_hinting/sql/core_schema.py +64 -0
  156. machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
  157. machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
  158. machineconfig/type_hinting/typedict/__init__.py +1 -0
  159. machineconfig/type_hinting/typedict/ast_utils.py +130 -0
  160. machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
  161. machineconfig/type_hinting/typedict/generators.py +231 -0
  162. machineconfig/type_hinting/typedict/polars_schema.py +24 -0
  163. machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
  164. machineconfig/utils/accessories.py +24 -0
  165. machineconfig/utils/code.py +41 -13
  166. machineconfig/utils/files/ascii_art.py +10 -14
  167. machineconfig/utils/files/headers.py +3 -5
  168. machineconfig/utils/files/read.py +8 -1
  169. machineconfig/utils/installer_utils/github_release_bulk.py +11 -91
  170. machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
  171. machineconfig/utils/installer_utils/install_from_url.py +1 -1
  172. machineconfig/utils/installer_utils/installer_class.py +12 -4
  173. machineconfig/utils/installer_utils/installer_cli.py +1 -15
  174. machineconfig/utils/installer_utils/installer_helper.py +2 -2
  175. machineconfig/utils/installer_utils/installer_locator_utils.py +13 -13
  176. machineconfig/utils/installer_utils/installer_runner.py +4 -4
  177. machineconfig/utils/io.py +25 -8
  178. machineconfig/utils/meta.py +6 -4
  179. machineconfig/utils/options.py +49 -19
  180. machineconfig/utils/options_utils/__init__.py +0 -0
  181. machineconfig/utils/options_utils/options_tv_linux.py +211 -0
  182. machineconfig/utils/options_utils/options_tv_windows.py +88 -0
  183. machineconfig/utils/options_utils/tv_options.py +37 -0
  184. machineconfig/utils/path_extended.py +6 -6
  185. machineconfig/utils/scheduler.py +8 -2
  186. machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
  187. machineconfig/utils/source_of_truth.py +6 -1
  188. machineconfig/utils/ssh.py +69 -18
  189. machineconfig/utils/ssh_utils/abc.py +1 -1
  190. machineconfig/utils/ssh_utils/copy_from_here.py +17 -12
  191. machineconfig/utils/ssh_utils/utils.py +21 -5
  192. machineconfig/utils/ssh_utils/wsl.py +107 -170
  193. machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
  194. machineconfig/utils/upgrade_packages.py +4 -8
  195. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/METADATA +29 -22
  196. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/RECORD +251 -211
  197. machineconfig/jobs/installer/check_installations.py +0 -248
  198. machineconfig/profile/backup.toml +0 -49
  199. machineconfig/profile/mapper.toml +0 -263
  200. machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
  201. machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
  202. machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
  203. machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -208
  204. machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
  205. machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
  206. machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
  207. machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
  208. machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
  209. machineconfig/scripts/python/helpers_network/ssh_add_identity.py +0 -116
  210. machineconfig/scripts/python/helpers_network/ssh_add_ssh_key.py +0 -153
  211. machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
  212. machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
  213. machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
  214. machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
  215. machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
  216. machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
  217. machineconfig/utils/options_tv.py +0 -119
  218. machineconfig/utils/tst.py +0 -20
  219. /machineconfig/{scripts/python/helpers_agents → jobs/installer/checks}/__init__.py +0 -0
  220. /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
  221. /machineconfig/scripts/python/{helpers_agents/agentic_frameworks → graph}/__init__.py +0 -0
  222. /machineconfig/scripts/python/{helpers_cloud → helpers}/__init__.py +0 -0
  223. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
  224. /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
  225. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_agents}/__init__.py +0 -0
  226. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
  227. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
  228. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
  229. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
  230. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
  231. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aichat/config.yaml +0 -0
  232. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aider/.aider.conf.yml +0 -0
  233. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/copilot/config.yml +0 -0
  234. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/crush/crush.json +0 -0
  235. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/gemini/settings.json +0 -0
  236. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/privacy.py +0 -0
  237. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
  238. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
  239. /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +0 -0
  240. /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_cloud}/__init__.py +0 -0
  241. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
  242. /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
  243. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_croshell}/__init__.py +0 -0
  244. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
  245. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
  246. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
  247. /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
  248. /machineconfig/scripts/python/{helpers_network → helpers/helpers_devops}/__init__.py +0 -0
  249. /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops/themes}/__init__.py +0 -0
  250. /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
  251. /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
  252. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
  253. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/f.py +0 -0
  254. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +0 -0
  255. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +0 -0
  256. /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_streamlit_helper.py +0 -0
  257. /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
  258. /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
  259. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nfs.py +0 -0
  260. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nw_drive.py +0 -0
  261. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
  262. /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
  263. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
  264. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
  265. /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
  266. /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
  267. /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
  268. /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
  269. /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
  270. /machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/pdf.py +0 -0
  271. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/WHEEL +0 -0
  272. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/entry_points.txt +0 -0
  273. {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,319 @@
1
+ import ast
2
+ import inspect
3
+ from pathlib import Path
4
+ from typing import Literal
5
+
6
+
7
+ WRAPPER_TYPES = {"ReadOnly", "NotRequired", "Optional", "Required", "Final"}
8
+ BUILTIN_TYPES = {"str", "int", "float", "bool", "bytes", "None", "list", "dict", "set", "tuple", "Any", "Literal"}
9
+ PYTHON_TYPE_TO_SERIES_TYPE: dict[str, str] = {"str": "str", "int": "int", "float": "float", "bool": "bool", "bytes": "bytes"}
10
+ PYTHON_TYPE_TO_POLARS_DTYPE: dict[str, str] = {"str": '"pl.String"', "int": '"pl.Int64"', "float": '"pl.Float64"', "bool": '"pl.Boolean"', "bytes": '"pl.Binary"'}
11
+
12
+
13
+ def get_types_class_name(class_name: str) -> str:
14
+ return f"{class_name}_Types"
15
+
16
+
17
+ def collect_type_names_from_annotation(annotation: ast.expr | None) -> set[str]:
18
+ if annotation is None:
19
+ return set()
20
+ names: set[str] = set()
21
+ if isinstance(annotation, ast.Name):
22
+ if annotation.id not in BUILTIN_TYPES and annotation.id not in WRAPPER_TYPES:
23
+ names.add(annotation.id)
24
+ elif isinstance(annotation, ast.Subscript):
25
+ names.update(collect_type_names_from_annotation(annotation.value))
26
+ names.update(collect_type_names_from_annotation(annotation.slice))
27
+ elif isinstance(annotation, ast.BinOp):
28
+ names.update(collect_type_names_from_annotation(annotation.left))
29
+ names.update(collect_type_names_from_annotation(annotation.right))
30
+ elif isinstance(annotation, ast.Tuple):
31
+ for elt in annotation.elts:
32
+ names.update(collect_type_names_from_annotation(elt))
33
+ return names
34
+
35
+
36
+ def extract_imports_from_source(source_file_path: Path) -> tuple[dict[str, str], dict[str, str], set[str]]:
37
+ source_content = source_file_path.read_text(encoding="utf-8")
38
+ tree = ast.parse(source_content)
39
+ imports: dict[str, str] = {}
40
+ local_type_aliases: dict[str, str] = {}
41
+ local_classes: set[str] = set()
42
+ for node in ast.walk(tree):
43
+ if isinstance(node, ast.ImportFrom) and node.module:
44
+ for alias in node.names:
45
+ name = alias.asname or alias.name
46
+ imports[name] = node.module
47
+ elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
48
+ if isinstance(node.annotation, ast.Name) and node.annotation.id == "TypeAlias" and node.value is not None:
49
+ local_type_aliases[node.target.id] = ast.unparse(node.value)
50
+ elif isinstance(node, ast.ClassDef):
51
+ local_classes.add(node.name)
52
+ return imports, local_type_aliases, local_classes
53
+
54
+
55
+ def unwrap_type_annotation(annotation: ast.expr | None) -> ast.expr | None:
56
+ if annotation is None:
57
+ return None
58
+ if isinstance(annotation, ast.Subscript) and isinstance(annotation.value, ast.Name) and annotation.value.id in WRAPPER_TYPES:
59
+ return unwrap_type_annotation(annotation.slice)
60
+ if isinstance(annotation, ast.Subscript) and isinstance(annotation.value, ast.Attribute) and annotation.value.attr in WRAPPER_TYPES:
61
+ return unwrap_type_annotation(annotation.slice)
62
+ return annotation
63
+
64
+
65
+ def is_builtin_type(annotation: ast.expr) -> bool:
66
+ if isinstance(annotation, ast.Name):
67
+ return annotation.id in BUILTIN_TYPES
68
+ if isinstance(annotation, ast.Constant):
69
+ return True
70
+ if isinstance(annotation, ast.Subscript):
71
+ return is_builtin_type(annotation.value) and is_builtin_type(annotation.slice)
72
+ if isinstance(annotation, ast.Attribute):
73
+ return False
74
+ if isinstance(annotation, ast.BinOp):
75
+ return is_builtin_type(annotation.left) and is_builtin_type(annotation.right)
76
+ if isinstance(annotation, ast.Tuple):
77
+ return all(is_builtin_type(elt) for elt in annotation.elts)
78
+ return False
79
+
80
+
81
+ def python_type_to_iterable_str(annotation: ast.expr | None) -> str:
82
+ unwrapped = unwrap_type_annotation(annotation)
83
+ if unwrapped is None:
84
+ return 'Iterable["Any"]'
85
+ type_str = ast.unparse(unwrapped)
86
+ if not is_builtin_type(unwrapped):
87
+ return f'Iterable["{type_str}"]'
88
+ return f"Iterable[{type_str}]"
89
+
90
+
91
+ def get_iterable_type_for_col(annotation: ast.expr | None) -> str:
92
+ unwrapped = unwrap_type_annotation(annotation)
93
+ if unwrapped is None:
94
+ return 'Annotated["pl.Series", Any]'
95
+ if isinstance(unwrapped, ast.Name):
96
+ dtype = PYTHON_TYPE_TO_POLARS_DTYPE.get(unwrapped.id)
97
+ if dtype:
98
+ return f'Annotated["pl.Series", {dtype}]'
99
+ return 'Annotated["pl.Series", Any]'
100
+ if isinstance(unwrapped, ast.Subscript) and isinstance(unwrapped.value, ast.Name):
101
+ if unwrapped.value.id == "list":
102
+ return 'Annotated["pl.Series", "pl.List"]'
103
+ return 'Annotated["pl.Series", Any]'
104
+
105
+
106
+ def get_random_value_expr(annotation: ast.expr | None) -> str:
107
+ unwrapped = unwrap_type_annotation(annotation)
108
+ if unwrapped is None:
109
+ return "None"
110
+ if isinstance(unwrapped, ast.Name):
111
+ type_name = unwrapped.id
112
+ if type_name == "str":
113
+ return "pl.Series([secrets.token_hex(8) for _ in range(n_rows)])"
114
+ if type_name == "int":
115
+ return "pl.Series(random.choices(range(-1000, 1000), k=n_rows))"
116
+ if type_name == "float":
117
+ return "pl.Series([random.uniform(-1000.0, 1000.0) for _ in range(n_rows)])"
118
+ if type_name == "bool":
119
+ return "pl.Series(random.choices([True, False], k=n_rows))"
120
+ if type_name == "bytes":
121
+ return "pl.Series([secrets.token_bytes(16) for _ in range(n_rows)])"
122
+ return "pl.Series([None] * n_rows)"
123
+ if isinstance(unwrapped, ast.Subscript) and isinstance(unwrapped.value, ast.Name):
124
+ if unwrapped.value.id == "list":
125
+ return "pl.Series([[random.randint(0, 100) for _ in range(3)] for _ in range(n_rows)])"
126
+ return "pl.Series([None] * n_rows)"
127
+
128
+
129
+ # def _check_random_imports_needed(field_infos: list[tuple[str, ast.expr | None]]) -> tuple[bool, bool]:
130
+ # needs_random = False
131
+ # needs_secrets = False
132
+ # for _field_name, annotation in field_infos:
133
+ # unwrapped = unwrap_type_annotation(annotation)
134
+ # if unwrapped is None:
135
+ # continue
136
+ # if isinstance(unwrapped, ast.Name):
137
+ # type_name = unwrapped.id
138
+ # if type_name in {"int", "float", "bool"}:
139
+ # needs_random = True
140
+ # elif type_name in {"str", "bytes"}:
141
+ # needs_secrets = True
142
+ # elif isinstance(unwrapped, ast.Subscript) and isinstance(unwrapped.value, ast.Name):
143
+ # if unwrapped.value.id == "list":
144
+ # needs_random = True
145
+ # return needs_random, needs_secrets
146
+
147
+
148
+ def quote_pl_in_annotation(annotation_str: str) -> str:
149
+ """Quote pl.X types in annotation strings since pl is only available under TYPE_CHECKING."""
150
+ import re
151
+ # Match pl.X only when NOT already inside quotes (preceded by ' or ")
152
+ # Use negative lookbehind for quotes
153
+ return re.sub(r"(?<!['\"])(\bpl\.\w+)(?!['\"])", r"'\1'", annotation_str)
154
+
155
+
156
+ def _get_module_name_from_output_path(file_path: Path) -> str:
157
+ """Get the module name from the output file path."""
158
+ resolved = file_path.resolve()
159
+ parts: list[str] = []
160
+ current = resolved.parent
161
+ while current != current.parent:
162
+ if not (current / "__init__.py").exists():
163
+ break
164
+ parts.append(current.name)
165
+ current = current.parent
166
+ parts.reverse()
167
+ return ".".join(parts) if parts else ""
168
+
169
+
170
+ def get_module_level_helper_functions() -> list[str]:
171
+ """Get helper functions to be defined once at module level for self-contained mode.
172
+ Returns only the function definitions, not imports (imports are handled separately at file top).
173
+ """
174
+ from machineconfig.type_hinting.typedict import polars_schema_typeddict
175
+
176
+ lines = []
177
+ lines.append("# Helper functions for self-contained mode (defined once at module level)")
178
+ lines.append("")
179
+
180
+ # Add all helper functions
181
+ for func_name in ["_unwrap_type", "_get_polars_type", "get_polars_schema_from_typeddict", "get_polars_df_random_data_from_typeddict"]:
182
+ func = getattr(polars_schema_typeddict, func_name)
183
+ source = inspect.getsource(func)
184
+ for line in source.splitlines():
185
+ lines.append(line)
186
+ lines.append("")
187
+
188
+ return lines
189
+
190
+
191
+ def generate_for_class(class_name: str, field_infos: list[tuple[str, ast.expr | None]], source_module: str, dependency: Literal["import", "self-contained"] = "self-contained", output_file_path: Path | None = None) -> list[str]:
192
+ lines: list[str] = []
193
+ field_names = [fn for fn, _ in field_infos]
194
+
195
+ types_class_name = get_types_class_name(class_name)
196
+
197
+ names_class_name = f"{class_name}Names"
198
+ lines.append(f"class {names_class_name}:")
199
+ if field_infos:
200
+ for field_name in field_names:
201
+ lines.append(f' {field_name}: Literal["{field_name}"] = "{field_name}"')
202
+ else:
203
+ lines.append(" pass")
204
+ lines.append("")
205
+ lines.append("")
206
+
207
+ names_literal = f"{class_name}_NAMES"
208
+ if field_names:
209
+ literal_values = ", ".join(f'"{fn}"' for fn in field_names)
210
+ lines.append(f'{names_literal}: TypeAlias = Literal[{literal_values}]')
211
+ else:
212
+ lines.append(f'{names_literal}: TypeAlias = Literal[""]')
213
+ lines.append("")
214
+ lines.append("")
215
+
216
+ lines.append(f"class {types_class_name}:")
217
+ if field_infos:
218
+ for field_name, annotation in field_infos:
219
+ if annotation is None:
220
+ raise ValueError(f"Field '{field_name}' in class '{class_name}' lacks an annotation")
221
+ unwrapped = unwrap_type_annotation(annotation)
222
+ if unwrapped is None:
223
+ raise ValueError(f"Field '{field_name}' in class '{class_name}' lacks an annotation")
224
+ annotation_source = ast.unparse(unwrapped)
225
+ annotation_source = quote_pl_in_annotation(annotation_source)
226
+ lines.append(f" {field_name}: TypeAlias = {annotation_source}")
227
+ else:
228
+ lines.append(" pass")
229
+ lines.append("")
230
+ lines.append("")
231
+
232
+ wrapper_class_name = f"{class_name}_Wrapper"
233
+ lines.append(f"class {wrapper_class_name}:")
234
+ lines.append(f" c = {names_class_name}")
235
+ lines.append(f" ct: TypeAlias = {names_literal}")
236
+ lines.append(f' e: TypeAlias = {class_name}')
237
+ lines.append(f" t: TypeAlias = {types_class_name}")
238
+ lines.append("")
239
+ lines.append(' def __init__(self, df: "pl.DataFrame") -> None:')
240
+ lines.append(" self.df = df")
241
+ lines.append("")
242
+
243
+ if field_infos:
244
+ # Group fields by their return type to reduce number of overloads
245
+ grouped_fields: dict[str, list[str]] = {}
246
+ for field_name, annotation in field_infos:
247
+ col_type = get_iterable_type_for_col(annotation)
248
+ grouped_fields.setdefault(col_type, []).append(field_name)
249
+
250
+ if len(grouped_fields) == 1:
251
+ col_type = list(grouped_fields.keys())[0]
252
+ lines.append(f' def get_col(self, name: {names_literal}) -> {col_type}:')
253
+ lines.append(" return self.df.select(name).to_series()")
254
+ lines.append("")
255
+ else:
256
+ for col_type, fields in grouped_fields.items():
257
+ lines.append(" @overload")
258
+ if len(fields) == 1:
259
+ lines.append(f' def get_col(self, name: Literal["{fields[0]}"]) -> {col_type}: ...')
260
+ else:
261
+ literals = ", ".join(f'"{f}"' for f in fields)
262
+ lines.append(f' def get_col(self, name: Literal[{literals}]) -> {col_type}: ...')
263
+
264
+ lines.append(f' def get_col(self, name: {names_literal}) -> Annotated["pl.Series", Any]:')
265
+ lines.append(" return self.df.select(name).to_series()")
266
+ lines.append("")
267
+
268
+ params: list[str] = []
269
+ dict_entries: list[str] = []
270
+ for field_name, annotation in field_infos:
271
+ iterable_type = python_type_to_iterable_str(annotation)
272
+ params.append(f"{field_name}: {iterable_type}")
273
+ dict_entries.append(f'"{field_name}": {field_name}')
274
+ params_str = ", ".join(params)
275
+ dict_str = "{" + ", ".join(dict_entries) + "}"
276
+ lines.append(" @staticmethod")
277
+ lines.append(f' def make({params_str}) -> "{wrapper_class_name}":')
278
+
279
+ if dependency == "import":
280
+ # Use fully qualified import from dtypes_utils
281
+ if output_file_path:
282
+ output_module = _get_module_name_from_output_path(output_file_path)
283
+ lines.append(f" from {output_module}.dtypes_utils import get_polars_schema_from_typeddict as get_polars_schema")
284
+ else:
285
+ lines.append(" from machineconfig.type_hinting.polars_schema_typeddict import get_polars_schema_from_typeddict as get_polars_schema")
286
+ else: # self-contained - use module-level function
287
+ lines.append(" get_polars_schema = get_polars_schema_from_typeddict")
288
+
289
+ lines.append(f" return {wrapper_class_name}(pl.DataFrame({dict_str}, schema=get_polars_schema({class_name})))")
290
+ lines.append("")
291
+
292
+ lines.append(" @staticmethod")
293
+ lines.append(f' def make_fake(n_rows: int) -> "{wrapper_class_name}":')
294
+
295
+ if dependency == "import":
296
+ # Use fully qualified import from dtypes_utils
297
+ if output_file_path:
298
+ output_module = _get_module_name_from_output_path(output_file_path)
299
+ lines.append(f" from {output_module}.dtypes_utils import get_polars_df_random_data_from_typeddict")
300
+ else:
301
+ lines.append(" from machineconfig.type_hinting.polars_schema_typeddict import get_polars_df_random_data_from_typeddict")
302
+ else: # self-contained - use module-level function
303
+ pass # No imports needed, function is at module level
304
+
305
+ lines.append(f" return {wrapper_class_name}(get_polars_df_random_data_from_typeddict({class_name}, n_rows))")
306
+ else:
307
+ lines.append(" @staticmethod")
308
+ lines.append(f' def make() -> "{wrapper_class_name}":')
309
+ lines.append(" import polars as pl")
310
+ lines.append(f" return {wrapper_class_name}(pl.DataFrame())")
311
+ lines.append("")
312
+ lines.append(" @staticmethod")
313
+ lines.append(f' def make_fake(n_rows: int) -> "{wrapper_class_name}":')
314
+ lines.append(" import polars as pl")
315
+ lines.append(" _ = n_rows")
316
+ lines.append(f" return {wrapper_class_name}(pl.DataFrame())")
317
+ lines.append("")
318
+ lines.append("")
319
+ return lines
@@ -0,0 +1,231 @@
1
+ import ast
2
+ import shutil
3
+ from pathlib import Path
4
+ from typing import Literal
5
+
6
+ from machineconfig.type_hinting.typedict.ast_utils import load_target_class_fields
7
+ from machineconfig.type_hinting.typedict.generator_helpers import (
8
+ collect_type_names_from_annotation,
9
+ extract_imports_from_source,
10
+ generate_for_class,
11
+ get_types_class_name,
12
+ unwrap_type_annotation,
13
+ )
14
+
15
+
16
+ def _get_module_name_from_path(file_path: Path) -> str:
17
+ resolved = file_path.resolve()
18
+ parts: list[str] = [resolved.stem]
19
+ current = resolved.parent
20
+ while current != current.parent:
21
+ if not (current / "__init__.py").exists():
22
+ break
23
+ parts.append(current.name)
24
+ current = current.parent
25
+ parts.reverse()
26
+ return ".".join(parts)
27
+
28
+
29
+ def generate_names_file(source_file_path: Path, output_file_path: Path, search_paths: list[Path] | None = None, dependency: Literal["import", "self-contained"] = "self-contained") -> Path:
30
+ target_classes = load_target_class_fields(source_file_path, search_paths)
31
+ target_path = Path(output_file_path).resolve()
32
+
33
+ # Handle dependency mode: copy dtypes_utils.py for 'import' mode
34
+ if dependency == "import":
35
+ source_polars_schema = Path(__file__).parent / "polars_schema_typeddict.py"
36
+ target_dtypes_utils = target_path.parent / "dtypes_utils.py"
37
+ shutil.copy2(source_polars_schema, target_dtypes_utils)
38
+
39
+ source_imports, local_type_aliases, local_classes = extract_imports_from_source(Path(source_file_path))
40
+
41
+ all_custom_types: dict[str, str | None] = {}
42
+ for _class_name, field_infos in target_classes:
43
+ for _field_name, annotation, field_imports in field_infos:
44
+ unwrapped = unwrap_type_annotation(annotation)
45
+ type_names = collect_type_names_from_annotation(unwrapped)
46
+ for type_name in type_names:
47
+ if type_name not in all_custom_types:
48
+ if type_name in field_imports:
49
+ all_custom_types[type_name] = field_imports[type_name][0]
50
+ else:
51
+ all_custom_types[type_name] = None
52
+
53
+ grouped_imports: dict[str, list[str]] = {}
54
+ needed_local_aliases: list[str] = []
55
+ needed_local_classes: list[str] = []
56
+ for type_name in sorted(all_custom_types.keys()):
57
+ module = all_custom_types[type_name]
58
+ if module:
59
+ grouped_imports.setdefault(module, []).append(type_name)
60
+ elif type_name in source_imports:
61
+ module = source_imports[type_name]
62
+ grouped_imports.setdefault(module, []).append(type_name)
63
+ elif type_name in local_type_aliases:
64
+ needed_local_aliases.append(type_name)
65
+ elif type_name in local_classes:
66
+ needed_local_classes.append(type_name)
67
+
68
+ # Check if Any is actually used in get_col return type annotations
69
+ uses_any = False
70
+ for _class_name, field_infos in target_classes:
71
+ if not field_infos: # Empty class won't have get_col with Any
72
+ continue
73
+ # Check if there are multiple different column types (which means we need Any fallback)
74
+ from machineconfig.type_hinting.typedict.generator_helpers import get_iterable_type_for_col
75
+ col_types = set()
76
+ for _field_name, annotation in [(fn, ann) for fn, ann, _ in field_infos]:
77
+ col_types.add(get_iterable_type_for_col(annotation))
78
+ if len(col_types) > 1:
79
+ uses_any = True
80
+ break
81
+
82
+ # Build typing imports based on what's needed
83
+ typing_imports = ["Annotated", "Literal", "TypeAlias", "TYPE_CHECKING", "overload"]
84
+ if uses_any:
85
+ typing_imports.insert(1, "Any") # Insert after Annotated
86
+
87
+ lines: list[str] = ["from collections.abc import Iterable", f"from typing import {', '.join(typing_imports)}"]
88
+
89
+ # Add self-contained mode imports right at the top
90
+ if dependency == "self-contained":
91
+ lines.append("from typing import ReadOnly, get_origin, get_args")
92
+ lines.append("import polars as pl")
93
+ lines.append("import random")
94
+ lines.append("import secrets")
95
+
96
+ lines.append("")
97
+
98
+ target_class_names = [class_name for class_name, _ in target_classes]
99
+ source_module = _get_module_name_from_path(source_file_path)
100
+ if target_class_names:
101
+ lines.append(f"from {source_module} import {', '.join(sorted(target_class_names))}")
102
+
103
+ for alias_name in sorted(needed_local_aliases):
104
+ lines.append(f"{alias_name}: TypeAlias = {local_type_aliases[alias_name]}")
105
+ if needed_local_aliases:
106
+ lines.append("")
107
+
108
+ # Runtime imports: types used in _Types classes (TypeAlias assignments) need to be available at runtime
109
+ for module, type_names in sorted(grouped_imports.items()):
110
+ lines.append(f"from {module} import {', '.join(sorted(type_names))}")
111
+
112
+ # Check if numpy (np) is used in type aliases - look through all annotations
113
+ needs_numpy = False
114
+ for _class_name, field_infos in target_classes:
115
+ for _field_name, annotation, _field_imports in field_infos:
116
+ if annotation:
117
+ import ast
118
+ annotation_str = ast.unparse(annotation)
119
+ if 'np.' in annotation_str:
120
+ needs_numpy = True
121
+ break
122
+ if needs_numpy:
123
+ break
124
+
125
+ if needs_numpy:
126
+ lines.append("import numpy as np")
127
+
128
+ lines.append("")
129
+ # Only add TYPE_CHECKING block for non-self-contained mode (self-contained imports polars at top)
130
+ if dependency != "self-contained":
131
+ lines.append("if TYPE_CHECKING:")
132
+ lines.append(" import polars as pl")
133
+ else:
134
+ # For self-contained, polars is already imported at the top
135
+ lines.append("if TYPE_CHECKING:")
136
+ lines.append(" pass")
137
+ all_type_checking_imports = sorted(set(needed_local_classes) - set(target_class_names))
138
+ if all_type_checking_imports:
139
+ lines.append(f" from {source_module} import {', '.join(all_type_checking_imports)}")
140
+ lines.append("")
141
+
142
+ # For self-contained mode, add helper functions at module level
143
+ if dependency == "self-contained":
144
+ from machineconfig.type_hinting.typedict.generator_helpers import get_module_level_helper_functions
145
+ helper_lines = get_module_level_helper_functions()
146
+ lines.extend(helper_lines)
147
+ lines.append("")
148
+
149
+ for class_name, field_infos in target_classes:
150
+ source_module = _get_module_name_from_path(source_file_path)
151
+ stripped_field_infos = [(fn, ann) for fn, ann, _ in field_infos]
152
+ lines.extend(generate_for_class(class_name, stripped_field_infos, source_module, dependency=dependency, output_file_path=target_path))
153
+
154
+ lines.append("")
155
+ lines.append('if __name__ == "__main__":')
156
+ lines.append(" import polars as pl")
157
+ lines.append("")
158
+
159
+ output_content = "\n".join(lines)
160
+ with target_path.open(mode="w", encoding="utf-8") as f:
161
+ f.write(output_content)
162
+ return target_path
163
+
164
+
165
+ def generate_types_file(source_file_path: Path, output_file_path: Path, search_paths: list[Path] | None = None) -> Path:
166
+ target_classes = load_target_class_fields(source_file_path, search_paths)
167
+ target_path = Path(output_file_path).resolve()
168
+
169
+ source_imports, local_type_aliases, local_classes = extract_imports_from_source(Path(source_file_path))
170
+
171
+ all_custom_types: dict[str, str | None] = {}
172
+ for _class_name, field_infos in target_classes:
173
+ for _field_name, annotation, field_imports in field_infos:
174
+ unwrapped = unwrap_type_annotation(annotation)
175
+ type_names = collect_type_names_from_annotation(unwrapped)
176
+ for type_name in type_names:
177
+ if type_name not in all_custom_types:
178
+ if type_name in field_imports:
179
+ all_custom_types[type_name] = field_imports[type_name][0]
180
+ else:
181
+ all_custom_types[type_name] = None
182
+
183
+ grouped_imports: dict[str, list[str]] = {}
184
+ needed_local_aliases: list[str] = []
185
+ needed_local_classes: list[str] = []
186
+ for type_name in sorted(all_custom_types.keys()):
187
+ module = all_custom_types[type_name]
188
+ if module:
189
+ grouped_imports.setdefault(module, []).append(type_name)
190
+ elif type_name in source_imports:
191
+ module = source_imports[type_name]
192
+ grouped_imports.setdefault(module, []).append(type_name)
193
+ elif type_name in local_type_aliases:
194
+ needed_local_aliases.append(type_name)
195
+ elif type_name in local_classes:
196
+ needed_local_classes.append(type_name)
197
+
198
+ lines: list[str] = ["from typing import TypeAlias"]
199
+ for module, type_names in sorted(grouped_imports.items()):
200
+ lines.append(f"from {module} import {', '.join(sorted(type_names))}")
201
+ if needed_local_classes:
202
+ source_module = _get_module_name_from_path(source_file_path)
203
+ lines.append(f"from {source_module} import {', '.join(sorted(needed_local_classes))}")
204
+ lines.append("")
205
+ for alias_name in sorted(needed_local_aliases):
206
+ lines.append(f"{alias_name}: TypeAlias = {local_type_aliases[alias_name]}")
207
+ if needed_local_aliases:
208
+ lines.append("")
209
+ lines.append("")
210
+
211
+ for class_name, field_infos in target_classes:
212
+ types_class_name = get_types_class_name(class_name)
213
+ lines.append(f"class {types_class_name}:")
214
+ if field_infos:
215
+ for field_name, annotation, _ in field_infos:
216
+ if annotation is None:
217
+ raise ValueError(f"Field '{field_name}' in class '{class_name}' lacks an annotation")
218
+ unwrapped = unwrap_type_annotation(annotation)
219
+ if unwrapped is None:
220
+ raise ValueError(f"Field '{field_name}' in class '{class_name}' lacks an annotation")
221
+ annotation_source = ast.unparse(unwrapped)
222
+ lines.append(f" {field_name}: TypeAlias = {annotation_source}")
223
+ else:
224
+ lines.append(" pass")
225
+ lines.append("")
226
+ lines.append("")
227
+
228
+ output_content = "\n".join(lines)
229
+ with target_path.open(mode="w", encoding="utf-8") as f:
230
+ f.write(output_content)
231
+ return target_path
@@ -0,0 +1,24 @@
1
+ from typing import Any, TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ import polars as pl
5
+
6
+
7
+ def get_polars_schema(typed_dict: type) -> "dict[str, pl.DataType]":
8
+ import polars as pl
9
+
10
+ def _get_polars_type(python_type: Any) -> pl.DataType:
11
+ if python_type == str:
12
+ return pl.String()
13
+ if python_type == float:
14
+ return pl.Float64()
15
+ if python_type == int:
16
+ return pl.Int64()
17
+ if python_type == bool:
18
+ return pl.Boolean()
19
+ return pl.String()
20
+
21
+ schema: dict[str, pl.DataType] = {}
22
+ for k, v in typed_dict.__annotations__.items():
23
+ schema[k] = _get_polars_type(v)
24
+ return schema
@@ -0,0 +1,63 @@
1
+ from typing import Any, ReadOnly, get_origin, get_args, TYPE_CHECKING
2
+ import random
3
+ import secrets
4
+
5
+ if TYPE_CHECKING:
6
+ import polars as pl
7
+
8
+
9
+ def _unwrap_type(python_type: Any) -> Any:
10
+ """Unwrap ReadOnly and other type wrappers to get the inner type."""
11
+ origin = get_origin(python_type)
12
+ if origin is ReadOnly:
13
+ args = get_args(python_type)
14
+ return args[0] if args else python_type
15
+ return python_type
16
+
17
+
18
+ def _get_polars_type(python_type: Any) -> "pl.DataType":
19
+ """Convert Python types to appropriate Polars types, handling ReadOnly wrappers."""
20
+ unwrapped = _unwrap_type(python_type)
21
+ import polars as pl
22
+ if unwrapped is str:
23
+ return pl.String()
24
+ if unwrapped is float:
25
+ return pl.Float64()
26
+ if unwrapped is int:
27
+ return pl.Int64()
28
+ if unwrapped is bool:
29
+ return pl.Boolean()
30
+ return pl.String()
31
+
32
+
33
+ def get_polars_schema_from_typeddict(typed_dict: type) -> dict[str, "pl.DataType"]:
34
+ """Convert a TypedDict to a Polars schema, properly handling ReadOnly wrappers."""
35
+ # import polars as pl
36
+ schema: dict[str, "pl.DataType"] = {}
37
+ for k, v in typed_dict.__annotations__.items():
38
+ schema[k] = _get_polars_type(v)
39
+ return schema
40
+
41
+
42
+ def get_polars_df_random_data_from_typeddict(typed_dict: type, n_rows: int) -> "pl.DataFrame":
43
+ """Generate a Polars DataFrame with random data based on a TypedDict definition."""
44
+ data: dict[str, "pl.Series"] = {}
45
+ import polars as pl
46
+ for k, v in typed_dict.__annotations__.items():
47
+ unwrapped = _unwrap_type(v)
48
+ if unwrapped is str:
49
+ data[k] = pl.Series([secrets.token_hex(8) for _ in range(n_rows)])
50
+ elif unwrapped is int:
51
+ data[k] = pl.Series(random.choices(range(-1000, 1000), k=n_rows))
52
+ elif unwrapped is float:
53
+ data[k] = pl.Series([random.uniform(-1000.0, 1000.0) for _ in range(n_rows)])
54
+ elif unwrapped is bool:
55
+ data[k] = pl.Series(random.choices([True, False], k=n_rows))
56
+ elif unwrapped is bytes:
57
+ data[k] = pl.Series([secrets.token_bytes(16) for _ in range(n_rows)])
58
+ elif get_origin(unwrapped) is list:
59
+ data[k] = pl.Series([[random.randint(0, 100) for _ in range(3)] for _ in range(n_rows)])
60
+ else:
61
+ data[k] = pl.Series([None] * n_rows)
62
+
63
+ return pl.DataFrame(data, schema=get_polars_schema_from_typeddict(typed_dict))
@@ -110,3 +110,27 @@ def get_repo_root(path: "Path") -> Optional["Path"]:
110
110
 
111
111
  if __name__ == "__main__":
112
112
  from pathlib import Path
113
+
114
+
115
+ def display_with_flashy_style(msg: str, title: str) -> None:
116
+ """Display a flashy, unmissable share URL announcement."""
117
+ from rich.console import Console
118
+ from rich.panel import Panel
119
+ from rich.text import Text
120
+ from rich.align import Align
121
+ console = Console()
122
+ url_text = Text(msg, style="bold bright_cyan underline")
123
+ message = Text.assemble(
124
+ ("🚀 ", "bright_red"),
125
+ url_text,
126
+ (" 🚀", "bright_red")
127
+ )
128
+ panel = Panel(
129
+ Align.center(message),
130
+ title=f"[bold bright_green]🌐 {title} 🌐[/bold bright_green]",
131
+ subtitle="[italic bright_yellow]⚡ Click the link above to access your shared files! ⚡[/italic bright_yellow]",
132
+ border_style="bright_magenta",
133
+ padding=(1, 2),
134
+ expand=False
135
+ )
136
+ console.print(panel)