Sitelet https://github.com/python/cpython/issues/89828
Skip to content

Problems caused by isinstance(list[int], type) returning True #89828

Description

@serhiy-storchaka
BPO 45665
Nosy @gvanrossum, @serhiy-storchaka, @wyfo, @Fidget-Spinner, @AlexWaygood, @martinitus
Dependencies
  • bpo-40296: help(list[int]) fails
  • bpo-45438: inspect not capturing type annotations created by class_getitem
  • bpo-45662: Incorrect repr of InitVar of a type alias
  • bpo-45663: is_dataclass() does not work for dataclasses which are subclasses of types.GenericAlias
  • bpo-45664: resolve_bases() and new_class() do not work with type alias of a built-in type
  • bpo-46032: functools' singledispatch does not support GenericAlias
  • 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

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2021-10-29.08:27:43.950>
    labels = ['type-bug', 'library', '3.9', '3.10', '3.11']
    title = 'Problems caused by isinstance(list[int], type) returning True'
    updated_at = <Date 2022-01-06.16:58:47.655>
    user = 'https://github.com/serhiy-storchaka'

    bugs.python.org fields:

    activity = <Date 2022-01-06.16:58:47.655>
    actor = 'AlexWaygood'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2021-10-29.08:27:43.950>
    creator = 'serhiy.storchaka'
    dependencies = ['40296', '45438', '45662', '45663', '45664', '46032']
    files = []
    hgrepos = []
    issue_num = 45665
    keywords = []
    message_count = 17.0
    messages = ['405290', '405291', '405427', '405429', '408207', '409167', '409233', '409679', '409691', '409694', '409697', '409701', '409702', '409703', '409711', '409792', '409881']
    nosy_count = 6.0
    nosy_names = ['gvanrossum', 'serhiy.storchaka', 'joperez', 'kj', 'AlexWaygood', 'martinitus']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue45665'
    versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

    Activity

    1. serhiy-storchaka commented on Oct 29, 2021

      @serhiy-storchaka
      MemberAuthor

      This is a meta-issue for problems caused by isinstance(list[int]) returning True.

      See also discussion in bpo-45438.

    2. added
      3.11only security fixes
      stdlibStandard Library Python modules in the Lib/ directory
      type-bugAn unexpected behavior, bug, or error
      on Oct 29, 2021
    3. serhiy-storchaka commented on Oct 29, 2021

      @serhiy-storchaka
      MemberAuthor

      isinstance(x, type) returns True for instances of types.GenericAlias (like list[int]). While it may help in some cases related to typing, in many unrelated cases it causes problems if the value which is not a type passes checks for types.

      Also, isinstance(x, type) been not equal to issubclass(type(x), type) can cause other problems. No matter what the result should be, it should be consistent.

      There are many occurrences of isinstance(..., type) in the code.

      $ find Lib -name '*.py' \! -path '*/test*' -exec egrep 'isinstance.*,
      type\)' '{}' + | wc -l
      55

      And all of them can potentially be broken if pass a types.GenericAlias instance. Many of them are safe, but every case should be analyzed.

    4. changed the title [-]Problems caused by isinstance(list[int]) returning True[/-] [+]Problems caused by isinstance(list[int], type) returning True[/+] on Oct 29, 2021
    5. changed the title [-]Problems caused by isinstance(list[int]) returning True[/-] [+]Problems caused by isinstance(list[int], type) returning True[/+] on Oct 29, 2021
    6. martinitus commented on Nov 1, 2021

      martinitusmannequin
      Mannequin

      One thing that probably should be considered in this context:

      isinstance(arg, type) == issubclass(type(arg), type)

      Holds True for arg in (Optional[X], Union[X, Y]). Both sides evaluate to False. (v3.10.0)

      While I still think both sides evaluating to True would be more intuitive, this supports the proposed change.

      Small test snippet:

      from typing import Dict, List, Set, Tuple, Optional, Union
      
      import pytest
      
      
      @pytest.mark.parametrize('arg', [
          list, List[int], list[int],
          dict, Dict[str, int], dict[str, int],
          set, Set[int], set[int],
          tuple, Tuple[str, int], tuple[str, int],
          Optional[int],
          Union[int, str]
      ])
      def test_invariant(arg):
          same = isinstance(arg, type) == issubclass(type(arg), type)
          result = "Check" if same else "Failed"
          print(f"\n{result}: Testing: {arg=} with {type(arg)=}: {isinstance(arg, type)=} <> {issubclass(type(arg), type)=}")
          assert same
      
      

      Any other commonly used annotations that could be added to the checklist?

    7. 12 remaining items

    8. pablogsal commented on Jan 5, 2022

      @pablogsal
      Member

      Gentle ping, as the next alpha will be release soon

    9. AlexWaygood commented on Jan 6, 2022

      @AlexWaygood
      Member

      We will still allow instantiating e.g. list[int], right?

      I certainly hope so! That would be a much more breaking change if we were to change that, and I can't personally see any benefit to doing so.

    10. transferred this issue fromon Apr 10, 2022
    11. added a commit that references this issue on Jun 12, 2022
    12. serhiy-storchaka commented on Jun 12, 2022

      @serhiy-storchaka
      MemberAuthor

      The cause what that list[int].__class__ returned type instead of types.GenericAlias.

      I suppose also that there may be problems caused by relaying other dunder methods. There is a list of exceptions, but it is not complete. typing._GenericAlias in general does not relay dunder methods (except __name__ and __qualname__).

    13. added a commit that references this issue on Jun 18, 2022
    14. added 2 commits that reference this issue on Jun 18, 2022
    15. johnslavik commented on Jan 17, 2023

      @johnslavik
      Member

      At this point I'd like to report the following inconsistency between C PyType_Check(t) and Python's isinstance(t, type) that I've noticed. I don't know if it's fixed at the moment, just so that it doesn't get lost:

      from abc import ABCMeta  # the C implementation is required for this snippet
      
      class MyABC(metaclass=ABCMeta):
          pass
      
      t = list[int]
      isinstance(t, type) and issubclass(t, MyABC)

      causing the following error:

      Traceback (most recent call last):
        File "...", line 9, in <module>
          isinstance(t, type) and issubclass(t, MyABC)
        File "/usr/lib/python3.10/abc.py", line 123, in __subclasscheck__
          return _abc_subclasscheck(cls, subclass)
      TypeError: issubclass() arg 1 must be a class
      

      But if we change abc import to _py_abc,

      from _py_abc import ABCMeta  # Python implementation
      
      class MyABC(metaclass=ABCMeta):
         pass
      
      t = list[int]
      isinstance(t, type) and issubclass(t, MyABC)

      the above absolutely does not produce any error.
      This is of course clearly a GenericAlias-related problem.

    16. gvanrossum commented on Jan 18, 2023

      @gvanrossum
      Member

      At this point I'd like to report the following inconsistency between C PyType_Check(t) and Python's isinstance(t, type) that I've noticed. I don't know if it's fixed at the moment, just so that it doesn't get lost:
      [...]

      What Python version? The most recent version where I can repro that error is 3.10. The fix appears to be in 3.11 and on main (3.12 alpha).

    17. johnslavik commented on Jan 19, 2023

      @johnslavik
      Member

      Oh, right. Yes, it was 3.10, like in the traceback.
      Sorry for not specifying the version and not checking if the bug is not already fixed in versions >3.10.
      Also sorry for causing unnecessary chaos.
      Thanks and good luck!

    18. serhiy-storchaka commented on Jan 19, 2023

      @serhiy-storchaka
      MemberAuthor

      There is not much that we can do with this in 3.10. The workaround in the user code is:

      isinstance(t, type) and not isinstance(t, types.GenericAlias) and issubclass(t, MyABC)

      The middle check is not needed in 3.11+.

      I think this issue can now be closed. I have not found other sites in the stdlib with user visible differences.

      But I have found an interesting difference in the behavior of issubclass(), which should rarely affect user code: #101162.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.10 (EOL)end of life3.11only security fixes3.9 (EOL)end of lifestdlibStandard Library Python modules in the Lib/ directorytopic-typingtype-bugAn unexpected behavior, bug, or error

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions