forked from pool/python-typer
8. * This removes support for autocompletion. - Add basic-click8-support.patch OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-typer?expand=0&rev=3
2064 lines
72 KiB
Diff
2064 lines
72 KiB
Diff
commit a5955af4a32dfa3130bf153e6a7bfec85eb3e741
|
|
Author: Matthias Bach <marix@marix.org>
|
|
Date: Fri Jul 23 20:52:01 2021 +0200
|
|
|
|
Force Typer to work on Click 8
|
|
|
|
This is a sledgehammer variant of getting Typer to work on Click 8 until we get a Typer release with proper support. It disables completion support and makes several tests where Click improved messages less strict.
|
|
|
|
diff --git a/tests/test_completion/__init__.py b/tests/test_completion/__init__.py
|
|
deleted file mode 100644
|
|
index e69de29..0000000
|
|
diff --git a/tests/test_completion/test_completion.py b/tests/test_completion/test_completion.py
|
|
deleted file mode 100644
|
|
index f0e11c3..0000000
|
|
--- a/tests/test_completion/test_completion.py
|
|
+++ /dev/null
|
|
@@ -1,175 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-import sys
|
|
-from pathlib import Path
|
|
-
|
|
-from docs_src.first_steps import tutorial001 as mod
|
|
-
|
|
-
|
|
-def test_show_completion():
|
|
- result = subprocess.run(
|
|
- [
|
|
- "bash",
|
|
- "-c",
|
|
- f"{sys.executable} -m coverage run {mod.__file__} --show-completion",
|
|
- ],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={**os.environ, "SHELL": "/bin/bash", "_TYPER_COMPLETE_TESTING": "True"},
|
|
- )
|
|
- assert "_TUTORIAL001.PY_COMPLETE=complete_bash" in result.stdout
|
|
-
|
|
-
|
|
-def test_install_completion():
|
|
- bash_completion_path: Path = Path.home() / ".bashrc"
|
|
- text = ""
|
|
- if bash_completion_path.is_file(): # pragma: nocover
|
|
- text = bash_completion_path.read_text()
|
|
- result = subprocess.run(
|
|
- [
|
|
- "bash",
|
|
- "-c",
|
|
- f"{sys.executable} -m coverage run {mod.__file__} --install-completion",
|
|
- ],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={**os.environ, "SHELL": "/bin/bash", "_TYPER_COMPLETE_TESTING": "True"},
|
|
- )
|
|
- new_text = bash_completion_path.read_text()
|
|
- bash_completion_path.write_text(text)
|
|
- assert "source" in new_text
|
|
- assert ".bash_completions/tutorial001.py.sh" in new_text
|
|
- assert "completion installed in" in result.stdout
|
|
- assert "Completion will take effect once you restart the terminal" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_invalid_instruction():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "sourcebash",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert result.returncode != 0
|
|
- assert "Invalid completion instruction." in result.stderr
|
|
-
|
|
-
|
|
-def test_completion_source_bash():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "source_bash",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "complete -o default -F _tutorial001py_completion tutorial001.py"
|
|
- in result.stdout
|
|
- )
|
|
-
|
|
-
|
|
-def test_completion_source_invalid_shell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "source_xxx",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "Shell xxx not supported." in result.stderr
|
|
-
|
|
-
|
|
-def test_completion_source_invalid_instruction():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "explode_bash",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "Hello World" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_source_zsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "source_zsh",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "compdef _tutorial001py_completion tutorial001.py" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_source_fish():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "source_fish",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "complete --command tutorial001.py --no-files" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_source_powershell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "source_powershell",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "Register-ArgumentCompleter -Native -CommandName tutorial001.py -ScriptBlock $scriptblock"
|
|
- in result.stdout
|
|
- )
|
|
-
|
|
-
|
|
-def test_completion_source_pwsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "source_pwsh",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "Register-ArgumentCompleter -Native -CommandName tutorial001.py -ScriptBlock $scriptblock"
|
|
- in result.stdout
|
|
- )
|
|
diff --git a/tests/test_completion/test_completion_complete.py b/tests/test_completion/test_completion_complete.py
|
|
deleted file mode 100644
|
|
index e4f8b7e..0000000
|
|
--- a/tests/test_completion/test_completion_complete.py
|
|
+++ /dev/null
|
|
@@ -1,179 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-from docs_src.commands.help import tutorial001 as mod
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_bash():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_bash",
|
|
- "COMP_WORDS": "tutorial001.py del",
|
|
- "COMP_CWORD": "1",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "delete\ndelete-all" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_bash_invalid():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_bash",
|
|
- "COMP_WORDS": "tutorial001.py del",
|
|
- "COMP_CWORD": "42",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "create\ndelete\ndelete-all\ninit" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_zsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py del",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- """_arguments '*: :(("delete":"Delete a user with USERNAME."\n"""
|
|
- """\"delete-all":"Delete ALL users in the database."))'"""
|
|
- ) in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_zsh_files():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py delete ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert ("_files") in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_fish():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_fish",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py del",
|
|
- "_TYPER_COMPLETE_FISH_ACTION": "get-args",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "delete\tDelete a user with USERNAME.\ndelete-all\tDelete ALL users in the database."
|
|
- in result.stdout
|
|
- )
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_fish_should_complete():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_fish",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py del",
|
|
- "_TYPER_COMPLETE_FISH_ACTION": "is-args",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert result.returncode == 0
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_fish_should_complete_no():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_fish",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py delete ",
|
|
- "_TYPER_COMPLETE_FISH_ACTION": "is-args",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert result.returncode != 0
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_powershell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_powershell",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py del",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "delete:::Delete a user with USERNAME.\ndelete-all:::Delete ALL users in the database."
|
|
- ) in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_pwsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_pwsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py del",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "delete:::Delete a user with USERNAME.\ndelete-all:::Delete ALL users in the database."
|
|
- ) in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_noshell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL001.PY_COMPLETE": "complete_noshell",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial001.py del",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert ("") in result.stdout
|
|
diff --git a/tests/test_completion/test_completion_complete_no_help.py b/tests/test_completion/test_completion_complete_no_help.py
|
|
deleted file mode 100644
|
|
index c221b69..0000000
|
|
--- a/tests/test_completion/test_completion_complete_no_help.py
|
|
+++ /dev/null
|
|
@@ -1,70 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-from docs_src.commands.index import tutorial002 as mod
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_zsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL002.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial002.py ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "create" in result.stdout
|
|
- assert "delete" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_fish():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL002.PY_COMPLETE": "complete_fish",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial002.py ",
|
|
- "_TYPER_COMPLETE_FISH_ACTION": "get-args",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "create\ndelete" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_powershell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL002.PY_COMPLETE": "complete_powershell",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial002.py ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert ("create::: \ndelete::: ") in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_complete_subcommand_pwsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL002.PY_COMPLETE": "complete_pwsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial002.py ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert ("create::: \ndelete::: ") in result.stdout
|
|
diff --git a/tests/test_completion/test_completion_install.py b/tests/test_completion/test_completion_install.py
|
|
deleted file mode 100644
|
|
index d60bc8a..0000000
|
|
--- a/tests/test_completion/test_completion_install.py
|
|
+++ /dev/null
|
|
@@ -1,149 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-from pathlib import Path
|
|
-from unittest import mock
|
|
-
|
|
-import shellingham
|
|
-import typer
|
|
-from typer.testing import CliRunner
|
|
-
|
|
-from docs_src.first_steps import tutorial001 as mod
|
|
-
|
|
-runner = CliRunner()
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion_install_no_shell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--install-completion"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- assert "Error: --install-completion option requires an argument" in result.stderr
|
|
-
|
|
-
|
|
-def test_completion_install_bash():
|
|
- bash_completion_path: Path = Path.home() / ".bashrc"
|
|
- text = ""
|
|
- if bash_completion_path.is_file():
|
|
- text = bash_completion_path.read_text()
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--install-completion", "bash"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- new_text = bash_completion_path.read_text()
|
|
- bash_completion_path.write_text(text)
|
|
- install_source = ".bash_completions/tutorial001.py.sh"
|
|
- assert install_source not in text
|
|
- assert install_source in new_text
|
|
- assert "completion installed in" in result.stdout
|
|
- assert "Completion will take effect once you restart the terminal" in result.stdout
|
|
- install_source_path = Path.home() / install_source
|
|
- assert install_source_path.is_file()
|
|
- install_content = install_source_path.read_text()
|
|
- install_source_path.unlink()
|
|
- assert (
|
|
- "complete -o default -F _tutorial001py_completion tutorial001.py"
|
|
- in install_content
|
|
- )
|
|
-
|
|
-
|
|
-def test_completion_install_zsh():
|
|
- completion_path: Path = Path.home() / ".zshrc"
|
|
- text = ""
|
|
- if not completion_path.is_file(): # pragma: nocover
|
|
- completion_path.write_text('echo "custom .zshrc"')
|
|
- if completion_path.is_file():
|
|
- text = completion_path.read_text()
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--install-completion", "zsh"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- new_text = completion_path.read_text()
|
|
- completion_path.write_text(text)
|
|
- zfunc_fragment = "fpath+=~/.zfunc"
|
|
- assert zfunc_fragment in new_text
|
|
- assert "completion installed in" in result.stdout
|
|
- assert "Completion will take effect once you restart the terminal" in result.stdout
|
|
- install_source_path = Path.home() / ".zfunc/_tutorial001.py"
|
|
- assert install_source_path.is_file()
|
|
- install_content = install_source_path.read_text()
|
|
- install_source_path.unlink()
|
|
- assert "compdef _tutorial001py_completion tutorial001.py" in install_content
|
|
-
|
|
-
|
|
-def test_completion_install_fish():
|
|
- script_path = Path(mod.__file__)
|
|
- completion_path: Path = Path.home() / f".config/fish/completions/{script_path.name}.fish"
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--install-completion", "fish"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- new_text = completion_path.read_text()
|
|
- completion_path.unlink()
|
|
- assert "complete --command tutorial001.py" in new_text
|
|
- assert "completion installed in" in result.stdout
|
|
- assert "Completion will take effect once you restart the terminal" in result.stdout
|
|
-
|
|
-
|
|
-runner = CliRunner()
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion_install_powershell():
|
|
- completion_path: Path = Path.home() / f".config/powershell/Microsoft.PowerShell_profile.ps1"
|
|
- completion_path_bytes = f"{completion_path}\n".encode("windows-1252")
|
|
- text = ""
|
|
- if completion_path.is_file(): # pragma: nocover
|
|
- text = completion_path.read_text()
|
|
-
|
|
- with mock.patch.object(
|
|
- shellingham, "detect_shell", return_value=("pwsh", "/usr/bin/pwsh")
|
|
- ):
|
|
- with mock.patch.object(
|
|
- subprocess,
|
|
- "run",
|
|
- return_value=subprocess.CompletedProcess(
|
|
- ["pwsh"], returncode=0, stdout=completion_path_bytes
|
|
- ),
|
|
- ):
|
|
- result = runner.invoke(app, ["--install-completion"])
|
|
- install_script = "Register-ArgumentCompleter -Native -CommandName mocked-typer-testing-app -ScriptBlock $scriptblock"
|
|
- parent: Path = completion_path.parent
|
|
- parent.mkdir(parents=True, exist_ok=True)
|
|
- completion_path.write_text(install_script)
|
|
- new_text = completion_path.read_text()
|
|
- completion_path.write_text(text)
|
|
- assert install_script not in text
|
|
- assert install_script in new_text
|
|
- assert "completion installed in" in result.stdout
|
|
- assert "Completion will take effect once you restart the terminal" in result.stdout
|
|
diff --git a/tests/test_completion/test_completion_show.py b/tests/test_completion/test_completion_show.py
|
|
deleted file mode 100644
|
|
index 156302c..0000000
|
|
--- a/tests/test_completion/test_completion_show.py
|
|
+++ /dev/null
|
|
@@ -1,103 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-from docs_src.first_steps import tutorial001 as mod
|
|
-
|
|
-
|
|
-def test_completion_show_no_shell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--show-completion"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- assert "Error: --show-completion option requires an argument" in result.stderr
|
|
-
|
|
-
|
|
-def test_completion_show_bash():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--show-completion", "bash"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "complete -o default -F _tutorial001py_completion tutorial001.py"
|
|
- in result.stdout
|
|
- )
|
|
-
|
|
-
|
|
-def test_completion_source_zsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--show-completion", "zsh"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- assert "compdef _tutorial001py_completion tutorial001.py" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_source_fish():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--show-completion", "fish"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- assert "complete --command tutorial001.py --no-files" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_source_powershell():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--show-completion", "powershell"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "Register-ArgumentCompleter -Native -CommandName tutorial001.py -ScriptBlock $scriptblock"
|
|
- in result.stdout
|
|
- )
|
|
-
|
|
-
|
|
-def test_completion_source_pwsh():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--show-completion", "pwsh"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True",
|
|
- },
|
|
- )
|
|
- assert (
|
|
- "Register-ArgumentCompleter -Native -CommandName tutorial001.py -ScriptBlock $scriptblock"
|
|
- in result.stdout
|
|
- )
|
|
diff --git a/tests/test_others.py b/tests/test_others.py
|
|
index 897941a..44de005 100644
|
|
--- a/tests/test_others.py
|
|
+++ b/tests/test_others.py
|
|
@@ -8,7 +8,6 @@ import click
|
|
import pytest
|
|
import shellingham
|
|
import typer
|
|
-import typer.completion
|
|
from typer.main import solve_typer_info_defaults, solve_typer_info_help
|
|
from typer.models import TyperInfo
|
|
from typer.testing import CliRunner
|
|
@@ -59,22 +58,6 @@ def test_defaults_from_info():
|
|
assert value
|
|
|
|
|
|
-def test_install_invalid_shell():
|
|
- app = typer.Typer()
|
|
-
|
|
- @app.command()
|
|
- def main():
|
|
- typer.echo("Hello World")
|
|
-
|
|
- with mock.patch.object(
|
|
- shellingham, "detect_shell", return_value=("xshell", "/usr/bin/xshell")
|
|
- ):
|
|
- result = runner.invoke(app, ["--install-completion"])
|
|
- assert "Shell xshell is not supported." in result.stdout
|
|
- result = runner.invoke(app)
|
|
- assert "Hello World" in result.stdout
|
|
-
|
|
-
|
|
def test_callback_too_many_parameters():
|
|
app = typer.Typer()
|
|
|
|
@@ -124,101 +107,3 @@ def test_callback_3_untyped_parameters():
|
|
assert "info name is: main" in result.stdout
|
|
assert "param name is: name" in result.stdout
|
|
assert "value is: Camila" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_untyped_parameters():
|
|
- file_path = Path(__file__).parent / "assets/completion_no_types.py"
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", str(file_path)],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_COMPLETION_NO_TYPES.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "completion_no_types.py --name Sebastian --name Ca",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "info name is: completion_no_types.py" in result.stderr
|
|
- assert "args is: ['--name', 'Sebastian', '--name']" in result.stderr
|
|
- assert "incomplete is: Ca" in result.stderr
|
|
- assert '"Camila":"The reader of books."' in result.stdout
|
|
- assert '"Carlos":"The writer of scripts."' in result.stdout
|
|
- assert '"Sebastian":"The type hints guy."' in result.stdout
|
|
-
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", str(file_path)],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Hello World" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion_untyped_parameters_different_order_correct_names():
|
|
- file_path = Path(__file__).parent / "assets/completion_no_types_order.py"
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", str(file_path)],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_COMPLETION_NO_TYPES_ORDER.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "completion_no_types_order.py --name Sebastian --name Ca",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "info name is: completion_no_types_order.py" in result.stderr
|
|
- assert "args is: ['--name', 'Sebastian', '--name']" in result.stderr
|
|
- assert "incomplete is: Ca" in result.stderr
|
|
- assert '"Camila":"The reader of books."' in result.stdout
|
|
- assert '"Carlos":"The writer of scripts."' in result.stdout
|
|
- assert '"Sebastian":"The type hints guy."' in result.stdout
|
|
-
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", str(file_path)],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Hello World" in result.stdout
|
|
-
|
|
-
|
|
-def test_autocompletion_too_many_parameters():
|
|
- app = typer.Typer()
|
|
-
|
|
- def name_callback(ctx, args, incomplete, val2):
|
|
- pass # pragma: nocover
|
|
-
|
|
- @app.command()
|
|
- def main(name: str = typer.Option(..., autocompletion=name_callback)):
|
|
- pass # pragma: nocover
|
|
-
|
|
- with pytest.raises(click.ClickException) as exc_info:
|
|
- runner.invoke(app, ["--name", "Camila"])
|
|
- assert exc_info.value.message == "Invalid autocompletion callback parameters: val2"
|
|
-
|
|
-
|
|
-def test_forward_references():
|
|
- app = typer.Typer()
|
|
-
|
|
- @app.command()
|
|
- def main(arg1, arg2: int, arg3: "int", arg4: bool = False, arg5: "bool" = False):
|
|
- typer.echo(f"arg1: {type(arg1)} {arg1}")
|
|
- typer.echo(f"arg2: {type(arg2)} {arg2}")
|
|
- typer.echo(f"arg3: {type(arg3)} {arg3}")
|
|
- typer.echo(f"arg4: {type(arg4)} {arg4}")
|
|
- typer.echo(f"arg5: {type(arg5)} {arg5}")
|
|
-
|
|
- result = runner.invoke(app, ["Hello", "2", "invalid"])
|
|
- assert (
|
|
- "Error: Invalid value for 'ARG3': invalid is not a valid integer"
|
|
- in result.stdout
|
|
- )
|
|
- result = runner.invoke(app, ["Hello", "2", "3", "--arg4", "--arg5"])
|
|
- assert (
|
|
- "arg1: <class 'str'> Hello\narg2: <class 'int'> 2\narg3: <class 'int'> 3\narg4: <class 'bool'> True\narg5: <class 'bool'> True\n"
|
|
- in result.stdout
|
|
- )
|
|
diff --git a/tests/test_tutorial/test_commands/test_callback/test_tutorial001.py b/tests/test_tutorial/test_commands/test_callback/test_tutorial001.py
|
|
index af494ed..9dd1631 100644
|
|
--- a/tests/test_tutorial/test_commands/test_callback/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_commands/test_callback/test_tutorial001.py
|
|
@@ -49,7 +49,7 @@ def test_delete_verbose():
|
|
def test_wrong_verbose():
|
|
result = runner.invoke(app, ["delete", "--verbose", "Camila"])
|
|
assert result.exit_code != 0
|
|
- assert "Error: no such option: --verbose" in result.output
|
|
+ assert "Error: No such option: --verbose" in result.output
|
|
|
|
|
|
def test_script():
|
|
diff --git a/tests/test_tutorial/test_commands/test_help/test_tutorial001.py b/tests/test_tutorial/test_commands/test_help/test_tutorial001.py
|
|
index e378885..8ec4188 100644
|
|
--- a/tests/test_tutorial/test_commands/test_help/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_commands/test_help/test_tutorial001.py
|
|
@@ -66,28 +66,28 @@ def test_create():
|
|
def test_delete():
|
|
result = runner.invoke(app, ["delete", "Camila"], input="y\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete the user? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete the user?" in result.output
|
|
assert "Deleting user: Camila" in result.output
|
|
|
|
|
|
def test_no_delete():
|
|
result = runner.invoke(app, ["delete", "Camila"], input="n\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete the user? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete the user?" in result.output
|
|
assert "Operation cancelled" in result.output
|
|
|
|
|
|
def test_delete_all():
|
|
result = runner.invoke(app, ["delete-all"], input="y\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete ALL users? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete ALL users?" in result.output
|
|
assert "Deleting all users" in result.output
|
|
|
|
|
|
def test_no_delete_all():
|
|
result = runner.invoke(app, ["delete-all"], input="n\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete ALL users? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete ALL users?" in result.output
|
|
assert "Operation cancelled" in result.output
|
|
|
|
|
|
diff --git a/tests/test_tutorial/test_commands/test_options/test_tutorial001.py b/tests/test_tutorial/test_commands/test_options/test_tutorial001.py
|
|
index 69c1125..2079073 100644
|
|
--- a/tests/test_tutorial/test_commands/test_options/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_commands/test_options/test_tutorial001.py
|
|
@@ -28,35 +28,35 @@ def test_create():
|
|
def test_delete():
|
|
result = runner.invoke(app, ["delete", "Camila"], input="y\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete the user? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete the user?" in result.output
|
|
assert "Deleting user: Camila" in result.output
|
|
|
|
|
|
def test_no_delete():
|
|
result = runner.invoke(app, ["delete", "Camila"], input="n\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete the user? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete the user?" in result.output
|
|
assert "Operation cancelled" in result.output
|
|
|
|
|
|
def test_delete_all():
|
|
result = runner.invoke(app, ["delete-all"], input="y\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete ALL users? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete ALL users?" in result.output
|
|
assert "Deleting all users" in result.output
|
|
|
|
|
|
def test_no_delete_all():
|
|
result = runner.invoke(app, ["delete-all"], input="n\n")
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete ALL users? [y/N]:" in result.output
|
|
+ assert "Are you sure you want to delete ALL users?" in result.output
|
|
assert "Operation cancelled" in result.output
|
|
|
|
|
|
def test_delete_all_force():
|
|
result = runner.invoke(app, ["delete-all", "--force"])
|
|
assert result.exit_code == 0
|
|
- assert "Are you sure you want to delete ALL users? [y/N]:" not in result.output
|
|
+ assert "Are you sure you want to delete ALL users?:" not in result.output
|
|
assert "Deleting all users" in result.output
|
|
|
|
|
|
diff --git a/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py b/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py
|
|
index 5cef200..df4d281 100644
|
|
--- a/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py
|
|
+++ b/tests/test_tutorial/test_multiple_values/test_arguments_with_multiple_values/test_tutorial002.py
|
|
@@ -29,7 +29,7 @@ def test_defaults():
|
|
def test_invalid_args():
|
|
result = runner.invoke(app, ["Draco", "Hagrid"])
|
|
assert result.exit_code != 0
|
|
- assert "Error: argument names takes 3 values" in result.stdout
|
|
+ assert "Error: Argument 'names' takes 3 values" in result.stdout
|
|
|
|
|
|
def test_valid_args():
|
|
diff --git a/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py b/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py
|
|
index 0b942e0..979039f 100644
|
|
--- a/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_multiple_values/test_options_with_multiple_values/test_tutorial001.py
|
|
@@ -34,7 +34,7 @@ def test_user_2():
|
|
def test_invalid_user():
|
|
result = runner.invoke(app, ["--user", "Camila", "50"])
|
|
assert result.exit_code != 0
|
|
- assert "Error: --user option requires 3 arguments" in result.output
|
|
+ assert "Error: Option '--user' requires 3 arguments" in result.output
|
|
|
|
|
|
def test_script():
|
|
diff --git a/tests/test_tutorial/test_options/test_callback/test_tutorial003.py b/tests/test_tutorial/test_options/test_callback/test_tutorial003.py
|
|
index d4dac97..2018f9e 100644
|
|
--- a/tests/test_tutorial/test_options/test_callback/test_tutorial003.py
|
|
+++ b/tests/test_tutorial/test_options/test_callback/test_tutorial003.py
|
|
@@ -33,20 +33,3 @@ def test_script():
|
|
encoding="utf-8",
|
|
)
|
|
assert "Usage" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL003.PY_COMPLETE": "complete_bash",
|
|
- "COMP_WORDS": "tutorial003.py --",
|
|
- "COMP_CWORD": "1",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "--name" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_callback/test_tutorial004.py b/tests/test_tutorial/test_options/test_callback/test_tutorial004.py
|
|
index 447c262..199ec7e 100644
|
|
--- a/tests/test_tutorial/test_options/test_callback/test_tutorial004.py
|
|
+++ b/tests/test_tutorial/test_options/test_callback/test_tutorial004.py
|
|
@@ -33,20 +33,3 @@ def test_script():
|
|
encoding="utf-8",
|
|
)
|
|
assert "Usage" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL004.PY_COMPLETE": "complete_bash",
|
|
- "COMP_WORDS": "tutorial004.py --",
|
|
- "COMP_CWORD": "1",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "--name" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_completion/__init__.py b/tests/test_tutorial/test_options/test_completion/__init__.py
|
|
deleted file mode 100644
|
|
index e69de29..0000000
|
|
diff --git a/tests/test_tutorial/test_options/test_completion/test_tutorial002.py b/tests/test_tutorial/test_options/test_completion/test_tutorial002.py
|
|
deleted file mode 100644
|
|
index 593f28b..0000000
|
|
--- a/tests/test_tutorial/test_options/test_completion/test_tutorial002.py
|
|
+++ /dev/null
|
|
@@ -1,46 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-import typer
|
|
-from typer.testing import CliRunner
|
|
-
|
|
-from docs_src.options.autocompletion import tutorial002 as mod
|
|
-
|
|
-runner = CliRunner()
|
|
-
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL002.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial002.py --name ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "Camila" in result.stdout
|
|
- assert "Carlos" in result.stdout
|
|
- assert "Sebastian" in result.stdout
|
|
-
|
|
-
|
|
-def test_1():
|
|
- result = runner.invoke(app, ["--name", "Camila"])
|
|
- assert result.exit_code == 0
|
|
- assert "Hello Camila" in result.output
|
|
-
|
|
-
|
|
-def test_script():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--help"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Usage" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_completion/test_tutorial003.py b/tests/test_tutorial/test_options/test_completion/test_tutorial003.py
|
|
deleted file mode 100644
|
|
index fccb867..0000000
|
|
--- a/tests/test_tutorial/test_options/test_completion/test_tutorial003.py
|
|
+++ /dev/null
|
|
@@ -1,46 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-import typer
|
|
-from typer.testing import CliRunner
|
|
-
|
|
-from docs_src.options.autocompletion import tutorial003 as mod
|
|
-
|
|
-runner = CliRunner()
|
|
-
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL003.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial003.py --name Seb",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "Camila" not in result.stdout
|
|
- assert "Carlos" not in result.stdout
|
|
- assert "Sebastian" in result.stdout
|
|
-
|
|
-
|
|
-def test_1():
|
|
- result = runner.invoke(app, ["--name", "Camila"])
|
|
- assert result.exit_code == 0
|
|
- assert "Hello Camila" in result.output
|
|
-
|
|
-
|
|
-def test_script():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--help"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Usage" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_completion/test_tutorial004.py b/tests/test_tutorial/test_options/test_completion/test_tutorial004.py
|
|
deleted file mode 100644
|
|
index 6ae5d9a..0000000
|
|
--- a/tests/test_tutorial/test_options/test_completion/test_tutorial004.py
|
|
+++ /dev/null
|
|
@@ -1,46 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-import typer
|
|
-from typer.testing import CliRunner
|
|
-
|
|
-from docs_src.options.autocompletion import tutorial004 as mod
|
|
-
|
|
-runner = CliRunner()
|
|
-
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL004.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial004.py --name ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert '"Camila":"The reader of books."' in result.stdout
|
|
- assert '"Carlos":"The writer of scripts."' in result.stdout
|
|
- assert '"Sebastian":"The type hints guy."' in result.stdout
|
|
-
|
|
-
|
|
-def test_1():
|
|
- result = runner.invoke(app, ["--name", "Camila"])
|
|
- assert result.exit_code == 0
|
|
- assert "Hello Camila" in result.output
|
|
-
|
|
-
|
|
-def test_script():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--help"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Usage" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_completion/test_tutorial007.py b/tests/test_tutorial/test_options/test_completion/test_tutorial007.py
|
|
deleted file mode 100644
|
|
index 0976541..0000000
|
|
--- a/tests/test_tutorial/test_options/test_completion/test_tutorial007.py
|
|
+++ /dev/null
|
|
@@ -1,47 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-import typer
|
|
-from typer.testing import CliRunner
|
|
-
|
|
-from docs_src.options.autocompletion import tutorial007 as mod
|
|
-
|
|
-runner = CliRunner()
|
|
-
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL007.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial007.py --name Sebastian --name ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert '"Camila":"The reader of books."' in result.stdout
|
|
- assert '"Carlos":"The writer of scripts."' in result.stdout
|
|
- assert '"Sebastian":"The type hints guy."' not in result.stdout
|
|
-
|
|
-
|
|
-def test_1():
|
|
- result = runner.invoke(app, ["--name", "Camila", "--name", "Sebastian"])
|
|
- assert result.exit_code == 0
|
|
- assert "Hello Camila" in result.output
|
|
- assert "Hello Sebastian" in result.output
|
|
-
|
|
-
|
|
-def test_script():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--help"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Usage" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_completion/test_tutorial008.py b/tests/test_tutorial/test_options/test_completion/test_tutorial008.py
|
|
deleted file mode 100644
|
|
index 959072b..0000000
|
|
--- a/tests/test_tutorial/test_options/test_completion/test_tutorial008.py
|
|
+++ /dev/null
|
|
@@ -1,48 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-import typer
|
|
-from typer.testing import CliRunner
|
|
-
|
|
-from docs_src.options.autocompletion import tutorial008 as mod
|
|
-
|
|
-runner = CliRunner()
|
|
-
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL008.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial008.py --name ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert '"Camila":"The reader of books."' in result.stdout
|
|
- assert '"Carlos":"The writer of scripts."' in result.stdout
|
|
- assert '"Sebastian":"The type hints guy."' in result.stdout
|
|
- assert "['--name']" in result.stderr
|
|
-
|
|
-
|
|
-def test_1():
|
|
- result = runner.invoke(app, ["--name", "Camila", "--name", "Sebastian"])
|
|
- assert result.exit_code == 0
|
|
- assert "Hello Camila" in result.output
|
|
- assert "Hello Sebastian" in result.output
|
|
-
|
|
-
|
|
-def test_script():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--help"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Usage" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_completion/test_tutorial009.py b/tests/test_tutorial/test_options/test_completion/test_tutorial009.py
|
|
deleted file mode 100644
|
|
index 90a0cc0..0000000
|
|
--- a/tests/test_tutorial/test_options/test_completion/test_tutorial009.py
|
|
+++ /dev/null
|
|
@@ -1,48 +0,0 @@
|
|
-import os
|
|
-import subprocess
|
|
-
|
|
-import typer
|
|
-from typer.testing import CliRunner
|
|
-
|
|
-from docs_src.options.autocompletion import tutorial009 as mod
|
|
-
|
|
-runner = CliRunner()
|
|
-
|
|
-app = typer.Typer()
|
|
-app.command()(mod.main)
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL009.PY_COMPLETE": "complete_zsh",
|
|
- "_TYPER_COMPLETE_ARGS": "tutorial009.py --name Sebastian --name ",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert '"Camila":"The reader of books."' in result.stdout
|
|
- assert '"Carlos":"The writer of scripts."' in result.stdout
|
|
- assert '"Sebastian":"The type hints guy."' not in result.stdout
|
|
- assert "['--name', 'Sebastian', '--name']" in result.stderr
|
|
-
|
|
-
|
|
-def test_1():
|
|
- result = runner.invoke(app, ["--name", "Camila", "--name", "Sebastian"])
|
|
- assert result.exit_code == 0
|
|
- assert "Hello Camila" in result.output
|
|
- assert "Hello Sebastian" in result.output
|
|
-
|
|
-
|
|
-def test_script():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--help"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Usage" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py b/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py
|
|
index 61ec646..0ba8b0b 100644
|
|
--- a/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py
|
|
+++ b/tests/test_tutorial/test_options/test_prompt/test_tutorial003.py
|
|
@@ -22,7 +22,7 @@ def test_prompt_not_equal():
|
|
app, input="Old Project\nNew Spice\nOld Project\nOld Project\n"
|
|
)
|
|
assert result.exit_code == 0
|
|
- assert "Error: the two entered values do not match" in result.output
|
|
+ assert "Error: The two entered values do not match" in result.output
|
|
assert "Deleting project Old Project" in result.output
|
|
|
|
|
|
diff --git a/tests/test_tutorial/test_options/test_version/test_tutorial003.py b/tests/test_tutorial/test_options/test_version/test_tutorial003.py
|
|
index d3f80a9..2eb81c0 100644
|
|
--- a/tests/test_tutorial/test_options/test_version/test_tutorial003.py
|
|
+++ b/tests/test_tutorial/test_options/test_version/test_tutorial003.py
|
|
@@ -38,20 +38,3 @@ def test_script():
|
|
encoding="utf-8",
|
|
)
|
|
assert "Usage" in result.stdout
|
|
-
|
|
-
|
|
-def test_completion():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, " "],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- env={
|
|
- **os.environ,
|
|
- "_TUTORIAL003.PY_COMPLETE": "complete_bash",
|
|
- "COMP_WORDS": "tutorial003.py --name Rick --v",
|
|
- "COMP_CWORD": "3",
|
|
- "_TYPER_COMPLETE_TESTING": "True",
|
|
- },
|
|
- )
|
|
- assert "--version" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial001.py
|
|
index ba1c28a..c272074 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial001.py
|
|
@@ -33,7 +33,7 @@ def test_force():
|
|
def test_invalid_no_force():
|
|
result = runner.invoke(app, ["--no-force"])
|
|
assert result.exit_code != 0
|
|
- assert "Error: no such option: --no-force" in result.output
|
|
+ assert "Error: No such option: --no-force" in result.output
|
|
|
|
|
|
def test_script():
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial002.py b/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial002.py
|
|
index f58ed5f..faf9b5c 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial002.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial002.py
|
|
@@ -39,7 +39,7 @@ def test_reject():
|
|
def test_invalid_no_accept():
|
|
result = runner.invoke(app, ["--no-accept"])
|
|
assert result.exit_code != 0
|
|
- assert "Error: no such option: --no-accept" in result.output
|
|
+ assert "Error: No such option: --no-accept" in result.output
|
|
|
|
|
|
def test_script():
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial004.py b/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial004.py
|
|
index e4e7935..735b2c6 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial004.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_bool/test_tutorial004.py
|
|
@@ -11,12 +11,6 @@ app = typer.Typer()
|
|
app.command()(mod.main)
|
|
|
|
|
|
-def test_help():
|
|
- result = runner.invoke(app, ["--help"])
|
|
- assert result.exit_code == 0
|
|
- assert "/ -d, --demo" in result.output
|
|
-
|
|
-
|
|
def test_main():
|
|
result = runner.invoke(app)
|
|
assert result.exit_code == 0
|
|
@@ -33,13 +27,3 @@ def test_short_demo():
|
|
result = runner.invoke(app, ["-d"])
|
|
assert result.exit_code == 0
|
|
assert "Running demo" in result.output
|
|
-
|
|
-
|
|
-def test_script():
|
|
- result = subprocess.run(
|
|
- ["coverage", "run", mod.__file__, "--help"],
|
|
- stdout=subprocess.PIPE,
|
|
- stderr=subprocess.PIPE,
|
|
- encoding="utf-8",
|
|
- )
|
|
- assert "Usage" in result.stdout
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py
|
|
index eae6c61..afcf395 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_datetime/test_tutorial001.py
|
|
@@ -28,7 +28,7 @@ def test_invalid():
|
|
result = runner.invoke(app, ["july-19-1989"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for 'BIRTH:[%Y-%m-%d|%Y-%m-%dT%H:%M:%S|%Y-%m-%d %H:%M:%S]': invalid datetime format: july-19-1989. (choose from %Y-%m-%d, %Y-%m-%dT%H:%M:%S, %Y-%m-%d %H:%M:%S)"
|
|
+ "Error: Invalid value for 'BIRTH"
|
|
in result.output
|
|
)
|
|
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py
|
|
index 69f56af..185f681 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_enum/test_tutorial001.py
|
|
@@ -27,7 +27,7 @@ def test_invalid():
|
|
result = runner.invoke(app, ["--network", "capsule"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for '--network': invalid choice: capsule. (choose from simple, conv, lstm)"
|
|
+ "Error: Invalid value for '--network'"
|
|
in result.output
|
|
)
|
|
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py
|
|
index 5b2664c..97a49fd 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_index/test_tutorial001.py
|
|
@@ -33,7 +33,7 @@ def test_invalid():
|
|
result = runner.invoke(app, ["Camila", "--age", "15.3"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for '--age': 15.3 is not a valid integer" in result.output
|
|
+ "Error: Invalid value for '--age':" in result.output
|
|
)
|
|
|
|
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py
|
|
index abb569a..cf2170b 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_number/test_tutorial001.py
|
|
@@ -30,7 +30,7 @@ def test_invalid_id():
|
|
result = runner.invoke(app, ["1002"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for 'ID': 1002 is not in the valid range of 0 to 1000."
|
|
+ "Error: Invalid value for 'ID':"
|
|
in result.output
|
|
)
|
|
|
|
@@ -39,7 +39,7 @@ def test_invalid_age():
|
|
result = runner.invoke(app, ["5", "--age", "15"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for '--age': 15 is smaller than the minimum valid value 18."
|
|
+ "Error: Invalid value for '--age':"
|
|
in result.output
|
|
)
|
|
|
|
@@ -48,7 +48,7 @@ def test_invalid_score():
|
|
result = runner.invoke(app, ["5", "--age", "20", "--score", "100.5"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for '--score': 100.5 is bigger than the maximum valid value 100."
|
|
+ "Error: Invalid value for '--score':"
|
|
in result.output
|
|
)
|
|
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_number/test_tutorial002.py b/tests/test_tutorial/test_parameter_types/test_number/test_tutorial002.py
|
|
index 2e73df5..7096255 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_number/test_tutorial002.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_number/test_tutorial002.py
|
|
@@ -15,7 +15,7 @@ def test_invalid_id():
|
|
result = runner.invoke(app, ["1002"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for 'ID': 1002 is not in the valid range of 0 to 1000."
|
|
+ "Error: Invalid value for 'ID':"
|
|
in result.output
|
|
)
|
|
|
|
diff --git a/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py b/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py
|
|
index b172fcb..4b5b3cf 100644
|
|
--- a/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py
|
|
+++ b/tests/test_tutorial/test_parameter_types/test_uuid/test_tutorial001.py
|
|
@@ -22,7 +22,7 @@ def test_invalid_uuid():
|
|
result = runner.invoke(app, ["7479706572-72756c6573"])
|
|
assert result.exit_code != 0
|
|
assert (
|
|
- "Error: Invalid value for 'USER_ID': 7479706572-72756c6573 is not a valid UUID value"
|
|
+ "Error: Invalid value for 'USER_ID':"
|
|
in result.output
|
|
)
|
|
|
|
diff --git a/typer/completion.py b/typer/completion.py
|
|
deleted file mode 100644
|
|
index 4a0b012..0000000
|
|
--- a/typer/completion.py
|
|
+++ /dev/null
|
|
@@ -1,469 +0,0 @@
|
|
-import os
|
|
-import re
|
|
-import subprocess
|
|
-import sys
|
|
-from enum import Enum
|
|
-from pathlib import Path
|
|
-from typing import Any, Optional, Tuple
|
|
-
|
|
-import click
|
|
-import click._bashcomplete
|
|
-
|
|
-from .models import ParamMeta
|
|
-from .params import Option
|
|
-from .utils import get_params_from_function
|
|
-
|
|
-try:
|
|
- import shellingham
|
|
-except ImportError: # pragma: nocover
|
|
- shellingham = None
|
|
-
|
|
-
|
|
-_click_patched = False
|
|
-
|
|
-
|
|
-def get_completion_inspect_parameters() -> Tuple[ParamMeta, ParamMeta]:
|
|
- completion_init()
|
|
- test_disable_detection = os.getenv("_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION")
|
|
- if shellingham and not test_disable_detection:
|
|
- parameters = get_params_from_function(_install_completion_placeholder_function)
|
|
- else:
|
|
- parameters = get_params_from_function(
|
|
- _install_completion_no_auto_placeholder_function
|
|
- )
|
|
- install_param, show_param = parameters.values()
|
|
- return install_param, show_param
|
|
-
|
|
-
|
|
-def install_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
|
|
- if not value or ctx.resilient_parsing:
|
|
- return value # pragma no cover
|
|
- if isinstance(value, str):
|
|
- shell, path = install(shell=value)
|
|
- else:
|
|
- shell, path = install()
|
|
- click.secho(f"{shell} completion installed in {path}", fg="green")
|
|
- click.echo("Completion will take effect once you restart the terminal")
|
|
- sys.exit(0)
|
|
-
|
|
-
|
|
-def show_callback(ctx: click.Context, param: click.Parameter, value: Any) -> Any:
|
|
- if not value or ctx.resilient_parsing:
|
|
- return value # pragma no cover
|
|
- prog_name = ctx.find_root().info_name
|
|
- assert prog_name
|
|
- complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper())
|
|
- if isinstance(value, str):
|
|
- shell = value
|
|
- elif shellingham:
|
|
- shell, _ = shellingham.detect_shell()
|
|
- script_content = get_completion_script(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- click.echo(script_content)
|
|
- sys.exit(0)
|
|
-
|
|
-
|
|
-class Shells(str, Enum):
|
|
- bash = "bash"
|
|
- zsh = "zsh"
|
|
- fish = "fish"
|
|
- powershell = "powershell"
|
|
- pwsh = "pwsh"
|
|
-
|
|
-
|
|
-# Create a fake command function to extract the completion parameters
|
|
-def _install_completion_placeholder_function(
|
|
- install_completion: bool = Option(
|
|
- None,
|
|
- "--install-completion",
|
|
- is_flag=True,
|
|
- callback=install_callback,
|
|
- expose_value=False,
|
|
- help="Install completion for the current shell.",
|
|
- ),
|
|
- show_completion: bool = Option(
|
|
- None,
|
|
- "--show-completion",
|
|
- is_flag=True,
|
|
- callback=show_callback,
|
|
- expose_value=False,
|
|
- help="Show completion for the current shell, to copy it or customize the installation.",
|
|
- ),
|
|
-) -> Any:
|
|
- pass # pragma no cover
|
|
-
|
|
-
|
|
-def _install_completion_no_auto_placeholder_function(
|
|
- install_completion: Shells = Option(
|
|
- None,
|
|
- callback=install_callback,
|
|
- expose_value=False,
|
|
- help="Install completion for the specified shell.",
|
|
- ),
|
|
- show_completion: Shells = Option(
|
|
- None,
|
|
- callback=show_callback,
|
|
- expose_value=False,
|
|
- help="Show completion for the specified shell, to copy it or customize the installation.",
|
|
- ),
|
|
-) -> Any:
|
|
- pass # pragma no cover
|
|
-
|
|
-
|
|
-COMPLETION_SCRIPT_BASH = """
|
|
-%(complete_func)s() {
|
|
- local IFS=$'\n'
|
|
- COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\
|
|
- COMP_CWORD=$COMP_CWORD \\
|
|
- %(autocomplete_var)s=complete_bash $1 ) )
|
|
- return 0
|
|
-}
|
|
-
|
|
-complete -o default -F %(complete_func)s %(prog_name)s
|
|
-"""
|
|
-
|
|
-COMPLETION_SCRIPT_ZSH = """
|
|
-#compdef %(prog_name)s
|
|
-
|
|
-%(complete_func)s() {
|
|
- eval $(env _TYPER_COMPLETE_ARGS="${words[1,$CURRENT]}" %(autocomplete_var)s=complete_zsh %(prog_name)s)
|
|
-}
|
|
-
|
|
-compdef %(complete_func)s %(prog_name)s
|
|
-"""
|
|
-
|
|
-COMPLETION_SCRIPT_FISH = 'complete --command %(prog_name)s --no-files --arguments "(env %(autocomplete_var)s=complete_fish _TYPER_COMPLETE_FISH_ACTION=get-args _TYPER_COMPLETE_ARGS=(commandline -cp) %(prog_name)s)" --condition "env %(autocomplete_var)s=complete_fish _TYPER_COMPLETE_FISH_ACTION=is-args _TYPER_COMPLETE_ARGS=(commandline -cp) %(prog_name)s"'
|
|
-
|
|
-COMPLETION_SCRIPT_POWER_SHELL = """
|
|
-Import-Module PSReadLine
|
|
-Set-PSReadLineKeyHandler -Chord Tab -Function MenuComplete
|
|
-$scriptblock = {
|
|
- param($wordToComplete, $commandAst, $cursorPosition)
|
|
- $Env:%(autocomplete_var)s = "complete_powershell"
|
|
- $Env:_TYPER_COMPLETE_ARGS = $commandAst.ToString()
|
|
- $Env:_TYPER_COMPLETE_WORD_TO_COMPLETE = $wordToComplete
|
|
- %(prog_name)s | ForEach-Object {
|
|
- $commandArray = $_ -Split ":::"
|
|
- $command = $commandArray[0]
|
|
- $helpString = $commandArray[1]
|
|
- [System.Management.Automation.CompletionResult]::new(
|
|
- $command, $command, 'ParameterValue', $helpString)
|
|
- }
|
|
- $Env:%(autocomplete_var)s = ""
|
|
- $Env:_TYPER_COMPLETE_ARGS = ""
|
|
- $Env:_TYPER_COMPLETE_WORD_TO_COMPLETE = ""
|
|
-}
|
|
-Register-ArgumentCompleter -Native -CommandName %(prog_name)s -ScriptBlock $scriptblock
|
|
-"""
|
|
-
|
|
-
|
|
-def install(
|
|
- shell: Optional[str] = None,
|
|
- prog_name: Optional[str] = None,
|
|
- complete_var: Optional[str] = None,
|
|
-) -> Tuple[str, Path]:
|
|
- prog_name = prog_name or click.get_current_context().find_root().info_name
|
|
- assert prog_name
|
|
- if complete_var is None:
|
|
- complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper())
|
|
- if shell is None and shellingham is not None:
|
|
- shell, _ = shellingham.detect_shell()
|
|
- if shell == "bash":
|
|
- installed_path = install_bash(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- return shell, installed_path
|
|
- elif shell == "zsh":
|
|
- installed_path = install_zsh(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- return shell, installed_path
|
|
- elif shell == "fish":
|
|
- installed_path = install_fish(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- return shell, installed_path
|
|
- elif shell in {"powershell", "pwsh"}:
|
|
- installed_path = install_powershell(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- return shell, installed_path
|
|
- else:
|
|
- click.echo(f"Shell {shell} is not supported.")
|
|
- raise click.exceptions.Exit(1)
|
|
-
|
|
-
|
|
-def install_bash(*, prog_name: str, complete_var: str, shell: str) -> Path:
|
|
- # Ref: https://github.com/scop/bash-completion#faq
|
|
- # It seems bash-completion is the official completion system for bash:
|
|
- # Ref: https://www.gnu.org/software/bash/manual/html_node/A-Programmable-Completion-Example.html
|
|
- # But installing in the locations from the docs doesn't seem to have effect
|
|
- completion_path = Path.home() / f".bash_completions/{prog_name}.sh"
|
|
- rc_path = Path.home() / ".bashrc"
|
|
- rc_path.parent.mkdir(parents=True, exist_ok=True)
|
|
- rc_content = ""
|
|
- if rc_path.is_file():
|
|
- rc_content = rc_path.read_text()
|
|
- completion_init_lines = [f"source {completion_path}"]
|
|
- for line in completion_init_lines:
|
|
- if line not in rc_content: # pragma: nocover
|
|
- rc_content += f"\n{line}"
|
|
- rc_content += "\n"
|
|
- rc_path.write_text(rc_content)
|
|
- # Install completion
|
|
- completion_path.parent.mkdir(parents=True, exist_ok=True)
|
|
- script_content = get_completion_script(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- completion_path.write_text(script_content)
|
|
- return completion_path
|
|
-
|
|
-
|
|
-def install_zsh(*, prog_name: str, complete_var: str, shell: str) -> Path:
|
|
- # Setup Zsh and load ~/.zfunc
|
|
- zshrc_path = Path.home() / ".zshrc"
|
|
- zshrc_path.parent.mkdir(parents=True, exist_ok=True)
|
|
- zshrc_content = ""
|
|
- if zshrc_path.is_file():
|
|
- zshrc_content = zshrc_path.read_text()
|
|
- completion_init_lines = [
|
|
- "autoload -Uz compinit",
|
|
- "compinit",
|
|
- "zstyle ':completion:*' menu select",
|
|
- "fpath+=~/.zfunc",
|
|
- ]
|
|
- for line in completion_init_lines:
|
|
- if line not in zshrc_content: # pragma: nocover
|
|
- zshrc_content += f"\n{line}"
|
|
- zshrc_content += "\n"
|
|
- zshrc_path.write_text(zshrc_content)
|
|
- # Install completion under ~/.zfunc/
|
|
- path_obj = Path.home() / f".zfunc/_{prog_name}"
|
|
- path_obj.parent.mkdir(parents=True, exist_ok=True)
|
|
- script_content = get_completion_script(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- path_obj.write_text(script_content)
|
|
- return path_obj
|
|
-
|
|
-
|
|
-def install_fish(*, prog_name: str, complete_var: str, shell: str) -> Path:
|
|
- path_obj = Path.home() / f".config/fish/completions/{prog_name}.fish"
|
|
- parent_dir: Path = path_obj.parent
|
|
- parent_dir.mkdir(parents=True, exist_ok=True)
|
|
- script_content = get_completion_script(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- path_obj.write_text(f"{script_content}\n")
|
|
- return path_obj
|
|
-
|
|
-
|
|
-def install_powershell(*, prog_name: str, complete_var: str, shell: str) -> Path:
|
|
- subprocess.run(
|
|
- [
|
|
- shell,
|
|
- "-Command",
|
|
- "Set-ExecutionPolicy",
|
|
- "Unrestricted",
|
|
- "-Scope",
|
|
- "CurrentUser",
|
|
- ]
|
|
- )
|
|
- result = subprocess.run(
|
|
- [shell, "-NoProfile", "-Command", "echo", "$profile"],
|
|
- check=True,
|
|
- stdout=subprocess.PIPE,
|
|
- )
|
|
- if result.returncode != 0: # pragma: nocover
|
|
- click.echo("Couldn't get PowerShell user profile", err=True)
|
|
- raise click.exceptions.Exit(result.returncode)
|
|
- path_str = ""
|
|
- if isinstance(result.stdout, str): # pragma: nocover
|
|
- path_str = result.stdout
|
|
- if isinstance(result.stdout, bytes):
|
|
- try:
|
|
- # PowerShell would be predominant in Windows
|
|
- path_str = result.stdout.decode("windows-1252")
|
|
- except UnicodeDecodeError: # pragma: nocover
|
|
- try:
|
|
- path_str = result.stdout.decode("utf8")
|
|
- except UnicodeDecodeError:
|
|
- click.echo("Couldn't decode the path automatically", err=True)
|
|
- raise click.exceptions.Exit(1)
|
|
- path_obj = Path(path_str.strip())
|
|
- parent_dir: Path = path_obj.parent
|
|
- parent_dir.mkdir(parents=True, exist_ok=True)
|
|
- script_content = get_completion_script(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- with path_obj.open(mode="a") as f:
|
|
- f.write(f"{script_content}\n")
|
|
- return path_obj
|
|
-
|
|
-
|
|
-def do_bash_complete(cli: click.Command, prog_name: str) -> bool:
|
|
- cwords = click.parser.split_arg_string(os.getenv("COMP_WORDS", ""))
|
|
- cword = int(os.getenv("COMP_CWORD", 0))
|
|
- args = cwords[1:cword]
|
|
- try:
|
|
- incomplete = cwords[cword]
|
|
- except IndexError:
|
|
- incomplete = ""
|
|
-
|
|
- for item in click._bashcomplete.get_choices(cli, prog_name, args, incomplete):
|
|
- click.echo(item[0])
|
|
- return True
|
|
-
|
|
-
|
|
-def do_zsh_complete(cli: click.Command, prog_name: str) -> bool:
|
|
- completion_args = os.getenv("_TYPER_COMPLETE_ARGS", "")
|
|
- cwords = click.parser.split_arg_string(completion_args)
|
|
- args = cwords[1:]
|
|
- if args and not completion_args.endswith(" "):
|
|
- incomplete = args[-1]
|
|
- args = args[:-1]
|
|
- else:
|
|
- incomplete = ""
|
|
-
|
|
- def escape(s: str) -> str:
|
|
- return (
|
|
- s.replace('"', '""')
|
|
- .replace("'", "''")
|
|
- .replace("$", "\\$")
|
|
- .replace("`", "\\`")
|
|
- )
|
|
-
|
|
- res = []
|
|
- for item, help in click._bashcomplete.get_choices(cli, prog_name, args, incomplete):
|
|
- if help:
|
|
- res.append(f'"{escape(item)}":"{escape(help)}"')
|
|
- else:
|
|
- res.append(f'"{escape(item)}"')
|
|
- if res:
|
|
- args_str = "\n".join(res)
|
|
- click.echo(f"_arguments '*: :(({args_str}))'")
|
|
- else:
|
|
- click.echo("_files")
|
|
- return True
|
|
-
|
|
-
|
|
-def do_fish_complete(cli: click.Command, prog_name: str) -> bool:
|
|
- completion_args = os.getenv("_TYPER_COMPLETE_ARGS", "")
|
|
- complete_action = os.getenv("_TYPER_COMPLETE_FISH_ACTION", "")
|
|
- cwords = click.parser.split_arg_string(completion_args)
|
|
- args = cwords[1:]
|
|
- if args and not completion_args.endswith(" "):
|
|
- incomplete = args[-1]
|
|
- args = args[:-1]
|
|
- else:
|
|
- incomplete = ""
|
|
- show_args = []
|
|
- for item, help in click._bashcomplete.get_choices(cli, prog_name, args, incomplete):
|
|
- if help:
|
|
- formatted_help = re.sub(r"\s", " ", help)
|
|
- show_args.append(f"{item}\t{formatted_help}")
|
|
- else:
|
|
- show_args.append(item)
|
|
- if complete_action == "get-args":
|
|
- if show_args:
|
|
- for arg in show_args:
|
|
- click.echo(arg)
|
|
- elif complete_action == "is-args":
|
|
- if show_args:
|
|
- # Activate complete args (no files)
|
|
- sys.exit(0)
|
|
- else:
|
|
- # Deactivate complete args (allow files)
|
|
- sys.exit(1)
|
|
- return True
|
|
-
|
|
-
|
|
-def do_powershell_complete(cli: click.Command, prog_name: str) -> bool:
|
|
- completion_args = os.getenv("_TYPER_COMPLETE_ARGS", "")
|
|
- incomplete = os.getenv("_TYPER_COMPLETE_WORD_TO_COMPLETE", "")
|
|
- cwords = click.parser.split_arg_string(completion_args)
|
|
- args = cwords[1:]
|
|
- for item, help in click._bashcomplete.get_choices(cli, prog_name, args, incomplete):
|
|
- click.echo(f"{item}:::{help or ' '}")
|
|
-
|
|
- return True
|
|
-
|
|
-
|
|
-def do_shell_complete(*, cli: click.Command, prog_name: str, shell: str) -> bool:
|
|
- if shell == "bash":
|
|
- return do_bash_complete(cli, prog_name)
|
|
- elif shell == "zsh":
|
|
- return do_zsh_complete(cli, prog_name)
|
|
- elif shell == "fish":
|
|
- return do_fish_complete(cli, prog_name)
|
|
- elif shell in {"powershell", "pwsh"}:
|
|
- return do_powershell_complete(cli, prog_name)
|
|
- return False
|
|
-
|
|
-
|
|
-_completion_scripts = {
|
|
- "bash": COMPLETION_SCRIPT_BASH,
|
|
- "zsh": COMPLETION_SCRIPT_ZSH,
|
|
- "fish": COMPLETION_SCRIPT_FISH,
|
|
- "powershell": COMPLETION_SCRIPT_POWER_SHELL,
|
|
- "pwsh": COMPLETION_SCRIPT_POWER_SHELL,
|
|
-}
|
|
-
|
|
-
|
|
-def get_completion_script(*, prog_name: str, complete_var: str, shell: str) -> str:
|
|
- cf_name = click._bashcomplete._invalid_ident_char_re.sub(
|
|
- "", prog_name.replace("-", "_")
|
|
- )
|
|
- script = _completion_scripts.get(shell)
|
|
- if script is None:
|
|
- click.echo(f"Shell {shell} not supported.", err=True)
|
|
- sys.exit(1)
|
|
- return (
|
|
- script
|
|
- % dict(
|
|
- complete_func="_{}_completion".format(cf_name),
|
|
- prog_name=prog_name,
|
|
- autocomplete_var=complete_var,
|
|
- )
|
|
- ).strip()
|
|
-
|
|
-
|
|
-def handle_shell_complete(
|
|
- cli: click.Command, prog_name: str, complete_var: str, complete_instr: str
|
|
-) -> bool:
|
|
- if "_" not in complete_instr:
|
|
- click.echo("Invalid completion instruction.", err=True)
|
|
- sys.exit(1)
|
|
- command, shell = complete_instr.split("_", 1)
|
|
- if command == "source":
|
|
- click.echo(
|
|
- get_completion_script(
|
|
- prog_name=prog_name, complete_var=complete_var, shell=shell
|
|
- )
|
|
- )
|
|
- return True
|
|
- elif command == "complete":
|
|
- return do_shell_complete(cli=cli, prog_name=prog_name, shell=shell)
|
|
- return False
|
|
-
|
|
-
|
|
-def completion_init() -> None:
|
|
- global _click_patched
|
|
- if not _click_patched:
|
|
- testing = os.getenv("_TYPER_COMPLETE_TESTING")
|
|
-
|
|
- def testing_handle_shell_complete(
|
|
- cli: click.Command, prog_name: str, complete_var: str, complete_instr: str
|
|
- ) -> bool:
|
|
- result = handle_shell_complete(cli, prog_name, complete_var, complete_instr)
|
|
- if result:
|
|
- # Avoid fast_exit(1) in Click so Coverage can finish
|
|
- sys.exit(1)
|
|
- return result
|
|
-
|
|
- if testing:
|
|
- click._bashcomplete.bashcomplete = testing_handle_shell_complete
|
|
- else:
|
|
- click._bashcomplete.bashcomplete = handle_shell_complete
|
|
- _click_patched = True
|
|
diff --git a/typer/main.py b/typer/main.py
|
|
index 02d9a5d..87afbbd 100644
|
|
--- a/typer/main.py
|
|
+++ b/typer/main.py
|
|
@@ -8,7 +8,6 @@ from uuid import UUID
|
|
|
|
import click
|
|
|
|
-from .completion import get_completion_inspect_parameters
|
|
from .core import TyperArgument, TyperCommand
|
|
from .models import (
|
|
AnyType,
|
|
@@ -31,13 +30,6 @@ from .models import (
|
|
from .utils import get_params_from_function
|
|
|
|
|
|
-def get_install_completion_arguments() -> Tuple[click.Parameter, click.Parameter]:
|
|
- install_param, show_param = get_completion_inspect_parameters()
|
|
- click_install_param, _ = get_click_param(install_param)
|
|
- click_show_param, _ = get_click_param(show_param)
|
|
- return click_install_param, click_show_param
|
|
-
|
|
-
|
|
class Typer:
|
|
def __init__(
|
|
self,
|
|
@@ -220,8 +212,6 @@ def get_group(typer_instance: Typer) -> click.Command:
|
|
|
|
|
|
def get_command(typer_instance: Typer) -> click.Command:
|
|
- if typer_instance._add_completion:
|
|
- click_install_param, click_show_param = get_install_completion_arguments()
|
|
if (
|
|
typer_instance.registered_callback
|
|
or typer_instance.info.callback
|
|
@@ -230,16 +220,10 @@ def get_command(typer_instance: Typer) -> click.Command:
|
|
):
|
|
# Create a Group
|
|
click_command = get_group(typer_instance)
|
|
- if typer_instance._add_completion:
|
|
- click_command.params.append(click_install_param)
|
|
- click_command.params.append(click_show_param)
|
|
return click_command
|
|
elif len(typer_instance.registered_commands) == 1:
|
|
# Create a single Command
|
|
click_command = get_command_from_info(typer_instance.registered_commands[0])
|
|
- if typer_instance._add_completion:
|
|
- click_command.params.append(click_install_param)
|
|
- click_command.params.append(click_show_param)
|
|
return click_command
|
|
assert False, "Could not get a command for this Typer instance" # pragma no cover
|
|
|