redup 0.4.32__tar.gz → 0.4.35__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.
Files changed (117) hide show
  1. {redup-0.4.32/src/redup.egg-info → redup-0.4.35}/PKG-INFO +7 -5
  2. {redup-0.4.32 → redup-0.4.35}/README.md +6 -4
  3. {redup-0.4.32 → redup-0.4.35}/pyproject.toml +1 -1
  4. {redup-0.4.32 → redup-0.4.35}/src/redup/__init__.py +1 -1
  5. {redup-0.4.32 → redup-0.4.35}/src/redup/core/models.py +7 -9
  6. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner_filters.py +28 -3
  7. {redup-0.4.32 → redup-0.4.35/src/redup.egg-info}/PKG-INFO +7 -5
  8. {redup-0.4.32 → redup-0.4.35}/LICENSE +0 -0
  9. {redup-0.4.32 → redup-0.4.35}/setup.cfg +0 -0
  10. {redup-0.4.32 → redup-0.4.35}/src/redup/__main__.py +0 -0
  11. {redup-0.4.32 → redup-0.4.35}/src/redup/analysis_logic.py +0 -0
  12. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/__init__.py +0 -0
  13. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/compare_command.py +0 -0
  14. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/config_builder.py +0 -0
  15. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/fuzzy_similarity.py +0 -0
  16. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/intract_commands.py +0 -0
  17. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/main.py +0 -0
  18. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/output_writer.py +0 -0
  19. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/quality_commands.py +0 -0
  20. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/scan_commands.py +0 -0
  21. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/scan_helpers.py +0 -0
  22. {redup-0.4.32 → redup-0.4.35}/src/redup/cli_app/tasks_command.py +0 -0
  23. {redup-0.4.32 → redup-0.4.35}/src/redup/config.py +0 -0
  24. {redup-0.4.32 → redup-0.4.35}/src/redup/config_handler.py +0 -0
  25. {redup-0.4.32 → redup-0.4.35}/src/redup/core/__init__.py +0 -0
  26. {redup-0.4.32 → redup-0.4.35}/src/redup/core/cache.py +0 -0
  27. {redup-0.4.32 → redup-0.4.35}/src/redup/core/community.py +0 -0
  28. {redup-0.4.32 → redup-0.4.35}/src/redup/core/comparator.py +0 -0
  29. {redup-0.4.32 → redup-0.4.35}/src/redup/core/config.py +0 -0
  30. {redup-0.4.32 → redup-0.4.35}/src/redup/core/decision.py +0 -0
  31. {redup-0.4.32 → redup-0.4.35}/src/redup/core/differ.py +0 -0
  32. {redup-0.4.32 → redup-0.4.35}/src/redup/core/fuzzy_similarity.py +0 -0
  33. {redup-0.4.32 → redup-0.4.35}/src/redup/core/grouper.py +0 -0
  34. {redup-0.4.32 → redup-0.4.35}/src/redup/core/hash_cache.py +0 -0
  35. {redup-0.4.32 → redup-0.4.35}/src/redup/core/hasher.py +0 -0
  36. {redup-0.4.32 → redup-0.4.35}/src/redup/core/lazy_grouper.py +0 -0
  37. {redup-0.4.32 → redup-0.4.35}/src/redup/core/lsh_matcher.py +0 -0
  38. {redup-0.4.32 → redup-0.4.35}/src/redup/core/matcher.py +0 -0
  39. {redup-0.4.32 → redup-0.4.35}/src/redup/core/pipeline/__init__.py +0 -0
  40. {redup-0.4.32 → redup-0.4.35}/src/redup/core/pipeline/duplicate_finder.py +0 -0
  41. {redup-0.4.32 → redup-0.4.35}/src/redup/core/pipeline/groups.py +0 -0
  42. {redup-0.4.32 → redup-0.4.35}/src/redup/core/pipeline/phases.py +0 -0
  43. {redup-0.4.32 → redup-0.4.35}/src/redup/core/pipeline_utils.py +0 -0
  44. {redup-0.4.32 → redup-0.4.35}/src/redup/core/planner.py +0 -0
  45. {redup-0.4.32 → redup-0.4.35}/src/redup/core/python_parser.py +0 -0
  46. {redup-0.4.32 → redup-0.4.35}/src/redup/core/refactor_advisor.py +0 -0
  47. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner/__init__.py +0 -0
  48. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner.py +0 -0
  49. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner_cache.py +0 -0
  50. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner_loader.py +0 -0
  51. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner_models.py +0 -0
  52. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner_types.py +0 -0
  53. {redup-0.4.32 → redup-0.4.35}/src/redup/core/scanner_utils.py +0 -0
  54. {redup-0.4.32 → redup-0.4.35}/src/redup/core/semantic.py +0 -0
  55. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/__init__.py +0 -0
  56. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/config.py +0 -0
  57. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/dispatcher.py +0 -0
  58. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/__init__.py +0 -0
  59. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/base.py +0 -0
  60. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/c_family.py +0 -0
  61. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/dotnet.py +0 -0
  62. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/markup.py +0 -0
  63. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/php.py +0 -0
  64. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/query.py +0 -0
  65. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/ruby.py +0 -0
  66. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/shell.py +0 -0
  67. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/stylesheet.py +0 -0
  68. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/extractors/web.py +0 -0
  69. {redup-0.4.32 → redup-0.4.35}/src/redup/core/ts_extractor/main.py +0 -0
  70. {redup-0.4.32 → redup-0.4.35}/src/redup/core/universal_fuzzy.py +0 -0
  71. {redup-0.4.32 → redup-0.4.35}/src/redup/core/utils/__init__.py +0 -0
  72. {redup-0.4.32 → redup-0.4.35}/src/redup/core/utils/diff_helpers.py +0 -0
  73. {redup-0.4.32 → redup-0.4.35}/src/redup/core/utils/duplicate_finders.py +0 -0
  74. {redup-0.4.32 → redup-0.4.35}/src/redup/core/utils/function_extractor.py +0 -0
  75. {redup-0.4.32 → redup-0.4.35}/src/redup/core/utils/hash_utils.py +0 -0
  76. {redup-0.4.32 → redup-0.4.35}/src/redup/core/utils/language_dispatcher.py +0 -0
  77. {redup-0.4.32 → redup-0.4.35}/src/redup/integrations/__init__.py +0 -0
  78. {redup-0.4.32 → redup-0.4.35}/src/redup/integrations/intract/__init__.py +0 -0
  79. {redup-0.4.32 → redup-0.4.35}/src/redup/integrations/intract/adapter.py +0 -0
  80. {redup-0.4.32 → redup-0.4.35}/src/redup/integrations/intract/policy.py +0 -0
  81. {redup-0.4.32 → redup-0.4.35}/src/redup/integrations/planfile_integration.py +0 -0
  82. {redup-0.4.32 → redup-0.4.35}/src/redup/mcp/__init__.py +0 -0
  83. {redup-0.4.32 → redup-0.4.35}/src/redup/mcp/handlers.py +0 -0
  84. {redup-0.4.32 → redup-0.4.35}/src/redup/mcp/schemas.py +0 -0
  85. {redup-0.4.32 → redup-0.4.35}/src/redup/mcp/server.py +0 -0
  86. {redup-0.4.32 → redup-0.4.35}/src/redup/mcp/utils.py +0 -0
  87. {redup-0.4.32 → redup-0.4.35}/src/redup/mcp_server.py +0 -0
  88. {redup-0.4.32 → redup-0.4.35}/src/redup/mcp_server_clean.py +0 -0
  89. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters/__init__.py +0 -0
  90. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters/code2llm_reporter.py +0 -0
  91. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters/enhanced_reporter.py +0 -0
  92. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters/json_reporter.py +0 -0
  93. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters/markdown_reporter.py +0 -0
  94. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters/toon_reporter.py +0 -0
  95. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters/yaml_reporter.py +0 -0
  96. {redup-0.4.32 → redup-0.4.35}/src/redup/reporters.py +0 -0
  97. {redup-0.4.32 → redup-0.4.35}/src/redup/utils.py +0 -0
  98. {redup-0.4.32 → redup-0.4.35}/src/redup.egg-info/SOURCES.txt +0 -0
  99. {redup-0.4.32 → redup-0.4.35}/src/redup.egg-info/dependency_links.txt +0 -0
  100. {redup-0.4.32 → redup-0.4.35}/src/redup.egg-info/entry_points.txt +0 -0
  101. {redup-0.4.32 → redup-0.4.35}/src/redup.egg-info/requires.txt +0 -0
  102. {redup-0.4.32 → redup-0.4.35}/src/redup.egg-info/top_level.txt +0 -0
  103. {redup-0.4.32 → redup-0.4.35}/tests/test_cli_import_compat.py +0 -0
  104. {redup-0.4.32 → redup-0.4.35}/tests/test_compare.py +0 -0
  105. {redup-0.4.32 → redup-0.4.35}/tests/test_e2e.py +0 -0
  106. {redup-0.4.32 → redup-0.4.35}/tests/test_hasher.py +0 -0
  107. {redup-0.4.32 → redup-0.4.35}/tests/test_intent_integration.py +0 -0
  108. {redup-0.4.32 → redup-0.4.35}/tests/test_matcher.py +0 -0
  109. {redup-0.4.32 → redup-0.4.35}/tests/test_mcp_server.py +0 -0
  110. {redup-0.4.32 → redup-0.4.35}/tests/test_models.py +0 -0
  111. {redup-0.4.32 → redup-0.4.35}/tests/test_pipeline.py +0 -0
  112. {redup-0.4.32 → redup-0.4.35}/tests/test_planfile_integration.py +0 -0
  113. {redup-0.4.32 → redup-0.4.35}/tests/test_planner.py +0 -0
  114. {redup-0.4.32 → redup-0.4.35}/tests/test_quality_commands.py +0 -0
  115. {redup-0.4.32 → redup-0.4.35}/tests/test_reporters.py +0 -0
  116. {redup-0.4.32 → redup-0.4.35}/tests/test_scanner.py +0 -0
  117. {redup-0.4.32 → redup-0.4.35}/tests/test_ts_extractor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redup
