Repository navigation
MismatchedTokenError when parsing TypeVar with constraints in Python 3.12 #817
Copy link
Copy link
Closed
Labels
bugUnexpected or incorrect user-visible behaviorUnexpected or incorrect user-visible behavior
Description
Describe the bug
When using Python 3.12’s new syntax for TypeVar with constraints, rope fails to correctly parse the function definition and raises a MismatchedTokenError.
To Reproduce
Run the code below:
from rope.base.project import Project
from rope.refactor.inline import InlineVariable
project = Project('.', ropefolder=None)
file = project.root.create_file('file.py')
file.write('''\
s = None
print(s)
def _[T: (A, B)](x):
pass
''')
try:
changes = InlineVariable(project, file, 0).get_changes('s')
project.do(changes)
print(file.read())
finally:
file.remove()
project.close()And get the following error:
Traceback (most recent call last):
File "Lib\site-packages\rope\refactor\patchedast.py", line 837, in consume
new_offset = self.source.index(token, self.offset)
ValueError: substring not found
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "rope_bug.py", line 14, in <module>
changes = InlineVariable(project, file, 0).get_changes('s')
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\refactor\inline.py", line 241, in __init__
super().__init__(*args, **kwds)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\refactor\inline.py", line 82, in __init__
self.pyname = _get_pyname(project, resource, offset)
~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\refactor\inline.py", line 684, in _get_pyname
pyname = evaluate.eval_location(pymodule, offset)
File "Lib\site-packages\rope\base\evaluate.py", line 22, in eval_location
return eval_location2(pymodule, offset)[1]
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\base\evaluate.py", line 28, in eval_location2
return pyname_finder.get_primary_and_pyname_at(offset)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "Lib\site-packages\rope\base\evaluate.py", line 95, in get_primary_and_pyname_at
holding_scope = self.module_scope.get_inner_scope_for_offset(offset)
File "Lib\site-packages\rope\base\pyscopes.py", line 156, in get_inner_scope_for_offset
return self._scope_finder.get_holding_scope_for_offset(self, offset)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
File "Lib\site-packages\rope\base\pyscopes.py", line 310, in get_holding_scope_for_offset
if inner_scope.in_region(offset):
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "Lib\site-packages\rope\base\pyscopes.py", line 114, in in_region
region = self.get_region()
File "Lib\site-packages\rope\base\pyscopes.py", line 103, in get_region
self._calculate_scope_regions_for_module()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "Lib\site-packages\rope\base\pyscopes.py", line 109, in _calculate_scope_regions_for_module
self._get_global_scope()._calculate_scope_regions()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "Lib\site-packages\rope\base\utils\__init__.py", line 12, in _wrapper
setattr(self, name, func(self, *args, **kwds))
~~~~^^^^^^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\base\pyscopes.py", line 140, in _calculate_scope_regions
patchedast.patch_ast(self.pyobject.get_ast(), source)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\refactor\patchedast.py", line 37, in patch_ast
walker(node)
~~~~~~^^^^^^
File "Lib\site-packages\rope\refactor\patchedast.py", line 80, in __call__
return method(node)
File "Lib\site-packages\rope\refactor\patchedast.py", line 625, in _Module
self._handle(node, list(node.body), eat_spaces=True)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\refactor\patchedast.py", line 113, in _handle
self(child)
~~~~^^^^^^^
File "Lib\site-packages\rope\refactor\patchedast.py", line 80, in __call__
return method(node)
File "Lib\site-packages\rope\refactor\patchedast.py", line 500, in _FunctionDef
self._handle_function_def_node(node, is_async=False)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\refactor\patchedast.py", line 497, in _handle_function_def_node
self._handle(node, children)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "Lib\site-packages\rope\refactor\patchedast.py", line 142, in _handle
start = self._handle_parens(children, start, formats)
File "Lib\site-packages\rope\refactor\patchedast.py", line 164, in _handle_parens
new_end = self.source.consume(")")[1]
~~~~~~~~~~~~~~~~~~~^^^^^
File "Lib\site-packages\rope\refactor\patchedast.py", line 843, in consume
raise MismatchedTokenError(
f"Token <{token}> at {self._get_location()} cannot be matched"
)
rope.refactor.patchedast.MismatchedTokenError: Token <)> at (5, 8) cannot be matched
It appears that the new parentheses in the TypeVar constraint are not handled correctly.
Editor information:
- Project Python version: 3.13.3
- Rope Python version: 3.13.3
- Rope version: 1.13.0
- Text editor/IDE and version: None (rope used as a library)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugUnexpected or incorrect user-visible behaviorUnexpected or incorrect user-visible behavior
Activity
Fixed Issue python-rope#817
lieryan commentedon Aug 20, 2026
Closing. This has been fixed by #854.