urllib.urlencode currently uses `str()` on its non-bytes objects before encoding the result. This causes a compatibility break when integer module constants are converted to IntEnum, as `str(IntEnum.MEMBER)` no longer returns the integer representation; however, `format()` does still return the integer representation.
The fix is to add a separate branch to check if the argument is an Enum, and use the value if so -- but it got me wondering: in general, are there differences between calling str() vs calling format() on Python objects?
If there's no format string, then object___format___impl() just calls PyObject_Str(). So unless the object overrides __format__, they're the same.
int does override __format__, in _PyLong_FormatAdvancedWriter(). It has a comment that says:
/* check for the special case of zero length format spec,
make
it equivalent to str(obj) */
So even in the case of it, str(obj) should be the same as
format(obj).
I thoughtPEP 3101 specifies this behavior, but I don't see it
there. It's hopelessly out of date, anyway. The docs for format()
say these weasel words: "The default format_spec is an
empty string which usually gives the same
effect as calling str(value)
.".
They're vague because a user defined type could do anything in
__format__, including ignore this advice. But I think all of the
built-in types conform to it.
Eric