Skip to content

Commit 3187fda

Browse files
committed
test tweaks
1 parent 0661301 commit 3187fda

File tree

7 files changed

+124
-39
lines changed

7 files changed

+124
-39
lines changed

profiling/profile.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"env": {
44
"django_typer": [
55
3,
6-
3,
7-
0
6+
2,
7+
2
88
],
99
"python": [
1010
3,

profiling/profile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ def polls_table():
468468
RunKey(cmd="polls", typer=True, app=True, rich=True, help=True),
469469
),
470470
(
471-
"shellcompletion (rich)",
471+
"shell completion (rich)",
472472
RunKey(
473473
cmd="shellcompletion", typer=True, app=True, rich=True, help=False
474474
),

src/django_typer/patch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def apply() -> None:
4848
PATCH_APPLIED = True
4949

5050
try:
51-
# Django as of <=5.0 calls colorama.init() if colorama is installed
51+
# Django calls colorama.init() if colorama is installed
5252
# this screws up forced terminals on platforms other than windows that
5353
# are not attached to ttys. Upstream Django should change the init
5454
# call to a just_fix_windows_console - we undo this and redo the right

tests/apps/perf_no_typer/management/commands/perf.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ class Command(BaseCommand):
99

1010
def add_arguments(self, parser: CommandParser) -> None:
1111
parser.add_argument("test_arg", type=int)
12-
parser.add_argument("--test-option", action="store_true")
12+
parser.add_argument("--print", action="store_true")
1313
return super().add_arguments(parser)
1414

15-
def handle(self, test_arg, test_option, **_):
16-
return json.dumps(
17-
{
18-
"no_typer": test_arg,
19-
"test_option": test_option,
20-
"modules": list(sys.modules.keys()),
21-
}
22-
)
15+
def handle(self, test_arg, print, **_):
16+
if print:
17+
return json.dumps(
18+
{
19+
"no_typer": test_arg,
20+
"print": print,
21+
"modules": list(sys.modules.keys()),
22+
}
23+
)

tests/apps/perf_typer/management/commands/perf.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ class Command(TyperCommand):
77
requires_system_checks = []
88
requires_migrations_checks = False
99

10-
def handle(self, test_arg: int, test_option: bool = False):
11-
return json.dumps(
12-
{
13-
"typer": test_arg,
14-
"test_option": test_option,
15-
"modules": list(sys.modules.keys()),
16-
}
17-
)
10+
def handle(self, test_arg: int, print: bool = False):
11+
if print:
12+
return json.dumps(
13+
{
14+
"typer": test_arg,
15+
"print": print,
16+
"modules": list(sys.modules.keys()),
17+
}
18+
)

tests/test_perf.py

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pytest
55
from pprint import pformat
66
from .utils import rich_installed
7+
import platform
78

89

910
@pytest.mark.no_rich
@@ -27,13 +28,13 @@ def test_performance_regression():
2728
result, stderr, retcode = run_command(
2829
"perf",
2930
"5",
30-
"--test-option",
31+
"--print",
3132
env={**env, "DJANGO_SETTINGS_MODULE": "tests.settings.perf_no_typer"},
3233
)
3334
end = time.perf_counter()
3435
if retcode:
3536
pytest.fail(stderr)
36-
assert result["test_option"]
37+
assert result["print"]
3738
assert result["no_typer"] == 5
3839
mods_no_typer = result["modules"]
3940
no_typer_time = end - start
@@ -42,13 +43,13 @@ def test_performance_regression():
4243
result, stderr, retcode = run_command(
4344
"perf",
4445
"5",
45-
"--test-option",
46+
"--print",
4647
env={**env, "DJANGO_SETTINGS_MODULE": "tests.settings.perf_typer"},
4748
)
4849
end = time.perf_counter()
4950
if retcode:
5051
pytest.fail(stderr)
51-
assert result["test_option"]
52+
assert result["print"]
5253
assert result["typer"] == 5
5354
mods_typer = result["modules"]
5455
typer_time = end - start
@@ -57,13 +58,13 @@ def test_performance_regression():
5758
result, stderr, retcode = run_command(
5859
"perf",
5960
"5",
60-
"--test-option",
61+
"--print",
6162
env={**env, "DJANGO_SETTINGS_MODULE": "tests.settings.perf_typer_no_app"},
6263
)
6364
end = time.perf_counter()
6465
if retcode:
6566
pytest.fail(stderr)
66-
assert result["test_option"]
67+
assert result["print"]
6768
assert result["typer"] == 5
6869
mods_typer_no_app = result["modules"]
6970
typer_no_app_time = end - start
@@ -89,6 +90,68 @@ def test_performance_regression():
8990
f"Typer modules added: \n{pformat(set(mods_typer_no_app) - set(mods_no_typer))}"
9091
)
9192

92-
# notify us if adding typer inflates command exec time by more than 50 percent
93-
assert no_typer_time / typer_time > 0.5
94-
assert no_typer_time / typer_no_app_time > 0.5
93+
# notify us if adding typer inflates command exec time by more than 20 percent
94+
assert no_typer_time / typer_time > 0.2
95+
assert no_typer_time / typer_no_app_time > 0.2
96+
97+
98+
@pytest.mark.no_rich
99+
@pytest.mark.skipif(
100+
rich_installed, reason="Rich should not be installed to test module bloat."
101+
)
102+
@pytest.mark.skipif(platform.system() != "Darwin", reason="Test is only for macOS")
103+
def test_timing():
104+
env = dict(os.environ)
105+
# disable coverage
106+
for var in [
107+
"COVERAGE_PROCESS_START",
108+
"COV_CORE_SOURCE",
109+
"COV_CORE_CONFIG",
110+
"COV_CORE_DATAFILE",
111+
"PYTEST_XDIST_WORKER",
112+
]:
113+
env.pop(var, None)
114+
115+
result, stderr, retcode, no_typer_seconds = run_command(
116+
"perf",
117+
"5",
118+
env={**env, "DJANGO_SETTINGS_MODULE": "tests.settings.perf_no_typer"},
119+
time=True,
120+
)
121+
if retcode:
122+
pytest.fail(stderr)
123+
assert not result, "perf should not have printed"
124+
125+
result, stderr, retcode, typer_seconds = run_command(
126+
"perf",
127+
"5",
128+
env={**env, "DJANGO_SETTINGS_MODULE": "tests.settings.perf_typer"},
129+
time=True,
130+
)
131+
if retcode:
132+
pytest.fail(stderr)
133+
assert not result, "perf should not have printed"
134+
135+
result, stderr, retcode, typer_no_app_seconds = run_command(
136+
"perf",
137+
"5",
138+
env={**env, "DJANGO_SETTINGS_MODULE": "tests.settings.perf_typer_no_app"},
139+
time=True,
140+
)
141+
if retcode:
142+
pytest.fail(stderr)
143+
assert not result, "perf should not have printed"
144+
145+
# print the stats
146+
print("\nWithout typer:\n\t")
147+
print(f"\ttime: {no_typer_seconds:0.4f}")
148+
149+
print("\nWith typer:\n\t")
150+
print(f"\ttime: {typer_seconds:0.4f}")
151+
152+
print("\nWith typer, but app not installed:\n\t")
153+
print(f"\ttime: {typer_no_app_seconds:0.4f}")
154+
155+
# notify us if adding typer inflates command exec time by more than 20 percent
156+
assert no_typer_seconds / typer_seconds > 0.2
157+
assert no_typer_seconds / typer_no_app_seconds > 0.2

tests/utils.py

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ def interact(command, *args, **kwargs):
162162

163163

164164
def run_command(
165-
command, *args, parse_json=True, chdir=True, **kwargs
166-
) -> Tuple[str, str, int]:
165+
command, *args, parse_json=True, chdir=True, time=False, **kwargs
166+
) -> Union[Tuple[str, str, int], Tuple[str, str, int, float]]:
167167
# we want to use the same test database that was created for the test suite run
168168
cwd = os.getcwd()
169169
try:
@@ -173,13 +173,17 @@ def run_command(
173173
env["PYTHONUTF8"] = "1"
174174
if chdir:
175175
os.chdir(manage_py.parent)
176+
cmd = [
177+
sys.executable,
178+
f"./{manage_py.name}" if chdir else manage_py,
179+
command,
180+
*args,
181+
]
182+
time_seconds = 0.0
183+
if time:
184+
cmd.insert(0, "time")
176185
result = subprocess.run(
177-
[
178-
sys.executable,
179-
f"./{manage_py.name}" if chdir else manage_py,
180-
command,
181-
*args,
182-
],
186+
cmd,
183187
capture_output=True,
184188
text=False,
185189
env=env,
@@ -193,6 +197,8 @@ def run_command(
193197
"utf-8" # getattr(from_bytes(result.stderr).best(), "encoding", "utf-8")
194198
)
195199
stderr = result.stderr.decode(stderr_encoding)
200+
if time:
201+
time_seconds = float(stderr.split("real")[0].strip())
196202

197203
# Check the return code to ensure the script ran successfully
198204
if result.returncode != 0:
@@ -202,10 +208,24 @@ def run_command(
202208
if result.stdout:
203209
if parse_json:
204210
try:
205-
return json.loads(stdout), stderr, result.returncode
211+
if time:
212+
return (
213+
json.loads(stdout),
214+
stderr,
215+
result.returncode,
216+
time_seconds,
217+
)
218+
else:
219+
return json.loads(stdout), stderr, result.returncode
206220
except json.JSONDecodeError:
221+
if time:
222+
return stdout, stderr, result.returncode, time_seconds
207223
return stdout, stderr, result.returncode
224+
if time:
225+
return stdout, stderr, result.returncode, time_seconds
208226
return stdout, stderr, result.returncode
227+
if time:
228+
return stdout, stderr, result.returncode, time_seconds
209229
return stdout, stderr, result.returncode
210230
finally:
211231
os.chdir(cwd)

0 commit comments

Comments
 (0)