3
- Version: 0.4.32
3
+ Version: 0.4.35
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
@@ -94,16 +94,18 @@ Dynamic: license-file
94
94
  [![PyPI](https://img.shields.io/pypi/v/redup)](https://pypi.org/project/redup/)
95
95
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
96
96
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://python.org)
97
- [![Version](https://img.shields.io/badge/version-0.4.32-green.svg)](https://pypi.org/project/redup/)
97
+ [![Version](https://img.shields.io/badge/version-0.4.35-green.svg)](https://pypi.org/project/redup/)
98
98
 
99
99
 
100
100
  ## AI Cost Tracking
101
101
 
102
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.50-yellow) ![AI Model](https://img.shields.io/badge/AI%20Model-openrouter%2Fdeep%2Fdeep-v4-pro-lightgrey)
102
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.4.35-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
103
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$10.53-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-31.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fdeep%2Fdeep--v4--pro-lightgrey)
103
104
 
104
- This project uses AI-generated code. Total cost: **$7.5000** with **79** AI commits.
105
+ - 🤖 **LLM usage:** $10.5256 (81 commits)
106
+ - 👤 **Human dev:** ~$3164 (31.6h @ $100/h, 30min dedup)
105
107
 
106
- Generated on 2026-06-29 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/models/openrouter/deep/deep-v4-pro)
108
+ Generated on 2026-07-05 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
107
109
 
108
110
  ---
109
111
 
@@ -5,16 +5,18 @@
5
5
  [![PyPI](https://img.shields.io/pypi/v/redup)](https://pypi.org/project/redup/)
6
6
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
7
7
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://python.org)
8
- [![Version](https://img.shields.io/badge/version-0.4.32-green.svg)](https://pypi.org/project/redup/)
8
+ [![Version](https://img.shields.io/badge/version-0.4.35-green.svg)](https://pypi.org/project/redup/)
9
9
 
10
10
 
11
11
  ## AI Cost Tracking
12
12
 
13
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.50-yellow) ![AI Model](https://img.shields.io/badge/AI%20Model-openrouter%2Fdeep%2Fdeep-v4-pro-lightgrey)
13
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.4.35-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
14
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$10.53-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-31.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fdeep%2Fdeep--v4--pro-lightgrey)
14
15
 
15
- This project uses AI-generated code. Total cost: **$7.5000** with **79** AI commits.
16
+ - 🤖 **LLM usage:** $10.5256 (81 commits)
17
+ - 👤 **Human dev:** ~$3164 (31.6h @ $100/h, 30min dedup)
16
18
 
17
- Generated on 2026-06-29 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/models/openrouter/deep/deep-v4-pro)
19
+ Generated on 2026-07-05 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
18
20
 
19
21
  ---
20
22
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "redup"
7
- version = "0.4.32"
7
+ version = "0.4.35"
8
8
  description = "Code duplication analyzer and refactoring planner for LLMs"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "0.4.32"
5
+ __version__ = "0.4.35"
6
6
 
7
7
  # Click compatibility shim for older typer versions
8
8
  # This must run before any typer imports
@@ -68,21 +68,19 @@ class ScanConfig:
68
68
  "*.pyo",
69
69
  "*.pyd",
70
70
  "$py.class",
71
- "python*",
72
- "python3*",
73
- "Python*",
74
- "venv*",
75
- "env*",
76
- ".venv*",
77
- ".env*",
71
+ "venv",
72
+ ".venv",
73
+ "env",
74
+ ".env",
75
+ "virtualenv",
76
+ ".virtualenv",
77
+ "site-packages",
78
78
  "*.egg-info",
79
79
  "*.egg",
80
80
  "build",
81
81
  "dist",
82
82
  ".installer",
83
83
  ".eggs",
84
- "lib",
85
- "lib64",
86
84
  "parts",
87
85
  "sdist",
88
86
  "var",
@@ -72,19 +72,32 @@ def _collect_target_files(config: ScanConfig) -> list[Path]:
72
72
  def _collect_files(config: ScanConfig) -> list[Path]:
73
73
  """Collect all files to scan based on configuration.
74
74
 
75
- Uses os.walk with topdown pruning to skip hidden directories early,
76
- avoiding descent into .rebuild_ev/, .regres/, etc.
75
+ Uses os.walk with topdown pruning to skip hidden and excluded
76
+ directories early, avoiding descent into .rebuild_ev/, venv/,
77
+ node_modules/, site-packages/, etc. Without this, a populated
78
+ virtualenv (tens of thousands of files) gets fully walked and
79
+ stat'd before its files are filtered out, making every scan of a
80
+ repo root dramatically slower than scanning a subdirectory.
77
81
  """
78
82
  if config.target_files is not None:
79
83
  return _collect_target_files(config)
80
84
 
81
85
  files = []
86
+ seen_real_paths = set()
82
87
  ext_set = set(config.extensions)
83
88
  exclude_patterns = tuple(config.exclude_patterns)
84
89
  root_str = str(config.root)
85
90
 
86
91
  for dirpath, dirnames, filenames in os.walk(root_str, topdown=True):
87
- dirnames[:] = [d for d in dirnames if not d.startswith(".")]
92
+ kept = []
93
+ for d in dirnames:
94
+ if d.startswith("."):
95
+ continue
96
+ relative_dir = _project_relative_path(Path(os.path.join(dirpath, d)), config.root)
97
+ if _should_exclude(relative_dir, exclude_patterns):
98
+ continue
99
+ kept.append(d)
100
+ dirnames[:] = kept
88
101
 
89
102
  for filename in filenames:
90
103
  file_path = Path(os.path.join(dirpath, filename))
@@ -96,6 +109,18 @@ def _collect_files(config: ScanConfig) -> list[Path]:
96
109
  continue
97
110
  if not config.include_tests and _is_test_file(relative_path):
98
111
  continue
112
+ # Symlinks (common for sharing one canonical file across
113
+ # multiple deploy targets, e.g. per-board firmware entry
114
+ # points) resolve to the same real file. Without this,
115
+ # each symlink is read and hashed independently, reporting
116
+ # a single shared file as duplicated across every alias.
117
+ try:
118
+ real_path = file_path.resolve()
119
+ except OSError:
120
+ continue
121
+ if real_path in seen_real_paths:
122
+ continue
123
+ seen_real_paths.add(real_path)
99
124
  try:
100
125
  if file_path.stat().st_size > config.max_file_size_kb * 1024:
101
126
  continue
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redup
3
- Version: 0.4.32
3
+ Version: 0.4.35
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
@@ -94,16 +94,18 @@ Dynamic: license-file
94
94
  [![PyPI](https://img.shields.io/pypi/v/redup)](https://pypi.org/project/redup/)
95
95
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
96
96
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://python.org)
97
- [![Version](https://img.shields.io/badge/version-0.4.32-green.svg)](https://pypi.org/project/redup/)
97
+ [![Version](https://img.shields.io/badge/version-0.4.35-green.svg)](https://pypi.org/project/redup/)
98
98
 
99
99
 
100
100
  ## AI Cost Tracking
101
101
 
102
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.50-yellow) ![AI Model](https://img.shields.io/badge/AI%20Model-openrouter%2Fdeep%2Fdeep-v4-pro-lightgrey)
102
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.4.35-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
103
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$10.53-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-31.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fdeep%2Fdeep--v4--pro-lightgrey)
103
104
 
104
- This project uses AI-generated code. Total cost: **$7.5000** with **79** AI commits.
105
+ - 🤖 **LLM usage:** $10.5256 (81 commits)
106
+ - 👤 **Human dev:** ~$3164 (31.6h @ $100/h, 30min dedup)
105
107
 
106
- Generated on 2026-06-29 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/models/openrouter/deep/deep-v4-pro)
108
+ Generated on 2026-07-05 using [openrouter/deep/deep-v4-pro](https://openrouter.ai/deep/deep-v4-pro)
107
109
 
108
110
  ---
109
111
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes