Skip to content

Commit 0e1b9da

Browse files
committed
fix: escape all dynamic text in Rich markup strings to prevent MarkupError
- Add em() helper (wraps rich.markup.escape) to src/utils.py and src/debug.py - Fix .format() templates: em() in arguments, not inside template placeholders - Protect all f-string interpolations in Rich markup with em(str(...)) - Escape traceback output in handle_astroquery_exception - Protect user-input variables (object_name, target, range_str) in .format() calls - Regenerate PO/MO translation files via update-po.sh (fixes mismatched Rich tags)
1 parent 08c5c55 commit 0e1b9da

31 files changed

Lines changed: 7875 additions & 7449 deletions

locales/fr/LC_MESSAGES/messages.mo

-1.1 KB
Binary file not shown.

locales/fr/LC_MESSAGES/messages.po

Lines changed: 648 additions & 661 deletions
Large diffs are not rendered by default.

locales/ja/LC_MESSAGES/messages.mo

-1.17 KB
Binary file not shown.

locales/ja/LC_MESSAGES/messages.po

Lines changed: 644 additions & 658 deletions
Large diffs are not rendered by default.

locales/messages.pot

Lines changed: 613 additions & 657 deletions
Large diffs are not rendered by default.

locales/zh/LC_MESSAGES/messages.mo

-957 Bytes
Binary file not shown.

locales/zh/LC_MESSAGES/messages.po

Lines changed: 644 additions & 658 deletions
Large diffs are not rendered by default.

src/debug.py

Lines changed: 81 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,197 @@
11
import os
22
from rich.console import Console
3+
from rich.markup import escape
34
from rich.panel import Panel
45
from rich.table import Table
56
from rich.text import Text
67
import sys
78
import traceback
89
from typing import Any, Dict, Optional
910

