Skip to content

Instantly share code, notes, and snippets.

@msullivan
Last active March 17, 2023 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save msullivan/169cd943414aeab0a86b6cad7d010e8a to your computer and use it in GitHub Desktop.
Save msullivan/169cd943414aeab0a86b6cad7d010e8a to your computer and use it in GitHub Desktop.
Library for dynamically building properly indented output using f strings
import textwrap
from typing import Any
# Escape delimeters for maintaining a nesting structure in strings
# that the user produces. Obviously, as with all schemes for in-band
# signalling, all hell can break loose if the signals appear in the
# input data unescaped.
#
# Our signal sequences contain a null byte and both kinds of quote
# character, so you should be fine as long as any untrusted data
# either:
# * Has no null bytes
# * Has at least one kind of quote character escaped in it somehow
LEFT_ESCAPE = "\0'\"<<{<[<[{{<!!!"
RIGHT_ESCAPE = "\0'\"!!!>}}]>]>}>>"
ESCAPE_LEN = len(LEFT_ESCAPE)
assert len(RIGHT_ESCAPE) == ESCAPE_LEN
LINE_BLANK = LEFT_ESCAPE[:-1] + "||||||" + RIGHT_ESCAPE[1:]
def escape(s: str) -> str:
return LEFT_ESCAPE + s.strip('\n') + RIGHT_ESCAPE
Rep = list[str | list[Any]]
def parse(s: str, start: int) -> tuple[Rep, int]:
frags = []
while start < len(s):
nleft = s.find(LEFT_ESCAPE, start)
nright = s.find(RIGHT_ESCAPE, start)
if nleft == nright == -1:
frags.append(s[start:])
start = len(s)
elif nleft != -1 and nleft < nright:
if nleft > start:
frags.append(s[start:nleft])
subfrag, start = parse(s, nleft + ESCAPE_LEN)
# If it is the special magic line blanking fragment,
# delete up through the last newline. Otherwise collect it.
if subfrag == [LINE_BLANK] and frags:
frags[-1] = frags[-1].rsplit('\n', 1)[0]
else:
frags.append(subfrag)
else:
assert nright >= 0
frags.append(s[start:nright])
start = nright + ESCAPE_LEN
break
return frags, start
def format_rep(rep: Rep) -> str:
# cpython does some really dubious things to make appending in place
# to a string efficient, and we depend on them here
out_str = ""
# TODO: I think there ought to be a more complicated algorithm
# that builds a list of lines + indentation metadata and then
# fixes it all up in one go?
for frag in rep:
if isinstance(frag, str):
out_str += frag
else:
fixed_frag = format_rep(frag)
# If there is a newline in the final result, we need to indent
# it to our current position on the current line.
if '\n' in fixed_frag:
last_nl = out_str.rfind('\n')
indent = 0 if last_nl < 0 else len(out_str) - last_nl - 1
# Indent all the lines but the first (since that goes
# onto our current line)
fixed_frag = textwrap.indent(fixed_frag, ' ' * indent)[indent:]
out_str += fixed_frag
return textwrap.dedent(out_str).removesuffix('\n')
def xdedent(s: str) -> str:
# Hate needing the leading slash
s = s.removeprefix('\n')
parsed, _ = parse(s, 0)
return format_rep(parsed)
#####
X = escape
EXPECTED_1 = '''
call_something()
foo = 10
while True:
if bar:
do_something(
foo,
bar,
[1, 2, 3,
4, 5, 6],
reify(
spam
),
reify(
eggs
),
reify(
ham
)
)
another
more
'''.strip('\n')
EXPECTED_2 = '''
call_something()
foo = 10
while True:
if bar:
another
more
'''.strip('\n')
def test_1(do_something=True):
foo = 'foo'
bar = 'bar'
left = '''
[1, 2, 3,
4, 5, 6]
'''
things = []
for thing in ['spam', 'eggs', 'ham']:
things.append(f'''
reify(
{thing}
)
''')
sep = ",\n"
if do_something:
orig = f'''
do_something(
{foo},
{bar},
{X(left)},
{X(sep.join(X(x) for x in things))}
)
'''
else:
orig = LINE_BLANK
return xdedent(f'''
call_something()
{X(foo)} = 10
while True:
if {bar}:
{X(orig)}
another
more
''')
assert test_1(do_something=True) == EXPECTED_1
assert test_1(do_something=False) == EXPECTED_2
def test_2():
import itertools
dels = {
'a': '(DELETE DeleteTest)',
'b': '(DELETE LinkingType)',
}
for binds, uses in itertools.product(
list(itertools.permutations(dels.keys())),
list(itertools.permutations(dels.keys())),
):
nl = '\n'
q = xdedent(f'''
with
{X(nl.join(X(f'{k} := {dels[k]},') for k in binds))}
select {{{', '.join(uses)}}};
''')
print(q)
test_2()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment