Skip to content

ctypes POINTER invalid incompatible type with None #12736

Closed

Description

@caffeinepills

With type checkers (PyCharm's, MyPy) I get the error:
mypy_test.py:6: error: Argument 1 to "POINTER" has incompatible type "None"; expected "type[Never]" [arg-type]

Using this simple example:

from ctypes import POINTER
void = None
POINTER(void)

POINTER(None) in ctypes is equivalent to c_void_p and is valid when ran. Minor issue but is technically a compatible type.

Activity

  1. junkmd commented on Oct 7, 2024

    @junkmd
    Contributor

    Is this change reasonable?

    typeshed/stdlib/_ctypes.pyi

    Lines 101 to 102 in dbd0d35

    def POINTER(type: type[_CT], /) -> type[_Pointer[_CT]]: ...

    +@overload
    +def POINTER(type: None, /) -> type[c_void_p]: ...
    +@overload
    def POINTER(type: type[_CT], /) -> type[_Pointer[_CT]]: ...
  2. srittau commented on Oct 8, 2024

    @srittau
    Collaborator

    I'm no expert for ctypes, but I think c_void_p (without type) is the correct return type:

    In [6]: POINTER(None) is c_void_p
    Out[6]: True
  3. added
    help wantedAn actionable problem of low to medium complexity where a PR would be very welcome
    on Oct 8, 2024
  4. junkmd commented on Oct 8, 2024

    @junkmd
    Contributor

    ctypes.POINTER returns a pointer type for the given type, based on the private _pointer_type_cache mapping.

    The private function _reset_cache is called when the module is loaded and clears that mapping, assigning None as the key and c_void_p as the value.

    Therefore, I think it is reasonable that POINTER(None) returns type[c_void_p].

    I recently dived into the ctypes implementation while maintaining a project that needed to be updated to accommodate recent changes made to ctypes. This is where I gained this insight.

    I'm planning to submit a PR regarding this.

  5. added a commit that references this issue on Oct 8, 2024
  6. Avasam commented on Oct 9, 2024

    @Avasam
    SponsorCollaborator

    I'm no expert for ctypes, but I think c_void_p (without type) is the correct return type:

    In [6]: POINTER(None) is c_void_p
    Out[6]: True

    Come to think of it with fresh eyes. Doesn't that confirm the return is indeed the class to be instanciated? (represented by type[c_void_p])?

    >>> import ctypes
    >>> ctypes.POINTER(None) is ctypes.c_void_p
    True
    >>> isinstance(ctypes.POINTER(None)(), ctypes.c_void_p)
    True

    Let's do the same exercise with a simple type (int):

    >>> int is int
    True
    >>> isinstance(int(), int)
    True

    I'm not sure where the confusion was, maybe I was also too sleepy ^^"

  7. srittau commented on Oct 10, 2024

    @srittau
    Collaborator

    I'm not sure where the confusion was, maybe I was also too sleepy ^^"

    You're completely right, of course. No idea why I was confused.

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

    help wantedAn actionable problem of low to medium complexity where a PR would be very welcomestubs: false positiveType checkers report false errors

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions