From: Vladimír Vondruš Date: Sun, 14 Jul 2019 10:51:25 +0000 (+0200) Subject: documentation/python: properly handle invalid annotation types. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=776e42d2883c037dbc5a47fae4e0f39053a14835;p=blog.git documentation/python: properly handle invalid annotation types. Such as using a tuple instead of Tuple or putting a function there instead of a type. --- diff --git a/documentation/python.py b/documentation/python.py index 38b3532f..2b03d11d 100755 --- a/documentation/python.py +++ b/documentation/python.py @@ -773,7 +773,7 @@ def extract_annotation(state: State, referrer_path: List[str], annotation) -> st # If the annotation is from the typing module, it could be a "bracketed" # type, in which case we want to recurse to its types as well. Otherwise # just get its name. - elif annotation.__module__ == 'typing': + elif hasattr(annotation, '__module__') and annotation.__module__ == 'typing': if sys.version_info >= (3, 7): name = annotation._name elif annotation is typing.Any: @@ -785,6 +785,12 @@ def extract_annotation(state: State, referrer_path: List[str], annotation) -> st else: return 'typing.' + name + # Things like (float, int) instead of Tuple[float, int] or using np.array + # instead of np.ndarray. Ignore with a warning. + elif not isinstance(annotation, type): + logging.warning("invalid annotation %s in %s, ignoring", annotation, '.'.join(referrer_path)) + return None + # Otherwise it's a plain type. Turn it into a link. return make_name_link(state, referrer_path, map_name_prefix(state, extract_type(annotation))) diff --git a/documentation/test_python/inspect_annotations/inspect_annotations.html b/documentation/test_python/inspect_annotations/inspect_annotations.html index f7d3b198..070c5491 100644 --- a/documentation/test_python/inspect_annotations/inspect_annotations.html +++ b/documentation/test_python/inspect_annotations/inspect_annotations.html @@ -57,6 +57,14 @@ third: str = 'hello') -> Foo
An annotated function
+
+ def annotation_func_instead_of_type(a) +
+
Annotation with a function instead of a type, ignored
+
+ def annotation_tuple_instead_of_tuple(a) +
+
Annotation with a tuple instead of Tuple, ignored
def args_kwargs(a, b, *args, **kwargs)
diff --git a/documentation/test_python/inspect_annotations/inspect_annotations.py b/documentation/test_python/inspect_annotations/inspect_annotations.py index fbf143fc..bde1f3e9 100644 --- a/documentation/test_python/inspect_annotations/inspect_annotations.py +++ b/documentation/test_python/inspect_annotations/inspect_annotations.py @@ -30,6 +30,12 @@ def partial_annotation(foo, param: Tuple[int, int], unannotated, cls: Foo): """Partially annotated function""" pass +def annotation_tuple_instead_of_tuple(a: (float, int)): + """Annotation with a tuple instead of Tuple, ignored""" + +def annotation_func_instead_of_type(a: open): + """Annotation with a function instead of a type, ignored""" + # Only possible with native code now, https://www.python.org/dev/peps/pep-0570/ #def positionals_only(positional_only, /, positional_kw): #"""Function with explicitly delimited positional args"""