diff --git a/CHANGELOG.md b/CHANGELOG.md index 7398e6d4..a91699d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ## Unreleased: pdoc next +- pdoc now strips `collections.abc.` from type annotations to make them more concise. + ([#736](https://github.com/mitmproxy/pdoc/pull/736), @mhils) ## 2024-08-27: pdoc 14.6.1 diff --git a/pdoc/doc.py b/pdoc/doc.py index 32730edf..5f3c881e 100644 --- a/pdoc/doc.py +++ b/pdoc/doc.py @@ -1132,9 +1132,11 @@ def default_value_str(self) -> str: if self.default_value is empty: return "" if isinstance(self.default_value, TypeAliasType): - return formatannotation(self.default_value.__value__) + formatted = formatannotation(self.default_value.__value__) + return _remove_collections_abc(formatted) elif self.annotation == TypeAlias: - return formatannotation(self.default_value) + formatted = formatannotation(self.default_value) + return _remove_collections_abc(formatted) # This is not perfect, but a solid attempt at preventing accidental leakage of secrets. # If you have input on how to improve the heuristic, please send a pull request! @@ -1166,7 +1168,8 @@ def default_value_str(self) -> str: def annotation_str(self) -> str: """The variable's type annotation as a pretty-printed str.""" if self.annotation is not empty: - return f": {formatannotation(self.annotation)}" + formatted = formatannotation(self.annotation) + return f": {_remove_collections_abc(formatted)}" else: return "" @@ -1202,6 +1205,7 @@ def _params(self) -> list[str]: for param in self.parameters.values(): formatted = str(param) formatted = _remove_memory_addresses(formatted) + formatted = _remove_collections_abc(formatted) kind = param.kind @@ -1238,7 +1242,8 @@ def _params(self) -> list[str]: def _return_annotation_str(self) -> str: if self.return_annotation is not empty: - return formatannotation(self.return_annotation) + formatted = formatannotation(self.return_annotation) + return _remove_collections_abc(formatted) else: return "" @@ -1333,3 +1338,8 @@ def _safe_getdoc(obj: Any) -> str: def _remove_memory_addresses(x: str) -> str: """Remove memory addresses from repr() output""" return re.sub(r" at 0x[0-9a-fA-F]+(?=>)", "", x) + + +def _remove_collections_abc(x: str) -> str: + """Remove 'collections.abc' from type signatures.""" + return re.sub(r"(?!\.)\bcollections\.abc\.", "", x) diff --git a/test/test_snapshot.py b/test/test_snapshot.py index 04bd8e56..be3c0a65 100755 --- a/test/test_snapshot.py +++ b/test/test_snapshot.py @@ -96,6 +96,7 @@ def outfile(self, format: str) -> Path: snapshots = [ Snapshot("ast_parsing"), + Snapshot("collections_abc", min_version=(3, 9)), Snapshot("demo", min_version=(3, 9)), Snapshot("enums", min_version=(3, 12)), Snapshot("flavors_google"), diff --git a/test/testdata/collections_abc.html b/test/testdata/collections_abc.html new file mode 100644 index 00000000..bc92da9d --- /dev/null +++ b/test/testdata/collections_abc.html @@ -0,0 +1,147 @@ + + + + + + + collections_abc API documentation + + + + + + + + + +
+
+

+collections_abc

+ +

Test that we remove 'collections.abc' from type signatures.

+
+ + + + + +
 1"""Test that we remove 'collections.abc' from type signatures."""
+ 2
+ 3from collections.abc import Awaitable
+ 4from collections.abc import Container
+ 5
+ 6
+ 7def func(bar: Awaitable[None]) -> Awaitable[None]:
+ 8    return bar
+ 9
+10
+11class Class(Container[str]):
+12    """
+13    For subclasses, we currently display the full classname.
+14    Mostly because it's easier, but it also makes a bit more sense here.
+15    """
+16
+17    def __contains__(self, item):
+18        return item == "Bar"
+19
+20
+21var: Container[str] = "baz"
+
+ + +
+
+ +
+ + def + func(bar: Awaitable[None]) -> Awaitable[None]: + + + +
+ +
8def func(bar: Awaitable[None]) -> Awaitable[None]:
+9    return bar
+
+ + + + +
+
+ +
+ + class + Class(collections.abc.Container[str]): + + + +
+ +
12class Class(Container[str]):
+13    """
+14    For subclasses, we currently display the full classname.
+15    Mostly because it's easier, but it also makes a bit more sense here.
+16    """
+17
+18    def __contains__(self, item):
+19        return item == "Bar"
+
+ + +

For subclasses, we currently display the full classname. +Mostly because it's easier, but it also makes a bit more sense here.

+
+ + +
+
+
+ var: Container[str] = +'baz' + + +
+ + + + +
+
+ + \ No newline at end of file diff --git a/test/testdata/collections_abc.py b/test/testdata/collections_abc.py new file mode 100644 index 00000000..09324ed6 --- /dev/null +++ b/test/testdata/collections_abc.py @@ -0,0 +1,21 @@ +"""Test that we remove 'collections.abc' from type signatures.""" + +from collections.abc import Awaitable +from collections.abc import Container + + +def func(bar: Awaitable[None]) -> Awaitable[None]: + return bar + + +class Class(Container[str]): + """ + For subclasses, we currently display the full classname. + Mostly because it's easier, but it also makes a bit more sense here. + """ + + def __contains__(self, item): + return item == "Bar" + + +var: Container[str] = "baz" diff --git a/test/testdata/collections_abc.txt b/test/testdata/collections_abc.txt new file mode 100644 index 00000000..df60323e --- /dev/null +++ b/test/testdata/collections_abc.txt @@ -0,0 +1,7 @@ + Awaitable[None]: ...> + + > + +> \ No newline at end of file