4

I have a long string with many formatting braces and many double braces that are not for format. I also have a dictionary with all the values to be used for formatting. Short example:

text = """There are {n_cats:} cats and {n_dogs:} dogs.
A total of {7}.
Except that there is some {{normal text}}.
"""

kwargs = {'n_cats': 3, 'n_dogs': 4}

print(text.format(**kwargs))

This results in:

Traceback (most recent call last):
    print(text.format(**kwargs))
IndexError: tuple index out of range

And obviously one can see that instead of {7} there should be either 7 or {{7}}. But my real text is much much longer. Is there a way to easily find the place where format() breaks?

rpoleski
  • 988
  • 5
  • 12
  • `{7}` is going to get the 7th positional argument. You gave 0. – Klaus D. Feb 10 '21 at 18:34
  • 1
    @KlausD. It's also stated in the question. The problem is not why the error occurs. – Asocia Feb 10 '21 at 18:34
  • 1
    You won't see more with the CPython iterpreter. IPython gives a little more info: `IndexError: Replacement index 7 out of range for positional args tuple` – Klaus D. Feb 10 '21 at 18:40
  • 1
    Maybe you can search for problematic parts with regex. `re.search(r"\{\d+\}", text)` will give you `` – Asocia Feb 10 '21 at 18:47
  • 1
    This gets to an issue of maintainability. If you have a single "line" that can fail in non-obvious ways, you should probably break it up into multiple lines, at least until you can piece it back together into a more robust single line. – chepner Feb 10 '21 at 18:48
  • @KlausD. thanks now I understand why a good ide helps ! – pippo1980 Feb 10 '21 at 18:48
  • 1
    Could You subclass Formatter ? in such a wy that printds the index raising the error ?? I don't know how to do it but after readibg this maybe ia a way to go for :https://stackoverflow.com/questions/17215400/format-string-unused-named-arguments/17215533#17215533 third answer – pippo1980 Feb 10 '21 at 18:56
  • @Asocia This is helpful, but the patern would need to be extended as it also finds `{{7}}`. I'll combine it with my answer below. Thanks! – rpoleski Feb 10 '21 at 19:47

1 Answers1

0

Thanks guys. The comments by @Asocia and @chepner gave me the idea which identifies the line in which the problem occurs. We can divide text into lines and apply format to each one of them (having too many keys in kwargs is not a problem). Code:

try:
    print(text.format(**kwargs))
except Exception:
    for (i, t) in enumerate(text.split("\n")):
        try:
            t.format(**kwargs)
        except Exception:
            raise ValueError("Failed in line {:}".format(i+1))
rpoleski
  • 988
  • 5
  • 12