tree-sitter-analyzer 0.1.0__py3-none-any.whl → 0.1.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 tree-sitter-analyzer might be problematic. Click here for more details.

@@ -51,7 +51,7 @@ Examples:
51
51
  # Get framework information
52
52
  tree-sitter-analyzer info
53
53
 
54
- For more information, visit: https://github.com/tree-sitter-analyzer/tree-sitter-analyzer
54
+ For more information, visit: https://github.com/aimasteracc/tree-sitter-analyzer
55
55
  """
56
56
  )
57
57
 
@@ -209,7 +209,10 @@ class TreeSitterAnalyzerMCPServer:
209
209
  raise ValueError(f"Unknown tool: {name}")
210
210
 
211
211
  except Exception as e:
212
- logger.error(f"Tool call error for {name}: {e}")
212
+ try:
213
+ logger.error(f"Tool call error for {name}: {e}")
214
+ except (ValueError, OSError):
215
+ pass # Silently ignore logging errors during shutdown
213
216
  return [
214
217
  TextContent(
215
218
  type="text",
@@ -258,11 +261,17 @@ class TreeSitterAnalyzerMCPServer:
258
261
  raise ValueError(f"Resource not found: {uri}")
259
262
 
260
263
  except Exception as e:
261
- logger.error(f"Resource read error for {uri}: {e}")
264
+ try:
265
+ logger.error(f"Resource read error for {uri}: {e}")
266
+ except (ValueError, OSError):
267
+ pass # Silently ignore logging errors during shutdown
262
268
  raise
263
269
 
264
270
  self.server = server
265
- logger.info("MCP server created successfully")
271
+ try:
272
+ logger.info("MCP server created successfully")
273
+ except (ValueError, OSError):
274
+ pass # Silently ignore logging errors during shutdown
266
275
  return server
267
276
 
268
277
  def set_project_path(self, project_path: str) -> None:
@@ -273,7 +282,10 @@ class TreeSitterAnalyzerMCPServer:
273
282
  project_path: Path to the project directory
274
283
  """
275
284
  self.project_stats_resource.set_project_path(project_path)
276
- logger.info(f"Set project path to: {project_path}")
285
+ try:
286
+ logger.info(f"Set project path to: {project_path}")
287
+ except (ValueError, OSError):
288
+ pass # Silently ignore logging errors during shutdown
277
289
 
278
290
  async def run(self) -> None:
279
291
  """
@@ -293,14 +305,27 @@ class TreeSitterAnalyzerMCPServer:
293
305
  capabilities=MCP_INFO["capabilities"],
294
306
  )
295
307
 
296
- logger.info(f"Starting MCP server: {self.name} v{self.version}")
308
+ try:
309
+ logger.info(f"Starting MCP server: {self.name} v{self.version}")
310
+ except (ValueError, OSError):
311
+ pass # Silently ignore logging errors during shutdown
297
312
 
298
313
  try:
299
314
  async with stdio_server() as (read_stream, write_stream):
300
315
  await server.run(read_stream, write_stream, options)
301
316
  except Exception as e:
302
- logger.error(f"Server error: {e}")
317
+ # Use safe logging to avoid I/O errors during shutdown
318
+ try:
319
+ logger.error(f"Server error: {e}")
320
+ except (ValueError, OSError):
321
+ pass # Silently ignore logging errors during shutdown
303
322
  raise
323
+ finally:
324
+ # Safe cleanup
325
+ try:
326
+ logger.info("MCP server shutting down")
327
+ except (ValueError, OSError):
328
+ pass # Silently ignore logging errors during shutdown
304
329
 
305
330
 
306
331
  async def main() -> None:
@@ -309,10 +334,22 @@ async def main() -> None:
309
334
  server = TreeSitterAnalyzerMCPServer()
310
335
  await server.run()
311
336
  except KeyboardInterrupt:
312
- logger.info("Server stopped by user")
337
+ try:
338
+ logger.info("Server stopped by user")
339
+ except (ValueError, OSError):
340
+ pass # Silently ignore logging errors during shutdown
313
341
  except Exception as e:
314
- logger.error(f"Server failed: {e}")
342
+ try:
343
+ logger.error(f"Server failed: {e}")
344
+ except (ValueError, OSError):
345
+ pass # Silently ignore logging errors during shutdown
315
346
  sys.exit(1)
347
+ finally:
348
+ # Ensure clean shutdown
349
+ try:
350
+ logger.info("MCP server shutdown complete")
351
+ except (ValueError, OSError):
352
+ pass # Silently ignore logging errors during shutdown
316
353
 
317
354
 
318
355
  if __name__ == "__main__":
@@ -8,6 +8,7 @@ Provides logging, debugging, and common utility functions.
8
8
 
9
9
  import logging
10
10
  import sys
11
+ import atexit
11
12
  from functools import wraps
12
13
  from typing import Any, Optional
13
14
 
@@ -33,7 +34,8 @@ def setup_logger(
33
34
  logger = logging.getLogger(name)
34
35
 
35
36
  if not logger.handlers: # Avoid duplicate handlers
36
- handler = logging.StreamHandler(sys.stdout)
37
+ # Create a safe handler that won't fail on closed streams
38
+ handler = SafeStreamHandler(sys.stdout)
37
39
  formatter = logging.Formatter(
38
40
  "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
39
41
  )
@@ -44,28 +46,97 @@ def setup_logger(
44
46
  return logger
45
47
 
46
48
 
49
+ class SafeStreamHandler(logging.StreamHandler):
50
+ """
51
+ A StreamHandler that safely handles closed streams
52
+ """
53
+
54
+ def emit(self, record):
55
+ """
56
+ Emit a record, safely handling closed streams
57
+ """
58
+ try:
59
+ # Check if stream is closed before writing
60
+ if hasattr(self.stream, 'closed') and self.stream.closed:
61
+ return
62
+
63
+ # Check if we can write to the stream
64
+ if not hasattr(self.stream, 'write'):
65
+ return
66
+
67
+ super().emit(record)
68
+ except (ValueError, OSError, AttributeError):
69
+ # Silently ignore I/O errors during shutdown
70
+ pass
71
+ except Exception:
72
+ # For any other unexpected errors, use handleError
73
+ self.handleError(record)
74
+
75
+
76
+ def setup_safe_logging_shutdown():
77
+ """
78
+ Setup safe logging shutdown to prevent I/O errors
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
+
47
106
  # Global logger instance