11+
12+
def em(text: str) -> str:
13+
return escape(str(text))
14+
15+
1016
class DebugManager:
1117
def __init__(self):
1218
self.console = Console()
1319
self._debug_enabled = os.getenv("AQC_DEBUG", "").lower() in ("1", "true", "yes")
14-
self._verbose_enabled = os.getenv("AQC_VERBOSE", "").lower() in ("1", "true", "yes")
15-
20+
self._verbose_enabled = os.getenv("AQC_VERBOSE", "").lower() in (
21+
"1",
22+
"true",
23+
"yes",
24+
)
25+
1626
@property
1727
def debug_enabled(self) -> bool:
1828
return self._debug_enabled
19-
29+
2030
@property
2131
def verbose_enabled(self) -> bool:
2232
return self._verbose_enabled or self._debug_enabled
23-
33+
2434
def enable_debug(self):
2535
self._debug_enabled = True
2636
os.environ["AQC_DEBUG"] = "1"
27-
37+
2838
def enable_verbose(self):
2939
self._verbose_enabled = True
3040
os.environ["AQC_VERBOSE"] = "1"
31-
41+
3242
def debug(self, message: str, prefix: str = "DEBUG"):
3343
if self.debug_enabled:
34-
self.console.print(f"[dim cyan]{prefix}: {message}[/dim cyan]")
35-
44+
self.console.print(f"[dim cyan]{em(prefix)}: {em(message)}[/dim cyan]")
45+
3646
def verbose(self, message: str, prefix: str = "INFO"):
3747
if self.verbose_enabled:
38-
self.console.print(f"[dim]{prefix}: {message}[/dim]")
39-
48+
self.console.print(f"[dim]{em(prefix)}: {em(message)}[/dim]")
49+
4050
def success(self, message: str):
4151
if self.verbose_enabled:
42-
self.console.print(f"[dim green]SUCCESS: {message}[/dim green]")
43-
52+
self.console.print(f"[dim green]SUCCESS: {em(message)}[/dim green]")
53+
4454
def warning(self, message: str):
4555
if self.verbose_enabled:
46-
self.console.print(f"[dim yellow]WARNING: {message}[/dim yellow]")
47-
56+
self.console.print(f"[dim yellow]WARNING: {em(message)}[/dim yellow]")
57+
4858
def error(self, message: str, exception: Optional[Exception] = None):
4959
if self.verbose_enabled:
50-
self.console.print(f"[dim red]ERROR: {message}[/dim red]")
60+
self.console.print(f"[dim red]ERROR: {em(message)}[/dim red]")
5161
if exception and self.debug_enabled:
52-
self.console.print(f"[dim red]Exception: {str(exception)}[/dim red]")
53-
if hasattr(exception, '__traceback__'):
62+
self.console.print(
63+
f"[dim red]Exception: {em(str(exception))}[/dim red]"
64+
)
65+
if hasattr(exception, "__traceback__"):
5466
tb_lines = traceback.format_tb(exception.__traceback__)
5567
for line in tb_lines:
5668
self.console.print(f"[dim red]{line.strip()}[/dim red]")
57-
69+
5870
def print_config_info(self, config_data: Dict[str, Any]):
5971
if not self.verbose_enabled:
6072
return
61-
62-
table = Table(title="Configuration Information", show_header=True, header_style="bold blue")
73+
74+
table = Table(
75+
title="Configuration Information",
76+
show_header=True,
77+
header_style="bold blue",
78+
)
6379
table.add_column("Setting", style="cyan")
6480
table.add_column("Value", style="green")
65-
81+
6682
for key, value in config_data.items():
6783
table.add_row(str(key), str(value))
68-
84+
6985
self.console.print(table)
70-
86+
7187
def print_environment_info(self):
7288
if not self.debug_enabled:
7389
return
74-
90+
7591
env_vars = {k: v for k, v in os.environ.items() if k.startswith("AQC_")}
76-
77-
table = Table(title="Environment Variables", show_header=True, header_style="bold blue")
92+
93+
table = Table(
94+
title="Environment Variables", show_header=True, header_style="bold blue"
95+
)
7896
table.add_column("Variable", style="cyan")
7997
table.add_column("Value", style="green")
80-
98+
8199
for key, value in env_vars.items():
82100
table.add_row(key, value)
83-
101+
84102
if not env_vars:
85103
table.add_row("No AQC_* variables found", "")
86-
104+
87105
self.console.print(table)
88-
106+
89107
def print_system_info(self):
90108
if not self.debug_enabled:
91109
return
92-
110+
93111
import platform
94-
112+
95113
info = {
96114
"Python Version": platform.python_version(),
97115
"Platform": platform.platform(),
98116
"Architecture": platform.architecture()[0],
99117
"Working Directory": os.getcwd(),
100-
"Script Path": sys.argv[0] if sys.argv else "Unknown"
118+
"Script Path": sys.argv[0] if sys.argv else "Unknown",
101119
}
102-
103-
table = Table(title="System Information", show_header=True, header_style="bold blue")
120+
121+
table = Table(
122+
title="System Information", show_header=True, header_style="bold blue"
123+
)
104124
table.add_column("Property", style="cyan")
105125
table.add_column("Value", style="green")
106-
126+
107127
for key, value in info.items():
108128
table.add_row(key, str(value))
109-
129+
110130
self.console.print(table)
111-
131+
112132
def print_translation_info(self, lang_code: str, translator_info: Dict[str, Any]):
113133
if not self.debug_enabled:
114134
return
115-
116-
table = Table(title=f"Translation Information ({lang_code})", show_header=True, header_style="bold blue")
135+
136+
table = Table(
137+
title=f"Translation Information ({lang_code})",
138+
show_header=True,
139+
header_style="bold blue",
140+
)
117141
table.add_column("Property", style="cyan")
118142
table.add_column("Value", style="green")
119-
143+
120144
for key, value in translator_info.items():
121145
table.add_row(str(key), str(value))
122-
146+
123147
self.console.print(table)
124-
125-
def trace_function_call(self, func_name: str, args: tuple = (), kwargs: dict = None):
148+
149+
def trace_function_call(
150+
self, func_name: str, args: tuple = (), kwargs: dict = None
151+
):
126152
if not self.debug_enabled:
127153
return
128-
154+
129155
kwargs = kwargs or {}
130156
args_str = ", ".join([repr(arg) for arg in args])
131157
kwargs_str = ", ".join([f"{k}={repr(v)}" for k, v in kwargs.items()])
132-
158+
133159
all_args = ", ".join(filter(None, [args_str, kwargs_str]))
134160
self.debug(f"Calling {func_name}({all_args})", "TRACE")
135161

162+
136163
# Global debug manager instance
137164
debug_manager = DebugManager()
138165

166+
139167
# Convenience functions
140168
def debug(message: str, prefix: str = "DEBUG"):
141169
debug_manager.debug(message, prefix)
142170

171+
143172
def verbose(message: str, prefix: str = "INFO"):
144173
debug_manager.verbose(message, prefix)
145174

175+
146176
def success(message: str):
147177
debug_manager.success(message)
148178

179+
149180
def warning(message: str):
150181
debug_manager.warning(message)
151182

183+
152184
def error(message: str, exception: Optional[Exception] = None):
153185
debug_manager.error(message, exception)
154186

187+
155188
def trace_call(func_name: str, args: tuple = (), kwargs: dict = None):
156189
debug_manager.trace_function_call(func_name, args, kwargs)
157190

191+
158192
def is_debug_enabled() -> bool:
159193
return debug_manager.debug_enabled
160194

195+
161196
def is_verbose_enabled() -> bool:
162197
return debug_manager.verbose_enabled
-1023 Bytes
Binary file not shown.
-953 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)