tree-sitter-analyzer 0.2.0__py3-none-any.whl → 0.3.0__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 tree-sitter-analyzer might be problematic. Click here for more details.
- tree_sitter_analyzer/__init__.py +133 -121
- tree_sitter_analyzer/__main__.py +11 -12
- tree_sitter_analyzer/api.py +531 -539
- tree_sitter_analyzer/cli/__init__.py +39 -39
- tree_sitter_analyzer/cli/__main__.py +12 -13
- tree_sitter_analyzer/cli/commands/__init__.py +26 -27
- tree_sitter_analyzer/cli/commands/advanced_command.py +88 -88
- tree_sitter_analyzer/cli/commands/base_command.py +160 -155
- tree_sitter_analyzer/cli/commands/default_command.py +18 -19
- tree_sitter_analyzer/cli/commands/partial_read_command.py +141 -133
- tree_sitter_analyzer/cli/commands/query_command.py +81 -82
- tree_sitter_analyzer/cli/commands/structure_command.py +138 -121
- tree_sitter_analyzer/cli/commands/summary_command.py +101 -93
- tree_sitter_analyzer/cli/commands/table_command.py +232 -233
- tree_sitter_analyzer/cli/info_commands.py +120 -121
- tree_sitter_analyzer/cli_main.py +277 -276
- tree_sitter_analyzer/core/__init__.py +15 -20
- tree_sitter_analyzer/core/analysis_engine.py +591 -574
- tree_sitter_analyzer/core/cache_service.py +320 -330
- tree_sitter_analyzer/core/engine.py +557 -560
- tree_sitter_analyzer/core/parser.py +293 -288
- tree_sitter_analyzer/core/query.py +494 -502
- tree_sitter_analyzer/encoding_utils.py +458 -460
- tree_sitter_analyzer/exceptions.py +337 -340
- tree_sitter_analyzer/file_handler.py +217 -222
- tree_sitter_analyzer/formatters/__init__.py +1 -1
- tree_sitter_analyzer/formatters/base_formatter.py +167 -168
- tree_sitter_analyzer/formatters/formatter_factory.py +78 -74
- tree_sitter_analyzer/formatters/java_formatter.py +287 -270
- tree_sitter_analyzer/formatters/python_formatter.py +255 -235
- tree_sitter_analyzer/interfaces/__init__.py +9 -10
- tree_sitter_analyzer/interfaces/cli.py +528 -557
- tree_sitter_analyzer/interfaces/cli_adapter.py +322 -319
- tree_sitter_analyzer/interfaces/mcp_adapter.py +180 -170
- tree_sitter_analyzer/interfaces/mcp_server.py +405 -416
- tree_sitter_analyzer/java_analyzer.py +218 -219
- tree_sitter_analyzer/language_detector.py +398 -400
- tree_sitter_analyzer/language_loader.py +224 -228
- tree_sitter_analyzer/languages/__init__.py +10 -11
- tree_sitter_analyzer/languages/java_plugin.py +1129 -1113
- tree_sitter_analyzer/languages/python_plugin.py +737 -712
- tree_sitter_analyzer/mcp/__init__.py +31 -32
- tree_sitter_analyzer/mcp/resources/__init__.py +44 -47
- tree_sitter_analyzer/mcp/resources/code_file_resource.py +212 -213
- tree_sitter_analyzer/mcp/resources/project_stats_resource.py +560 -550
- tree_sitter_analyzer/mcp/server.py +333 -345
- tree_sitter_analyzer/mcp/tools/__init__.py +30 -31
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool.py +621 -557
- tree_sitter_analyzer/mcp/tools/analyze_scale_tool_cli_compatible.py +242 -245
- tree_sitter_analyzer/mcp/tools/base_tool.py +54 -55
- tree_sitter_analyzer/mcp/tools/read_partial_tool.py +300 -302
- tree_sitter_analyzer/mcp/tools/table_format_tool.py +362 -359
- tree_sitter_analyzer/mcp/tools/universal_analyze_tool.py +543 -476
- tree_sitter_analyzer/mcp/utils/__init__.py +105 -106
- tree_sitter_analyzer/mcp/utils/error_handler.py +549 -549
- tree_sitter_analyzer/models.py +470 -481
- tree_sitter_analyzer/output_manager.py +261 -264
- tree_sitter_analyzer/plugins/__init__.py +333 -334
- tree_sitter_analyzer/plugins/base.py +477 -446
- tree_sitter_analyzer/plugins/java_plugin.py +608 -625
- tree_sitter_analyzer/plugins/javascript_plugin.py +446 -439
- tree_sitter_analyzer/plugins/manager.py +362 -355
- tree_sitter_analyzer/plugins/plugin_loader.py +85 -83
- tree_sitter_analyzer/plugins/python_plugin.py +606 -598
- tree_sitter_analyzer/plugins/registry.py +374 -366
- tree_sitter_analyzer/queries/__init__.py +26 -27
- tree_sitter_analyzer/queries/java.py +391 -394
- tree_sitter_analyzer/queries/javascript.py +148 -149
- tree_sitter_analyzer/queries/python.py +285 -286
- tree_sitter_analyzer/queries/typescript.py +229 -230
- tree_sitter_analyzer/query_loader.py +254 -260
- tree_sitter_analyzer/table_formatter.py +468 -448
- tree_sitter_analyzer/utils.py +277 -277
- {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.3.0.dist-info}/METADATA +21 -6
- tree_sitter_analyzer-0.3.0.dist-info/RECORD +77 -0
- tree_sitter_analyzer-0.2.0.dist-info/RECORD +0 -77
- {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.3.0.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-0.2.0.dist-info → tree_sitter_analyzer-0.3.0.dist-info}/entry_points.txt +0 -0
tree_sitter_analyzer/utils.py
CHANGED
|
@@ -1,277 +1,277 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import logging
|
|
10
|
-
import sys
|
|
11
|
-
import
|
|
12
|
-
from
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
env_level
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
logger.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def cleanup_logging():
|
|
81
|
-
"""Clean up logging handlers safely"""
|
|
82
|
-
try:
|
|
83
|
-
# Get all loggers
|
|
84
|
-
loggers = [logging.getLogger()] + [
|
|
85
|
-
logging.getLogger(name) for name in logging.Logger.manager.loggerDict
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
for logger in loggers:
|
|
89
|
-
for handler in logger.handlers[:]:
|
|
90
|
-
try:
|
|
91
|
-
handler.close()
|
|
92
|
-
logger.removeHandler(handler)
|
|
93
|
-
except:
|
|
94
|
-
pass
|
|
95
|
-
except:
|
|
96
|
-
pass
|
|
97
|
-
|
|
98
|
-
# Register cleanup function
|
|
99
|
-
atexit.register(cleanup_logging)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# Setup safe shutdown on import
|
|
103
|
-
setup_safe_logging_shutdown()
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
# Global logger instance
|
|
107
|
-
logger = setup_logger()
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def log_info(message: str, *args: Any, **kwargs: Any) -> None:
|
|
111
|
-
"""Log info message"""
|
|
112
|
-
try:
|
|
113
|
-
logger.info(message, *args, **kwargs)
|
|
114
|
-
except (ValueError, OSError):
|
|
115
|
-
pass # Silently ignore I/O errors
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
|
|
119
|
-
"""Log warning message"""
|
|
120
|
-
try:
|
|
121
|
-
logger.warning(message, *args, **kwargs)
|
|
122
|
-
except (ValueError, OSError):
|
|
123
|
-
pass # Silently ignore I/O errors
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def log_error(message: str, *args: Any, **kwargs: Any) -> None:
|
|
127
|
-
"""Log error message"""
|
|
128
|
-
try:
|
|
129
|
-
logger.error(message, *args, **kwargs)
|
|
130
|
-
except (ValueError, OSError):
|
|
131
|
-
pass # Silently ignore I/O errors
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
|
|
135
|
-
"""Log debug message"""
|
|
136
|
-
try:
|
|
137
|
-
logger.debug(message, *args, **kwargs)
|
|
138
|
-
except (ValueError, OSError):
|
|
139
|
-
pass # Silently ignore I/O errors
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def suppress_output(func: Any) -> Any:
|
|
143
|
-
"""Decorator to suppress print statements in production"""
|
|
144
|
-
|
|
145
|
-
@wraps(func)
|
|
146
|
-
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
147
|
-
# Check if we're in test/debug mode
|
|
148
|
-
if getattr(sys, "_testing", False):
|
|
149
|
-
return func(*args, **kwargs)
|
|
150
|
-
|
|
151
|
-
# Redirect stdout to suppress prints
|
|
152
|
-
old_stdout = sys.stdout
|
|
153
|
-
try:
|
|
154
|
-
sys.stdout = (
|
|
155
|
-
open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
|
|
156
|
-
)
|
|
157
|
-
result = func(*args, **kwargs)
|
|
158
|
-
finally:
|
|
159
|
-
try:
|
|
160
|
-
sys.stdout.close()
|
|
161
|
-
except:
|
|
162
|
-
pass
|
|
163
|
-
sys.stdout = old_stdout
|
|
164
|
-
|
|
165
|
-
return result
|
|
166
|
-
|
|
167
|
-
return wrapper
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class QuietMode:
|
|
171
|
-
"""Context manager for quiet execution"""
|
|
172
|
-
|
|
173
|
-
def __init__(self, enabled: bool = True):
|
|
174
|
-
self.enabled = enabled
|
|
175
|
-
self.old_level:
|
|
176
|
-
|
|
177
|
-
def __enter__(self) -> "QuietMode":
|
|
178
|
-
if self.enabled:
|
|
179
|
-
self.old_level = logger.level
|
|
180
|
-
logger.setLevel(logging.ERROR)
|
|
181
|
-
return self # type: ignore
|
|
182
|
-
|
|
183
|
-
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
184
|
-
if self.enabled and self.old_level is not None:
|
|
185
|
-
logger.setLevel(self.old_level)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def safe_print(message: str, level: str = "info", quiet: bool = False) -> None:
|
|
189
|
-
"""Safe print function that can be controlled"""
|
|
190
|
-
if quiet:
|
|
191
|
-
return
|
|
192
|
-
|
|
193
|
-
level_map = {
|
|
194
|
-
"info": log_info,
|
|
195
|
-
"warning": log_warning,
|
|
196
|
-
"error": log_error,
|
|
197
|
-
"debug": log_debug,
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
log_func = level_map.get(level.lower(), log_info)
|
|
201
|
-
log_func(message)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
def create_performance_logger(name: str) -> logging.Logger:
|
|
205
|
-
"""Create performance-focused logger"""
|
|
206
|
-
perf_logger = logging.getLogger(f"{name}.performance")
|
|
207
|
-
|
|
208
|
-
if not perf_logger.handlers:
|
|
209
|
-
handler = SafeStreamHandler()
|
|
210
|
-
formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
|
|
211
|
-
handler.setFormatter(formatter)
|
|
212
|
-
perf_logger.addHandler(handler)
|
|
213
|
-
perf_logger.setLevel(logging.INFO)
|
|
214
|
-
|
|
215
|
-
return perf_logger
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
# Performance logger instance
|
|
219
|
-
perf_logger = create_performance_logger("tree_sitter_analyzer")
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def log_performance(
|
|
223
|
-
operation: str,
|
|
224
|
-
execution_time:
|
|
225
|
-
details:
|
|
226
|
-
) -> None:
|
|
227
|
-
"""Log performance metrics"""
|
|
228
|
-
try:
|
|
229
|
-
message = f"{operation}"
|
|
230
|
-
if execution_time is not None:
|
|
231
|
-
message += f": {execution_time:.4f}s"
|
|
232
|
-
if details:
|
|
233
|
-
if isinstance(details, dict):
|
|
234
|
-
detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
|
|
235
|
-
else:
|
|
236
|
-
detail_str = str(details)
|
|
237
|
-
message += f" - {detail_str}"
|
|
238
|
-
perf_logger.info(message)
|
|
239
|
-
except (ValueError, OSError):
|
|
240
|
-
pass # Silently ignore I/O errors
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def setup_performance_logger() -> logging.Logger:
|
|
244
|
-
"""Set up performance logging"""
|
|
245
|
-
perf_logger = logging.getLogger("performance")
|
|
246
|
-
|
|
247
|
-
# Add handler if not already configured
|
|
248
|
-
if not perf_logger.handlers:
|
|
249
|
-
handler = SafeStreamHandler()
|
|
250
|
-
formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
|
|
251
|
-
handler.setFormatter(formatter)
|
|
252
|
-
perf_logger.addHandler(handler)
|
|
253
|
-
perf_logger.setLevel(logging.INFO)
|
|
254
|
-
|
|
255
|
-
return perf_logger
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
class LoggingContext:
|
|
259
|
-
"""Context manager for controlling logging behavior"""
|
|
260
|
-
|
|
261
|
-
def __init__(self, enabled: bool = True, level:
|
|
262
|
-
self.enabled = enabled
|
|
263
|
-
self.level = level
|
|
264
|
-
self.old_level:
|
|
265
|
-
self.target_logger = (
|
|
266
|
-
logging.getLogger()
|
|
267
|
-
) # Use root logger for compatibility with tests
|
|
268
|
-
|
|
269
|
-
def __enter__(self) -> "LoggingContext":
|
|
270
|
-
if self.enabled and self.level is not None:
|
|
271
|
-
self.old_level = self.target_logger.level
|
|
272
|
-
self.target_logger.setLevel(self.level)
|
|
273
|
-
return self # type: ignore
|
|
274
|
-
|
|
275
|
-
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
276
|
-
if self.enabled and self.old_level is not None:
|
|
277
|
-
self.target_logger.setLevel(self.old_level)
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Utilities for Tree-sitter Analyzer
|
|
4
|
+
|
|
5
|
+
Provides logging, debugging, and common utility functions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import atexit
|
|
9
|
+
import logging
|
|
10
|
+
import sys
|
|
11
|
+
from functools import wraps
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Configure global logger
|
|
16
|
+
def setup_logger(
|
|
17
|
+
name: str = "tree_sitter_analyzer", level: int = logging.INFO
|
|
18
|
+
) -> logging.Logger:
|
|
19
|
+
"""Setup unified logger for the project"""
|
|
20
|
+
import os
|
|
21
|
+
|
|
22
|
+
# 環境変数からログレベルを取得
|
|
23
|
+
env_level = os.environ.get("LOG_LEVEL", "").upper()
|
|
24
|
+
if env_level == "DEBUG":
|
|
25
|
+
level = logging.DEBUG
|
|
26
|
+
elif env_level == "INFO":
|
|
27
|
+
level = logging.INFO
|
|
28
|
+
elif env_level == "WARNING":
|
|
29
|
+
level = logging.WARNING
|
|
30
|
+
elif env_level == "ERROR":
|
|
31
|
+
level = logging.ERROR
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(name)
|
|
34
|
+
|
|
35
|
+
if not logger.handlers: # Avoid duplicate handlers
|
|
36
|
+
# Create a safe handler that won't fail on closed streams
|
|
37
|
+
handler = SafeStreamHandler(sys.stdout)
|
|
38
|
+
formatter = logging.Formatter(
|
|
39
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
40
|
+
)
|
|
41
|
+
handler.setFormatter(formatter)
|
|
42
|
+
logger.addHandler(handler)
|
|
43
|
+
logger.setLevel(level)
|
|
44
|
+
|
|
45
|
+
return logger
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SafeStreamHandler(logging.StreamHandler):
|
|
49
|
+
"""
|
|
50
|
+
A StreamHandler that safely handles closed streams
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def emit(self, record):
|
|
54
|
+
"""
|
|
55
|
+
Emit a record, safely handling closed streams
|
|
56
|
+
"""
|
|
57
|
+
try:
|
|
58
|
+
# Check if stream is closed before writing
|
|
59
|
+
if hasattr(self.stream, "closed") and self.stream.closed:
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
# Check if we can write to the stream
|
|
63
|
+
if not hasattr(self.stream, "write"):
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
super().emit(record)
|
|
67
|
+
except (ValueError, OSError, AttributeError):
|
|
68
|
+
# Silently ignore I/O errors during shutdown
|
|
69
|
+
pass
|
|
70
|
+
except Exception:
|
|
71
|
+
# For any other unexpected errors, use handleError
|
|
72
|
+
self.handleError(record)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def setup_safe_logging_shutdown():
|
|
76
|
+
"""
|
|
77
|
+
Setup safe logging shutdown to prevent I/O errors
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def cleanup_logging():
|
|
81
|
+
"""Clean up logging handlers safely"""
|
|
82
|
+
try:
|
|
83
|
+
# Get all loggers
|
|
84
|
+
loggers = [logging.getLogger()] + [
|
|
85
|
+
logging.getLogger(name) for name in logging.Logger.manager.loggerDict
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
for logger in loggers:
|
|
89
|
+
for handler in logger.handlers[:]:
|
|
90
|
+
try:
|
|
91
|
+
handler.close()
|
|
92
|
+
logger.removeHandler(handler)
|
|
93
|
+
except Exception:
|
|
94
|
+
pass
|
|
95
|
+
except Exception:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
# Register cleanup function
|
|
99
|
+
atexit.register(cleanup_logging)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# Setup safe shutdown on import
|
|
103
|
+
setup_safe_logging_shutdown()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# Global logger instance
|
|
107
|
+
logger = setup_logger()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def log_info(message: str, *args: Any, **kwargs: Any) -> None:
|
|
111
|
+
"""Log info message"""
|
|
112
|
+
try:
|
|
113
|
+
logger.info(message, *args, **kwargs)
|
|
114
|
+
except (ValueError, OSError):
|
|
115
|
+
pass # Silently ignore I/O errors
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
|
|
119
|
+
"""Log warning message"""
|
|
120
|
+
try:
|
|
121
|
+
logger.warning(message, *args, **kwargs)
|
|
122
|
+
except (ValueError, OSError):
|
|
123
|
+
pass # Silently ignore I/O errors
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def log_error(message: str, *args: Any, **kwargs: Any) -> None:
|
|
127
|
+
"""Log error message"""
|
|
128
|
+
try:
|
|
129
|
+
logger.error(message, *args, **kwargs)
|
|
130
|
+
except (ValueError, OSError):
|
|
131
|
+
pass # Silently ignore I/O errors
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
|
|
135
|
+
"""Log debug message"""
|
|
136
|
+
try:
|
|
137
|
+
logger.debug(message, *args, **kwargs)
|
|
138
|
+
except (ValueError, OSError):
|
|
139
|
+
pass # Silently ignore I/O errors
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def suppress_output(func: Any) -> Any:
|
|
143
|
+
"""Decorator to suppress print statements in production"""
|
|
144
|
+
|
|
145
|
+
@wraps(func)
|
|
146
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
147
|
+
# Check if we're in test/debug mode
|
|
148
|
+
if getattr(sys, "_testing", False):
|
|
149
|
+
return func(*args, **kwargs)
|
|
150
|
+
|
|
151
|
+
# Redirect stdout to suppress prints
|
|
152
|
+
old_stdout = sys.stdout
|
|
153
|
+
try:
|
|
154
|
+
sys.stdout = (
|
|
155
|
+
open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
|
|
156
|
+
)
|
|
157
|
+
result = func(*args, **kwargs)
|
|
158
|
+
finally:
|
|
159
|
+
try:
|
|
160
|
+
sys.stdout.close()
|
|
161
|
+
except Exception:
|
|
162
|
+
pass
|
|
163
|
+
sys.stdout = old_stdout
|
|
164
|
+
|
|
165
|
+
return result
|
|
166
|
+
|
|
167
|
+
return wrapper
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class QuietMode:
|
|
171
|
+
"""Context manager for quiet execution"""
|
|
172
|
+
|
|
173
|
+
def __init__(self, enabled: bool = True):
|
|
174
|
+
self.enabled = enabled
|
|
175
|
+
self.old_level: int | None = None
|
|
176
|
+
|
|
177
|
+
def __enter__(self) -> "QuietMode":
|
|
178
|
+
if self.enabled:
|
|
179
|
+
self.old_level = logger.level
|
|
180
|
+
logger.setLevel(logging.ERROR)
|
|
181
|
+
return self # type: ignore
|
|
182
|
+
|
|
183
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
184
|
+
if self.enabled and self.old_level is not None:
|
|
185
|
+
logger.setLevel(self.old_level)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def safe_print(message: str, level: str = "info", quiet: bool = False) -> None:
|
|
189
|
+
"""Safe print function that can be controlled"""
|
|
190
|
+
if quiet:
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
level_map = {
|
|
194
|
+
"info": log_info,
|
|
195
|
+
"warning": log_warning,
|
|
196
|
+
"error": log_error,
|
|
197
|
+
"debug": log_debug,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
log_func = level_map.get(level.lower(), log_info)
|
|
201
|
+
log_func(message)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def create_performance_logger(name: str) -> logging.Logger:
|
|
205
|
+
"""Create performance-focused logger"""
|
|
206
|
+
perf_logger = logging.getLogger(f"{name}.performance")
|
|
207
|
+
|
|
208
|
+
if not perf_logger.handlers:
|
|
209
|
+
handler = SafeStreamHandler()
|
|
210
|
+
formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
|
|
211
|
+
handler.setFormatter(formatter)
|
|
212
|
+
perf_logger.addHandler(handler)
|
|
213
|
+
perf_logger.setLevel(logging.INFO)
|
|
214
|
+
|
|
215
|
+
return perf_logger
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
# Performance logger instance
|
|
219
|
+
perf_logger = create_performance_logger("tree_sitter_analyzer")
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def log_performance(
|
|
223
|
+
operation: str,
|
|
224
|
+
execution_time: float | None = None,
|
|
225
|
+
details: dict | None = None,
|
|
226
|
+
) -> None:
|
|
227
|
+
"""Log performance metrics"""
|
|
228
|
+
try:
|
|
229
|
+
message = f"{operation}"
|
|
230
|
+
if execution_time is not None:
|
|
231
|
+
message += f": {execution_time:.4f}s"
|
|
232
|
+
if details:
|
|
233
|
+
if isinstance(details, dict):
|
|
234
|
+
detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
|
|
235
|
+
else:
|
|
236
|
+
detail_str = str(details)
|
|
237
|
+
message += f" - {detail_str}"
|
|
238
|
+
perf_logger.info(message)
|
|
239
|
+
except (ValueError, OSError):
|
|
240
|
+
pass # Silently ignore I/O errors
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def setup_performance_logger() -> logging.Logger:
|
|
244
|
+
"""Set up performance logging"""
|
|
245
|
+
perf_logger = logging.getLogger("performance")
|
|
246
|
+
|
|
247
|
+
# Add handler if not already configured
|
|
248
|
+
if not perf_logger.handlers:
|
|
249
|
+
handler = SafeStreamHandler()
|
|
250
|
+
formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
|
|
251
|
+
handler.setFormatter(formatter)
|
|
252
|
+
perf_logger.addHandler(handler)
|
|
253
|
+
perf_logger.setLevel(logging.INFO)
|
|
254
|
+
|
|
255
|
+
return perf_logger
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class LoggingContext:
|
|
259
|
+
"""Context manager for controlling logging behavior"""
|
|
260
|
+
|
|
261
|
+
def __init__(self, enabled: bool = True, level: int | None = None):
|
|
262
|
+
self.enabled = enabled
|
|
263
|
+
self.level = level
|
|
264
|
+
self.old_level: int | None = None
|
|
265
|
+
self.target_logger = (
|
|
266
|
+
logging.getLogger()
|
|
267
|
+
) # Use root logger for compatibility with tests
|
|
268
|
+
|
|
269
|
+
def __enter__(self) -> "LoggingContext":
|
|
270
|
+
if self.enabled and self.level is not None:
|
|
271
|
+
self.old_level = self.target_logger.level
|
|
272
|
+
self.target_logger.setLevel(self.level)
|
|
273
|
+
return self # type: ignore
|
|
274
|
+
|
|
275
|
+
def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
|
|
276
|
+
if self.enabled and self.old_level is not None:
|
|
277
|
+
self.target_logger.setLevel(self.old_level)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tree-sitter-analyzer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Extensible multi-language code analyzer framework using Tree-sitter with dynamic plugin architecture
|
|
5
5
|
Project-URL: Homepage, https://github.com/aimasteracc/tree-sitter-analyzer
|
|
6
6
|
Project-URL: Documentation, https://github.com/aimasteracc/tree-sitter-analyzer#readme
|
|
@@ -51,7 +51,6 @@ Provides-Extra: cpp
|
|
|
51
51
|
Requires-Dist: tree-sitter-cpp>=0.23.4; extra == 'cpp'
|
|
52
52
|
Provides-Extra: dev
|
|
53
53
|
Requires-Dist: black>=24.0.0; extra == 'dev'
|
|
54
|
-
Requires-Dist: flake8>=7.0.0; extra == 'dev'
|
|
55
54
|
Requires-Dist: isort>=5.13.0; extra == 'dev'
|
|
56
55
|
Requires-Dist: memory-profiler>=0.61.0; extra == 'dev'
|
|
57
56
|
Requires-Dist: mypy>=1.17.0; extra == 'dev'
|
|
@@ -61,11 +60,11 @@ Requires-Dist: pytest-asyncio>=1.1.0; extra == 'dev'
|
|
|
61
60
|
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
62
61
|
Requires-Dist: pytest-mock>=3.14.1; extra == 'dev'
|
|
63
62
|
Requires-Dist: pytest>=8.4.1; extra == 'dev'
|
|
63
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
64
64
|
Requires-Dist: types-psutil>=5.9.0; extra == 'dev'
|
|
65
65
|
Provides-Extra: full
|
|
66
66
|
Requires-Dist: anyio>=4.9.0; extra == 'full'
|
|
67
67
|
Requires-Dist: black>=24.0.0; extra == 'full'
|
|
68
|
-
Requires-Dist: flake8>=7.0.0; extra == 'full'
|
|
69
68
|
Requires-Dist: httpx>=0.28.1; extra == 'full'
|
|
70
69
|
Requires-Dist: isort>=5.13.0; extra == 'full'
|
|
71
70
|
Requires-Dist: mcp>=1.12.2; extra == 'full'
|
|
@@ -79,6 +78,7 @@ Requires-Dist: pytest-asyncio>=1.1.0; extra == 'full'
|
|
|
79
78
|
Requires-Dist: pytest-cov>=4.0.0; extra == 'full'
|
|
80
79
|
Requires-Dist: pytest-mock>=3.14.1; extra == 'full'
|
|
81
80
|
Requires-Dist: pytest>=8.4.1; extra == 'full'
|
|
81
|
+
Requires-Dist: ruff>=0.1.0; extra == 'full'
|
|
82
82
|
Requires-Dist: tree-sitter-c>=0.20.0; extra == 'full'
|
|
83
83
|
Requires-Dist: tree-sitter-cpp>=0.23.4; extra == 'full'
|
|
84
84
|
Requires-Dist: tree-sitter-go>=0.20.0; extra == 'full'
|
|
@@ -198,7 +198,7 @@ Add to your Claude Desktop config file:
|
|
|
198
198
|
uv add "tree-sitter-analyzer[popular]"
|
|
199
199
|
|
|
200
200
|
# Step 1: Check file scale
|
|
201
|
-
uv run python -m tree_sitter_analyzer examples/Sample.java --advanced
|
|
201
|
+
uv run python -m tree_sitter_analyzer examples/Sample.java --advanced --output-format=text
|
|
202
202
|
|
|
203
203
|
# Step 2: Analyze structure (for large files)
|
|
204
204
|
uv run python -m tree_sitter_analyzer examples/Sample.java --table=full
|
|
@@ -252,7 +252,7 @@ Four powerful MCP tools for AI assistants:
|
|
|
252
252
|
|
|
253
253
|
**Step 1: Basic analysis (Check file scale):**
|
|
254
254
|
```bash
|
|
255
|
-
uv run python -m tree_sitter_analyzer examples/Sample.java --advanced
|
|
255
|
+
uv run python -m tree_sitter_analyzer examples/Sample.java --advanced --output-format=text
|
|
256
256
|
```
|
|
257
257
|
|
|
258
258
|
**Step 2: Structure analysis (For large files that exceed LLM limits):**
|
|
@@ -268,7 +268,7 @@ uv run python -m tree_sitter_analyzer examples/Sample.java --partial-read --star
|
|
|
268
268
|
**Additional Options:**
|
|
269
269
|
```bash
|
|
270
270
|
# Quiet mode (suppress INFO messages, show only errors)
|
|
271
|
-
uv run python -m tree_sitter_analyzer examples/Sample.java --advanced --quiet
|
|
271
|
+
uv run python -m tree_sitter_analyzer examples/Sample.java --advanced --output-format=text --quiet
|
|
272
272
|
|
|
273
273
|
# Table output with quiet mode
|
|
274
274
|
uv run python -m tree_sitter_analyzer examples/Sample.java --table=full --quiet
|
|
@@ -326,6 +326,21 @@ MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
326
326
|
|
|
327
327
|
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
328
328
|
|
|
329
|
+
### 🤖 AI/LLM Collaboration
|
|
330
|
+
|
|
331
|
+
This project supports AI-assisted development with specialized quality controls:
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# For AI systems - run before generating code
|
|
335
|
+
python check_quality.py --new-code-only
|
|
336
|
+
python llm_code_checker.py --check-all
|
|
337
|
+
|
|
338
|
+
# For AI-generated code review
|
|
339
|
+
python llm_code_checker.py path/to/new_file.py
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
📖 **See our [AI Collaboration Guide](AI_COLLABORATION_GUIDE.md) and [LLM Coding Guidelines](LLM_CODING_GUIDELINES.md) for detailed instructions on working with AI systems.**
|
|
343
|
+
|
|
329
344
|
---
|
|
330
345
|
|
|
331
346
|
**Made with ❤️ for developers who work with large codebases and AI assistants.**
|