redup 0.3.23__tar.gz → 0.3.24__tar.gz
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.
- {redup-0.3.23 → redup-0.3.24}/PKG-INFO +2 -2
- {redup-0.3.23 → redup-0.3.24}/README.md +1 -1
- {redup-0.3.23 → redup-0.3.24}/pyproject.toml +1 -1
- {redup-0.3.23 → redup-0.3.24}/src/redup/__init__.py +1 -1
- {redup-0.3.23 → redup-0.3.24}/src/redup/cli_app/config_builder.py +2 -2
- {redup-0.3.23 → redup-0.3.24}/src/redup/cli_app/scan_commands.py +4 -4
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/pipeline.py +28 -32
- redup-0.3.24/src/redup/core/scanner.py +647 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup.egg-info/PKG-INFO +2 -2
- {redup-0.3.23 → redup-0.3.24}/src/redup.egg-info/SOURCES.txt +0 -3
- redup-0.3.23/src/redup/core/memory_scanner.py +0 -285
- redup-0.3.23/src/redup/core/parallel_scanner.py +0 -234
- redup-0.3.23/src/redup/core/scanner.py +0 -373
- redup-0.3.23/src/redup/core/ultra_fast_scanner.py +0 -358
- {redup-0.3.23 → redup-0.3.24}/LICENSE +0 -0
- {redup-0.3.23 → redup-0.3.24}/setup.cfg +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/__main__.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/cli_app/__init__.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/cli_app/fuzzy_similarity.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/cli_app/main.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/cli_app/output_writer.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/cli_app/scan_helpers.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/__init__.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/cache.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/config.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/differ.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/fuzzy_similarity.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/hash_cache.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/hasher.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/lazy_grouper.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/lsh_matcher.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/matcher.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/models.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/planner.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/ts_extractor.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/universal_fuzzy.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/utils/__init__.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/utils/duplicate_finders.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/utils/function_extractor.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/utils/hash_utils.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/core/utils/language_dispatcher.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/reporters/__init__.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/reporters/code2llm_reporter.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/reporters/enhanced_reporter.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/reporters/json_reporter.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/reporters/markdown_reporter.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/reporters/toon_reporter.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup/reporters/yaml_reporter.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup.egg-info/dependency_links.txt +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup.egg-info/entry_points.txt +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup.egg-info/requires.txt +0 -0
- {redup-0.3.23 → redup-0.3.24}/src/redup.egg-info/top_level.txt +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_e2e.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_hasher.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_matcher.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_models.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_pipeline.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_planner.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_reporters.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_scanner.py +0 -0
- {redup-0.3.23 → redup-0.3.24}/tests/test_ts_extractor.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: redup
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.24
|
|
4
4
|
Summary: Code duplication analyzer and refactoring planner for LLMs
|
|
5
5
|
Author-email: Tom Sapletta <tom@sapletta.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -84,7 +84,7 @@ Dynamic: license-file
|
|
|
84
84
|
[](https://pypi.org/project/redup/)
|
|
85
85
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
86
86
|
[](https://python.org)
|
|
87
|
-
[](https://pypi.org/project/redup/)
|
|
88
88
|
|
|
89
89
|
reDUP scans codebases for duplicated functions, blocks, and structural patterns — then builds a prioritized refactoring map that LLMs can consume to eliminate redundancy systematically.
|
|
90
90
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://pypi.org/project/redup/)
|
|
6
6
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
7
7
|
[](https://python.org)
|
|
8
|
-
[](https://pypi.org/project/redup/)
|
|
9
9
|
|
|
10
10
|
reDUP scans codebases for duplicated functions, blocks, and structural patterns — then builds a prioritized refactoring map that LLMs can consume to eliminate redundancy systematically.
|
|
11
11
|
|
|
@@ -42,13 +42,13 @@ def build_config_with_file_support(
|
|
|
42
42
|
if extensions is not None:
|
|
43
43
|
scan_config.extensions = [e.strip() for e in extensions.split(',')]
|
|
44
44
|
if min_lines is not None:
|
|
45
|
-
scan_config.
|
|
45
|
+
scan_config.min_block_lines = min_lines
|
|
46
46
|
if min_similarity is not None:
|
|
47
47
|
scan_config.min_similarity = min_similarity
|
|
48
48
|
if include_tests is not None:
|
|
49
49
|
scan_config.include_tests = include_tests
|
|
50
50
|
if functions_only:
|
|
51
|
-
scan_config.
|
|
51
|
+
scan_config.functions_only = functions_only
|
|
52
52
|
|
|
53
53
|
# Add fuzzy support
|
|
54
54
|
scan_config.fuzzy_enabled = fuzzy
|
|
@@ -33,16 +33,16 @@ def scan_command(
|
|
|
33
33
|
"""Scan a project for code duplicates."""
|
|
34
34
|
|
|
35
35
|
# Build configuration
|
|
36
|
-
if any([extensions, min_lines, min_similarity, include_tests, functions_only, parallel, max_workers, incremental, memory_cache, max_cache_mb]):
|
|
36
|
+
if any([extensions, min_lines, min_similarity, include_tests, functions_only, parallel, max_workers, incremental, memory_cache, max_cache_mb, fuzzy]):
|
|
37
37
|
config = build_config_with_file_support(
|
|
38
38
|
path, extensions, min_lines, min_similarity, include_tests,
|
|
39
|
-
parallel, max_workers, incremental, memory_cache, max_cache_mb, functions_only
|
|
39
|
+
parallel, max_workers, incremental, memory_cache, max_cache_mb, functions_only, fuzzy, fuzzy_threshold
|
|
40
40
|
)
|
|
41
41
|
else:
|
|
42
42
|
config = build_config(path, extensions, min_lines, min_similarity, include_tests)
|
|
43
43
|
|
|
44
44
|
# Print scan header
|
|
45
|
-
print_scan_header(path, config.extensions, config.
|
|
45
|
+
print_scan_header(path, config.extensions, config.min_block_lines, config.min_similarity)
|
|
46
46
|
|
|
47
47
|
# Run analysis
|
|
48
48
|
if parallel and max_workers and max_workers > 1:
|
|
@@ -92,7 +92,7 @@ def check_command(
|
|
|
92
92
|
path, extensions, min_lines, min_similarity, include_tests
|
|
93
93
|
)
|
|
94
94
|
|
|
95
|
-
print_scan_header(path, config.extensions, config.
|
|
95
|
+
print_scan_header(path, config.extensions, config.min_block_lines, config.min_similarity)
|
|
96
96
|
|
|
97
97
|
dup_map = analyze(config)
|
|
98
98
|
print_scan_summary(dup_map)
|
|
@@ -16,7 +16,7 @@ from redup.core.hasher import (
|
|
|
16
16
|
)
|
|
17
17
|
from redup.core.lsh_matcher import find_near_duplicates
|
|
18
18
|
from redup.core.matcher import MatchResult, refine_structural_matches
|
|
19
|
-
from redup.core.
|
|
19
|
+
from redup.core.scanner import scan_project, ScanStrategy
|
|
20
20
|
from redup.core.models import (
|
|
21
21
|
DuplicateFragment,
|
|
22
22
|
DuplicateGroup,
|
|
@@ -26,10 +26,9 @@ from redup.core.models import (
|
|
|
26
26
|
ScanStats,
|
|
27
27
|
)
|
|
28
28
|
from redup.core.planner import generate_suggestions
|
|
29
|
-
from redup.core.scanner import CodeBlock, ScannedFile
|
|
29
|
+
from redup.core.scanner import CodeBlock, ScannedFile
|
|
30
30
|
from redup.core.cache import HashCache, build_hash_index_with_cache
|
|
31
31
|
from redup.core.lazy_grouper import find_all_duplicates_lazy, DuplicateGroupCollector
|
|
32
|
-
from redup.core.memory_scanner import scan_project_memory_optimized, scan_project_parallel_memory_optimized
|
|
33
32
|
|
|
34
33
|
|
|
35
34
|
def _blocks_to_group(
|
|
@@ -184,26 +183,29 @@ def analyze_optimized(
|
|
|
184
183
|
# Phase 1: Optimized scanning with memory cache
|
|
185
184
|
if config.parallel_workers and config.parallel_workers > 1:
|
|
186
185
|
# Explicit worker count specified
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
186
|
+
strategy = ScanStrategy(
|
|
187
|
+
parallel=True,
|
|
188
|
+
max_workers=config.parallel_workers,
|
|
189
|
+
memory_cache=use_memory_cache,
|
|
190
|
+
max_cache_mb=max_cache_mb if use_memory_cache else 256
|
|
191
|
+
)
|
|
192
|
+
scanned_files, stats = scan_project(config, strategy, function_level_only=True)
|
|
193
193
|
elif config.parallel_workers is None and (getattr(config, '_parallel_enabled', False) or config.parallel_workers is None):
|
|
194
194
|
# Auto-detect CPU count when parallel_workers is None (default behavior)
|
|
195
195
|
import multiprocessing as mp
|
|
196
196
|
auto_workers = mp.cpu_count()
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
strategy = ScanStrategy(
|
|
198
|
+
parallel=True,
|
|
199
|
+
max_workers=auto_workers,
|
|
200
|
+
memory_cache=use_memory_cache,
|
|
201
|
+
max_cache_mb=max_cache_mb if use_memory_cache else 256
|
|
202
|
+
)
|
|
203
|
+
scanned_files, stats = scan_project(config, strategy, function_level_only=True)
|
|
203
204
|
elif use_memory_cache:
|
|
204
|
-
|
|
205
|
+
strategy = ScanStrategy(memory_cache=True, max_cache_mb=max_cache_mb)
|
|
206
|
+
scanned_files, stats = scan_project(config, strategy, function_level_only=True)
|
|
205
207
|
else:
|
|
206
|
-
scanned_files, stats =
|
|
208
|
+
scanned_files, stats = scan_project(config, function_level_only=True)
|
|
207
209
|
|
|
208
210
|
# Phase 2: Process blocks
|
|
209
211
|
all_blocks = _process_blocks(scanned_files, function_level_only)
|
|
@@ -260,15 +262,8 @@ def _scan_phase(config: ScanConfig, function_level_only: bool = False) -> tuple[
|
|
|
260
262
|
|
|
261
263
|
def _scan_phase_parallel(config: ScanConfig, max_workers: int | None = None) -> tuple[list[ScannedFile], ScanStats]:
|
|
262
264
|
"""Phase 1: Scan project files in parallel."""
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
extensions=config.extensions,
|
|
266
|
-
exclude_patterns=config.exclude_patterns,
|
|
267
|
-
include_tests=config.include_tests,
|
|
268
|
-
function_level_only=True, # Always function-level for parallel
|
|
269
|
-
max_file_size=config.max_file_size_kb,
|
|
270
|
-
max_workers=max_workers,
|
|
271
|
-
)
|
|
265
|
+
strategy = ScanStrategy(parallel=True, max_workers=max_workers or 4)
|
|
266
|
+
return scan_project(config, strategy, function_level_only=True)
|
|
272
267
|
|
|
273
268
|
|
|
274
269
|
def _process_blocks(
|
|
@@ -552,12 +547,13 @@ def analyze_optimized(
|
|
|
552
547
|
|
|
553
548
|
try:
|
|
554
549
|
# Phase 1: Optimized Scan (parallel + memory cache)
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
550
|
+
strategy = ScanStrategy(
|
|
551
|
+
parallel=True,
|
|
552
|
+
max_workers=None, # Auto-detect
|
|
553
|
+
memory_cache=use_memory_cache,
|
|
554
|
+
max_cache_mb=max_cache_mb
|
|
555
|
+
)
|
|
556
|
+
scanned_files, stats = scan_project(config, strategy, function_level_only=True)
|
|
561
557
|
|
|
562
558
|
# Phase 2: Process blocks
|
|
563
559
|
all_blocks = _process_blocks(scanned_files, function_level_only)
|