Skip to content

patched_ast will set region[0] to None when unmatched parenthesis inside string #499

Description

@eivindjahren

Describe the bug
patched_ast will set region[0] to None when the code has an unmatched parenthesis inside an f-string.

To Reproduce
Steps to reproduce the behavior:

  1. Code before refactoring:
class A:
    def __init__(self):
        pass

    def _unmatched_inside_f_string(self, val):
        if val < 0:
            raise IndexError(
                (
                    f"{val})"
                )
            )

    def other_func(self):
        pass

  1. Rename class A to B

  2. Expected code after refactoring:

class B:
    def __init__(self):
        pass

    def _unmatched_inside_f_string(self, val):
        if val < 0:
            raise IndexError(
                (
                    f"{val})"
                )
            )

    def other_func(self):
        pass

  1. Describe the error or unexpected result that you are getting
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/eivind/Projects/ropemode/src/ropemode/decorators.py", line 54, in newfunc
    return func(*args, **kwds)
  File "/home/eivind/Projects/ropemode/src/ropemode/interface.py", line 52, in do_refactor
    refactoring(self, self.env).show(initial_asking=initial_asking)
  File "/home/eivind/Projects/ropemode/src/ropemode/refactor.py", line 33, in show
    self._create_refactoring()
  File "/home/eivind/Projects/ropemode/src/ropemode/refactor.py", line 119, in _create_refactoring
    self.renamer = rope.refactor.rename.Rename(
  File "/home/eivind/Projects/rope/rope/refactor/rename.py", line 32, in __init__
    self.old_instance, self.old_pyname = evaluate.eval_location2(
  File "/home/eivind/Projects/rope/rope/base/evaluate.py", line 21, in eval_location2
    return pyname_finder.get_primary_and_pyname_at(offset)
  File "/home/eivind/Projects/rope/rope/base/evaluate.py", line 87, in get_primary_and_pyname_at
    holding_scope = self.module_scope.get_inner_scope_for_offset(offset)
  File "/home/eivind/Projects/rope/rope/base/pyscopes.py", line 160, in get_inner_scope_for_offset
    return self._scope_finder.get_holding_scope_for_offset(self, offset)
  File "/home/eivind/Projects/rope/rope/base/pyscopes.py", line 317, in get_holding_scope_for_offset
    if inner_scope.in_region(offset):
  File "/home/eivind/Projects/rope/rope/base/pyscopes.py", line 118, in in_region
    return region[0] < offset < region[1]
TypeError: '<' not supported between instances of 'NoneType' and 'int'

Additional context
The problem seems to be that under certain conditions, a region tuple gets its first value assigned to 0 when there is an unmatched parenthesis inside a string. The following test can be used to reproduce:

    def test_works_with_unmatched_parens_inside_string(self):
        source = """
class A:
    def __init__(self):
        pass

    def _unmatched_inside_f_string(self, val):
        if val < 0:
            raise IndexError(
                (
                    f"{val})"
                )
            )

    def other_func(self):
        pass
        """
        ast_frag = patchedast.get_patched_ast(source, True)
        assert ast_frag.body[-1].region[0] != None

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugUnexpected or incorrect user-visible behaviorrename-refactor

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions