Skip to content

TypeError when running example recipe under "Runtime use of types" in the documentation #531

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

Closed
DavidOGrady opened this issue Feb 19, 2025 · 4 comments · Fixed by #532
Closed

Comments

@DavidOGrady
Copy link

Hello,

I believe I have found a potential issue in either typing-extensions or the documentation for typing-extensions when running the example recipe code under "Runtime use of types" in the documentation. Link to documentation: https://typing-extensions.readthedocs.io/en/latest/#runtime-use-of-types

Im have created the following script to test out typing-extensions on my wsl environment.

import functools
import typing
import typing_extensions
from typing import Tuple, Any
from functools import partial
from typing_extensions import get_origin

# Use an unbounded cache for this function, for optimal performance
@functools.lru_cache(maxsize=None)
def get_typing_objects_by_name_of(name: str) -> Tuple[Any, ...]:
    result = tuple(
        getattr(module, name)
        # You could potentially also include mypy_extensions here,
        # if your library supports mypy_extensions
        for module in (typing, typing_extensions)
        if hasattr(module, name)
    )
    if not result:
        raise ValueError(
            f"Neither typing nor typing_extensions has an object called {name!r}"
        )
    return result


# Use a cache here as well, but make it a bounded cache
# (the default cache size is 128)
@functools.lru_cache()
def is_typing_name(obj: object, name: str) -> bool:
    return any(obj is thing for thing in get_typing_objects_by_name_of(name))


if __name__ == "__main__":
    print("Hello world")
    is_literal = partial(is_typing_name, name="Literal")
    print(is_literal(typing.Literal))
    print(is_literal(typing_extensions.Literal))
    print(is_literal(typing.Any))
    print(is_literal(get_origin(typing.Literal[42])))
    print(is_literal(get_origin(typing_extensions.Final[42])))

However, when i run this code (after using pip to install typing-extensions 4.12.2 and using python version 3.8.10), I get the following error:

test-user@test-vm:~$ cd temp-venv/
test-user@test-vm:~/temp-venv$ source bin/activate
(temp-venv) test-user@test-vm:~/temp-venv$ python
Python 3.8.10 (default, Jan 17 2025, 14:40:23)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
(temp-venv) test-user@test-vm:~/temp-venv$ ls
bin  include  lib  lib64  pyvenv.cfg  share
(temp-venv) test-user@test-vm:~/temp-venv$ cd bin
(temp-venv) test-user@test-vm:~/temp-venv/bin$ ls
Activate.ps1  activate.csh   easy_install      pip   pip3.8  python3
activate      activate.fish  easy_install-3.8  pip3  python  test-typing-example.py
(temp-venv) test-user@test-vm:~/temp-venv/bin$ pip list
Package           Version
----------------- -------
pip               20.0.2
pkg-resources     0.0.0
setuptools        44.0.0
typing-extensions 4.12.2
(temp-venv) test-user@test-vm:~/temp-venv/bin$ python3 test-typing-example.py
Hello world
True
True
False
True
Traceback (most recent call last):
  File "test-typing-example.py", line 39, in <module>
    print(is_literal(get_origin(typing_extensions.Final[42])))
  File "/usr/lib/python3.8/typing.py", line 261, in inner
    return func(*args, **kwds)
  File "/usr/lib/python3.8/typing.py", line 350, in __getitem__
    item = _type_check(parameters, f'{self._name} accepts only single type.')
  File "/usr/lib/python3.8/typing.py", line 149, in _type_check
    raise TypeError(f"{msg} Got {arg!r:.100}.")
TypeError: Final accepts only single type. Got 42.

Out of interest, I ran the same test file on clean Python docker images (with the latest tag which had Python 3.13.2 and an older image that had Python 3.9.21, i also manually installed typing-extensions on both docker containers using pip install typing-extensions). The image that had Python 3.13.2 installed did not show any issues and print False as expected. However, the docker image that had Python 3.9.21 installed on it also showed the same TypeError. Out of interest, I replaced typing_extensions.Final with typing.Final the same error was seen.

Also, if I replaced the 42 with the word int and the TypeError was not seen.

I don't suppose this is a typo in the documentation or are there specific versions of Python 3.8 and 3.9 that don't work with typing-extensions 4.12.2?

Any help or advice would be appreciated.
Thanks,

@JelleZijlstra
Copy link
Member

We made a change in recent versions of Python to allow invalid types inside Final[]; I suppose we didn't backport that to typing-extensions.

However, this isn't essential to the example. We should just change the example to something like Final[int]. PR welcome!

@Daraan
Copy link
Contributor

Daraan commented Feb 19, 2025

Some background info:

Since Python 3.8 typing_extensions re-exports typing.Final, they are the same object.

In Python 3.11 the restrictions (checked by typing._type_check) on what is allowed to pass as arguments became more lax. This allows for easier backporting in the future, but also to pass arguments that are not valid from a type-checker perspective, e.g. 42.

I guess the documentation was run with 3.11+ :)

@DavidOGrady
Copy link
Author

Hi @JelleZijlstra and @Daraan,

Thank you for getting back to me so quickly.
I don't have a lot of experience with the typing or typing_extensions modules with Python so I was wondering if I could pick your brain with a few follow-up questions.

I'm installing typing_extensions as it is a requirement for SQLalchemy and I ran this example test script to verify that typing_extensions was installed on my environment correctly. Is it fair to assume that by changing 42 to int and getting false back, typing_extensions is working correctly?

Also, with regards to fixing this error, what would the fix be? Does the documentation need to be updated to say int? My biggest concern is, given that I can't upgrade my current version of Python for other unrelated reasons, I'm afraid that there might be functional impacts to SQLalchemy.

Thanks,

@JelleZijlstra
Copy link
Member

Your installation is fine; it's just a mistake in our documentation.

JelleZijlstra added a commit that referenced this issue Feb 21, 2025
This fails at runtime in older versions, and in any case it is an invalid type.

Fixes #531
hauntsaninja pushed a commit that referenced this issue Feb 21, 2025
This fails at runtime in older versions, and in any case it is an invalid type.

Fixes #531
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants