Fix for typing.get_type_hints() on Python 3.9 or lower (#4228)

* fix

* fix docstring

* type hint fix

* fix test

* Update gradio/utils.py

Co-authored-by: Aarni Koskela <akx@iki.fi>

* fix indentation

---------

Co-authored-by: Aarni Koskela <akx@iki.fi>
This commit is contained in:
Abubakar Abid 2023-05-16 14:21:35 -04:00 committed by GitHub
parent 7241cdaf91
commit 6bace9765c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 5 deletions

View File

@ -6,12 +6,14 @@
- Added `format` argument to `Audio` component by [@freddyaboulton](https://github.com/freddyaboulton) in [PR 4178](https://github.com/gradio-app/gradio/pull/4178)
- Add JS client code snippets to use via api page by [@aliabd](https://github.com/aliabd) in [PR 3927](https://github.com/gradio-app/gradio/pull/3927).
## Bug Fixes:
- Fix "TypeError: issubclass() arg 1 must be a class" When use Optional[Types] by [@lingfengchencn](https://github.com/lingfengchencn) in [PR 4200](https://github.com/gradio-app/gradio/pull/4200).
- Gradio will no longer send any analytics if analytics are disabled with the GRADIO_ANALYTICS_ENABLED environment variable. By [@akx](https://github.com/akx) in [PR 4194](https://github.com/gradio-app/gradio/pull/4194)
- The deprecation warnings for kwargs now show the actual stack level for the invocation, by [@akx](https://github.com/akx) in [PR 4203](https://github.com/gradio-app/gradio/pull/4203).
- Fix "TypeError: issubclass() arg 1 must be a class" When use Optional[Types] by [@lingfengchencn](https://github.com/lingfengchencn) in [PR 4200](https://github.com/gradio-app/gradio/pull/4200).
- Fixes a bug with typing.get_type_hints() on Python 3.9 by [@abidlabs](https://github.com/abidlabs) in [PR 4228](https://github.com/gradio-app/gradio/pull/4228).
## Other Changes:

View File

@ -683,11 +683,41 @@ def get_cancel_function(
def get_type_hints(fn):
# Importing gradio with the canonical abbreviation. Used in typing._eval_type.
import gradio as gr # noqa: F401
from gradio import Request # noqa: F401
if inspect.isfunction(fn) or inspect.ismethod(fn):
return typing.get_type_hints(fn)
pass
elif callable(fn):
return typing.get_type_hints(fn.__call__)
return {}
fn = fn.__call__
else:
return {}
try:
return typing.get_type_hints(fn)
except TypeError:
# On Python 3.9 or earlier, get_type_hints throws a TypeError if the function
# has a type annotation that include "|". We resort to parsing the signature
# manually using inspect.signature.
type_hints = {}
sig = inspect.signature(fn)
for name, param in sig.parameters.items():
if param.annotation is inspect.Parameter.empty:
continue
if "|" in str(param.annotation):
continue
# To convert the string annotation to a class, we use the
# internal typing._eval_type function. This is not ideal, but
# it's the only way to do it without eval-ing the string.
# Since the API is internal, it may change in the future.
try:
type_hints[name] = typing._eval_type( # type: ignore
typing.ForwardRef(param.annotation), globals(), locals()
)
except (NameError, TypeError):
pass
return type_hints
def is_special_typed_parameter(name, parameter_types):

View File

@ -1,9 +1,10 @@
from __future__ import annotations
import copy
import os
import sys
import unittest.mock as mock
import warnings
from typing import List
from unittest.mock import MagicMock
import pytest
@ -570,7 +571,7 @@ class TestGetTypeHints:
assert len(get_type_hints(GenericObject())) == 0
def test_is_special_typed_parameter(self):
def func(a: List[str], b: Literal["a", "b"], c, d: Request):
def func(a: list[str], b: Literal["a", "b"], c, d: Request):
pass
hints = get_type_hints(func)
@ -579,6 +580,15 @@ class TestGetTypeHints:
assert not is_special_typed_parameter("c", hints)
assert is_special_typed_parameter("d", hints)
def test_is_special_typed_parameter_with_pipe(self):
def func(a: Request, b: str | int, c: list[str]):
pass
hints = get_type_hints(func)
assert is_special_typed_parameter("a", hints)
assert not is_special_typed_parameter("b", hints)
assert not is_special_typed_parameter("c", hints)
class TestCheckFunctionInputsMatch:
def test_check_function_inputs_match(self):