Table/issue 2868

This finishes up @cherti's original PR at #3055 by rebasing on master and updating to work on master.  I also fixed a few bugs and reformatted the code a bit.  After I submit this PR I'm probably going to rebase again to collapse down some of @cherti's original commits, but will still make sure they get credit.
Why is this changed to `TypeError`?  I think `ValueError` is more consistent since the value of the format specification is incorrect, not the type.  Also:
```
----> 1 '{:5.2f}'.format("string")

ValueError: Unknown format code 'f' for object of type 'str'
```