--- /dev/null
+#!/usr/bin/env python3
+
+"""
+This isn't really an example of pyutils but rather a development
+tool I used as part of a git pre-commit hook...
+
+f)ind f)ucked f)-strings
+
+Searches python files for suspicious looking strings that seem to
+use f-string {interpolations} without acutally being f-strings.
+
+Usage: fff.py *.py
+"""
+
+import re
+import sys
+import tokenize
+from pathlib import Path
+from token import STRING
+from typing import List, Tuple
+
+from pyutils import ansi
+
+curly = re.compile(r'\{[^\}]+\}')
+
+
+def looks_suspicious(q: str, previous_tokens: List[Tuple[int, str]]) -> bool:
+ for pair in previous_tokens:
+ if ':' in pair[1]:
+ return False
+ return q[0] != 'f' and curly.search(q) is not None
+
+
+for filename in sys.argv[1:]:
+ path = Path(filename)
+ if path.suffix != ".py":
+ print(f"{filename} doesn't look like python; skipping.", file=sys.stderr)
+ continue
+ with tokenize.open(filename) as f:
+ previous_tokens = []
+ for token in tokenize.generate_tokens(f.readline):
+ (ttype, text, (start_row, _), (end_row, _), _) = token
+ if ttype == STRING:
+ if (
+ 'r"' not in text
+ and "r'" not in text
+ and looks_suspicious(text, previous_tokens)
+ ):
+ print(
+ f"{ansi.fg('green')}{filename}:{start_row}-{end_row}>{ansi.reset()}"
+ )
+ for (n, line) in enumerate(text.split('\n')):
+ print(
+ f'{ansi.fg("dark gray")}{start_row+n}:{ansi.reset()} {line}'
+ )
+ # print('Previous context:')
+ # for pair in previous_tokens:
+ # print(f'{pair[0]} ({pair[1]})', end=' + ')
+ # print()
+ previous_tokens.append((ttype, text))
+ previous_tokens = previous_tokens[-3:]