Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open issue: typing_objects function definitions #14

Open
Viicos opened this issue Feb 18, 2025 · 0 comments
Open

Open issue: typing_objects function definitions #14

Viicos opened this issue Feb 18, 2025 · 0 comments
Labels
open issues Open issues to be discussed with other users of the runtime typing ecosystem

Comments

@Viicos
Copy link
Member

Viicos commented Feb 18, 2025

Currently, typing-inspection works on the supported Python versions (3.9-3.14) and has a lower bound on typing-extensions:

dependencies = [
'typing-extensions>=4.12.0',
]

Version 4.12.0 was released almost a year ago, so it seemed reasonable to choose it as a lower bound. In the future, it would be great if typing-extensions could keep this lower bound as long as possible. This means that the typing_objects inspection functions need to handle several different cases. For a typing member TypingObj:

  • Both typing.TypingObj and typing_extensions.TypingObj exist.
    • typing_extensions is simply reexporting typing.TypingObj, in this case, typing_objects.is_typingobj() can be implemented as:
      def is_typingobj(obj, /) -> bool:
          return obj is typing.TypingObj
    • typing_extensions backports a different version of TypingObj. In this case, the check can be implemented as:
      def is_typingobj(obj, /) -> bool:
          return obj is typing.TypingObj or obj is typing_extensions.TypingObj
  • Only typing_extensions.TypingObj exists (e.g. when not on the latest Python version):
    def is_typingobj(obj, /) -> bool:
         return obj is typing_extensions.TypingObj
  • Only typing.TypingObj exists (e.g. when not on the latest typing_extensions version):
    def is_typingobj(obj, /) -> bool:
         return obj is typing.TypingObj
  • TypingObj doesn't exist in both modules:
    def is_typingobj(obj, /) -> bool:
         return False

Several options are offered to us to implement the checks:

  • At the module level, use hasattr()/sys.version_info checks to define the functions. This can get repetitive and unreadable very quickly.
  • At the module level, define a set containing the members to check against:
    _typingobj_members = {}
    if hasattr(typing, 'TypingObj'):
        _typingobj_members.add(typing.TypingObj)
    if hasattr(typing_extensions, 'TypingObj'):
        _typingobj_members.add(typing_extensions.TypingObj)
    
    def is_typingobj(obj, /) -> bool:
        return obj in _typingobj_members
    A bit less repetitive.
  • Do the hasattr()/sys.version_info checks in the function. This could degrade performance slightly (in Pydantic, we rely a lot on thes introspection functions, and noticed small performance improvements (~1-5%) when optimizing them).
  • Dynamically create the functions. This is what _compile_identity_check_function()/_compile_isinstance_check_function() are currently doing.

The chosen approach works fine, but requires generating typing stubs, and conceptually feels a bit hacky (functions are generated using exec()). I'm open to suggestions that would provide a cleaner implementation without hurting performance.

@Viicos Viicos added the open issues Open issues to be discussed with other users of the runtime typing ecosystem label Feb 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
open issues Open issues to be discussed with other users of the runtime typing ecosystem
Projects
None yet
Development

No branches or pull requests

1 participant