cpython icon indicating copy to clipboard operation
cpython copied to clipboard

`ISNONTERMINAL` and `ISTERMINAL` in `token.py` accept float arguments in CPython but raise TypeError in PyPy

Open EgodPrime opened this issue 2 months ago • 1 comments

Bug report

Bug description:

Hi, I'm working on a Python testing project, and our tool detected the following issue:

from token import ISNONTERMINAL, ISTERMINAL

ISNONTERMINAL(0.5)
ISTERMINAL(0.5)

As it turned out, CPython had no complaints and executed smoothly.

However, the CPython source file token.py indicates that the input for ISNONTERMINAL and ISTERMINAL should be integer-type enumeration values, or more strictly, should only accept values defined within token.py.

Coincidentally, I ran the same test on the same version of PyPy and found that PyPy produced a different but more reasonable error:

TypeError: expected integer, got float object

This indicates that PyPy performs the relevant checks, even if not in the strictest form.

This may be considered an implementation bug in CPython. Type checking for input values should be supplemented to produce behavior similar to PyPy.

By the way, in my view, the approach suggested for issue 86353 is also a workable solution.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

  • gh-143385

EgodPrime avatar Dec 19 '25 02:12 EgodPrime

Note that we want to deprecate these, see #86353.

StanFromIreland avatar Jan 03 '26 17:01 StanFromIreland

I don't think it's relevant and considering we want to deprecate it it's also un-necessary IMO.

This may be considered an implementation bug in CPython. Type checking for input values should be supplemented to produce behavior similar to PyPy.

Why should CPython be responsible for this? I think the intent is sufficient. Performing an isinstance() check is costly and I would only be willing to actually change the docs then (but a new issue should be created).

Considering, in addition, that we are already typing the function, I don't want to add an isinstance() check for each consumer (such function could be called multiple times in a loop, and therefore have expensive isinstance checks). typeshed already assumes that the input is an int: https://github.com/python/typeshed/blob/eb347f3a1c13dc00449bf178a53c24f2ae838450/stdlib/token.pyi#L167-L168.

picnixz avatar Jan 04 '26 14:01 picnixz