Skip to content

Commit 34769a3

Browse files
committed
fix #206 fix #207
1 parent 55d1251 commit 34769a3

File tree

8 files changed

+103
-24
lines changed

8 files changed

+103
-24
lines changed

doc/source/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Change Log
77
v3.1.0 (2024-03-31)
88
===================
99

10+
* Fixed `Fish shell completion fails for any script named something other than "manage" <https://github.com/django-commons/django-typer/issues/207>`_
11+
* Fixed `shellcompletion install fails on fish when the command resolves to a script path <https://github.com/django-commons/django-typer/issues/206>`_
1012
* Implemented `Add completer for settings names. <https://github.com/django-commons/django-typer/issues/203>`_
1113
* Fixed `Shell completion tests let failures through in CI <https://github.com/django-commons/django-typer/issues/194>`_
1214
* Fixed `fish completion installs should respect XDG_CONFIG_HOME <https://github.com/django-commons/django-typer/issues/193>`_

src/django_typer/templates/shell_complete/fish.fish

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ function __fish_{{prog_name}}_complete
4444
end;
4545
end
4646

47-
complete -c {{ manage_script_name }} --no-files --arguments '(__fish_manage_complete)'
47+
complete -c {{ manage_script_name }} --no-files --arguments '(__fish_{{prog_name}}_complete)'

src/django_typer/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def get_usage_script(script: t.Optional[str] = None) -> t.Union[Path, str]:
7474
if (
7575
on_path
7676
and on_path.is_absolute()
77-
and (on_path != cmd_pth.absolute() or not cmd_pth.is_file())
77+
and (on_path == cmd_pth.absolute() or not cmd_pth.is_file())
7878
):
7979
return cmd_pth.name
8080
try:

