From 1618f83e683449a00ec00db00ee6bae772edfeba Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Thu, 23 Apr 2020 13:03:19 -0700 Subject: [PATCH 01/10] fix root level namespace issues --- src/pytkdocs/objects.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/pytkdocs/objects.py b/src/pytkdocs/objects.py index 751e675..e776f1d 100644 --- a/src/pytkdocs/objects.py +++ b/src/pytkdocs/objects.py @@ -173,20 +173,26 @@ def relative_file_path(self) -> str: If the relative file path cannot be determined, the value returned is `""` (empty string). """ - top_package_name = self.path.split(".", 1)[0] - try: - top_package = sys.modules[top_package_name] - except KeyError: + + subspace_count = len(self.path.split(".")) + namespaces = [".".join(self.path.split(".", maxsplit=maxsplit)[:-1]) for maxsplit in range(1, subspace_count)] + + for namespace in namespaces: try: - importlib.import_module(top_package_name) - except ImportError: + top_package = sys.modules[namespace] + except KeyError: + try: + importlib.import_module(namespace) + except ImportError: + return "" + top_package = sys.modules[namespace] + try: + top_package_path = Path(inspect.getabsfile(top_package)).parent + return str(Path(self.file_path).relative_to(top_package_path.parent)) + except ValueError: return "" - top_package = sys.modules[top_package_name] - top_package_path = Path(inspect.getabsfile(top_package)).parent - try: - return str(Path(self.file_path).relative_to(top_package_path.parent)) - except ValueError: - return "" + except TypeError: + pass @property def name_to_check(self) -> str: From 93615816f301c8d9f86da1bc104490e8ac7fd34f Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Thu, 23 Apr 2020 13:39:26 -0700 Subject: [PATCH 02/10] return empty_string if loop finishes. --- src/pytkdocs/objects.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pytkdocs/objects.py b/src/pytkdocs/objects.py index e776f1d..ff0d24e 100644 --- a/src/pytkdocs/objects.py +++ b/src/pytkdocs/objects.py @@ -194,6 +194,8 @@ def relative_file_path(self) -> str: except TypeError: pass + return "" + @property def name_to_check(self) -> str: """The attribute to check against name properties regular expressions (private, class-private, special).""" From 62b17ff3fd69a72ee4cce0775a568b02e9ee0927 Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Thu, 23 Apr 2020 13:40:20 -0700 Subject: [PATCH 03/10] more efficient namespace itteration --- src/pytkdocs/objects.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pytkdocs/objects.py b/src/pytkdocs/objects.py index ff0d24e..65c58bd 100644 --- a/src/pytkdocs/objects.py +++ b/src/pytkdocs/objects.py @@ -174,8 +174,8 @@ def relative_file_path(self) -> str: If the relative file path cannot be determined, the value returned is `""` (empty string). """ - subspace_count = len(self.path.split(".")) - namespaces = [".".join(self.path.split(".", maxsplit=maxsplit)[:-1]) for maxsplit in range(1, subspace_count)] + parts = self.path.split(".") + namespaces = [".".join(parts[:l]) for l in range(1, len(parts))] for namespace in namespaces: try: From a74349fbe2a0e314d1e59b4275ea9b91a6f906aa Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Thu, 23 Apr 2020 13:48:43 -0700 Subject: [PATCH 04/10] more readable code and documentation --- src/pytkdocs/objects.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/pytkdocs/objects.py b/src/pytkdocs/objects.py index 65c58bd..a79ea0f 100644 --- a/src/pytkdocs/objects.py +++ b/src/pytkdocs/objects.py @@ -179,20 +179,24 @@ def relative_file_path(self) -> str: for namespace in namespaces: try: + importlib.import_module(namespace) top_package = sys.modules[namespace] - except KeyError: - try: - importlib.import_module(namespace) - except ImportError: - return "" - top_package = sys.modules[namespace] + except (KeyError, ImportError): + """ + Triggered if we can't import the package via importlib + Or if package isn't findable by it's canonical name even after importing + """ + return "" + try: top_package_path = Path(inspect.getabsfile(top_package)).parent return str(Path(self.file_path).relative_to(top_package_path.parent)) - except ValueError: - return "" except TypeError: + # Triggered if getabsfile() can't be found in the case of a Namespace package pass + except ValueError: + # Triggered if Path().relative_to can't find an appropriate path + return "" return "" From c5261b3964cf9e7aa028634c5c05facf5eadc207 Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Thu, 23 Apr 2020 13:59:32 -0700 Subject: [PATCH 05/10] update comment format --- src/pytkdocs/objects.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pytkdocs/objects.py b/src/pytkdocs/objects.py index a79ea0f..644f862 100644 --- a/src/pytkdocs/objects.py +++ b/src/pytkdocs/objects.py @@ -182,10 +182,10 @@ def relative_file_path(self) -> str: importlib.import_module(namespace) top_package = sys.modules[namespace] except (KeyError, ImportError): - """ - Triggered if we can't import the package via importlib - Or if package isn't findable by it's canonical name even after importing - """ + # ImportError: Triggered if the package is not importable + # KeyError: Triggered if the imported package isn't referenced under the same fully qualified name + # Namespace packages are importable, so this should work for them + return "" try: From 82ade97807e01c837aee028cb67f1fd51c35d890 Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Sat, 25 Apr 2020 09:00:34 -0700 Subject: [PATCH 06/10] add namespace fixture --- tests/fixtures/test_namespace/subspace/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/fixtures/test_namespace/subspace/__init__.py diff --git a/tests/fixtures/test_namespace/subspace/__init__.py b/tests/fixtures/test_namespace/subspace/__init__.py new file mode 100644 index 0000000..3097a32 --- /dev/null +++ b/tests/fixtures/test_namespace/subspace/__init__.py @@ -0,0 +1 @@ +"The subspace package docstring." From e5b30f8448f87f9884c7112540761be7455eaa3e Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Sat, 25 Apr 2020 09:01:44 -0700 Subject: [PATCH 07/10] add test for namespace package loading --- tests/test_loader.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_loader.py b/tests/test_loader.py index a2d4fda..7a4a6cf 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -1,11 +1,14 @@ """Tests for [the `loader` module][pytkdocs.loader].""" import sys +from pathlib import Path import pytest from pytkdocs.loader import Loader, get_object_tree +from . import FIXTURES_DIR + def test_import_no_path(): with pytest.raises(ValueError): @@ -82,6 +85,15 @@ def test_loading_package(): assert obj.docstring == "The package docstring." +def test_loading_namespace_package(): + loader = Loader() + old_paths = list(sys.path) + sys.path.append(str(Path(FIXTURES_DIR).resolve())) + obj = loader.get_object_documentation("test_namespace.subspace") + assert obj.docstring == "The subspace package docstring." + sys.path = old_paths + + def test_loading_module(): loader = Loader() obj = loader.get_object_documentation("tests.fixtures.the_package.the_module") From bd0b4b3c172a9d118464d43a57b8582e69f658b6 Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Sat, 25 Apr 2020 10:45:41 -0700 Subject: [PATCH 08/10] check the relative_file_path --- tests/test_loader.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_loader.py b/tests/test_loader.py index 7a4a6cf..2dfa22a 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -91,6 +91,7 @@ def test_loading_namespace_package(): sys.path.append(str(Path(FIXTURES_DIR).resolve())) obj = loader.get_object_documentation("test_namespace.subspace") assert obj.docstring == "The subspace package docstring." + assert obj.relative_file_path == "subspace/__init__.py" sys.path = old_paths From abd9ba713048bb8447eae7b8557e4d083e7f9e0b Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Sat, 25 Apr 2020 10:47:01 -0700 Subject: [PATCH 09/10] iterate all sub namespaces even if its a module --- src/pytkdocs/objects.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pytkdocs/objects.py b/src/pytkdocs/objects.py index 644f862..ec5f4db 100644 --- a/src/pytkdocs/objects.py +++ b/src/pytkdocs/objects.py @@ -175,17 +175,17 @@ def relative_file_path(self) -> str: """ parts = self.path.split(".") - namespaces = [".".join(parts[:l]) for l in range(1, len(parts))] - + namespaces = [".".join(parts[:l]) for l in range(1, len(parts) + 1)] + # Itterate through all sub namespaces including the last incase its a module for namespace in namespaces: try: importlib.import_module(namespace) top_package = sys.modules[namespace] - except (KeyError, ImportError): - # ImportError: Triggered if the package is not importable + except (ImportError, ModuleNotFoundError, KeyError): + # ImportError: Triggered if the namespace is not importable + # ModuleNotFoundError: Triggered if the namespace is not a module # KeyError: Triggered if the imported package isn't referenced under the same fully qualified name # Namespace packages are importable, so this should work for them - return "" try: From 9de9579f4c810a5b0135d8a16989f9ebc913f11d Mon Sep 17 00:00:00 2001 From: Shyam Dwaraknath Date: Sat, 25 Apr 2020 11:13:27 -0700 Subject: [PATCH 10/10] fix typos --- src/pytkdocs/objects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pytkdocs/objects.py b/src/pytkdocs/objects.py index ec5f4db..6ec23d0 100644 --- a/src/pytkdocs/objects.py +++ b/src/pytkdocs/objects.py @@ -176,7 +176,7 @@ def relative_file_path(self) -> str: parts = self.path.split(".") namespaces = [".".join(parts[:l]) for l in range(1, len(parts) + 1)] - # Itterate through all sub namespaces including the last incase its a module + # Iterate through all sub namespaces including the last in case it is a module for namespace in namespaces: try: importlib.import_module(namespace)