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.
- machineconfig/cluster/remote/run_cluster.py +1 -1
- machineconfig/cluster/remote/run_remote.py +1 -1
- machineconfig/cluster/sessions_managers/utils/maker.py +10 -8
- machineconfig/cluster/sessions_managers/wt_local.py +1 -1
- machineconfig/cluster/sessions_managers/wt_local_manager.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_local.py +1 -1
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +1 -1
- machineconfig/jobs/installer/checks/check_installations.py +133 -0
- machineconfig/jobs/installer/checks/install_utils.py +132 -0
- machineconfig/jobs/installer/checks/report_utils.py +39 -0
- machineconfig/jobs/installer/checks/vt_utils.py +89 -0
- machineconfig/jobs/installer/installer_data.json +225 -140
- machineconfig/jobs/installer/linux_scripts/docker.sh +6 -9
- machineconfig/jobs/installer/package_groups.py +10 -9
- machineconfig/jobs/installer/python_scripts/boxes.py +1 -2
- machineconfig/jobs/installer/python_scripts/code.py +10 -8
- machineconfig/jobs/installer/python_scripts/hx.py +30 -13
- machineconfig/jobs/installer/python_scripts/nerfont_windows_helper.py +6 -5
- machineconfig/jobs/installer/python_scripts/sysabc.py +25 -19
- machineconfig/jobs/installer/python_scripts/yazi.py +33 -17
- machineconfig/jobs/scripts/powershell_scripts/cmatrix.ps1 +52 -0
- machineconfig/jobs/scripts/powershell_scripts/mount_ssh.ps1 +1 -1
- machineconfig/jobs/scripts_dynamic/a.py +413 -10
- machineconfig/profile/create_links.py +77 -20
- machineconfig/profile/create_links_export.py +63 -58
- machineconfig/profile/mapper_data.toml +30 -0
- machineconfig/profile/mapper_dotfiles.toml +253 -0
- machineconfig/scripts/python/agents.py +70 -172
- machineconfig/scripts/python/ai/initai.py +3 -1
- machineconfig/scripts/python/ai/scripts/__init__.py +1 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.ps1 +2 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +7 -5
- machineconfig/scripts/python/ai/solutions/claude/claude.py +1 -1
- machineconfig/scripts/python/ai/solutions/cline/cline.py +1 -1
- machineconfig/scripts/python/ai/solutions/copilot/github_copilot.py +1 -1
- machineconfig/scripts/python/ai/solutions/copilot/instructions/python/dev.instructions.md +29 -0
- machineconfig/scripts/python/ai/solutions/crush/crush.py +1 -1
- machineconfig/scripts/python/ai/solutions/cursor/cursors.py +1 -1
- machineconfig/scripts/python/ai/solutions/gemini/gemini.py +1 -1
- machineconfig/scripts/python/ai/solutions/gemini/settings.json +3 -0
- machineconfig/scripts/python/ai/{solutions → utils}/generic.py +2 -15
- machineconfig/scripts/python/ai/utils/vscode_tasks.py +6 -3
- machineconfig/scripts/python/cloud.py +58 -11
- machineconfig/scripts/python/croshell.py +4 -156
- machineconfig/scripts/python/devops.py +57 -40
- machineconfig/scripts/python/devops_navigator.py +17 -3
- machineconfig/scripts/python/fire_jobs.py +8 -207
- machineconfig/scripts/python/ftpx.py +5 -225
- machineconfig/scripts/python/graph/cli_graph.json +8743 -0
- machineconfig/scripts/python/{env_manager → helper_env}/path_manager_tui.py +2 -2
- machineconfig/scripts/python/{env_manager → helpers/helper_env}/env_manager_tui.py +1 -1
- machineconfig/scripts/python/helpers/helper_env/path_manager_tui.py +228 -0
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.py +1 -1
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_cursor_agents.py +1 -1
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_gemini.py +1 -1
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_qwen.py +1 -1
- machineconfig/scripts/python/helpers/helpers_agents/agents_impl.py +168 -0
- machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_launch.py +5 -5
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_copy.py +6 -6
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_mount.py +10 -5
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_sync.py +3 -3
- machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers2.py +1 -1
- machineconfig/scripts/python/helpers/helpers_croshell/croshell_impl.py +225 -0
- machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/scheduler.py +4 -4
- machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/start_slidev.py +7 -6
- machineconfig/scripts/python/helpers/helpers_devops/backup_config.py +149 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_backup_retrieve.py +267 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_config.py +98 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_config_dotfile.py +274 -0
- machineconfig/scripts/python/helpers/helpers_devops/cli_data.py +76 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_nw.py +52 -72
- machineconfig/scripts/python/helpers/helpers_devops/cli_repos.py +274 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_self.py +40 -23
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_file.py +44 -30
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_server.py +26 -43
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/cli_share_terminal.py +12 -6
- machineconfig/scripts/python/helpers/helpers_devops/cli_ssh.py +167 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_status.py +12 -6
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/devops_update_repos.py +1 -1
- machineconfig/scripts/python/{interactive.py → helpers/helpers_devops/interactive.py} +68 -52
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/run_script.py +75 -58
- machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.ps1 +41 -0
- machineconfig/scripts/python/helpers/helpers_devops/themes/choose_starship_theme.sh +48 -0
- machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_wezterm_theme.py +3 -3
- machineconfig/scripts/python/helpers/helpers_fire_command/fire_jobs_impl.py +233 -0
- machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_route_helper.py +3 -3
- machineconfig/scripts/python/helpers/helpers_msearch/msearch_impl.py +248 -0
- machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_linux/fzfg +4 -3
- machineconfig/scripts/python/helpers/helpers_msearch/scripts_linux/search_with_context.sh +48 -0
- machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/scripts_windows/fzfg.ps1 +1 -1
- machineconfig/scripts/python/helpers/helpers_navigator/__init__.py +20 -0
- machineconfig/scripts/python/helpers/helpers_navigator/cli_graph_loader.py +234 -0
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/command_builder.py +61 -13
- machineconfig/scripts/python/helpers/helpers_navigator/command_detail.py +153 -0
- machineconfig/scripts/python/helpers/helpers_navigator/command_tree.py +45 -0
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/data_models.py +18 -11
- machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/main_app.py +5 -5
- machineconfig/scripts/python/helpers/helpers_network/__init__.py +0 -0
- machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address.py +15 -17
- machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/address_switch.py +1 -1
- machineconfig/scripts/python/helpers/helpers_network/ftpx_impl.py +276 -0
- machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_ssh.py +2 -2
- machineconfig/scripts/python/helpers/helpers_network/ssh_add_identity.py +73 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_add_ssh_key.py +175 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_debug_linux.py +319 -0
- machineconfig/scripts/python/helpers/helpers_network/ssh_debug_windows.py +275 -0
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action.py +3 -3
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/action_helper.py +3 -3
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/cloud_repo_sync.py +117 -33
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/grource.py +3 -2
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/record.py +33 -13
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_2.py +63 -19
- machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/update.py +0 -6
- machineconfig/scripts/python/helpers/helpers_search/script_help.py +81 -0
- machineconfig/scripts/python/helpers/helpers_sessions/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_sessions/sessions_impl.py +186 -0
- machineconfig/scripts/python/{helpers_sessions → helpers/helpers_sessions}/sessions_multiprocess.py +1 -1
- machineconfig/scripts/python/helpers/helpers_terminal/__init__.py +0 -0
- machineconfig/scripts/python/helpers/helpers_terminal/terminal_impl.py +96 -0
- machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/download.py +1 -1
- machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/python.py +47 -26
- machineconfig/scripts/python/helpers/helpers_utils/specs.py +246 -0
- machineconfig/scripts/python/mcfg_entry.py +133 -48
- machineconfig/scripts/python/msearch.py +15 -61
- machineconfig/scripts/python/sessions.py +59 -194
- machineconfig/scripts/python/terminal.py +18 -96
- machineconfig/scripts/python/utils.py +101 -20
- machineconfig/settings/atuin/config.toml +294 -0
- machineconfig/settings/atuin/themes/catppuccin-mocha-mauve.toml +12 -0
- machineconfig/settings/linters/.ruff.toml +1 -0
- machineconfig/settings/mprocs/windows/mprocs.yaml +2 -2
- machineconfig/settings/shells/bash/init.sh +6 -3
- machineconfig/settings/shells/pwsh/init.ps1 +69 -1
- machineconfig/settings/shells/pwsh/search_pwsh_history.ps1 +99 -0
- machineconfig/settings/shells/wezterm/wezterm.lua +4 -1
- machineconfig/settings/shells/wt/settings.json +20 -7
- machineconfig/settings/shells/zsh/init.sh +25 -4
- machineconfig/settings/television/cable_unix/bash-history.toml +1 -1
- machineconfig/settings/television/cable_windows/pwsh-history.toml +1 -1
- machineconfig/settings/tv/config.toml +234 -0
- machineconfig/settings/tv/themes/catppuccin-mocha-sky.toml +22 -0
- machineconfig/settings/wsl/.wslconfig +5 -30
- machineconfig/settings/yazi/yazi_linux.toml +18 -8
- machineconfig/settings/zellij/layouts/st.kdl +2 -2
- machineconfig/settings/zellij/layouts/st2.kdl +1 -1
- machineconfig/setup_linux/web_shortcuts/interactive.sh +10 -10
- machineconfig/setup_linux/web_shortcuts/live_from_github.sh +3 -0
- machineconfig/setup_mac/__init__.py +0 -2
- machineconfig/setup_windows/__init__.py +0 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +14 -13
- machineconfig/setup_windows/web_shortcuts/live_from_github.ps1 +4 -3
- machineconfig/setup_windows/web_shortcuts/quick_init.ps1 +3 -3
- machineconfig/type_hinting/sql/__init__.py +1 -0
- machineconfig/type_hinting/sql/base.py +216 -0
- machineconfig/type_hinting/sql/core_schema.py +64 -0
- machineconfig/type_hinting/sql/core_schema_typeddict.py +41 -0
- machineconfig/type_hinting/sql/typeddict_codegen.py +222 -0
- machineconfig/type_hinting/typedict/__init__.py +1 -0
- machineconfig/type_hinting/typedict/ast_utils.py +130 -0
- machineconfig/type_hinting/typedict/generator_helpers.py +319 -0
- machineconfig/type_hinting/typedict/generators.py +231 -0
- machineconfig/type_hinting/typedict/polars_schema.py +24 -0
- machineconfig/type_hinting/typedict/polars_schema_typeddict.py +63 -0
- machineconfig/utils/accessories.py +24 -0
- machineconfig/utils/code.py +41 -13
- machineconfig/utils/files/ascii_art.py +10 -14
- machineconfig/utils/files/headers.py +3 -5
- machineconfig/utils/files/read.py +8 -1
- machineconfig/utils/installer_utils/github_release_bulk.py +11 -91
- machineconfig/utils/installer_utils/github_release_scraper.py +99 -0
- machineconfig/utils/installer_utils/install_from_url.py +1 -1
- machineconfig/utils/installer_utils/installer_class.py +12 -4
- machineconfig/utils/installer_utils/installer_cli.py +1 -15
- machineconfig/utils/installer_utils/installer_helper.py +2 -2
- machineconfig/utils/installer_utils/installer_locator_utils.py +13 -13
- machineconfig/utils/installer_utils/installer_runner.py +4 -4
- machineconfig/utils/io.py +25 -8
- machineconfig/utils/meta.py +6 -4
- machineconfig/utils/options.py +49 -19
- machineconfig/utils/options_utils/__init__.py +0 -0
- machineconfig/utils/options_utils/options_tv_linux.py +211 -0
- machineconfig/utils/options_utils/options_tv_windows.py +88 -0
- machineconfig/utils/options_utils/tv_options.py +37 -0
- machineconfig/utils/path_extended.py +6 -6
- machineconfig/utils/scheduler.py +8 -2
- machineconfig/utils/schemas/fire_agents/fire_agents_input.py +1 -1
- machineconfig/utils/source_of_truth.py +6 -1
- machineconfig/utils/ssh.py +69 -18
- machineconfig/utils/ssh_utils/abc.py +1 -1
- machineconfig/utils/ssh_utils/copy_from_here.py +17 -12
- machineconfig/utils/ssh_utils/utils.py +21 -5
- machineconfig/utils/ssh_utils/wsl.py +107 -170
- machineconfig/utils/ssh_utils/wsl_helper.py +217 -0
- machineconfig/utils/upgrade_packages.py +4 -8
- {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/METADATA +29 -22
- {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/RECORD +251 -211
- machineconfig/jobs/installer/check_installations.py +0 -248
- machineconfig/profile/backup.toml +0 -49
- machineconfig/profile/mapper.toml +0 -263
- machineconfig/scripts/python/helpers_devops/cli_config.py +0 -105
- machineconfig/scripts/python/helpers_devops/cli_config_dotfile.py +0 -89
- machineconfig/scripts/python/helpers_devops/cli_data.py +0 -25
- machineconfig/scripts/python/helpers_devops/cli_repos.py +0 -208
- machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py +0 -80
- machineconfig/scripts/python/helpers_devops/themes/choose_starship_theme.bash +0 -3
- machineconfig/scripts/python/helpers_navigator/__init__.py +0 -20
- machineconfig/scripts/python/helpers_navigator/command_detail.py +0 -44
- machineconfig/scripts/python/helpers_navigator/command_tree.py +0 -620
- machineconfig/scripts/python/helpers_network/ssh_add_identity.py +0 -116
- machineconfig/scripts/python/helpers_network/ssh_add_ssh_key.py +0 -153
- machineconfig/scripts/python/helpers_network/ssh_debug_linux.py +0 -391
- machineconfig/scripts/python/helpers_network/ssh_debug_windows.py +0 -338
- machineconfig/scripts/python/helpers_repos/entrypoint.py +0 -77
- machineconfig/setup_mac/ssh/openssh_setup.sh +0 -114
- machineconfig/setup_windows/ssh/add-sshkey.ps1 +0 -29
- machineconfig/setup_windows/ssh/openssh-server.ps1 +0 -37
- machineconfig/utils/options_tv.py +0 -119
- machineconfig/utils/tst.py +0 -20
- /machineconfig/{scripts/python/helpers_agents → jobs/installer/checks}/__init__.py +0 -0
- /machineconfig/scripts/python/ai/{solutions/_shared.py → utils/shared.py} +0 -0
- /machineconfig/scripts/python/{helpers_agents/agentic_frameworks → graph}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_cloud → helpers}/__init__.py +0 -0
- /machineconfig/scripts/python/{env_manager → helpers/helper_env}/__init__.py +0 -0
- /machineconfig/scripts/python/{env_manager → helpers/helper_env}/path_manager_backend.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_agents}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_devops → helpers/helpers_agents/agentic_frameworks}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/agentic_frameworks/fire_crush.json +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_help_search.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_helper_types.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/fire_agents_load_balancer.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aichat/config.yaml +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/aider/.aider.conf.yml +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/copilot/config.yml +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/crush/crush.json +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/configs/gemini/settings.json +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/privacy/privacy.py +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/prompt.txt +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.ps1 +0 -0
- /machineconfig/scripts/python/{helpers_agents → helpers/helpers_agents}/templates/template.sh +0 -0
- /machineconfig/scripts/python/{helpers_devops/themes → helpers/helpers_cloud}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/cloud_helpers.py +0 -0
- /machineconfig/scripts/python/{helpers_cloud → helpers/helpers_cloud}/helpers5.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_croshell}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/crosh.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/pomodoro.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer.py +0 -0
- /machineconfig/scripts/python/{helpers_croshell → helpers/helpers_croshell}/viewer_template.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_devops}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_sessions → helpers/helpers_devops/themes}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_devops → helpers/helpers_devops}/themes/choose_pwsh_theme.ps1 +0 -0
- /machineconfig/scripts/python/{helpers_devops/themes/choose_starship_theme.ps1 → helpers/helpers_fire_command/__init__.py} +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/cloud_manager.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/f.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/file_wrangler.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_args_helper.py +0 -0
- /machineconfig/scripts/python/{helpers_fire_command → helpers/helpers_fire_command}/fire_jobs_streamlit_helper.py +0 -0
- /machineconfig/scripts/python/{helpers_msearch → helpers/helpers_msearch}/__init__.py +0 -0
- /machineconfig/scripts/python/{helpers_navigator → helpers/helpers_navigator}/search_bar.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nfs.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/mount_nw_drive.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/onetimeshare.py +0 -0
- /machineconfig/scripts/python/{helpers_network → helpers/helpers_network}/wifi_conn.py +0 -0
- /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/clone.py +0 -0
- /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/repo_analyzer_1.py +0 -0
- /machineconfig/scripts/python/{helpers_repos → helpers/helpers_repos}/sync.py +0 -0
- /machineconfig/scripts/python/helpers/{ast_search.py → helpers_search/ast_search.py} +0 -0
- /machineconfig/scripts/python/helpers/{qr_code.py → helpers_search/qr_code.py} +0 -0
- /machineconfig/scripts/python/helpers/{repo_rag.py → helpers_search/repo_rag.py} +0 -0
- /machineconfig/scripts/python/helpers/{symantic_search.py → helpers_search/symantic_search.py} +0 -0
- /machineconfig/scripts/python/{helpers_utils → helpers/helpers_utils}/pdf.py +0 -0
- {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/WHEEL +0 -0
- {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/entry_points.txt +0 -0
- {machineconfig-8.14.dist-info → machineconfig-8.50.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# from uuid import uuid4
|
|
2
|
+
# import enum
|
|
3
|
+
# from datetime import date, datetime, time, timedelta
|
|
4
|
+
|
|
5
|
+
# import sqlalchemy as sa
|
|
6
|
+
# from sqlalchemy import (
|
|
7
|
+
# BigInteger,
|
|
8
|
+
# Boolean,
|
|
9
|
+
# CHAR,
|
|
10
|
+
# Date,
|
|
11
|
+
# DateTime,
|
|
12
|
+
# Float,
|
|
13
|
+
# Integer,
|
|
14
|
+
# Interval,
|
|
15
|
+
# LargeBinary,
|
|
16
|
+
# Numeric,
|
|
17
|
+
# SmallInteger,
|
|
18
|
+
# String,
|
|
19
|
+
# Text,
|
|
20
|
+
# Time,
|
|
21
|
+
# JSON,
|
|
22
|
+
# Enum,
|
|
23
|
+
# )
|
|
24
|
+
# from sqlalchemy.dialects.postgresql import (
|
|
25
|
+
# ARRAY,
|
|
26
|
+
# JSONB,
|
|
27
|
+
# UUID,
|
|
28
|
+
# )
|
|
29
|
+
# from sqlalchemy.orm import (
|
|
30
|
+
# DeclarativeBase,
|
|
31
|
+
# Mapped,
|
|
32
|
+
# mapped_column,
|
|
33
|
+
# )
|
|
34
|
+
|
|
35
|
+
# # Python enum type — stored generally as a VARCHAR or ENUM in the DB
|
|
36
|
+
# class ColorEnum(enum.Enum):
|
|
37
|
+
# RED = "red"
|
|
38
|
+
# GREEN = "green"
|
|
39
|
+
# BLUE = "blue"
|
|
40
|
+
|
|
41
|
+
# class Base(DeclarativeBase):
|
|
42
|
+
# pass
|
|
43
|
+
|
|
44
|
+
# class AllTypesExample(Base):
|
|
45
|
+
# __tablename__ = "all_types_example"
|
|
46
|
+
|
|
47
|
+
# # ----------------------------------
|
|
48
|
+
# # Integer types
|
|
49
|
+
# # ----------------------------------
|
|
50
|
+
|
|
51
|
+
# id: Mapped[int] = mapped_column(
|
|
52
|
+
# Integer,
|
|
53
|
+
# primary_key=True,
|
|
54
|
+
# comment="Typical SQL INTEGER (~int32 on many databases)"
|
|
55
|
+
# )
|
|
56
|
+
|
|
57
|
+
# small_num: Mapped[int] = mapped_column(
|
|
58
|
+
# SmallInteger,
|
|
59
|
+
# comment="SMALLINT (~int16)"
|
|
60
|
+
# )
|
|
61
|
+
|
|
62
|
+
# big_num: Mapped[int] = mapped_column(
|
|
63
|
+
# BigInteger,
|
|
64
|
+
# comment="BIGINT (~int64)"
|
|
65
|
+
# )
|
|
66
|
+
|
|
67
|
+
# # ----------------------------------
|
|
68
|
+
# # Floating-point & precision numbers
|
|
69
|
+
# # ----------------------------------
|
|
70
|
+
|
|
71
|
+
# float_num: Mapped[float] = mapped_column(
|
|
72
|
+
# Float,
|
|
73
|
+
# comment="FLOAT → typically float32/float64 depending on precision [Float maps to SQL FLOAT/REAL] (SQLAlchemy docs) :contentReference[oaicite:0]{index=0}"
|
|
74
|
+
# )
|
|
75
|
+
|
|
76
|
+
# decimal_value: Mapped[float] = mapped_column(
|
|
77
|
+
# Numeric(12, 4),
|
|
78
|
+
# comment="NUMERIC/DECIMAL fixed precision; client uses python Decimal by default (~exact decimal, not float)"
|
|
79
|
+
# )
|
|
80
|
+
|
|
81
|
+
# # ----------------------------------
|
|
82
|
+
# # Strings, text, character
|
|
83
|
+
# # ----------------------------------
|
|
84
|
+
|
|
85
|
+
# short_str: Mapped[str] = mapped_column(
|
|
86
|
+
# String(50),
|
|
87
|
+
# comment="VARCHAR(n) fixed limit"
|
|
88
|
+
# )
|
|
89
|
+
|
|
90
|
+
# long_text: Mapped[str] = mapped_column(
|
|
91
|
+
# Text,
|
|
92
|
+
# comment="TEXT (unbounded string)"
|
|
93
|
+
# )
|
|
94
|
+
|
|
95
|
+
# # ----------------------------------
|
|
96
|
+
# # Boolean
|
|
97
|
+
# # ----------------------------------
|
|
98
|
+
|
|
99
|
+
# is_active: Mapped[bool] = mapped_column(
|
|
100
|
+
# Boolean,
|
|
101
|
+
# comment="BOOLEAN (True/False)"
|
|
102
|
+
# )
|
|
103
|
+
|
|
104
|
+
# # ----------------------------------
|
|
105
|
+
# # Dates and times
|
|
106
|
+
# # ----------------------------------
|
|
107
|
+
|
|
108
|
+
# date_field: Mapped[date] = mapped_column(
|
|
109
|
+
# Date,
|
|
110
|
+
# comment="DATE only (year/month/day)"
|
|
111
|
+
# )
|
|
112
|
+
|
|
113
|
+
# time_field: Mapped[time] = mapped_column(
|
|
114
|
+
# Time,
|
|
115
|
+
# comment="TIME only (hh:mm:ss)"
|
|
116
|
+
# )
|
|
117
|
+
|
|
118
|
+
# datetime_field: Mapped[datetime] = mapped_column(
|
|
119
|
+
# DateTime,
|
|
120
|
+
# comment="TIMESTAMP without timezone"
|
|
121
|
+
# )
|
|
122
|
+
|
|
123
|
+
# interval_field: Mapped[timedelta] = mapped_column(
|
|
124
|
+
# Interval,
|
|
125
|
+
# comment="INTERVAL type (duration)"
|
|
126
|
+
# )
|
|
127
|
+
|
|
128
|
+
# # ----------------------------------
|
|
129
|
+
# # Binary / blobs
|
|
130
|
+
# # ----------------------------------
|
|
131
|
+
|
|
132
|
+
# binary_data: Mapped[bytes] = mapped_column(
|
|
133
|
+
# LargeBinary,
|
|
134
|
+
# comment="Large binary / BLOB"
|
|
135
|
+
# )
|
|
136
|
+
|
|
137
|
+
# # ----------------------------------
|
|
138
|
+
# # JSON
|
|
139
|
+
# # ----------------------------------
|
|
140
|
+
|
|
141
|
+
# json_data: Mapped[dict] = mapped_column(
|
|
142
|
+
# JSON,
|
|
143
|
+
# comment="Generic JSON type (engine specific)"
|
|
144
|
+
# )
|
|
145
|
+
|
|
146
|
+
# jsonb_data: Mapped[dict] = mapped_column(
|
|
147
|
+
# JSONB,
|
|
148
|
+
# comment="PostgreSQL JSONB (binary JSON)"
|
|
149
|
+
# )
|
|
150
|
+
|
|
151
|
+
# # ----------------------------------
|
|
152
|
+
# # Enum
|
|
153
|
+
# # ----------------------------------
|
|
154
|
+
|
|
155
|
+
# color: Mapped[ColorEnum] = mapped_column(
|
|
156
|
+
# Enum(ColorEnum),
|
|
157
|
+
# nullable=False,
|
|
158
|
+
# comment="ENUM type"
|
|
159
|
+
# )
|
|
160
|
+
|
|
161
|
+
# # ----------------------------------
|
|
162
|
+
# # UUID
|
|
163
|
+
# # ----------------------------------
|
|
164
|
+
|
|
165
|
+
# uuid_field: Mapped[str] = mapped_column(
|
|
166
|
+
# UUID(as_uuid=True),
|
|
167
|
+
# default=uuid4,
|
|
168
|
+
# comment="GUID/UUID (128-bit unique identifier)"
|
|
169
|
+
# )
|
|
170
|
+
|
|
171
|
+
# # ----------------------------------
|
|
172
|
+
# # Array — PostgreSQL only
|
|
173
|
+
# # ----------------------------------
|
|
174
|
+
|
|
175
|
+
# int_array: Mapped[list[int]] = mapped_column(
|
|
176
|
+
# ARRAY(Integer),
|
|
177
|
+
# comment="ARRAY of INTEGER (~list[int32])"
|
|
178
|
+
# )
|
|
179
|
+
|
|
180
|
+
# str_array: Mapped[list[str]] = mapped_column(
|
|
181
|
+
# ARRAY(String),
|
|
182
|
+
# comment="ARRAY of VARCHAR strings"
|
|
183
|
+
# )
|
|
184
|
+
|
|
185
|
+
# # ----------------------------------
|
|
186
|
+
# # Constraints & defaults
|
|
187
|
+
# # ----------------------------------
|
|
188
|
+
|
|
189
|
+
# unique_code: Mapped[str] = mapped_column(
|
|
190
|
+
# String(20),
|
|
191
|
+
# unique=True,
|
|
192
|
+
# nullable=False,
|
|
193
|
+
# comment="Unique code"
|
|
194
|
+
# )
|
|
195
|
+
|
|
196
|
+
# created_at: Mapped[datetime] = mapped_column(
|
|
197
|
+
# DateTime,
|
|
198
|
+
# server_default=sa.func.now(),
|
|
199
|
+
# comment="timestamp default now"
|
|
200
|
+
# )
|
|
201
|
+
|
|
202
|
+
# # ----------------------------------
|
|
203
|
+
# # Foreign key
|
|
204
|
+
# # ----------------------------------
|
|
205
|
+
|
|
206
|
+
# related_id: Mapped[int] = mapped_column(
|
|
207
|
+
# Integer,
|
|
208
|
+
# sa.ForeignKey("other_table.id"),
|
|
209
|
+
# comment="Foreign key reference"
|
|
210
|
+
# )
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# if __name__ == "__main__":
|
|
214
|
+
# # Example usage: create the tables in an in-memory SQLite database
|
|
215
|
+
# q = AllTypesExample()
|
|
216
|
+
# q.created_at.__qualname__
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import enum
|
|
2
|
+
from uuid import uuid4
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
from sqlalchemy import BigInteger, Boolean, Column, Date, DateTime, Float, ForeignKey, Integer, Interval, JSON, LargeBinary, MetaData, Numeric, SmallInteger, String, Table, Text, Time
|
|
6
|
+
from sqlalchemy.dialects.postgresql import ARRAY, JSONB, UUID
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ColorEnum(enum.Enum):
|
|
10
|
+
RED = "red"
|
|
11
|
+
GREEN = "green"
|
|
12
|
+
BLUE = "blue"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
metadata: MetaData = MetaData()
|
|
16
|
+
|
|
17
|
+
other_table: Table = Table(
|
|
18
|
+
"other_table",
|
|
19
|
+
metadata,
|
|
20
|
+
Column("id", Integer, primary_key=True, comment="Referenced by all_types_example.related_id"),
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
all_types_example: Table = Table(
|
|
24
|
+
"all_types_example",
|
|
25
|
+
metadata,
|
|
26
|
+
Column("id", Integer, primary_key=True, comment="Typical SQL INTEGER (~int32 on many databases)"),
|
|
27
|
+
Column("small_num", SmallInteger, comment="SMALLINT (~int16)"),
|
|
28
|
+
Column("big_num", BigInteger, comment="BIGINT (~int64)"),
|
|
29
|
+
Column("float_num", Float, comment="FLOAT → typically float32/float64 depending on precision"),
|
|
30
|
+
Column(
|
|
31
|
+
"decimal_value",
|
|
32
|
+
Numeric(12, 4),
|
|
33
|
+
comment="NUMERIC/DECIMAL fixed precision; client uses python Decimal by default (~exact decimal, not float)",
|
|
34
|
+
),
|
|
35
|
+
Column("short_str", String(50), comment="VARCHAR(n) fixed limit"),
|
|
36
|
+
Column("long_text", Text, comment="TEXT (unbounded string)"),
|
|
37
|
+
Column("is_active", Boolean, comment="BOOLEAN (True/False)"),
|
|
38
|
+
Column("date_field", Date, comment="DATE only (year/month/day)"),
|
|
39
|
+
Column("time_field", Time, comment="TIME only (hh:mm:ss)"),
|
|
40
|
+
Column("datetime_field", DateTime, comment="TIMESTAMP without timezone"),
|
|
41
|
+
Column("interval_field", Interval, comment="INTERVAL type (duration)"),
|
|
42
|
+
Column("binary_data", LargeBinary, comment="Large binary / BLOB"),
|
|
43
|
+
Column("json_data", JSON, comment="Generic JSON type (engine specific)"),
|
|
44
|
+
Column("jsonb_data", JSONB, comment="PostgreSQL JSONB (binary JSON)"),
|
|
45
|
+
Column("color", sa.Enum(ColorEnum), nullable=False, comment="ENUM type"),
|
|
46
|
+
Column("uuid_field", UUID(as_uuid=True), default=uuid4, comment="GUID/UUID (128-bit unique identifier)"),
|
|
47
|
+
Column("int_array", ARRAY(Integer), comment="ARRAY of INTEGER (~list[int32])"),
|
|
48
|
+
Column("str_array", ARRAY(String), comment="ARRAY of VARCHAR strings"),
|
|
49
|
+
Column("unique_code", String(20), unique=True, nullable=False, comment="Unique code"),
|
|
50
|
+
Column("created_at", DateTime, server_default=sa.func.now(), comment="timestamp default now"),
|
|
51
|
+
Column("related_id", Integer, ForeignKey("other_table.id"), comment="Foreign key reference"),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
__all__: tuple[str, ...] = (
|
|
56
|
+
"ColorEnum",
|
|
57
|
+
"all_types_example",
|
|
58
|
+
"metadata",
|
|
59
|
+
"other_table",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
q = all_types_example
|
|
64
|
+
# q.colo
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Any, Literal, TypedDict, TypeAlias
|
|
3
|
+
|
|
4
|
+
import datetime
|
|
5
|
+
import decimal
|
|
6
|
+
import uuid
|
|
7
|
+
|
|
8
|
+
AllTypesExampleColor: TypeAlias = Literal["red", "green", "blue"]
|
|
9
|
+
|
|
10
|
+
class OtherTableRow(TypedDict):
|
|
11
|
+
id: int
|
|
12
|
+
|
|
13
|
+
class AllTypesExampleRow(TypedDict):
|
|
14
|
+
id: int
|
|
15
|
+
small_num: int | None
|
|
16
|
+
big_num: int | None
|
|
17
|
+
float_num: float | None
|
|
18
|
+
decimal_value: decimal.Decimal | None
|
|
19
|
+
short_str: str | None
|
|
20
|
+
long_text: str | None
|
|
21
|
+
is_active: bool | None
|
|
22
|
+
date_field: datetime.date | None
|
|
23
|
+
time_field: datetime.time | None
|
|
24
|
+
datetime_field: datetime.datetime | None
|
|
25
|
+
interval_field: datetime.timedelta | None
|
|
26
|
+
binary_data: bytes | None
|
|
27
|
+
json_data: Any | None
|
|
28
|
+
jsonb_data: Any | None
|
|
29
|
+
color: AllTypesExampleColor
|
|
30
|
+
uuid_field: uuid.UUID | None
|
|
31
|
+
int_array: list[int] | None
|
|
32
|
+
str_array: list[str] | None
|
|
33
|
+
unique_code: str
|
|
34
|
+
created_at: datetime.datetime | None
|
|
35
|
+
related_id: int | None
|
|
36
|
+
|
|
37
|
+
__all__: tuple[str, ...] = (
|
|
38
|
+
"OtherTableRow",
|
|
39
|
+
"AllTypesExampleRow",
|
|
40
|
+
"AllTypesExampleColor",
|
|
41
|
+
)
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
|
|
2
|
+
import enum
|
|
3
|
+
import re
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
from sqlalchemy.dialects.postgresql import ARRAY as PG_ARRAY
|
|
11
|
+
from sqlalchemy.dialects.postgresql import JSONB, UUID as PG_UUID
|
|
12
|
+
from sqlalchemy.sql.type_api import TypeEngine
|
|
13
|
+
from sqlalchemy.sql.sqltypes import (
|
|
14
|
+
BigInteger,
|
|
15
|
+
Boolean,
|
|
16
|
+
Date,
|
|
17
|
+
DateTime,
|
|
18
|
+
Float,
|
|
19
|
+
Integer,
|
|
20
|
+
Interval,
|
|
21
|
+
JSON,
|
|
22
|
+
LargeBinary,
|
|
23
|
+
Numeric,
|
|
24
|
+
SmallInteger,
|
|
25
|
+
String,
|
|
26
|
+
Text,
|
|
27
|
+
Time,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True, slots=True)
|
|
32
|
+
class GeneratedModule:
|
|
33
|
+
code: str
|
|
34
|
+
exports: tuple[str, ...]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _pascal_case(value: str) -> str:
|
|
38
|
+
parts = [p for p in re.split(r"[^0-9A-Za-z]+", value) if p]
|
|
39
|
+
if not parts:
|
|
40
|
+
return "X"
|
|
41
|
+
return "".join(p[:1].upper() + p[1:] for p in parts)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _identifier(value: str) -> str:
|
|
45
|
+
candidate = re.sub(r"[^0-9A-Za-z_]", "_", value)
|
|
46
|
+
if not candidate:
|
|
47
|
+
return "x"
|
|
48
|
+
if candidate[0].isdigit():
|
|
49
|
+
return f"x_{candidate}"
|
|
50
|
+
return candidate
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _enum_literal_alias_name(table_name: str, column_name: str) -> str:
|
|
54
|
+
return f"{_pascal_case(table_name)}{_pascal_case(column_name)}"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _literal_union(values: Sequence[str]) -> str:
|
|
58
|
+
escaped = [v.replace("\\", "\\\\").replace('"', '\\"') for v in values]
|
|
59
|
+
return "Literal[" + ", ".join(f'"{v}"' for v in escaped) + "]"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True, slots=True)
|
|
63
|
+
class _TypeExpr:
|
|
64
|
+
expr: str
|
|
65
|
+
needs_datetime: bool
|
|
66
|
+
needs_decimal: bool
|
|
67
|
+
needs_uuid: bool
|
|
68
|
+
needs_any: bool
|
|
69
|
+
needs_literal: bool
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _union_with_none(type_expr: str, is_nullable: bool) -> str:
|
|
73
|
+
return f"{type_expr} | None" if is_nullable else type_expr
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _type_expr_for_sqla_type(*, column_type: TypeEngine[Any], table_name: str, column_name: str) -> tuple[_TypeExpr, dict[str, str]]:
|
|
77
|
+
enum_aliases: dict[str, str] = {}
|
|
78
|
+
|
|
79
|
+
if isinstance(column_type, (Integer, SmallInteger, BigInteger)):
|
|
80
|
+
return _TypeExpr("int", False, False, False, False, False), enum_aliases
|
|
81
|
+
if isinstance(column_type, Float):
|
|
82
|
+
return _TypeExpr("float", False, False, False, False, False), enum_aliases
|
|
83
|
+
if isinstance(column_type, Numeric):
|
|
84
|
+
return _TypeExpr("decimal.Decimal", False, True, False, False, False), enum_aliases
|
|
85
|
+
|
|
86
|
+
if hasattr(column_type, "enum_class"):
|
|
87
|
+
enum_class = getattr(column_type, "enum_class")
|
|
88
|
+
if isinstance(enum_class, type) and issubclass(enum_class, enum.Enum):
|
|
89
|
+
values = [str(member.value) for member in enum_class]
|
|
90
|
+
alias_name = _enum_literal_alias_name(table_name=table_name, column_name=column_name)
|
|
91
|
+
enum_aliases[alias_name] = _literal_union(values)
|
|
92
|
+
return _TypeExpr(alias_name, False, False, False, False, True), enum_aliases
|
|
93
|
+
|
|
94
|
+
if isinstance(column_type, (String, Text)):
|
|
95
|
+
return _TypeExpr("str", False, False, False, False, False), enum_aliases
|
|
96
|
+
if isinstance(column_type, Boolean):
|
|
97
|
+
return _TypeExpr("bool", False, False, False, False, False), enum_aliases
|
|
98
|
+
if isinstance(column_type, Date):
|
|
99
|
+
return _TypeExpr("datetime.date", True, False, False, False, False), enum_aliases
|
|
100
|
+
if isinstance(column_type, Time):
|
|
101
|
+
return _TypeExpr("datetime.time", True, False, False, False, False), enum_aliases
|
|
102
|
+
if isinstance(column_type, DateTime):
|
|
103
|
+
return _TypeExpr("datetime.datetime", True, False, False, False, False), enum_aliases
|
|
104
|
+
if isinstance(column_type, Interval):
|
|
105
|
+
return _TypeExpr("datetime.timedelta", True, False, False, False, False), enum_aliases
|
|
106
|
+
if isinstance(column_type, LargeBinary):
|
|
107
|
+
return _TypeExpr("bytes", False, False, False, False, False), enum_aliases
|
|
108
|
+
|
|
109
|
+
if isinstance(column_type, (JSON, JSONB)):
|
|
110
|
+
return _TypeExpr("Any", False, False, False, True, False), enum_aliases
|
|
111
|
+
|
|
112
|
+
if isinstance(column_type, PG_UUID):
|
|
113
|
+
return _TypeExpr("uuid.UUID", False, False, True, False, False), enum_aliases
|
|
114
|
+
|
|
115
|
+
if isinstance(column_type, PG_ARRAY):
|
|
116
|
+
item_type = column_type.item_type
|
|
117
|
+
item_expr, item_aliases = _type_expr_for_sqla_type(column_type=item_type, table_name=table_name, column_name=column_name)
|
|
118
|
+
enum_aliases |= item_aliases
|
|
119
|
+
return (
|
|
120
|
+
_TypeExpr(f"list[{item_expr.expr}]", item_expr.needs_datetime, item_expr.needs_decimal, item_expr.needs_uuid, item_expr.needs_any, item_expr.needs_literal),
|
|
121
|
+
enum_aliases,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
return _TypeExpr("Any", False, False, False, True, False), enum_aliases
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def generate_typeddict_module_code_for_tables(*, tables: Sequence[sa.Table], module_name: str) -> GeneratedModule:
|
|
128
|
+
alias_defs: dict[str, str] = {}
|
|
129
|
+
typed_dict_defs: list[str] = []
|
|
130
|
+
|
|
131
|
+
needs_datetime = False
|
|
132
|
+
needs_decimal = False
|
|
133
|
+
needs_uuid = False
|
|
134
|
+
needs_any = False
|
|
135
|
+
needs_literal = False
|
|
136
|
+
|
|
137
|
+
exports: list[str] = []
|
|
138
|
+
|
|
139
|
+
for table in tables:
|
|
140
|
+
table_name = table.name
|
|
141
|
+
td_name = f"{_pascal_case(table_name)}Row"
|
|
142
|
+
exports.append(td_name)
|
|
143
|
+
|
|
144
|
+
lines: list[str] = [f"class {td_name}(TypedDict):"]
|
|
145
|
+
for column in table.columns:
|
|
146
|
+
col_name = column.name
|
|
147
|
+
type_expr, new_aliases = _type_expr_for_sqla_type(column_type=column.type, table_name=table_name, column_name=col_name)
|
|
148
|
+
alias_defs |= new_aliases
|
|
149
|
+
|
|
150
|
+
needs_datetime = needs_datetime or type_expr.needs_datetime
|
|
151
|
+
needs_decimal = needs_decimal or type_expr.needs_decimal
|
|
152
|
+
needs_uuid = needs_uuid or type_expr.needs_uuid
|
|
153
|
+
needs_any = needs_any or type_expr.needs_any
|
|
154
|
+
needs_literal = needs_literal or type_expr.needs_literal
|
|
155
|
+
|
|
156
|
+
field_name = _identifier(col_name)
|
|
157
|
+
field_type = _union_with_none(type_expr.expr, column.nullable)
|
|
158
|
+
lines.append(f" {field_name}: {field_type}")
|
|
159
|
+
|
|
160
|
+
typed_dict_defs.append("\n".join(lines))
|
|
161
|
+
|
|
162
|
+
for alias_name in sorted(alias_defs.keys()):
|
|
163
|
+
exports.append(alias_name)
|
|
164
|
+
|
|
165
|
+
_ = module_name
|
|
166
|
+
|
|
167
|
+
typing_import_names: list[str] = ["TypedDict"]
|
|
168
|
+
if alias_defs:
|
|
169
|
+
typing_import_names.append("TypeAlias")
|
|
170
|
+
if needs_any:
|
|
171
|
+
typing_import_names.insert(0, "Any")
|
|
172
|
+
if needs_literal:
|
|
173
|
+
typing_import_names.insert(0 if not needs_any else 1, "Literal")
|
|
174
|
+
|
|
175
|
+
import_lines: list[str] = [
|
|
176
|
+
"",
|
|
177
|
+
f"from typing import {', '.join(typing_import_names)}",
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
stdlib_imports: list[str] = []
|
|
181
|
+
if needs_datetime:
|
|
182
|
+
stdlib_imports.append("import datetime")
|
|
183
|
+
if needs_decimal:
|
|
184
|
+
stdlib_imports.append("import decimal")
|
|
185
|
+
if needs_uuid:
|
|
186
|
+
stdlib_imports.append("import uuid")
|
|
187
|
+
if stdlib_imports:
|
|
188
|
+
import_lines.extend(["", *stdlib_imports])
|
|
189
|
+
|
|
190
|
+
code_parts: list[str] = []
|
|
191
|
+
code_parts.extend(import_lines)
|
|
192
|
+
|
|
193
|
+
if alias_defs:
|
|
194
|
+
code_parts.append("")
|
|
195
|
+
for alias_name in sorted(alias_defs.keys()):
|
|
196
|
+
literal_expr = alias_defs[alias_name]
|
|
197
|
+
code_parts.append(f"{alias_name}: TypeAlias = {literal_expr}")
|
|
198
|
+
|
|
199
|
+
code_parts.append("")
|
|
200
|
+
code_parts.append("\n\n".join(typed_dict_defs))
|
|
201
|
+
|
|
202
|
+
exports_tuple = tuple(exports)
|
|
203
|
+
exports_rendered = ",\n ".join(f"\"{name}\"" for name in exports_tuple)
|
|
204
|
+
code_parts.append("")
|
|
205
|
+
code_parts.append("__all__: tuple[str, ...] = (\n " + exports_rendered + ",\n)\n")
|
|
206
|
+
|
|
207
|
+
return GeneratedModule(code="\n".join(code_parts), exports=exports_tuple)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def generate_typeddict_module_code_for_table(*, table: sa.Table, module_name: str) -> GeneratedModule:
|
|
211
|
+
return generate_typeddict_module_code_for_tables(tables=(table,), module_name=module_name)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def write_generated_module(*, generated: GeneratedModule, output_path: Path) -> None:
|
|
215
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
216
|
+
output_path.write_text(generated.code, encoding="utf-8")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def write_typeddict_module_next_to_source(*, generated: GeneratedModule, source_file_path: Path) -> Path:
|
|
220
|
+
output_path = source_file_path.with_name(f"{source_file_path.stem}_typeddict.py")
|
|
221
|
+
write_generated_module(generated=generated, output_path=output_path)
|
|
222
|
+
return output_path
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type FieldInfo = tuple[str, ast.expr | None, dict[str, tuple[str, str]]]
|
|
7
|
+
type ClassFields = tuple[str, list[FieldInfo]]
|
|
8
|
+
|
|
9
|
+
_file_cache: dict[Path, ast.Module] = {}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _get_ast(path: Path) -> ast.Module:
|
|
13
|
+
if path not in _file_cache:
|
|
14
|
+
_file_cache[path] = ast.parse(path.read_text(encoding="utf-8"))
|
|
15
|
+
return _file_cache[path]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class FileContext:
|
|
20
|
+
path: Path
|
|
21
|
+
tree: ast.Module
|
|
22
|
+
classes: dict[str, ast.ClassDef] = field(default_factory=dict)
|
|
23
|
+
imports: dict[str, tuple[str, str]] = field(default_factory=dict)
|
|
24
|
+
|
|
25
|
+
def __post_init__(self):
|
|
26
|
+
self.classes = {node.name: node for node in ast.walk(self.tree) if isinstance(node, ast.ClassDef)}
|
|
27
|
+
for node in ast.walk(self.tree):
|
|
28
|
+
if isinstance(node, ast.ImportFrom) and node.module:
|
|
29
|
+
for alias in node.names:
|
|
30
|
+
self.imports[alias.asname or alias.name] = (node.module, alias.name)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get_context(path: Path) -> FileContext:
|
|
34
|
+
tree = _get_ast(path)
|
|
35
|
+
return FileContext(path, tree)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _resolve_imported_class(module_name: str, class_name: str, search_paths: list[Path]) -> tuple[ast.ClassDef, FileContext] | None:
|
|
39
|
+
parts = module_name.split(".")
|
|
40
|
+
for root in search_paths:
|
|
41
|
+
file_path = root.joinpath(*parts).with_suffix(".py")
|
|
42
|
+
if file_path.exists():
|
|
43
|
+
try:
|
|
44
|
+
context = _get_context(file_path)
|
|
45
|
+
if class_name in context.classes:
|
|
46
|
+
return context.classes[class_name], context
|
|
47
|
+
except Exception:
|
|
48
|
+
pass
|
|
49
|
+
init_path = root.joinpath(*parts, "__init__.py")
|
|
50
|
+
if init_path.exists():
|
|
51
|
+
try:
|
|
52
|
+
context = _get_context(init_path)
|
|
53
|
+
if class_name in context.classes:
|
|
54
|
+
return context.classes[class_name], context
|
|
55
|
+
except Exception:
|
|
56
|
+
pass
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def load_target_class_fields(source_file_path: Path, search_paths: list[Path] | None = None) -> list[ClassFields]:
|
|
61
|
+
source_path = Path(source_file_path).resolve()
|
|
62
|
+
if search_paths is None:
|
|
63
|
+
search_paths = []
|
|
64
|
+
|
|
65
|
+
if not source_path.exists():
|
|
66
|
+
raise FileNotFoundError(f"Source file not found: {source_path}")
|
|
67
|
+
|
|
68
|
+
initial_context = _get_context(source_path)
|
|
69
|
+
|
|
70
|
+
def get_parent_node(base: ast.expr, context: FileContext) -> tuple[ast.ClassDef, FileContext] | None:
|
|
71
|
+
if isinstance(base, ast.Name):
|
|
72
|
+
if base.id in context.classes:
|
|
73
|
+
return context.classes[base.id], context
|
|
74
|
+
if base.id in context.imports:
|
|
75
|
+
module_name, original_name = context.imports[base.id]
|
|
76
|
+
return _resolve_imported_class(module_name, original_name, search_paths) # type: ignore
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
def collect_fields(class_node: ast.ClassDef, context: FileContext, visited: set[str]) -> list[FieldInfo]:
|
|
80
|
+
key = f"{context.path}:{class_node.name}"
|
|
81
|
+
if key in visited:
|
|
82
|
+
return []
|
|
83
|
+
visited.add(key)
|
|
84
|
+
field_info: list[FieldInfo] = []
|
|
85
|
+
for base in class_node.bases:
|
|
86
|
+
parent_info = get_parent_node(base, context)
|
|
87
|
+
if parent_info:
|
|
88
|
+
parent_node, parent_context = parent_info
|
|
89
|
+
field_info.extend(collect_fields(parent_node, parent_context, visited))
|
|
90
|
+
for statement in class_node.body:
|
|
91
|
+
if isinstance(statement, ast.AnnAssign) and isinstance(statement.target, ast.Name):
|
|
92
|
+
field_info.append((statement.target.id, statement.annotation, context.imports))
|
|
93
|
+
return field_info
|
|
94
|
+
|
|
95
|
+
def deduplicate_fields(fields: list[FieldInfo]) -> list[FieldInfo]:
|
|
96
|
+
deduped: dict[str, FieldInfo] = {}
|
|
97
|
+
for item in fields:
|
|
98
|
+
field_name = item[0]
|
|
99
|
+
deduped[field_name] = item
|
|
100
|
+
return list(deduped.values())
|
|
101
|
+
|
|
102
|
+
def is_typeddict(node: ast.ClassDef, context: FileContext, visited: set[str]) -> bool:
|
|
103
|
+
key = f"{context.path}:{node.name}"
|
|
104
|
+
if key in visited:
|
|
105
|
+
return False
|
|
106
|
+
visited.add(key)
|
|
107
|
+
for base in node.bases:
|
|
108
|
+
if (isinstance(base, ast.Name) and base.id == "TypedDict") or (isinstance(base, ast.Attribute) and base.attr == "TypedDict"):
|
|
109
|
+
return True
|
|
110
|
+
parent_info = get_parent_node(base, context)
|
|
111
|
+
if parent_info:
|
|
112
|
+
parent_node, parent_context = parent_info
|
|
113
|
+
if is_typeddict(parent_node, parent_context, visited):
|
|
114
|
+
return True
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
target_classes: list[ClassFields] = []
|
|
118
|
+
for node in ast.walk(initial_context.tree):
|
|
119
|
+
if not isinstance(node, ast.ClassDef):
|
|
120
|
+
continue
|
|
121
|
+
is_dataclass = any(
|
|
122
|
+
(isinstance(decorator, ast.Name) and decorator.id == "dataclass")
|
|
123
|
+
or (isinstance(decorator, ast.Attribute) and decorator.attr == "dataclass")
|
|
124
|
+
or (isinstance(decorator, ast.Call) and ((isinstance(decorator.func, ast.Name) and decorator.func.id == "dataclass") or (isinstance(decorator.func, ast.Attribute) and decorator.func.attr == "dataclass")))
|
|
125
|
+
for decorator in node.decorator_list
|
|
126
|
+
)
|
|
127
|
+
if is_dataclass or is_typeddict(node, initial_context, set()):
|
|
128
|
+
fields = collect_fields(node, initial_context, set())
|
|
129
|
+
target_classes.append((node.name, deduplicate_fields(fields)))
|
|
130
|
+
return target_classes
|