tests/shellcompletion/__init__.py

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,8 @@ class _InstalledScriptCompleteTestCase(_CompleteTestCase):
433433
"""
434434

435435
MANAGE_SCRIPT_TMPL = Path(__file__).parent / "django_manage.py"
436-
manage_script = "django_manage"
437-
launch_script = "django_manage"
436+
manage_script = "django-admin"
437+
launch_script = "django-admin"
438438

439439
@classmethod
440440
def setUpClass(cls):
@@ -505,7 +505,11 @@ def test_multi_install(self):
505505
def test_prompt_install(self, env={}, directory: t.Optional[Path] = None):
506506
import pexpect
507507

508-
env = {**dict(os.environ), **env}
508+
env = {
509+
**dict(os.environ),
510+
"DJANGO_SETTINGS_MODULE": "tests.settings.completion",
511+
**env,
512+
}
509513

510514
rex = re.compile
511515
expected = [
@@ -560,3 +564,76 @@ def wait_for_output(child) -> t.Tuple[int, t.Optional[str]]:
560564
break
561565

562566
self.verify_install(directory=directory)
567+
568+
else:
569+
570+
def test_prompt_install(self, env={}, directory: t.Optional[Path] = None):
571+
env = {
572+
**dict(os.environ),
573+
"DJANGO_SETTINGS_MODULE": "tests.settings.completion",
574+
**env,
575+
}
576+
577+
rex = re.compile
578+
expected_patterns = [
579+
rex(r"Append the above contents to (?P<file>.*)\?"), # 0
580+
rex(r"Create (?P<file>.*) with the above contents\?"), # 1
581+
rex(r"Aborted shell completion installation."), # 2
582+
rex(rf"Installed autocompletion for {self.shell}"), # 3
583+
]
584+
585+
install_command = [
586+
self.manage_script,
587+
"shellcompletion",
588+
"--no-color",
589+
"--shell",
590+
self.shell,
591+
"install",
592+
]
593+
self.remove()
594+
self.verify_remove(directory=directory)
595+
596+
def run_with_response(responses: t.List[str]):
597+
process = subprocess.Popen(
598+
install_command,
599+
env=env,
600+
cwd=directory,
601+
stdin=subprocess.PIPE,
602+
stdout=subprocess.PIPE,
603+
stderr=subprocess.STDOUT,
604+
text=True,
605+
)
606+
607+
output = ""
608+
for response in responses:
609+
while True:
610+
line = process.stdout.readline()
611+
if not line:
612+
break
613+
output += line
614+
615+
matched_index, matched_file = match_output(line)
616+
if matched_index is not None:
617+
process.stdin.write(response + "\n")
618+
process.stdin.flush()
619+
break
620+
621+
process.wait()
622+
return output
623+
624+
def match_output(line: str) -> t.Tuple[t.Optional[int], t.Optional[str]]:
625+
for i, pattern in enumerate(expected_patterns):
626+
match = pattern.search(line)
627+
if match:
628+
return i, match.groupdict().get("file")
629+
return None, None
630+
631+
# Test abort sequence
632+
abort_output = run_with_response(["N", "N"])
633+
self.assertIn("Aborted shell completion installation.", abort_output)
634+
self.verify_remove(directory=directory)
635+
636+
# Test install sequence
637+
install_output = run_with_response(["Y", "Y"])
638+
self.assertIn(f"Installed autocompletion for {self.shell}", install_output)
639+
self.verify_install(directory=directory)

tests/shellcompletion/test_bash.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import shutil
33
import sys
44
from pathlib import Path
5+
import typing as t
56

67
import pytest
78
from django.test import TestCase
@@ -20,21 +21,23 @@ class BashTests(_ScriptCompleteTestCase, TestCase):
2021
tabs = "\t\t"
2122

2223
environment = [
23-
f"export DJANGO_SETTINGS_MODULE=tests.settings.completion",
24+
"export DJANGO_SETTINGS_MODULE=tests.settings.completion",
2425
f"export PATH={Path(sys.executable).parent}:$PATH",
25-
f"source ~/.bashrc",
26+
"source ~/.bashrc",
2627
f"source {Path(sys.executable).absolute().parent / 'activate'}",
2728
]
2829

29-
def verify_install(self, script=None):
30+
def verify_install(self, script=None, directory: t.Optional[Path] = None):
31+
directory = directory or self.directory
3032
if not script:
3133
script = self.manage_script
32-
self.assertTrue((self.directory / f"{script}.sh").exists())
34+
self.assertTrue((directory / f"{script}.sh").exists())
3335

34-
def verify_remove(self, script=None):
36+
def verify_remove(self, script=None, directory: t.Optional[Path] = None):
37+
directory = directory or self.directory
3538
if not script:
3639
script = self.manage_script
37-
self.assertFalse((self.directory / f"{script}.sh").exists())
40+
self.assertFalse((directory / f"{script}.sh").exists())
3841

3942
@pytest.mark.rich
4043
@pytest.mark.no_rich

tests/shellcompletion/test_fish.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import shutil
22
import sys
33
from pathlib import Path
4+
import typing as t
45

56
import pytest
67
from django.test import TestCase
@@ -24,12 +25,14 @@ class _FishMixin:
2425
f"source {Path(sys.executable).absolute().parent / 'activate.fish'}",
2526
]
2627

27-
def verify_install(self, script=None):
28+
def verify_install(self, script=None, directory: t.Optional[Path] = None):
29+
directory = directory or self.directory
2830
if not script:
2931
script = self.manage_script
3032
self.assertTrue((self.directory / f"{script}.fish").exists())
3133

32-
def verify_remove(self, script=None):
34+
def verify_remove(self, script=None, directory: t.Optional[Path] = None):
35+
directory = directory or self.directory
3336
if not script:
3437
script = self.manage_script
3538
self.assertFalse((self.directory / f"{script}.fish").exists())
@@ -107,6 +110,3 @@ def test_multi_install(self): ...
107110

108111
@pytest.mark.skip(reason="TODO")
109112
def test_path_completion(self): ...
110-
111-
@pytest.mark.skip(reason="TODO")
112-
def test_prompt_install(self): ...

tests/shellcompletion/test_powershell.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33
from pathlib import Path
44
import platform
5+
import typing as t
56

67
import pytest
78
from django.core.management import CommandError
@@ -34,7 +35,7 @@ def setUpClass(cls) -> None:
3435
cls.profile = cls.completer_class().get_user_profile()
3536
return super().setUpClass()
3637

37-
def verify_install(self, script=None):
38+
def verify_install(self, script=None, directory: t.Optional[Path] = None):
3839
if not script:
3940
script = self.manage_script
4041
self.assertTrue(self.profile.exists())
@@ -43,7 +44,7 @@ def verify_install(self, script=None):
4344
in self.profile.read_text()
4445
)
4546

46-
def verify_remove(self, script=None):
47+
def verify_remove(self, script=None, directory: t.Optional[Path] = None):
4748
if not script:
4849
script = self.manage_script
4950
if self.profile.exists():

tests/shellcompletion/test_zsh.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ZshTests(_ScriptCompleteTestCase, TestCase):
2727
]
2828

2929
def verify_install(self, script=None, directory: t.Optional[Path] = None):
30+
directory = directory or self.directory
3031
if not script:
3132
script = self.manage_script
3233
self.assertTrue((directory / f"_{script}").exists())
@@ -35,12 +36,7 @@ def verify_remove(self, script=None, directory: t.Optional[Path] = None):
3536
directory = directory or self.directory
3637
if not script:
3738
script = self.manage_script
38-
try:
39-
self.assertFalse((directory / f"_{script}").exists())
40-
except AssertionError:
41-
import ipdb
42-
43-
ipdb.set_trace()
39+
self.assertFalse((directory / f"_{script}").exists())
4440

4541

4642
@pytest.mark.skipif(shutil.which("zsh") is None, reason="Z-Shell not available")

0 commit comments

Comments
 (0)