48
107
  logger = setup_logger()
49
108
 
50
109
 
51
110
  def log_info(message: str, *args: Any, **kwargs: Any) -> None:
52
111
  """Log info message"""
53
- logger.info(message, *args, **kwargs)
112
+ try:
113
+ logger.info(message, *args, **kwargs)
114
+ except (ValueError, OSError):
115
+ pass # Silently ignore I/O errors
54
116
 
55
117
 
56
118
  def log_warning(message: str, *args: Any, **kwargs: Any) -> None:
57
119
  """Log warning message"""
58
- logger.warning(message, *args, **kwargs)
120
+ try:
121
+ logger.warning(message, *args, **kwargs)
122
+ except (ValueError, OSError):
123
+ pass # Silently ignore I/O errors
59
124
 
60
125
 
61
126
  def log_error(message: str, *args: Any, **kwargs: Any) -> None:
62
127
  """Log error message"""
63
- logger.error(message, *args, **kwargs)
128
+ try:
129
+ logger.error(message, *args, **kwargs)
130
+ except (ValueError, OSError):
131
+ pass # Silently ignore I/O errors
64
132
 
65
133
 
66
134
  def log_debug(message: str, *args: Any, **kwargs: Any) -> None:
67
135
  """Log debug message"""
68
- logger.debug(message, *args, **kwargs)
136
+ try:
137
+ logger.debug(message, *args, **kwargs)
138
+ except (ValueError, OSError):
139
+ pass # Silently ignore I/O errors
69
140
 
70
141
 
71
142
  def suppress_output(func: Any) -> Any:
@@ -79,14 +150,16 @@ def suppress_output(func: Any) -> Any:
79
150
 
80
151
  # Redirect stdout to suppress prints
81
152
  old_stdout = sys.stdout
82
- sys.stdout = (
83
- open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
84
- )
85
-
86
153
  try:
154
+ sys.stdout = (
155
+ open("/dev/null", "w") if sys.platform != "win32" else open("nul", "w")
156
+ )
87
157
  result = func(*args, **kwargs)
88
158
  finally:
89
- sys.stdout.close()
159
+ try:
160
+ sys.stdout.close()
161
+ except:
162
+ pass
90
163
  sys.stdout = old_stdout
91
164
 
92
165
  return result
@@ -133,7 +206,7 @@ def create_performance_logger(name: str) -> logging.Logger:
133
206
  perf_logger = logging.getLogger(f"{name}.performance")
134
207
 
135
208
  if not perf_logger.handlers:
136
- handler = logging.StreamHandler()
209
+ handler = SafeStreamHandler()
137
210
  formatter = logging.Formatter("%(asctime)s - PERF - %(message)s")
138
211
  handler.setFormatter(formatter)
139
212
  perf_logger.addHandler(handler)
