Skip to content

Commit 2078746

Browse files
authored
chore: Add test to verify shiny isn't importing itself internally (#1921)
1 parent 51693b8 commit 2078746

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

tests/pytest/test_shiny_import.py

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from __future__ import annotations
2+
3+
import glob
4+
from pathlib import Path
5+
6+
from tests.pytest._utils import skip_on_windows
7+
8+
9+
class BadLine:
10+
def __init__(self, path: Path, line_number: int, line_text: str):
11+
self.path = path
12+
self.line_number = line_number
13+
self.line_text = line_text
14+
15+
def __repr__(self):
16+
return f"{self.path}:{self.line_number} - {self.line_text}"
17+
18+
19+
@skip_on_windows
20+
def test_shiny_import_itself():
21+
"""
22+
VSCode likes to import from the shiny module itself within the shiny package. While it works... it relies on import magic, not relative imports.
23+
24+
Bad: `from shiny import ui`
25+
Good: `from . import ui`
26+
"""
27+
28+
root_here = Path(__file__).parent.parent.parent
29+
shiny_files = glob.glob(str(root_here / "shiny" / "**" / "*.py"), recursive=True)
30+
31+
shiny_files = [
32+
path
33+
for path in shiny_files
34+
if "/api-examples/" not in path
35+
and "/templates/" not in path
36+
and Path(path).is_file()
37+
]
38+
39+
assert len(shiny_files) > 0
40+
41+
# bad_entries: list[tuple[Path, int, str]] = []
42+
bad_entries: list[BadLine] = []
43+
44+
# For every python file...
45+
for path in shiny_files:
46+
path = Path(path)
47+
48+
file_txt = path.read_text(encoding="utf-8")
49+
while True:
50+
if "\ndef " in file_txt:
51+
file_txt = file_txt.split("\ndef ")[0]
52+
elif "\nasync def " in file_txt:
53+
file_txt = file_txt.split("\nasync def ")[0]
54+
elif "\nclass " in file_txt:
55+
file_txt = file_txt.split("\nclass ")[0]
56+
else:
57+
break
58+
59+
for search_txt in ("\nfrom shiny.", "\nfrom shiny ", "\nimport shiny\n"):
60+
if search_txt == "\nimport shiny\n" and path.name.endswith("_main.py"):
61+
# skip shiny/_main.py file
62+
continue
63+
64+
if search_txt in file_txt:
65+
66+
for i, line in enumerate(file_txt.split("\n")):
67+
if line.startswith(search_txt.strip()):
68+
# bad_entries.append((path.relative_to(root_here), i + 1, line))
69+
bad_entries.append(
70+
BadLine(path.relative_to(root_here), i + 1, line)
71+
)
72+
73+
if len(bad_entries) > 0:
74+
print("Bad entries found:")
75+
for entry in bad_entries:
76+
print(entry)
77+
# Ensure no bad entries exist
78+
assert (
79+
len(bad_entries) == 0
80+
), "Unexpected shiny files containing `from shiny.FOO import BAR`, `from shiny import FOO`, or `import shiny`"

0 commit comments

Comments
 (0)