aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests/test_imports_resolve.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/tests/test_imports_resolve.py')
-rw-r--r--packages/meshbay-node/tests/test_imports_resolve.py38
1 files changed, 38 insertions, 0 deletions
diff --git a/packages/meshbay-node/tests/test_imports_resolve.py b/packages/meshbay-node/tests/test_imports_resolve.py
new file mode 100644
index 0000000..2d6610b
--- /dev/null
+++ b/packages/meshbay-node/tests/test_imports_resolve.py
@@ -0,0 +1,38 @@
+"""
+Every `from meshbay_… import NAME` in the node's source names something that
+exists — including the imports inside function bodies, which nothing loads
+until that function runs.
+
+When code moves between modules, an import at the top of a file breaks at
+once, and loudly. One inside a function breaks the first time somebody clicks
+the button that calls it: the Peers tab answered 500 that way after
+`_get_remote_ip` left `webrtc_server.py`.
+"""
+
+import ast
+import importlib
+from pathlib import Path
+
+SRC = Path(__file__).resolve().parents[1] / "src"
+
+
+def test_every_import_in_the_node_names_something_that_exists():
+ missing, checked = [], 0
+ for path in sorted(SRC.rglob("*.py")):
+ tree = ast.parse(path.read_text(encoding="utf-8"))
+ for node in ast.walk(tree):
+ if not (isinstance(node, ast.ImportFrom) and node.level == 0
+ and node.module and node.module.startswith("meshbay_")):
+ continue
+ module = importlib.import_module(node.module)
+ for alias in node.names:
+ checked += 1
+ if alias.name == "*" or hasattr(module, alias.name):
+ continue
+ try:
+ importlib.import_module(f"{node.module}.{alias.name}")
+ except ImportError:
+ missing.append(f"{path.relative_to(SRC)}:{node.lineno} "
+ f"{node.module}.{alias.name}")
+ assert checked > 300, "the walk found almost nothing to check"
+ assert not missing, "imports of names that do not exist:\n" + "\n".join(missing)