:sparkles: Add docs for testing, password, version, context. Extra tests, include callback and autocompletion PR (#68)
* :sparkles: Implement custom handling for callbacks with types
* :sparkles: Implement type-based handling for completion functions
* :sparkles: Add examples for custom completion
* :memo: Add docs for custom autocompletion
* :white_check_mark: Add tests for autocompletion
* :sparkles: Document using the context
* :white_check_mark: Add tests for using the context
* :white_check_mark: Add tests init for context
* :wrench: Update Mypy config
* :white_check_mark: Add extra tests for completion
* :pencil2: Fix format, typos, and minor texts
* :sparkles: Update docs for printing, include stdout, stderr, and stdin
* :pencil2: Add references to FastAPI, fix typos
* :pencil2: Fix typo in Typer CLI
* :memo: Update docs for version
* :memo: Update docs for callbacks
* :memo: Update references to stdout/stderr in autocompletion
* :memo: Add docs for password in CLI option
* :memo: Add docs and tests for Testing
* :memo: Add new sections to docs
* :art: Fix formatting
2020-03-18 21:17:47 +01:00
|
|
|
import os
|
|
|
|
import subprocess
|
|
|
|
from pathlib import Path
|
2020-01-05 22:20:54 +01:00
|
|
|
from typing import Optional
|
2020-03-16 13:21:58 +01:00
|
|
|
from unittest import mock
|
2020-01-05 22:20:54 +01:00
|
|
|
|
:sparkles: Add docs for testing, password, version, context. Extra tests, include callback and autocompletion PR (#68)
* :sparkles: Implement custom handling for callbacks with types
* :sparkles: Implement type-based handling for completion functions
* :sparkles: Add examples for custom completion
* :memo: Add docs for custom autocompletion
* :white_check_mark: Add tests for autocompletion
* :sparkles: Document using the context
* :white_check_mark: Add tests for using the context
* :white_check_mark: Add tests init for context
* :wrench: Update Mypy config
* :white_check_mark: Add extra tests for completion
* :pencil2: Fix format, typos, and minor texts
* :sparkles: Update docs for printing, include stdout, stderr, and stdin
* :pencil2: Add references to FastAPI, fix typos
* :pencil2: Fix typo in Typer CLI
* :memo: Update docs for version
* :memo: Update docs for callbacks
* :memo: Update references to stdout/stderr in autocompletion
* :memo: Add docs for password in CLI option
* :memo: Add docs and tests for Testing
* :memo: Add new sections to docs
* :art: Fix formatting
2020-03-18 21:17:47 +01:00
|
|
|
import click
|
|
|
|
import pytest
|
2020-03-16 13:21:58 +01:00
|
|
|
import shellingham
|
2020-01-05 22:20:54 +01:00
|
|
|
import typer
|
2020-03-16 13:21:58 +01:00
|
|
|
import typer.completion
|
2020-01-05 22:20:54 +01:00
|
|
|
from typer.main import solve_typer_info_defaults, solve_typer_info_help
|
|
|
|
from typer.models import TyperInfo
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
|
|
|
|
|
|
def test_optional():
|
|
|
|
app = typer.Typer()
|
|
|
|
|
|
|
|
@app.command()
|
|
|
|
def opt(user: Optional[str] = None):
|
|
|
|
if user:
|
|
|
|
typer.echo(f"User: {user}")
|
|
|
|
else:
|
|
|
|
typer.echo("No user")
|
|
|
|
|
|
|
|
result = runner.invoke(app)
|
|
|
|
assert result.exit_code == 0
|
|
|
|
assert "No user" in result.output
|
|
|
|
|
|
|
|
result = runner.invoke(app, ["--user", "Camila"])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
assert "User: Camila" in result.output
|
|
|
|
|
|
|
|
|
|
|
|
def test_no_type():
|
|
|
|
app = typer.Typer()
|
|
|
|
|
|
|
|
@app.command()
|
|
|
|
def no_type(user):
|
|
|
|
typer.echo(f"User: {user}")
|
|
|
|
|
|
|
|
result = runner.invoke(app, ["Camila"])
|
|
|
|
assert result.exit_code == 0
|
|
|
|
assert "User: Camila" in result.output
|
|
|
|
|
|
|
|
|
|
|
|
def test_help_from_info():
|
|
|
|
# Mainly for coverage/completeness
|
|
|
|
value = solve_typer_info_help(TyperInfo())
|
|
|
|
assert value is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_defaults_from_info():
|
|
|
|
# Mainly for coverage/completeness
|
|
|
|
value = solve_typer_info_defaults(TyperInfo())
|
|
|
|
assert value
|
2020-03-16 13:21:58 +01:00
|
|
|
|
|
|
|
|
|
|
|
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
|
:sparkles: Add docs for testing, password, version, context. Extra tests, include callback and autocompletion PR (#68)
* :sparkles: Implement custom handling for callbacks with types
* :sparkles: Implement type-based handling for completion functions
* :sparkles: Add examples for custom completion
* :memo: Add docs for custom autocompletion
* :white_check_mark: Add tests for autocompletion
* :sparkles: Document using the context
* :white_check_mark: Add tests for using the context
* :white_check_mark: Add tests init for context
* :wrench: Update Mypy config
* :white_check_mark: Add extra tests for completion
* :pencil2: Fix format, typos, and minor texts
* :sparkles: Update docs for printing, include stdout, stderr, and stdin
* :pencil2: Add references to FastAPI, fix typos
* :pencil2: Fix typo in Typer CLI
* :memo: Update docs for version
* :memo: Update docs for callbacks
* :memo: Update references to stdout/stderr in autocompletion
* :memo: Add docs for password in CLI option
* :memo: Add docs and tests for Testing
* :memo: Add new sections to docs
* :art: Fix formatting
2020-03-18 21:17:47 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_callback_too_many_parameters():
|
|
|
|
app = typer.Typer()
|
|
|
|
|
|
|
|
def name_callback(ctx, param, val1, val2):
|
|
|
|
pass # pragma: nocover
|
|
|
|
|
|
|
|
@app.command()
|
|
|
|
def main(name: str = typer.Option(..., callback=name_callback)):
|
|
|
|
pass # pragma: nocover
|
|
|
|
|
|
|
|
with pytest.raises(click.ClickException) as exc_info:
|
|
|
|
runner.invoke(app, ["--name", "Camila"])
|
|
|
|
assert (
|
|
|
|
exc_info.value.message == "Too many CLI parameter callback function parameters"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_callback_2_untyped_parameters():
|
|
|
|
app = typer.Typer()
|
|
|
|
|
|
|
|
def name_callback(ctx, value):
|
|
|
|
typer.echo(f"info name is: {ctx.info_name}")
|
|
|
|
typer.echo(f"value is: {value}")
|
|
|
|
|
|
|
|
@app.command()
|
|
|
|
def main(name: str = typer.Option(..., callback=name_callback)):
|
|
|
|
typer.echo("Hello World")
|
|
|
|
|
|
|
|
result = runner.invoke(app, ["--name", "Camila"])
|
|
|
|
assert "info name is: main" in result.stdout
|
|
|
|
assert "value is: Camila" in result.stdout
|
|
|
|
|
|
|
|
|
|
|
|
def test_callback_3_untyped_parameters():
|
|
|
|
app = typer.Typer()
|
|
|
|
|
|
|
|
def name_callback(ctx, param, value):
|
|
|
|
typer.echo(f"info name is: {ctx.info_name}")
|
|
|
|
typer.echo(f"param name is: {param.name}")
|
|
|
|
typer.echo(f"value is: {value}")
|
|
|
|
|
|
|
|
@app.command()
|
|
|
|
def main(name: str = typer.Option(..., callback=name_callback)):
|
|
|
|
typer.echo("Hello World")
|
|
|
|
|
|
|
|
result = runner.invoke(app, ["--name", "Camila"])
|
|
|
|
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"
|