From: Vladimír Vondruš Date: Thu, 8 Oct 2020 10:51:18 +0000 (+0200) Subject: documentation/python: pile on more workarounds for typing.Union. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=0b94575561f7f1ecc19642e7f3ca680cc71d6eac;p=blog.git documentation/python: pile on more workarounds for typing.Union. SIGH. --- diff --git a/documentation/python.py b/documentation/python.py index 48b0bd6f..af89bfd9 100755 --- a/documentation/python.py +++ b/documentation/python.py @@ -1147,9 +1147,19 @@ def extract_annotation(state: State, referrer_path: List[str], annotation) -> Tu if hasattr(annotation, '__origin__') and annotation.__origin__ is typing.Union: # FOR SOME REASON `annotation.__args__[1] is None` is always False, # so we have to use isinstance(). HOWEVER, we *can't* use - # isinstance if it's a "bracketed" type -- it'll die. So check that - # first. - if len(annotation.__args__) == 2 and not hasattr(annotation.__args__[1], '__args__') and isinstance(None, annotation.__args__[1]): + # isinstance if: + # - it's a "bracketed" type, having __args__ + # (see the `annotation_union_second_bracketed()` test) + # - it's a ForwardRef because get_type_hints_or_nothing() failed + # due to a type error (see the `annotation_union_of_undefined()` + # test) + # because it'll die. So check that first. + if (len(annotation.__args__) == 2 and + not hasattr(annotation.__args__[1], '__args__') and + # Same 3.6 ForwardRef workaround as above + not isinstance(annotation.__args__[1], typing.ForwardRef if sys.version_info >= (3, 7) else typing._ForwardRef) and + isinstance(None, annotation.__args__[1]) + ): name = 'typing.Optional' args = annotation.__args__[:1] else: diff --git a/documentation/test_python/inspect_annotations/inspect_annotations.html b/documentation/test_python/inspect_annotations/inspect_annotations.html index f8275251..494ccc15 100644 --- a/documentation/test_python/inspect_annotations/inspect_annotations.html +++ b/documentation/test_python/inspect_annotations/inspect_annotations.html @@ -115,6 +115,10 @@ def annotation_union(a: typing.Union[float, int])
Annotation with the Union type
+
+ def annotation_union_of_undefined(a: typing.Union[int, something.Undefined]) +
+
Annotation with an union that has an undefined type inside, where we can't use isinstance either
def annotation_union_second_bracketed(a: typing.Union[float, typing.List[int]])
diff --git a/documentation/test_python/inspect_annotations/inspect_annotations.py b/documentation/test_python/inspect_annotations/inspect_annotations.py index 11802cb0..c9b1cf20 100644 --- a/documentation/test_python/inspect_annotations/inspect_annotations.py +++ b/documentation/test_python/inspect_annotations/inspect_annotations.py @@ -65,6 +65,15 @@ def annotation_any(a: Any): def annotation_union(a: Union[float, int]): """Annotation with the Union type""" +def annotation_optional(a: Optional[float]): + """Annotation with the Optional type""" + +def annotation_union_second_bracketed(a: Union[float, List[int]]): + """Annotation with the Union type and second type bracketed, where we can't use isinstance""" + +def annotation_union_of_undefined(a: Union[int, 'something.Undefined']): + """Annotation with an union that has an undefined type inside, where we can't use isinstance either""" + def annotation_list_noparam(a: List): """Annotation with the unparametrized List type. 3.7 adds an implicit TypeVar to it, 3.6 not, emulate that to make the test pass on older versions""" if sys.version_info < (3, 7): @@ -73,12 +82,6 @@ if sys.version_info < (3, 7): def annotation_generic(a: List[_T]) -> _T: """Annotation with a generic type""" -def annotation_optional(a: Optional[float]): - """Annotation with the Optional type""" - -def annotation_union_second_bracketed(a: Union[float, List[int]]): - """Annotation with the Union type and second type bracketed, where we can't use isinstance""" - def annotation_callable(a: Callable[[float, int], str]): """Annotation with the Callable type"""