sqlsaber 0.28.0__py3-none-any.whl → 0.29.1__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 sqlsaber might be problematic. Click here for more details.

sqlsaber/theme/manager.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """Theme management for unified theming across Rich and prompt_toolkit."""
2
2
 
3
+ import json
3
4
  import os
4
- import tomllib
5
5
  from dataclasses import dataclass
6
6
  from functools import lru_cache
7
7
  from typing import Dict
@@ -10,20 +10,14 @@ from platformdirs import user_config_dir
10
10
  from prompt_toolkit.styles import Style as PTStyle
11
11
  from prompt_toolkit.styles.pygments import style_from_pygments_cls
12
12
  from pygments.styles import get_style_by_name
13
+ from pygments.token import Token
14
+ from pygments.util import ClassNotFound
13
15
  from rich.console import Console
14
16
  from rich.theme import Theme
15
17
 
16
18
  DEFAULT_THEME_NAME = "nord"
17
19
 
18
20
  DEFAULT_ROLE_PALETTE = {
19
- # base roles
20
- "primary": "cyan",
21
- "accent": "magenta",
22
- "success": "green",
23
- "warning": "yellow",
24
- "error": "red",
25
- "info": "cyan",
26
- "muted": "dim",
27
21
  # components
28
22
  "table.header": "bold $primary",
29
23
  "panel.border.user": "$info",
@@ -43,89 +37,97 @@ DEFAULT_ROLE_PALETTE = {
43
37
  "title": "bold $success",
44
38
  }
45
39
 
46
- # Theme presets using exact Pygments colors
47
- THEME_PRESETS = {
48
- # Nord - exact colors from pygments nord theme
49
- "nord": {
50
- "primary": "#81a1c1", # Keyword (frost)
51
- "accent": "#b48ead", # Number (aurora purple)
52
- "success": "#a3be8c", # String (aurora green)
53
- "warning": "#ebcb8b", # String.Escape (aurora yellow)
54
- "error": "#bf616a", # Error/Generic.Error (aurora red)
55
- "info": "#88c0d0", # Name.Function (frost cyan)
56
- "muted": "dim",
57
- },
58
- # Dracula - exact colors from pygments dracula theme
59
- "dracula": {
60
- "primary": "#bd93f9", # purple
61
- "accent": "#ff79c6", # pink
62
- "success": "#50fa7b", # green
63
- "warning": "#f1fa8c", # yellow
64
- "error": "#ff5555", # red
65
- "info": "#8be9fd", # cyan
66
- "muted": "dim",
67
- },
68
- # Solarized Light - exact colors from pygments solarized-light theme
69
- "solarized-light": {
70
- "primary": "#268bd2", # blue
71
- "accent": "#d33682", # magenta
72
- "success": "#859900", # green
73
- "warning": "#b58900", # yellow
74
- "error": "#dc322f", # red
75
- "info": "#2aa198", # cyan
76
- "muted": "dim",
77
- },
78
- # VS (Visual Studio Light) - exact colors from pygments vs theme
79
- "vs": {
80
- "primary": "#0000ff", # Keyword (blue)
81
- "accent": "#2b91af", # Keyword.Type/Name.Class
82
- "success": "#008000", # Comment (green)
83
- "warning": "#b58900", # (using solarized yellow as fallback)
84
- "error": "#dc322f", # (using solarized red as fallback)
85
- "info": "#2aa198", # (using solarized cyan as fallback)
86
- "muted": "dim",
87
- },
88
- # Material (approximation based on material design colors)
89
- "material": {
90
- "primary": "#89ddff", # cyan
91
- "accent": "#f07178", # pink/red
92
- "success": "#c3e88d", # green
93
- "warning": "#ffcb6b", # yellow
94
- "error": "#ff5370", # red
95
- "info": "#82aaff", # blue
96
- "muted": "dim",
97
- },
98
- # One Dark - exact colors from pygments one-dark theme
99
- "one-dark": {
100
- "primary": "#c678dd", # Keyword (purple)
101
- "accent": "#e06c75", # Name (red)
102
- "success": "#98c379", # String (green)
103
- "warning": "#e5c07b", # Keyword.Type (yellow)
104
- "error": "#e06c75", # Name (red, used for errors)
105
- "info": "#61afef", # Name.Function (blue)
106
- "muted": "dim",
107
- },
108
- # Lightbulb - exact colors from pygments lightbulb theme (minimal dark)
109
- "lightbulb": {
110
- "primary": "#73d0ff", # Keyword.Type/Name.Class (blue_1)
111
- "accent": "#dfbfff", # Number (magenta_1)
112
- "success": "#d5ff80", # String (green_1)
113
- "warning": "#ffd173", # Name.Function (yellow_1)
114
- "error": "#f88f7f", # Error (red_1)
115
- "info": "#95e6cb", # Name.Entity (cyan_1)
116
- "muted": "dim",
117
- },
40
+ ROLE_TOKEN_PREFERENCES: dict[str, tuple] = {
41
+ "primary": (
42
+ Token.Keyword,
43
+ Token.Keyword.Namespace,
44
+ Token.Name.Tag,
45
+ ),
46
+ "accent": (
47
+ Token.Name.Tag,
48
+ Token.Keyword.Type,
49
+ Token.Literal.Number,
50
+ Token.Operator.Word,
51
+ ),
52
+ "success": (
53
+ Token.Literal.String,
54
+ Token.Generic.Inserted,
55
+ Token.Name.Attribute,
56
+ ),
57
+ "warning": (
58
+ Token.Literal.String.Escape,
59
+ Token.Name.Constant,
60
+ Token.Generic.Emph,
61
+ ),
62
+ "error": (
63
+ Token.Error,
64
+ Token.Generic.Error,
65
+ Token.Generic.Deleted,
66
+ Token.Name.Exception,
67
+ ),
68
+ "info": (
69
+ Token.Name.Function,
70
+ Token.Name.Builtin,
71
+ Token.Keyword.Type,
72
+ ),
73
+ "muted": (
74
+ Token.Comment,
75
+ Token.Generic.Subheading,
76
+ Token.Text,
77
+ ),
118
78
  }
119
79
 
120
80
 
81
+ def _normalize_hex(color: str | None) -> str | None:
82
+ if not color:
83
+ return None
84
+ color = color.strip()
85
+ if not color:
86
+ return None
87
+ if color.startswith("#"):
88
+ color = color[1:]
89
+ if len(color) == 3:
90
+ color = "".join(ch * 2 for ch in color)
91
+ if len(color) != 6:
92
+ return None
93
+ return f"#{color.lower()}"
94
+
95
+
96
+ def _build_role_palette_from_style(style_name: str) -> dict[str, str]:
97
+ try:
98
+ style_cls = get_style_by_name(style_name)
99
+ except ClassNotFound:
100
+ return {}
101
+
102
+ palette: dict[str, str] = {}
103
+ try:
104
+ base_color = _normalize_hex(style_cls.style_for_token(Token.Text).get("color"))
105
+ except KeyError:
106
+ base_color = None
107
+ for role, tokens in ROLE_TOKEN_PREFERENCES.items():
108
+ for token in tokens:
109
+ try:
110
+ style_def = style_cls.style_for_token(token)
111
+ except KeyError:
112
+ continue
113
+ color = _normalize_hex(style_def.get("color"))
114
+ if not color or color == base_color:
115
+ continue
116
+ if role == "accent" and color == palette.get("primary"):
117
+ continue
118
+ palette[role] = color
119
+ break
120
+ return palette
121
+
122
+
121
123
  def _load_user_theme_config() -> dict:
122
124
  """Load theme configuration from user config directory."""
123
125
  cfg_dir = user_config_dir("sqlsaber")
124
- path = os.path.join(cfg_dir, "theme.toml")
126
+ path = os.path.join(cfg_dir, "theme.json")
125
127
  if not os.path.exists(path):
126
128
  return {}
127
- with open(path, "rb") as f:
128
- return tomllib.load(f)
129
+ with open(path, "r") as f:
130
+ return json.load(f)
129
131
 
130
132
 
131
133
  def _resolve_refs(palette: dict[str, str]) -> dict[str, str]:
@@ -204,7 +206,7 @@ def get_theme_manager() -> ThemeManager:
204
206
  pygments_style = user_cfg.get("theme", {}).get("pygments_style") or name
205
207
 
206
208
  roles = dict(DEFAULT_ROLE_PALETTE)
207
- roles.update(THEME_PRESETS.get(name, {}))
209
+ roles.update(_build_role_palette_from_style(pygments_style))
208
210
  roles.update(user_cfg.get("roles", {}))
209
211
 
210
212
  cfg = ThemeConfig(name=name, pygments_style=pygments_style, roles=roles)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlsaber
3
- Version: 0.28.0
3
+ Version: 0.29.1
4
4
  Summary: SQLsaber - Open-source agentic SQL assistant
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -5,28 +5,29 @@ sqlsaber/agents/base.py,sha256=40-MKEoz5rGrqVIylV1U2DaAUSPFcC75ohRin4E3-kk,2668
5
5
  sqlsaber/agents/mcp.py,sha256=Pn8tdDRUEVLYQyEi5nHRp9MKNePwHVVoeNI-uqWcr0Y,757
6
6
  sqlsaber/agents/pydantic_ai_agent.py,sha256=wBxKz0pjOkL-HI-TXV6B67bczZNgu7k26Rr3w5usR3o,10064
7
7
  sqlsaber/application/__init__.py,sha256=KY_-d5nEdQyAwNOsK5r-f7Tb69c63XbuEkHPeLpJal8,84
8
- sqlsaber/application/auth_setup.py,sha256=cbS2VTwL7mwm24UFRz84PhC13XMzC1F7JkN-ze7tApY,5104
9
- sqlsaber/application/db_setup.py,sha256=qtMxCd_KO7GsD4W_iRBpDRvLriiyvOXPvZdcvm6KVDM,6849
10
- sqlsaber/application/model_selection.py,sha256=xZI-nvUgYZikaTK38SCmEWvWSfRsDpFu2VthbVdI95g,3187
8
+ sqlsaber/application/auth_setup.py,sha256=D94dyU9bOVfnNHLnnFJb5PaeWsKPTL21CiS_DLcY93A,5114
9
+ sqlsaber/application/db_setup.py,sha256=ZSgR9rJJVHttIjsbYQS9GEIyzkM09k5RLrVGdegrfYc,6859
10
+ sqlsaber/application/model_selection.py,sha256=fSC06MZNKinHDR-csMFVYYJFyK8MydKf6pStof74Jp0,3191
11
11
  sqlsaber/application/prompts.py,sha256=4rMGcWpYJbNWPMzqVWseUMx0nwvXOkWS6GaTAJ5mhfc,3473
12
12
  sqlsaber/cli/__init__.py,sha256=qVSLVJLLJYzoC6aj6y9MFrzZvAwc4_OgxU9DlkQnZ4M,86
13
- sqlsaber/cli/auth.py,sha256=ysDBXEFR8Jz7wYbIP6X7yWA2ivd8SDnUp_jUg_qYNWk,6088
14
- sqlsaber/cli/commands.py,sha256=-rTxr-kW7j2rR8wAg0tATKoh284pMDPKVMpQKaJwtqk,8540
13
+ sqlsaber/cli/auth.py,sha256=elUpw8gypHGlxbHx4a4_z4wFznx2vr6V1h8lqpeC6OQ,6121
14
+ sqlsaber/cli/commands.py,sha256=Pii_SlVKpNEtt57_QPQzwC1u-x6tA8kuG8yd43undWE,8628
15
15
  sqlsaber/cli/completers.py,sha256=g-hLDq5fiBx7gg8Bte1Lq8GU-ZxCYVs4dcPsmHPIcK4,6574
16
- sqlsaber/cli/database.py,sha256=hh8PdWnhaD0fO2jwvSSQyxsjwk-JyvmcY7f5tuHfnAQ,10663
16
+ sqlsaber/cli/database.py,sha256=Tqy8H5MnjsrmOSPcbA5Qy-u-IOYJCIXRJVhk0veLNDk,10726
17
17
  sqlsaber/cli/display.py,sha256=WB5JCumhXadziDEX1EZHG3vN1Chol5FNAaTXHieqFK0,17892
18
- sqlsaber/cli/interactive.py,sha256=u1gvdMZJkFWelZQ2urOS6-EH1uShKF4u_edfr_BzDNk,13479
19
- sqlsaber/cli/memory.py,sha256=gKP-JJ0w1ya1YTM_Lk7Gw-7wL9ptyj6cZtg-uoW8K7A,7818
20
- sqlsaber/cli/models.py,sha256=NozZbnisSjbPKo7PW7CltJMIkGcPqTDpDQEY-C_eLhk,8504
21
- sqlsaber/cli/onboarding.py,sha256=l6FFWn8J1OVQUxr-xIAzKaFhAz8rFh6IEWwIyPWqR6U,11438
18
+ sqlsaber/cli/interactive.py,sha256=PcY6mszImo_3PsqjjWmx_cOfj44OmKvD9ENOvGA-wjU,13715
19
+ sqlsaber/cli/memory.py,sha256=IKq09DUbqpvvtATsyDlpm7rDlGqWEhdUX9wgnR-oiq4,7850
20
+ sqlsaber/cli/models.py,sha256=iMTw3DCKIQbWfSfikwy-nQ5tiHWjoN4cbKA-G6RFlj4,8535
21
+ sqlsaber/cli/onboarding.py,sha256=iBGT-W-OJFRvQoEpuHYyO1c9Mym5c97eIefRvxGHtTg,11265
22
22
  sqlsaber/cli/streaming.py,sha256=1XoZGPPMoTmBQVgp_Bqk483MR93j9oXxSV6Tx_-TpOg,6923
23
- sqlsaber/cli/threads.py,sha256=5EV4ckRzKqhWeTKpTfQSNCBuqs3onsJURKT09g4E4XM,13634
23
+ sqlsaber/cli/theme.py,sha256=hP0kmsMLCtqaT7b5wB1dk1hW1hV94oP4BHdz8S6887A,4243
24
+ sqlsaber/cli/threads.py,sha256=o9q9Hst1Wt7cxSyrpAtwG6pkUct6csgiAmN_0P_WO3k,13637
24
25
  sqlsaber/config/__init__.py,sha256=olwC45k8Nc61yK0WmPUk7XHdbsZH9HuUAbwnmKe3IgA,100
25
- sqlsaber/config/api_keys.py,sha256=bjogRmIuxNNGusyKXKi0ZpJWeS5Fyn53zrAD8hsoYx4,3671
26
+ sqlsaber/config/api_keys.py,sha256=9RyhD5Bntq8NMFRPiZZo8YEHACK9MPyFGp8dsmQZ1iI,3678
26
27
  sqlsaber/config/auth.py,sha256=b5qB2h1doXyO9Bn8z0CcL8LAR2jF431gGXBGKLgTmtQ,2756
27
28
  sqlsaber/config/database.py,sha256=Yec6_0wdzq-ADblMNnbgvouYCimYOY_DWHT9oweaISc,11449
28
- sqlsaber/config/oauth_flow.py,sha256=VNbq4TZPk0hVJIcOh7JUO5qSxJnNzqDj0vwjCn-59Ok,10316
29
- sqlsaber/config/oauth_tokens.py,sha256=SC-lXVcKCV7uiWtBiU2mxvx1z7ryW8tOSKHBApPsXtE,5931
29
+ sqlsaber/config/oauth_flow.py,sha256=P81lHhtICdhiQu8lNwyqn2m45FGEqCEzLgUQTLG5UW0,10343
30
+ sqlsaber/config/oauth_tokens.py,sha256=V4U8GAQHjTfgUcTzwjRVaIE7DeN0tF9OsSjiasHw7Uc,5970
30
31
  sqlsaber/config/providers.py,sha256=JFjeJv1K5Q93zWSlWq3hAvgch1TlgoF0qFa0KJROkKY,2957
31
32
  sqlsaber/config/settings.py,sha256=iB4CnGQ4hw8gxkaa9CVLB_JEy6Y9h9FQTAams5OCVyI,6421
32
33
  sqlsaber/database/__init__.py,sha256=Gi9N_NOkD459WRWXDg3hSuGoBs3xWbMDRBvsTVmnGAg,2025
@@ -36,7 +37,7 @@ sqlsaber/database/duckdb.py,sha256=8HNKdx208aFK_YtwGjLz6LTne0xEmNevD-f9dRWlrFg,1
36
37
  sqlsaber/database/mysql.py,sha256=wMzDQqq4GFbfEdqXtv_sCb4Qbr9GSWqYAvOLeo5UryY,14472
37
38
  sqlsaber/database/postgresql.py,sha256=fuf2Wl29NKXvD3mqsR08PDleNQ1PG-fNvWSxT6HDh2M,13223
38
39
  sqlsaber/database/resolver.py,sha256=wSCcn__aCqwIfpt_LCjtW2Zgb8RpG5PlmwwZHli1q_U,3628
39
- sqlsaber/database/schema.py,sha256=68PrNcA-5eR9PZB3i-TUQw5_E7QatwiDU2wv9GgXgM4,6928
40
+ sqlsaber/database/schema.py,sha256=CuV0ewoVaERe1gj_fJFJFWAP8aEPgepmn6X6B7bgkfQ,6962
40
41
  sqlsaber/database/sqlite.py,sha256=iReEIiSpkhhS1VzITd79ZWqSL3fHMyfe3DRCDpM0DvE,9421
41
42
  sqlsaber/mcp/__init__.py,sha256=COdWq7wauPBp5Ew8tfZItFzbcLDSEkHBJSMhxzy8C9c,112
42
43
  sqlsaber/mcp/mcp.py,sha256=tpNPHpkaCre1Xjp7c4DHXbTKeuYpDQ8qhmJZvAyr7Vk,3939
@@ -44,7 +45,7 @@ sqlsaber/memory/__init__.py,sha256=GiWkU6f6YYVV0EvvXDmFWe_CxarmDCql05t70MkTEWs,6
44
45
  sqlsaber/memory/manager.py,sha256=p3fybMVfH-E4ApT1ZRZUnQIWSk9dkfUPCyfkmA0HALs,2739
45
46
  sqlsaber/memory/storage.py,sha256=ne8szLlGj5NELheqLnI7zu21V8YS4rtpYGGC7tOmi-s,5745
46
47
  sqlsaber/theme/__init__.py,sha256=qCICX1Cg4B6yCbZ1UrerxglWxcqldRFVSRrSs73na_8,188
47
- sqlsaber/theme/manager.py,sha256=0DWuVXn7JoC8NvAl5FSqc61eagKFTx5YnoY8SoCTxGM,7236
48
+ sqlsaber/theme/manager.py,sha256=xOi1ZLNr31ZtE8-WzxdtvywCB1rbJ7z2DTzcqHsCavY,6377
48
49
  sqlsaber/threads/__init__.py,sha256=Hh3dIG1tuC8fXprREUpslCIgPYz8_6o7aRLx4yNeO48,139
49
50
  sqlsaber/threads/storage.py,sha256=rsUdxT4CR52D7xtGir9UlsFnBMk11jZeflzDrk2q4ME,11183
50
51
  sqlsaber/tools/__init__.py,sha256=x3YdmX_7P0Qq_HtZHAgfIVKTLxYqKk6oc4tGsujQWsc,586
@@ -54,8 +55,8 @@ sqlsaber/tools/instructions.py,sha256=X-x8maVkkyi16b6Tl0hcAFgjiYceZaSwyWTfmrvx8U
54
55
  sqlsaber/tools/registry.py,sha256=HWOQMsNIdL4XZS6TeNUyrL-5KoSDH6PHsWd3X66o-18,3211
55
56
  sqlsaber/tools/sql_guard.py,sha256=dTDwcZP-N4xPGzcr7MQtKUxKrlDzlc1irr9aH5a4wvk,6182
56
57
  sqlsaber/tools/sql_tools.py,sha256=ujmAcfLkNaBrb5LWEgWcINQEQSX0LRPX3VK5Dag1Sj4,9178
57
- sqlsaber-0.28.0.dist-info/METADATA,sha256=oY9Awl9jLkdeJLa1oeTPHPGH94KktJ_HmBVUVLQs-do,7174
58
- sqlsaber-0.28.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
59
- sqlsaber-0.28.0.dist-info/entry_points.txt,sha256=qEbOB7OffXPFgyJc7qEIJlMEX5RN9xdzLmWZa91zCQQ,162
60
- sqlsaber-0.28.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
61
- sqlsaber-0.28.0.dist-info/RECORD,,
58
+ sqlsaber-0.29.1.dist-info/METADATA,sha256=kx_nQDGhcDUJp4DadT7Pi89QsUuf8S5W6IVqwaJfuXM,7174
59
+ sqlsaber-0.29.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
60
+ sqlsaber-0.29.1.dist-info/entry_points.txt,sha256=qEbOB7OffXPFgyJc7qEIJlMEX5RN9xdzLmWZa91zCQQ,162
61
+ sqlsaber-0.29.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
62
+ sqlsaber-0.29.1.dist-info/RECORD,,