From: Vladimír Vondruš Date: Thu, 7 May 2020 21:42:05 +0000 (+0200) Subject: documentation/python: more graceful handling of duplicate classes. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=f45a8b060c5cd875da1fe66982025627c2747359;p=blog.git documentation/python: more graceful handling of duplicate classes. Not ideal (as the resulting docs are confusing), but at least something. Creating two copies of the same class could easily lead to infinite recursion in code paths that don't expect it, so not doing that. --- diff --git a/documentation/python.py b/documentation/python.py index 933a4106..08ebcc83 100755 --- a/documentation/python.py +++ b/documentation/python.py @@ -377,10 +377,18 @@ def crawl_enum(state: State, path: List[str], enum_, parent_url): def crawl_class(state: State, path: List[str], class_): assert inspect.isclass(class_) - # TODO: if this fires, it means there's a class duplicated in more than one - # __all__ (or it gets picked up implicitly and then in __all__) -- how to - # handle gracefully? - assert id(class_) not in state.crawled + # If this fires, it means there's a class duplicated in more than one + # __all__ (or it gets picked up implicitly and then in __all__). It usually + # means there's a mess in imports, unfortunately this is more common than + # one would hope so we can't just assert. + if id(class_) in state.crawled: + for name, previous_entry in state.name_map.items(): + if previous_entry.object == class_: break + else: assert False + logging.error("Class %s previously found in %s, only one occurence will be chosen. Ensure each class is exposed only in a single module for generating correct documentation.", '.'.join(path), '.'.join(previous_entry.path)) + state.name_map['.'.join(path)] = previous_entry + return + state.crawled.add(id(class_)) class_entry = Empty() diff --git a/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.Bar.html b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.Bar.html new file mode 100644 index 00000000..8b9fbae5 --- /dev/null +++ b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.Bar.html @@ -0,0 +1,31 @@ + + + + + inspect_duplicate_class.Bar | My Python Project + + + + + +
+
+ + diff --git a/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.html b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.html new file mode 100644 index 00000000..18d4039f --- /dev/null +++ b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.html @@ -0,0 +1,56 @@ + + + + + inspect_duplicate_class | My Python Project + + + + + +
+
+
+
+
+

+ inspect_duplicate_class module +

+
+

Contents

+ +
+
+

Modules

+
+
module sub
+
A submodule.
+
+
+
+

Classes

+
+
class Bar
+
A class present in two modules.
+
+
+
+
+
+
+ + diff --git a/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.sub.html b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.sub.html new file mode 100644 index 00000000..627b3de9 --- /dev/null +++ b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class.sub.html @@ -0,0 +1,49 @@ + + + + + inspect_duplicate_class.sub | My Python Project + + + + + +
+
+ + diff --git a/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class/__init__.py b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class/__init__.py new file mode 100644 index 00000000..4bea8361 --- /dev/null +++ b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class/__init__.py @@ -0,0 +1,4 @@ + +from .sub import Foo as Bar + +__all__ = ['sub', 'Bar'] diff --git a/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class/sub.py b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class/sub.py new file mode 100644 index 00000000..3388acee --- /dev/null +++ b/documentation/test_python/inspect_duplicate_class/inspect_duplicate_class/sub.py @@ -0,0 +1,5 @@ +"""A submodule.""" + +class Foo: + """A class present in two modules.""" + pass diff --git a/documentation/test_python/test_inspect.py b/documentation/test_python/test_inspect.py index 7ecf4278..4fed48f3 100644 --- a/documentation/test_python/test_inspect.py +++ b/documentation/test_python/test_inspect.py @@ -257,3 +257,10 @@ class ValueFormatting(BaseInspectTestCase): def test(self): self.run_python({}) self.assertEqual(*self.actual_expected_contents('inspect_value_formatting.html')) + +class DuplicateClass(BaseInspectTestCase): + def test(self): + self.run_python({}) + self.assertEqual(*self.actual_expected_contents('inspect_duplicate_class.html')) + self.assertEqual(*self.actual_expected_contents('inspect_duplicate_class.sub.html')) + self.assertEqual(*self.actual_expected_contents('inspect_duplicate_class.Bar.html'))