Text formatting error: '=' alignment not allowed in string format specifier
Question:
What does '=' alignment
mean in the following error message, and why does this code cause it?
>>> "{num:03}".format(num="1")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: '=' alignment not allowed in string format specifier
The code has a subtle problem: the input value "1"
is text, not a number. But the error message doesn’t appear to have anything to do with that.
Nothing in the error message indicates why “’=’ alignment” is relevant,
and it does not appear in the code. So what is the significance of emitting that error message?
Answers:
This format would be acceptable
"{num}:03".format(num="1")
but the way you have the placeholder specified {num:03}
is not. That is an interesting ValueError though, if you remove the :
the interesting error is replaced by a standard KeyError
.
str.__format__
doesn’t know what to do with your 03
part. That only works with numbers:
>>> "{num:03}".format(num=1)
'001'
If you actually want to zero-pad a string, you can use rjust
:
>>> "1".rjust(3, "0")
'001'
Python 3.10 and later
This issue is corrected in Python 3.10 and later:
In string formatting, preceding the width field by ‘0’ no longer affects the default alignment for strings.
The example code no longer raises an error; instead, it gives the result '100'
because the default align
for non-numeric types is <
.
Python earlier than 3.10
The error message occurs because '=' alignment
has been implied by the format specifier.
The str.format
format spec mini-language parser has decided on the
alignment specifier “=” because:
Preceding the width field by a zero (‘0’) character enables
sign-aware zero-padding for numeric types. This is equivalent to a
fill character of ‘0’ with an alignment type of ‘=’.
So by specifying 0N
as the “zero-padding to N width”, you have implied both “the input is a numeric type”, and “the zeros should go between the sign and the digits”. That latter implication is what is meant by '=' alignment
.
Since the value "1"
is not numeric, the “=”-alignment handling code raises that exception. The message is written expecting you know what it’s talking about because you requested (by implication) the “=” alignment.
Yes, I think that error message needs to be improved. I’ve raised an issue for that. Thanks to Serhiy Storchaka for fixing this issue! Python 3.10 includes this change.
You are trying to insert ‘string->”1″ where a float->3.44 is required. Remove the quotes “1”, i.e. num=1, and it will work
A workaround is to use '>'
(right justify) padding, which is with the syntax:
[[fill]align][width]
with align being >
, fill being 0
and width being 3
.
>>> "{num:0>3}".format(num="1")
'001'
The problem was that there is a different 0
in the format specification:
format_spec ::= [[fill]align][sign][#][0][width][grouping_option][.precision][type]
# ^^^ This one
That zero just makes fill
default to 0
and align
to =
.
=
alignment is specified as:
Forces the padding to be placed after the sign (if any) but before the digits. This is used for printing fields in the form ‘+000000120’. This alignment option is only valid for numeric types. It becomes the default when ‘0’ immediately precedes the field width.
This expects the argument to be an int
, as strings don’t have signs. So we just manually set it to the normal default of >
(right justify).
Also note that 0
just specifies the default values for fill
and align
. You can change both or just the align.
>>> # fill defaults to '0', align is '>', `0` is set, width is `3`
>>> "{num:>03}".format(num=-1)
'0-1'
>>> # fill is `x`, align is '>', `0` is set (but does nothing), width is `"3"`
>>> "{num:x>03}".format(num=-1)
'x-1'
>>> # fill is `x`, align is '>', `0` is set (but does nothing), width is `"03"` (3)
>>> "{num:x>003}".format(num=-1)
'x-1'
In my case, I was trying to zero-pad a string instead of a number.
The solution was simply to convert the text to a number before applying the padding:
num_as_text = '23'
num_as_num = int(num_as_text)
padded_text = f'{num_as_num:03}'
Changed in version 3.10: Preceding the width field by ‘0’ no longer affects the default
alignment for strings.
Thanks to Serhiy Storchaka for fixing it.
The OP’s code sample runs fine in Python 3.10+. However note that it returns 100
because the default align
for non-numeric types is <
.
For older Python versions manually add the left alignment character: "{num:<03}".format(num="1")
Just for others who google searched and found this Q&A.
This error:
out_name = track_name_fmt.format(track, song)
ValueError: '=' alignment not allowed in string format specifier
Was fixed by using:
out_name = track_name_fmt.format(int(track), song)
Forcing track
to integer solved the problem.
What does '=' alignment
mean in the following error message, and why does this code cause it?
>>> "{num:03}".format(num="1")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: '=' alignment not allowed in string format specifier
The code has a subtle problem: the input value "1"
is text, not a number. But the error message doesn’t appear to have anything to do with that.
Nothing in the error message indicates why “’=’ alignment” is relevant,
and it does not appear in the code. So what is the significance of emitting that error message?
This format would be acceptable
"{num}:03".format(num="1")
but the way you have the placeholder specified {num:03}
is not. That is an interesting ValueError though, if you remove the :
the interesting error is replaced by a standard KeyError
.
str.__format__
doesn’t know what to do with your 03
part. That only works with numbers:
>>> "{num:03}".format(num=1)
'001'
If you actually want to zero-pad a string, you can use rjust
:
>>> "1".rjust(3, "0")
'001'
Python 3.10 and later
This issue is corrected in Python 3.10 and later:
In string formatting, preceding the width field by ‘0’ no longer affects the default alignment for strings.
The example code no longer raises an error; instead, it gives the result '100'
because the default align
for non-numeric types is <
.
Python earlier than 3.10
The error message occurs because '=' alignment
has been implied by the format specifier.
The str.format
format spec mini-language parser has decided on the
alignment specifier “=” because:
Preceding the width field by a zero (‘0’) character enables
sign-aware zero-padding for numeric types. This is equivalent to a
fill character of ‘0’ with an alignment type of ‘=’.
So by specifying 0N
as the “zero-padding to N width”, you have implied both “the input is a numeric type”, and “the zeros should go between the sign and the digits”. That latter implication is what is meant by '=' alignment
.
Since the value "1"
is not numeric, the “=”-alignment handling code raises that exception. The message is written expecting you know what it’s talking about because you requested (by implication) the “=” alignment.
Yes, I think that error message needs to be improved. I’ve raised an issue for that. Thanks to Serhiy Storchaka for fixing this issue! Python 3.10 includes this change.
You are trying to insert ‘string->”1″ where a float->3.44 is required. Remove the quotes “1”, i.e. num=1, and it will work
A workaround is to use '>'
(right justify) padding, which is with the syntax:
[[fill]align][width]
with align being >
, fill being 0
and width being 3
.
>>> "{num:0>3}".format(num="1")
'001'
The problem was that there is a different 0
in the format specification:
format_spec ::= [[fill]align][sign][#][0][width][grouping_option][.precision][type] # ^^^ This one
That zero just makes fill
default to 0
and align
to =
.
=
alignment is specified as:
Forces the padding to be placed after the sign (if any) but before the digits. This is used for printing fields in the form ‘+000000120’. This alignment option is only valid for numeric types. It becomes the default when ‘0’ immediately precedes the field width.
This expects the argument to be an int
, as strings don’t have signs. So we just manually set it to the normal default of >
(right justify).
Also note that 0
just specifies the default values for fill
and align
. You can change both or just the align.
>>> # fill defaults to '0', align is '>', `0` is set, width is `3`
>>> "{num:>03}".format(num=-1)
'0-1'
>>> # fill is `x`, align is '>', `0` is set (but does nothing), width is `"3"`
>>> "{num:x>03}".format(num=-1)
'x-1'
>>> # fill is `x`, align is '>', `0` is set (but does nothing), width is `"03"` (3)
>>> "{num:x>003}".format(num=-1)
'x-1'
In my case, I was trying to zero-pad a string instead of a number.
The solution was simply to convert the text to a number before applying the padding:
num_as_text = '23'
num_as_num = int(num_as_text)
padded_text = f'{num_as_num:03}'
Changed in version 3.10: Preceding the width field by ‘0’ no longer affects the default
alignment for strings.
Thanks to Serhiy Storchaka for fixing it.
The OP’s code sample runs fine in Python 3.10+. However note that it returns 100
because the default align
for non-numeric types is <
.
For older Python versions manually add the left alignment character: "{num:<03}".format(num="1")
Just for others who google searched and found this Q&A.
This error:
out_name = track_name_fmt.format(track, song)
ValueError: '=' alignment not allowed in string format specifier
Was fixed by using:
out_name = track_name_fmt.format(int(track), song)
Forcing track
to integer solved the problem.