code-towel 1.0.3__tar.gz → 1.0.4__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.
- {code_towel-1.0.3/src/code_towel.egg-info → code_towel-1.0.4}/PKG-INFO +1 -1
- {code_towel-1.0.3 → code_towel-1.0.4}/pyproject.toml +1 -1
- {code_towel-1.0.3 → code_towel-1.0.4/src/code_towel.egg-info}/PKG-INFO +1 -1
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/cli.py +3 -1
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/refactor_engine.py +12 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/LICENSE +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/README.md +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/setup.cfg +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/code_towel.egg-info/SOURCES.txt +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/code_towel.egg-info/dependency_links.txt +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/code_towel.egg-info/entry_points.txt +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/code_towel.egg-info/requires.txt +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/code_towel.egg-info/top_level.txt +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/__init__.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/__init__.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/assignment_analyzer.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/ast_normalizer.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/ast_pretty_printer.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/binding_detector.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/block_signature.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/builtins.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/exceptions.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/extractor.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/models.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/nominal_unifier.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/orphan_detector.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/pipeline.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/project_layout.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/scope_analyzer.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/unifier.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/visitor_utils.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/src/towel/unification/visitors.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_ancestor_insertion.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_assignment_analyzer_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_ast_normalizer_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_ast_pretty_printer.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_ast_pretty_printer_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_ast_pretty_printer_more.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_binding_detector.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_binding_detector_edge_cases.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_bindings.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_bindings_additional.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_breakers.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_builtins_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_comprehensive_coverage.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_crossfile_integration.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_crossfile_observational_equivalence.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_engine_adversarial.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_exceptions.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_additional_branches.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_augassign_and_fstrings.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_callee_and_multi_return.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_edge_cases.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_final_lines.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_generate_call_variants.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_more_paths.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_preamble_and_call_mapping.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_remaining_branches.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_return_statements.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_extractor_substituter_and_helpers.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_final_coverage_push.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_free_variable_correspondence.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_fstrings.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_helpers.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_method_level_and_attributes.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_nominal_unifier.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_observational_equivalence.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_orphan_detection.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_orphan_detector_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_overlap_filtering.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_pipeline_api.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_pipeline_phases.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_progress_modes.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_project_layout_and_imports.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_project_layout_behavior.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_promotion_and_mangling.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_refactor_engine_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_refactor_engine_edge_cases.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_refactor_engine_more.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_refactor_engine_targeted_branches.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_refactoring_engine.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_regression.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_regressions_broader.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_return_values.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_scope_analyzer.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_scope_analyzer_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_signature_prefilter.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_additional_branches.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_batch2.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_batch3.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_batch4.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_batch5.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_bound_variables.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_comprehensions.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_comprehensive.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_core.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_edge_cases.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_more_branches.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_unifier_state_reset.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_validation_partial_lifetime.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_variable_capture_bug.py +0 -0
- {code_towel-1.0.3 → code_towel-1.0.4}/tests/test_visitor_utils_comprehensive.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "code-towel"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "A Python tool that DRYs your code - finds and refactors repeated code using unification-based analysis"
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Eric Allen"}
|
|
@@ -700,7 +700,9 @@ def _run_interactive_llm_mode(
|
|
|
700
700
|
print(' {"__extracted_func_1": "calculate_total"}')
|
|
701
701
|
print(' {"src/utils.py:__extracted_func_2": "validate_input"}')
|
|
702
702
|
print()
|
|
703
|
-
print(
|
|
703
|
+
print(
|
|
704
|
+
"Paste the JSON response below, then press ENTER followed by Ctrl+D (or Ctrl+Z on Windows):"
|
|
705
|
+
)
|
|
704
706
|
print()
|
|
705
707
|
|
|
706
708
|
# Read LLM response from stdin
|
|
@@ -538,6 +538,7 @@ class UnificationRefactorEngine:
|
|
|
538
538
|
docstring_char: Optional[str] = None
|
|
539
539
|
last_import_line = 0
|
|
540
540
|
after_docstring = 0
|
|
541
|
+
in_multiline_import = False
|
|
541
542
|
|
|
542
543
|
for i, line in enumerate(lines):
|
|
543
544
|
stripped = line.strip()
|
|
@@ -557,8 +558,19 @@ class UnificationRefactorEngine:
|
|
|
557
558
|
after_docstring = i + 1
|
|
558
559
|
continue
|
|
559
560
|
|
|
561
|
+
# Check for start of multi-line import (has opening paren but no closing paren)
|
|
560
562
|
if stripped.startswith("import ") or stripped.startswith("from "):
|
|
561
563
|
last_import_line = i + 1
|
|
564
|
+
# Check if this is a multi-line import
|
|
565
|
+
if "(" in line and ")" not in line:
|
|
566
|
+
in_multiline_import = True
|
|
567
|
+
continue
|
|
568
|
+
|
|
569
|
+
# Inside a multi-line import - continue until we see closing paren
|
|
570
|
+
if in_multiline_import:
|
|
571
|
+
last_import_line = i + 1
|
|
572
|
+
if ")" in line:
|
|
573
|
+
in_multiline_import = False
|
|
562
574
|
continue
|
|
563
575
|
|
|
564
576
|
if last_import_line > 0 and stripped and not stripped.startswith("#"):
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|