tree-sitter-analyzer 1.6.1.3__py3-none-any.whl → 1.6.1.4__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 +1 -1
- tree_sitter_analyzer/encoding_utils.py +55 -0
- tree_sitter_analyzer/file_handler.py +43 -27
- {tree_sitter_analyzer-1.6.1.3.dist-info → tree_sitter_analyzer-1.6.1.4.dist-info}/METADATA +6 -6
- {tree_sitter_analyzer-1.6.1.3.dist-info → tree_sitter_analyzer-1.6.1.4.dist-info}/RECORD +7 -7
- {tree_sitter_analyzer-1.6.1.3.dist-info → tree_sitter_analyzer-1.6.1.4.dist-info}/WHEEL +0 -0
- {tree_sitter_analyzer-1.6.1.3.dist-info → tree_sitter_analyzer-1.6.1.4.dist-info}/entry_points.txt +0 -0
tree_sitter_analyzer/__init__.py
CHANGED
|
@@ -456,6 +456,61 @@ def extract_text_slice(
|
|
|
456
456
|
)
|
|
457
457
|
|
|
458
458
|
|
|
459
|
+
def read_file_safe_streaming(file_path: str | Path):
|
|
460
|
+
"""
|
|
461
|
+
Context manager for streaming file reading with automatic encoding detection.
|
|
462
|
+
|
|
463
|
+
This function opens a file with the correct encoding detected from the file's
|
|
464
|
+
content and yields a file handle that can be used for line-by-line reading.
|
|
465
|
+
This is memory-efficient for large files as it doesn't load the entire content.
|
|
466
|
+
|
|
467
|
+
Args:
|
|
468
|
+
file_path: Path to the file to read
|
|
469
|
+
|
|
470
|
+
Yields:
|
|
471
|
+
File handle opened with the correct encoding
|
|
472
|
+
|
|
473
|
+
Example:
|
|
474
|
+
with read_file_safe_streaming("large_file.txt") as f:
|
|
475
|
+
for line_num, line in enumerate(f, 1):
|
|
476
|
+
if line_num >= start_line:
|
|
477
|
+
# Process line
|
|
478
|
+
pass
|
|
479
|
+
"""
|
|
480
|
+
import contextlib
|
|
481
|
+
|
|
482
|
+
file_path = Path(file_path)
|
|
483
|
+
|
|
484
|
+
# First, detect encoding by reading a small sample
|
|
485
|
+
try:
|
|
486
|
+
with open(file_path, "rb") as f:
|
|
487
|
+
# Read first 8KB to detect encoding
|
|
488
|
+
sample_data = f.read(8192)
|
|
489
|
+
|
|
490
|
+
if not sample_data:
|
|
491
|
+
# Empty file, use default encoding
|
|
492
|
+
detected_encoding = EncodingManager.DEFAULT_ENCODING
|
|
493
|
+
else:
|
|
494
|
+
# Detect encoding from sample with file path for caching
|
|
495
|
+
detected_encoding = EncodingManager.detect_encoding(sample_data, str(file_path))
|
|
496
|
+
|
|
497
|
+
except OSError as e:
|
|
498
|
+
log_warning(f"Failed to read file for encoding detection {file_path}: {e}")
|
|
499
|
+
raise e
|
|
500
|
+
|
|
501
|
+
# Open file with detected encoding for streaming
|
|
502
|
+
@contextlib.contextmanager
|
|
503
|
+
def _file_context():
|
|
504
|
+
try:
|
|
505
|
+
with open(file_path, "r", encoding=detected_encoding, errors="replace") as f:
|
|
506
|
+
yield f
|
|
507
|
+
except OSError as e:
|
|
508
|
+
log_warning(f"Failed to open file for streaming {file_path}: {e}")
|
|
509
|
+
raise e
|
|
510
|
+
|
|
511
|
+
return _file_context()
|
|
512
|
+
|
|
513
|
+
|
|
459
514
|
def clear_encoding_cache() -> None:
|
|
460
515
|
"""Clear the global encoding cache"""
|
|
461
516
|
_encoding_cache.clear()
|
|
@@ -5,9 +5,10 @@ File Handler Module
|
|
|
5
5
|
This module provides file reading functionality with encoding detection and fallback.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import itertools
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
|
|
10
|
-
from .encoding_utils import read_file_safe
|
|
11
|
+
from .encoding_utils import read_file_safe, read_file_safe_streaming
|
|
11
12
|
from .utils import log_error, log_info, log_warning
|
|
12
13
|
|
|
13
14
|
|
|
@@ -81,7 +82,10 @@ def read_file_partial(
|
|
|
81
82
|
end_column: int | None = None,
|
|
82
83
|
) -> str | None:
|
|
83
84
|
"""
|
|
84
|
-
Read partial file content by line/column range
|
|
85
|
+
Read partial file content by line/column range using streaming approach.
|
|
86
|
+
|
|
87
|
+
This function uses a memory-efficient streaming approach that reads only
|
|
88
|
+
the required lines from the file, making it suitable for very large files.
|
|
85
89
|
|
|
86
90
|
Args:
|
|
87
91
|
file_path: Path to file
|
|
@@ -109,30 +113,39 @@ def read_file_partial(
|
|
|
109
113
|
return None
|
|
110
114
|
|
|
111
115
|
try:
|
|
112
|
-
#
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
116
|
+
# Use streaming approach for memory efficiency
|
|
117
|
+
with read_file_safe_streaming(file_path) as f:
|
|
118
|
+
# Convert to 0-based indexing
|
|
119
|
+
start_idx = start_line - 1
|
|
120
|
+
end_idx = end_line - 1 if end_line is not None else None
|
|
121
|
+
|
|
122
|
+
# Use itertools.islice for efficient line selection
|
|
123
|
+
if end_idx is not None:
|
|
124
|
+
# Read specific range
|
|
125
|
+
selected_lines_iter = itertools.islice(f, start_idx, end_idx + 1)
|
|
126
|
+
else:
|
|
127
|
+
# Read from start_line to end of file
|
|
128
|
+
selected_lines_iter = itertools.islice(f, start_idx, None)
|
|
129
|
+
|
|
130
|
+
# Convert iterator to list for processing
|
|
131
|
+
selected_lines = list(selected_lines_iter)
|
|
132
|
+
|
|
133
|
+
# Check if we got any lines
|
|
134
|
+
if not selected_lines:
|
|
135
|
+
# Check if start_line is beyond file length by counting lines
|
|
136
|
+
with read_file_safe_streaming(file_path) as f_count:
|
|
137
|
+
total_lines = sum(1 for _ in f_count)
|
|
138
|
+
|
|
139
|
+
if start_idx >= total_lines:
|
|
140
|
+
log_warning(
|
|
141
|
+
f"start_line ({start_line}) exceeds file length ({total_lines})"
|
|
142
|
+
)
|
|
143
|
+
return ""
|
|
144
|
+
else:
|
|
145
|
+
# File might be empty or other issue
|
|
146
|
+
return ""
|
|
134
147
|
|
|
135
|
-
# Handle column range
|
|
148
|
+
# Handle column range if specified
|
|
136
149
|
if start_column is not None or end_column is not None:
|
|
137
150
|
processed_lines = []
|
|
138
151
|
for i, line in enumerate(selected_lines):
|
|
@@ -167,7 +180,7 @@ def read_file_partial(
|
|
|
167
180
|
# Preserve original newline (except last line)
|
|
168
181
|
if i < len(selected_lines) - 1:
|
|
169
182
|
# Detect original newline char of the line
|
|
170
|
-
original_line =
|
|
183
|
+
original_line = selected_lines[i]
|
|
171
184
|
if original_line.endswith("\r\n"):
|
|
172
185
|
line_content += "\r\n"
|
|
173
186
|
elif original_line.endswith("\n"):
|
|
@@ -182,9 +195,12 @@ def read_file_partial(
|
|
|
182
195
|
# No column range: join lines directly
|
|
183
196
|
result = "".join(selected_lines)
|
|
184
197
|
|
|
198
|
+
# Calculate end line for logging
|
|
199
|
+
actual_end_line = end_line or (start_line + len(selected_lines) - 1)
|
|
200
|
+
|
|
185
201
|
log_info(
|
|
186
202
|
f"Successfully read partial file {file_path}: "
|
|
187
|
-
f"lines {start_line}-{
|
|
203
|
+
f"lines {start_line}-{actual_end_line}"
|
|
188
204
|
f"{f', columns {start_column}-{end_column}' if start_column is not None or end_column is not None else ''}"
|
|
189
205
|
)
|
|
190
206
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tree-sitter-analyzer
|
|
3
|
-
Version: 1.6.1.
|
|
3
|
+
Version: 1.6.1.4
|
|
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
|
|
@@ -165,11 +165,11 @@ Description-Content-Type: text/markdown
|
|
|
165
165
|
|
|
166
166
|
[](https://python.org)
|
|
167
167
|
[](LICENSE)
|
|
168
|
-
[](#quality-assurance)
|
|
169
169
|
[](#quality-assurance)
|
|
170
170
|
[](#quality-assurance)
|
|
171
171
|
[](https://pypi.org/project/tree-sitter-analyzer/)
|
|
172
|
-
[](https://github.com/aimasteracc/tree-sitter-analyzer/releases)
|
|
173
173
|
[](https://github.com/aimasteracc/tree-sitter-analyzer)
|
|
174
174
|
|
|
175
175
|
## 🚀 Enterprise-Grade Code Analysis Tool for the AI Era
|
|
@@ -224,7 +224,7 @@ Tree-sitter Analyzer is an enterprise-grade code analysis tool designed for the
|
|
|
224
224
|
- **More Languages** - Basic support for C/C++, Rust, Go
|
|
225
225
|
|
|
226
226
|
### 🏆 Production Ready
|
|
227
|
-
- **
|
|
227
|
+
- **1980 Tests** - Comprehensive test coverage, enterprise-grade quality assurance
|
|
228
228
|
- **71.48% Coverage** - Comprehensive test suite
|
|
229
229
|
- **Cross-Platform Support** - Full compatibility with Windows, macOS, Linux
|
|
230
230
|
- **Continuous Maintenance** - Active development and community support
|
|
@@ -731,7 +731,7 @@ Powerful file discovery and content search based on fd and ripgrep:
|
|
|
731
731
|
## 🏆 Quality Assurance
|
|
732
732
|
|
|
733
733
|
### 📊 Quality Metrics
|
|
734
|
-
- **
|
|
734
|
+
- **1980 Tests** - Comprehensive test coverage ✅
|
|
735
735
|
- **71.48% Code Coverage** - Comprehensive test suite
|
|
736
736
|
- **Zero Test Failures** - Production ready
|
|
737
737
|
- **Cross-Platform Support** - Windows, macOS, Linux
|
|
@@ -784,7 +784,7 @@ uv run pytest tests/test_mcp_server_initialization.py -v
|
|
|
784
784
|
**Verification Environment:**
|
|
785
785
|
- Operating Systems: Windows 10, macOS, Linux
|
|
786
786
|
- Python Version: 3.10+
|
|
787
|
-
- Project Version: tree-sitter-analyzer v1.6.1.
|
|
787
|
+
- Project Version: tree-sitter-analyzer v1.6.1.4
|
|
788
788
|
- Test Files: BigService.java (1419 lines), sample.py (256 lines), MultiClass.java (54 lines)
|
|
789
789
|
|
|
790
790
|
---
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
tree_sitter_analyzer/__init__.py,sha256=
|
|
1
|
+
tree_sitter_analyzer/__init__.py,sha256=uQLp3KXeuJDq1B5eHowray1HngjGdDoPOJu3Qf3gmiM,3069
|
|
2
2
|
tree_sitter_analyzer/__main__.py,sha256=Zl79tpe4UaMu-7yeztc06tgP0CVMRnvGgas4ZQP5SCs,228
|
|
3
3
|
tree_sitter_analyzer/api.py,sha256=jzwID6fJNdhQkJP3D0lzBVPhOnGIN4tyyMtmRYdK9zI,22753
|
|
4
4
|
tree_sitter_analyzer/cli_main.py,sha256=BuaM-L-Jx3G49qvAUOQVsw0wEM-X0UzPaRszRZBist4,10374
|
|
5
5
|
tree_sitter_analyzer/constants.py,sha256=7w3sLFt_6vPaKsxzrc21K1rOKpLGMyyA1203nu3pDOQ,1889
|
|
6
|
-
tree_sitter_analyzer/encoding_utils.py,sha256=
|
|
6
|
+
tree_sitter_analyzer/encoding_utils.py,sha256=hPPoRzMHHYZ2hLREjp3OHWkmmVmjC6H0TX3SxyBXcGg,16704
|
|
7
7
|
tree_sitter_analyzer/exceptions.py,sha256=AZryCQyKXekAg8lQZd3zqULnjhCKovBNNpnUlNGDhcI,11615
|
|
8
|
-
tree_sitter_analyzer/file_handler.py,sha256=
|
|
8
|
+
tree_sitter_analyzer/file_handler.py,sha256=f89N0CcnxfZxphu4QDpormc5AXoUko132EYK-kFoTx0,7753
|
|
9
9
|
tree_sitter_analyzer/language_detector.py,sha256=pn3nQClo8b_Ar8dS5X3hq9_t5IIlIcizIC0twMaowU4,11693
|
|
10
10
|
tree_sitter_analyzer/language_loader.py,sha256=gBUXGPTv91bRNs_urH23wzNKgh7ki6KkvpQ7iNPe3Rw,8922
|
|
11
11
|
tree_sitter_analyzer/logging_manager.py,sha256=pQYQAQi1RheWokGsokNuF9Ik466jQK5UQC8PSVOxpEU,12669
|
|
@@ -89,7 +89,7 @@ tree_sitter_analyzer/security/__init__.py,sha256=ZTqTt24hsljCpTXAZpJC57L7MU5lJLT
|
|
|
89
89
|
tree_sitter_analyzer/security/boundary_manager.py,sha256=3eeENRKWtz2pyZHzd8DiVaq8fdeC6s1eVOuBylSmQPg,9347
|
|
90
90
|
tree_sitter_analyzer/security/regex_checker.py,sha256=jWK6H8PTPgzbwRPfK_RZ8bBTS6rtEbgjY5vr3YWjQ_U,9616
|
|
91
91
|
tree_sitter_analyzer/security/validator.py,sha256=yR4qTWEcXpR--bSFwtWvSgY0AzqujOFAqlc1Z7dlTdk,9809
|
|
92
|
-
tree_sitter_analyzer-1.6.1.
|
|
93
|
-
tree_sitter_analyzer-1.6.1.
|
|
94
|
-
tree_sitter_analyzer-1.6.1.
|
|
95
|
-
tree_sitter_analyzer-1.6.1.
|
|
92
|
+
tree_sitter_analyzer-1.6.1.4.dist-info/METADATA,sha256=pjEnX5EfNgtmFlaQeQLjR_KUYp1olwOZHHAK32S49MQ,32236
|
|
93
|
+
tree_sitter_analyzer-1.6.1.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
94
|
+
tree_sitter_analyzer-1.6.1.4.dist-info/entry_points.txt,sha256=dEQkGMGmGGBzssEKlXW9F0-VlO3XJW2fJUv9i7898Ho,701
|
|
95
|
+
tree_sitter_analyzer-1.6.1.4.dist-info/RECORD,,
|
|
File without changes
|
{tree_sitter_analyzer-1.6.1.3.dist-info → tree_sitter_analyzer-1.6.1.4.dist-info}/entry_points.txt
RENAMED
|
File without changes
|