@@ -152,16 +225,19 @@ def log_performance(
152
225
  details: Optional[dict] = None,
153
226
  ) -> None:
154
227
  """Log performance metrics"""
155
- message = f"{operation}"
156
- if execution_time is not None:
157
- message += f": {execution_time:.4f}s"
158
- if details:
159
- if isinstance(details, dict):
160
- detail_str = ", ".join([f"{k}: {v}" for k, v in details.items()])
161
- else:
162
- detail_str = str(details)
163
- message += f" - {detail_str}"
164
- perf_logger.info(message)
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
165
241
 
166
242
 
167
243
  def setup_performance_logger() -> logging.Logger:
@@ -170,7 +246,7 @@ def setup_performance_logger() -> logging.Logger:
170
246
 
171
247
  # Add handler if not already configured
172
248
  if not perf_logger.handlers:
173
- handler = logging.StreamHandler()
249
+ handler = SafeStreamHandler()
174
250
  formatter = logging.Formatter("%(asctime)s - Performance - %(message)s")
175
251
  handler.setFormatter(formatter)
176
252
  perf_logger.addHandler(handler)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tree-sitter-analyzer
3
- Version: 0.1.0
3
+ Version: 0.1.1
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
@@ -12,7 +12,7 @@ tree_sitter_analyzer/models.py,sha256=2JZAQXM4nJVu7rfnsZFwpvPpv8fpk0POVHKCKeOMLM
12
12
  tree_sitter_analyzer/output_manager.py,sha256=dh_yfAmvn-XuF7RP5DM5vnqHGRzBUDOsuiVvTjcaOwg,8769
13
13
  tree_sitter_analyzer/query_loader.py,sha256=KrpNnf-plrtymDAfUF6ukw8ELtGWnqhikwPLW_z9vY8,10225
14
14
  tree_sitter_analyzer/table_formatter.py,sha256=FpYywpJOkXv3FfHEDFSWjfP5ZFa1WJZ6QqN_H0YtUC4,18274
15
- tree_sitter_analyzer/utils.py,sha256=Qh9kpFzxvKNTbLfmdl5jsIqVxuBIarIgZdBbizDOKH8,5978
15
+ tree_sitter_analyzer/utils.py,sha256=mL-TexPDTmapE3x7UErVQEJjXWn613KibPbZwgTpkd0,8332
16
16
  tree_sitter_analyzer/cli/__init__.py,sha256=zCYwQW0hKFfZ4w-qoSOnqVKZGtdZ-ziH60Ax0QBE2iQ,886
17
17
  tree_sitter_analyzer/cli/__main__.py,sha256=Sa02Ye57FhkDVTlGrb6U3m9V6II_TIuyzoQIwZtBkZ0,254
18
18
  tree_sitter_analyzer/cli/info_commands.py,sha256=B9fBryAJ2Ctt-wo8Tko86BKOfFCCBPhAWz9vz_3r1fs,4521
@@ -37,7 +37,7 @@ tree_sitter_analyzer/formatters/formatter_factory.py,sha256=_jw9Emd7t0vM3DroJwBx
37
37
  tree_sitter_analyzer/formatters/java_formatter.py,sha256=HmbQJgYsswg3whZ61p-M_CuHxg72yY-EtszOBVnjsw8,11285
38
38
  tree_sitter_analyzer/formatters/python_formatter.py,sha256=Fz84SHDExP2nSx3Iq43XbbY8Z9dWYQj5zJS9cmPLysA,9898
39
39
  tree_sitter_analyzer/interfaces/__init__.py,sha256=YrVFjBhhOkcJ4bRGmQnRBHwOSyPUsBLVy77Bc9eUYC8,303
40
- tree_sitter_analyzer/interfaces/cli.py,sha256=1eP1Ji4CnMMK9Iabatw0UrDqdhnncRGqF5dWkKBl5OU,17841
40
+ tree_sitter_analyzer/interfaces/cli.py,sha256=hTAIFew7yq9a9ejWnyGnwFHqadzckWXT-EaX-Q-La7I,17832
41
41
  tree_sitter_analyzer/interfaces/cli_adapter.py,sha256=0lxm8dQuzTohlXptFq2bZEjnL7YAmOnli2iN3C8V0TA,11461
42
42
  tree_sitter_analyzer/interfaces/mcp_adapter.py,sha256=vZcZy5FRYrSjJkRvdyu28OtqoESwiXkTqH9Nv7irRqM,6515
43
43
  tree_sitter_analyzer/interfaces/mcp_server.py,sha256=3zj02Ur00ceJvKSG5bkuxlU2bHLaiCWjW2367dNPlLM,16907
