Skip to content

Fix IndexError for a from-import at end of file without trailing newline - #928

Open
mcepl wants to merge 1 commit into
masterfrom
mcepl/fix-119-from-import-at-eof
Open

mcepl wants to merge 1 commit into
masterfrom
mcepl/fix-119-from-import-at-eof

Conversation

@mcepl

@mcepl mcepl commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Description

Worder.is_from_aliased() raised IndexError when a module ends with a from-import and has no trailing newline, for example a module containing only from os import system. It looks for an as keyword after the imported name, and the min(..., len(self.code)) clamp still points one past the last character, so _find_word_start() reads self.code[len(self.code)]. Rename and find_occurrences() crash whenever they scan such a module, which is the traceback in #119.

is_import_statement_aliased_module() already has an _has_enough_len_for_as() guard for the same situation (added in bd08f09), but is_from_aliased() never got one. This adds the same guard.

Fixes #119

Checklist (delete if not relevant):

  • I have added tests that prove my fix is effective or that my feature works
  • I have updated CHANGELOG.md

Tests added:

  • WordRangeFinderTest.test_is_from_aliased_at_end_of_file_without_newline fails without the fix.
  • WordRangeFinderTest.test_is_import_statement_aliased_module_at_end_of_file_without_newline covers the existing guard, so the two methods stay consistent.
  • RenameRefactoringTest.test_renaming_from_import_at_end_of_file_without_newline renames a function across three modules where the middle one ends without a newline. It fails without the fix.

The full test suite passes locally on Python 3.13: 2158 passed, 7 skipped, 5 xfailed.

When a module ends with a from-import and has no trailing
newline, such as `from os import system`,
Worder.is_from_aliased() looks for an `as` keyword one character
past the end of the source. The `min(..., len(self.code))` clamp
still points one past the last character, so _find_word_start()
raises IndexError. Rename and find_occurrences() crash whenever
they scan such a module.

is_import_statement_aliased_module() got an
_has_enough_len_for_as() guard for the same situation in 2021,
but is_from_aliased() never did. Add the same guard there, with
tests for both Worder methods and for a rename across modules
where the middle module ends without a newline.

Fixes: #119
@codecov

codecov Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.34%. Comparing base (46ebf37) to head (6eee7ef).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #928   +/-   ##
=======================================
  Coverage   95.34%   95.34%           
=======================================
  Files         134      134           
  Lines       26768    26789   +21     
=======================================
+ Hits        25522    25543   +21     
  Misses       1246     1246           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mcepl
mcepl requested review from lieryan and a balanced review from Copilot and removed request for Copilot November 2, 2026 23:03

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IndexError when searching for fields in files with no newline at the of the file

1 participant