Skip to content

Commit

Permalink
Handle the edge case where an f-string looks like f"#{some_var}"
Browse files Browse the repository at this point in the history
  • Loading branch information
rlbr committed Dec 3, 2024
1 parent 94a77b6 commit a67995c
Showing 1 changed file with 39 additions and 13 deletions.
52 changes: 39 additions & 13 deletions rope/refactor/similarfinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,26 @@ def get_region(self):


class CodeTemplate:
_dollar_name_pattern = r"(?P<name>\$\{[^\s\$\}]*\})"

def __init__(self, template):
self.template = template
self._find_names()

@classmethod
def _get_pattern(cls):
if cls._match_pattern is None:
pattern = "|".join(
(
codeanalyze.get_comment_pattern(),
codeanalyze.get_string_pattern(),
f"(?P<fstring>{codeanalyze.get_formatted_string_pattern()})",
cls._dollar_name_pattern,
)
)
cls._match_pattern = re.compile(pattern)
return cls._match_pattern

def _find_names(self):
self.names = {}
for match in CodeTemplate._get_pattern().finditer(self.template):
Expand All @@ -283,6 +299,29 @@ def _find_names(self):
self.names[name] = []
self.names[name].append((start, end))

elif "fstring" in match.groupdict() and match.group("fstring") is not None:
self._fstring_case(match)

def _fstring_case(self, fstring_match: re.Match):
"""Needed because CodeTemplate._match_pattern short circuits
as soon as it sees a '#', even if that '#' is inside a f-string
that has a ${variable}."""

string_start, string_end = fstring_match.span("fstring")

for match in re.finditer(self._dollar_name_pattern, self.template):
if match.start("name") < string_start:
continue

if match.end("name") > string_end:
break

start, end = match.span("name")
name = self.template[start + 2 : end - 1]
if name not in self.names:
self.names[name] = []
self.names[name].append((start, end))

def get_names(self):
return self.names.keys()

Expand All @@ -298,19 +337,6 @@ def substitute(self, mapping):

_match_pattern = None

@classmethod
def _get_pattern(cls):
if cls._match_pattern is None:
pattern = (
codeanalyze.get_comment_pattern()
+ "|"
+ codeanalyze.get_string_pattern()
+ "|"
+ r"(?P<name>\$\{[^\s\$\}]*\})"
)
cls._match_pattern = re.compile(pattern)
return cls._match_pattern


class _RopeVariable:
"""Transform and identify rope inserted wildcards"""
Expand Down

0 comments on commit a67995c

Please sign in to comment.