Skip to content
This repository has been archived by the owner on Apr 6, 2024. It is now read-only.

✨ Refactor to make Typer CLI compatible with (and require) Typer >=0.4.0 and Click 8.x.x #82

Merged
merged 12 commits into from
Feb 16, 2023
Merged
13 changes: 6 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
workflow_dispatch:
inputs:
debug_enabled:
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
required: false
default: false

Expand All @@ -16,13 +16,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
python-version: ["3.7", "3.8", "3.9", "3.10"]
fail-fast: false

steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v1
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
# Allow debugging with tmate
Expand All @@ -37,7 +37,7 @@ jobs:
- name: Install poetry
run: |
python -m pip install --upgrade pip
python -m pip install "poetry>=1.2.0a1"
python -m pip install "poetry>=1.2.0a1,<=1.2.0b1"
python -m poetry plugin add poetry-version-plugin
- name: Configure poetry
run: python -m poetry config virtualenvs.in-project true
Expand All @@ -53,9 +53,8 @@ jobs:
- name: Install Dependencies
run: python -m poetry install
- name: Lint
if: matrix.python-version != 3.6
run: python -m poetry run bash scripts/lint.sh
- name: Test
run: python -m poetry run bash scripts/test.sh
- name: Upload coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v2
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ __pycache__
typer_cli.egg-info
.pytest_cache
.coverage
.coverage.*
poetry.lock
11 changes: 6 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Libraries",
Expand All @@ -34,18 +35,18 @@ classifiers = [
]

[tool.poetry.dependencies]
python = "^3.6"
typer = "^0.3.0"
python = "^3.7"
typer = ">=0.4.0,<=0.7.0"
colorama = "^0.4.3"
shellingham = "^1.3.2"

[tool.poetry.dev-dependencies]
pytest = "^7.0.1"
black = {version = "^20.8b1", allow-prereleases = true}
black = "^22.3"
pytest-cov = "^2.8.1"
pytest-xdist = "^2.1.0"
pytest-sugar = "^0.9.2"
mypy = "^0.782"
mypy = "^0.910"
flake8 = "^4.0.1"
isort = "^5.0.6"
autoflake = "^1.3.1"
Expand Down
2 changes: 1 addition & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ set -e
set -x

# Use xdist-pytest --forked to ensure modified sys.path to import relative modules in examples keeps working
pytest --cov=typer_cli --cov=tests --cov-report=term-missing -o console_output_style=progress --forked --numprocesses=auto ${@}
pytest --cov=typer_cli --cov=tests --cov-report=term-missing --cov-report=xml -o console_output_style=progress --forked --numprocesses=auto ${@}
1 change: 1 addition & 0 deletions tests/test_completion_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def test_script_completion_run():
env={
**os.environ,
"___MAIN__.PY_COMPLETE": "complete_bash",
"_PYTHON _M TYPER_CLI_COMPLETE": "complete_bash",
"COMP_WORDS": "typer tests/assets/sample.py",
"COMP_CWORD": "2",
"_TYPER_COMPLETE_TESTING": "True",
Expand Down
1 change: 1 addition & 0 deletions tests/test_sub_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ def test_script_completion_run():
env={
**os.environ,
"___MAIN__.PY_COMPLETE": "complete_bash",
"_PYTHON _M TYPER_CLI_COMPLETE": "complete_bash",
"COMP_WORDS": "typer tests/assets/sample.py run hello --",
"COMP_CWORD": "4",
"_TYPER_COMPLETE_TESTING": "True",
Expand Down
27 changes: 6 additions & 21 deletions typer_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
import re
import sys
from pathlib import Path
from typing import Any, Iterable, List, Optional, Tuple, cast
from typing import Any, List, Optional, cast

import click
import click.core
import typer
import typer.core
from click import Command, Group, Option
from click._bashcomplete import get_choices as original_get_choices # type: ignore
from click._bashcomplete import resolve_ctx # type: ignore

from . import __version__

Expand Down Expand Up @@ -53,8 +51,8 @@ def maybe_update_state(ctx: click.Context) -> None:
state.func = func_name


class TyperCLIGroup(click.Group):
def list_commands(self, ctx: click.Context) -> Iterable[str]:
class TyperCLIGroup(typer.core.TyperGroup):
def list_commands(self, ctx: click.Context) -> List[str]:
self.maybe_add_run(ctx)
return super().list_commands(ctx)

Expand All @@ -74,7 +72,7 @@ def maybe_add_run(self, ctx: click.Context) -> None:
def get_typer_from_module(module: Any) -> Optional[typer.Typer]:
# Try to get defined app
if state.app:
obj: typer.Typer = getattr(module, state.app, None)
obj = getattr(module, state.app, None)
if not isinstance(obj, typer.Typer):
typer.echo(f"Not a Typer object: --app {state.app}", err=True)
sys.exit(1)
Expand Down Expand Up @@ -151,26 +149,14 @@ def maybe_add_run_to_cli(cli: click.Group) -> None:
cli.add_command(click_obj)


def get_choices(
cli: Command, prog_name: str, args: List[str], incomplete: str
) -> List[Tuple[str, str]]:
ctx: typer.Context = resolve_ctx(cli, prog_name, args)
if ctx.parent is None:
assert isinstance(cli, Group)
cli = cast(Group, cli)
maybe_update_state(ctx)
maybe_add_run_to_cli(cli)
return original_get_choices(cli, prog_name, args, incomplete)


def print_version(ctx: click.Context, param: Option, value: bool) -> None:
if not value or ctx.resilient_parsing:
return
typer.echo(f"Typer CLI version: {__version__}")
raise typer.Exit()


@app.callback(cls=TyperCLIGroup)
@app.callback(cls=TyperCLIGroup, no_args_is_help=True)
def callback(
ctx: typer.Context,
*,
Expand Down Expand Up @@ -302,5 +288,4 @@ def docs(


def main() -> Any:
click._bashcomplete.get_choices = get_choices
return app()