@@ -45,7 +45,7 @@ tree_sitter_analyzer/languages/__init__.py,sha256=MAZEb-ifvdttqAQts_n3Cj9jtMd1cy
45
45
  tree_sitter_analyzer/languages/java_plugin.py,sha256=2VdS2ZoNhd8q-Dqlc08vpfhoGqpN-vqEkRkFF4uuczE,46174
46
46
  tree_sitter_analyzer/languages/python_plugin.py,sha256=to_mg-x4nJZO27i7geP5sTmHCLXiv2_gjFCCPB0ELZU,28839
47
47
  tree_sitter_analyzer/mcp/__init__.py,sha256=QX4WA9HrxASLW1q-aVKhmXyONBy__2X9jOj9YctEj9Q,783
48
- tree_sitter_analyzer/mcp/server.py,sha256=Si8Vado3N3v9oXa-7zof0216ZRE0pT9s_FQ1WBjUaPo,12033
48
+ tree_sitter_analyzer/mcp/server.py,sha256=wOG1NQpty_8cVe_vmgO87m--mAdxjZDonLv6zLcp9Bk,13622
49
49
  tree_sitter_analyzer/mcp/resources/__init__.py,sha256=caWz1n3l22IaxBZ1plSjIUfroassWNNDRWEwEp1vaMw,1490
50
50
  tree_sitter_analyzer/mcp/resources/code_file_resource.py,sha256=p3XrTAHPasl92f7mdiWnRv2nl338GPeKlYdCIzLyYqg,6541
51
51
  tree_sitter_analyzer/mcp/resources/project_stats_resource.py,sha256=CkvfOSr7Bk6mJlJt-MkXw3kmUC0VAAsw8w1-AcGO0ek,19854
@@ -72,7 +72,7 @@ tree_sitter_analyzer/queries/java.py,sha256=hmaj7jKQ_m9nmOAnyiWQhzH-6g41xIi3fwt5
72
72
  tree_sitter_analyzer/queries/javascript.py,sha256=TSe6uSHhBuQU0r2B8YBqpEYkU4q9CYRuTUqRK0WfM5o,4183
73
73
  tree_sitter_analyzer/queries/python.py,sha256=V5MsKmI9A_FqAT2PKkrSL_Xp9bGKBUSpyVPoBmLxxWg,8018
74
74
  tree_sitter_analyzer/queries/typescript.py,sha256=T8a9PwqqGkwLr8clVsAfu0IUIrLKH8u4sBqlU1Cz-FE,7138
75
- tree_sitter_analyzer-0.1.0.dist-info/METADATA,sha256=Lae0km9mLIkZ_2omwxhIkOv1iUv9wRZFDOa5iWJCHG8,20459
76
- tree_sitter_analyzer-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
77
- tree_sitter_analyzer-0.1.0.dist-info/entry_points.txt,sha256=SJQuz4-IsroAsZHTfT1Q9BnAyEIULOSUiB_NaUSrjPE,354
78
- tree_sitter_analyzer-0.1.0.dist-info/RECORD,,
75
+ tree_sitter_analyzer-0.1.1.dist-info/METADATA,sha256=1Isr-NuXUcAmSICuHE8f8MJIhZgIY6olfl19D9kBXTc,20459
76
+ tree_sitter_analyzer-0.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
77
+ tree_sitter_analyzer-0.1.1.dist-info/entry_points.txt,sha256=-XEh1racqnCT30mhKWMv5-bgX0iqd_J6b08lZS9J4eg,336
78
+ tree_sitter_analyzer-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,8 @@
1
+ [console_scripts]
2
+ code-analyzer = tree_sitter_analyzer.cli_main:main
3
+ java-analyzer = tree_sitter_analyzer.cli_main:main
4
+ tree-sitter-analyzer = tree_sitter_analyzer.cli_main:main
5
+
6
+ [tree_sitter_analyzer.plugins]
7
+ java = tree_sitter_analyzer.languages.java_plugin:JavaPlugin
8
+ python = tree_sitter_analyzer.plugins.python_plugin:PythonPlugin
@@ -1,8 +0,0 @@
1
- [console_scripts]
2
- code-analyzer = tree_sitter_analyzer.interfaces.cli:main
3
- java-analyzer = tree_sitter_analyzer.interfaces.cli:main
4
- tree-sitter-analyzer = tree_sitter_analyzer.interfaces.cli:main
5
-
6
- [tree_sitter_analyzer.plugins]
7
- java = tree_sitter_analyzer.languages.java_plugin:JavaPlugin
8
- python = tree_sitter_analyzer.plugins.python_plugin:PythonPlugin