bpo-36048: Deprecate implicit truncating when convert Python numbers to C integers: use index, not int
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
assignee=Noneclosed_at=<Date2019-03-14.14:58:36.318>created_at=<Date2018-03-05.21:07:14.038>labels= ['interpreter-core', '3.7', '3.8']
title='Making a class formattable as hex/oct integer with printf-style formatting requires both __int__ and __index__ for no good reason'updated_at=<Date2019-03-14.14:58:36.316>user='https://github.com/MojoVampire'
In Python 2, making a user-defined class support formatting using the integer-specific type codes required that __int__ be defined and nothing else (that is, '%x' % Foo() only required Foo to provide a __int__ method). In Python 3, this was changed to perform the conversion via __index__ for the %o, %x and %X format types (to match how oct and hex behave), not __int__, but the pre-check for validity in unicodeobject.c's mainformatlong function is still based on PyNumber_Check, not PyIndex_Check, and PyNumber_Check is concerned solely with __int__ and __float__, not __index__.
This means that a class with __index__ but not __int__ can't be used with the %o/%x/%X format codes (even though hex(mytype) and oct(mytype) work just fine).
It seems to me that either:
PyNumber_Check should be a superset of PyIndex_Check (broader change, probably out of scope)
mainformatlong should restrict the scope of the PyNumber_Check test to only being used for the non-'o'/'x'/'X' tests (where it's needed to avoid coercing strings and the like to integer).
Change #2 should be safe, with no major side-effects; since PyLong and subclasses always passed the existing PyNumber_Check test anyway, and PyNumber_Index already performs PyIndex_Check, the only path that needs PyNumber_Check is the one that ends in calling PyNumber_Long.
Note: Obviously, defining __index__ without defining __int__ is a little strange (it's *equivalent* to int, but can't be *coerced* to int?), so yet another fix would be addressing bpo-20092 so it wouldn't be possible for a type to define __index__ without (implicitly) defining __int__.