Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions phabfive/cli/create_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,13 @@ def options_given(ctx: typer.Context, options: dict) -> list:
list
The options given, in the order ``options`` lists them
"""
from click.core import ParameterSource

# By name, not against click.core.ParameterSource: from typer 0.26 the
# context is typer's own copy of click, whose enum is a different class,
# so an identity check calls every option given
return [
option
for name, option in options.items()
if ctx.get_parameter_source(name) not in (None, ParameterSource.DEFAULT)
if getattr(ctx.get_parameter_source(name), "name", "DEFAULT") != "DEFAULT"
]


Expand Down
56 changes: 56 additions & 0 deletions tests/click_layer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# -*- coding: utf-8 -*-
"""The click that typer builds phabfive's commands on.

Up to typer 0.25 that is the click package. From 0.26 typer carries its own
copy, `typer._click`, and its commands, contexts and completion registry
belong to that copy: `typer.main.get_command(app)` is no longer a
`click.Group` (typer's copy has no Group at all), and `click.shell_completion.get_completion_class` finds none
of the classes typer registers. A test that drives typer's commands through
click's API uses this module instead, so it runs against whichever click
typer is actually using.

`pyproject.toml` allows any typer from 0.12, so both layouts are supported.
"""

import typer.testing

try:
from typer._click import shell_completion
except ImportError:
from click import shell_completion

# The stream CliRunner swaps in for stdin, whose isatty a test patches to
# act interactive. typer 0.26 moved its runner, and this class, into
# typer.testing
try:
NamedTextIOWrapper = typer.testing._NamedTextIOWrapper
except AttributeError:
from click.testing import _NamedTextIOWrapper as NamedTextIOWrapper

get_completion_class = shell_completion.get_completion_class


class ShellComplete(shell_completion.ShellComplete):
"""click's completion base, made concrete.

typer's copy declares the shell-facing methods abstract. A test that only
asks `get_completions` what is offered has no shell to speak to, so
these are never called.
"""

def source_vars(self):
return {}

def get_completion_args(self):
return [], ""

def format_completion(self, item):
return item.value


__all__ = [
"NamedTextIOWrapper",
"ShellComplete",
"get_completion_class",
"shell_completion",
]
4 changes: 2 additions & 2 deletions tests/test_bash_completion_escaping.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
# 3rd party imports
from unittest.mock import MagicMock, patch

import click
import pytest
import typer

# phabfive imports
from phabfive.cli import app, completers
from phabfive.cli.shell_completion import escape_for_bash, install_bash_escaping
from tests.click_layer import get_completion_class


@pytest.mark.parametrize(
Expand Down Expand Up @@ -38,7 +38,7 @@ def _bash_complete(monkeypatch, comp_words):
monkeypatch.setenv("COMP_CWORD", str(len(words) - 1))

command = typer.main.get_command(app) # registers the completion classes
bash = click.shell_completion.get_completion_class("bash")
bash = get_completion_class("bash")
completion = bash(command, {}, "phabfive", "_PHABFIVE_COMPLETE")

phab = MagicMock()
Expand Down
14 changes: 6 additions & 8 deletions tests/test_completers.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,13 @@ def test_the_option_carries_the_completer(self, command_name, spelling):
def test_tab_on_the_option_offers_spec_files_only(
self, command_name, tmp_path, monkeypatch
):
import click

(tmp_path / "sprint-tasks.yaml").touch()
(tmp_path / "notes.md").touch()
monkeypatch.chdir(tmp_path)

option = self._option(command_name, "-f")
context = click.Context(click.Command(command_name))
command = self._command(command_name)
context = command.context_class(command)

offered = option.shell_complete(context, "s")

Expand All @@ -213,14 +212,13 @@ def test_a_directory_keeps_completion_walking(self, tmp_path, monkeypatch):
under it sharing a mistaken assumption is how that survived a full
CI matrix.
"""
import click

(tmp_path / "specs").mkdir()
(tmp_path / "specs" / "sprint.yaml").touch()
monkeypatch.chdir(tmp_path)

option = self._option("apply", "-f")
context = click.Context(click.Command("apply"))
command = self._command("apply")
context = command.context_class(command)

assert [one.value for one in option.shell_complete(context, "sp")] == ["specs/"]
assert [one.value for one in option.shell_complete(context, "specs/")] == [
Expand Down Expand Up @@ -282,10 +280,10 @@ class TestSpecFileCompletionInEveryShell:
"""

def _complete(self, shell, monkeypatch, line, tmp_path):
import click
import typer

from phabfive.cli import app
from tests.click_layer import get_completion_class

words = line.split(" ")

Expand All @@ -309,7 +307,7 @@ def _complete(self, shell, monkeypatch, line, tmp_path):
monkeypatch.chdir(tmp_path)

command = typer.main.get_command(app) # registers the classes
completion_class = click.shell_completion.get_completion_class(shell)
completion_class = get_completion_class(shell)
completion = completion_class(command, {}, "phabfive", "_PHABFIVE_COMPLETE")

return completion.complete()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_fixed_value_completers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

import pytest
import typer
from click.shell_completion import ShellComplete

# phabfive imports
from phabfive.cli import app, completers
from tests.click_layer import ShellComplete
from phabfive.constants import PROJECT_COLORS, PROJECT_ICONS, USER_ROLES


Expand Down
2 changes: 1 addition & 1 deletion tests/test_monogram_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
# 3rd party imports
import pytest
import typer
from click.shell_completion import ShellComplete

# phabfive imports
from phabfive.cli import app
from tests.click_layer import ShellComplete

SUBCOMMANDS = [
"edit",
Expand Down
2 changes: 1 addition & 1 deletion tests/test_space_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ def test_every_tab_probes_when_caching_is_off(self, monkeypatch):
def _offered(args, incomplete):
"""What shell completion offers for a value, through the real CLI."""
import typer
from click.shell_completion import ShellComplete

from phabfive.cli import app
from tests.click_layer import ShellComplete

command = typer.main.get_command(app)
completion = ShellComplete(command, {}, "phabfive", "_PHABFIVE_COMPLETE")
Expand Down
5 changes: 3 additions & 2 deletions tests/test_write_command_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from phabfive.cli import app
from phabfive.cli.output import is_machine_format
from phabfive.core import Phabfive
from tests import click_layer

runner = CliRunner()

Expand Down Expand Up @@ -396,7 +397,7 @@ def test_omitted_text_opens_the_editor(self):
with (
patch("phabfive.cli.maniphest._get_maniphest_app", return_value=maniphest),
# CliRunner swaps in its own stdin, so a patch of sys.stdin is lost
patch("click.testing._NamedTextIOWrapper.isatty", return_value=True),
patch.object(click_layer.NamedTextIOWrapper, "isatty", return_value=True),
patch(
"phabfive.cli.editor.edit_text", return_value="from the editor\n"
) as edit_text,
Expand All @@ -413,7 +414,7 @@ def test_a_cancelled_editor_posts_nothing(self):
with (
patch("phabfive.cli.maniphest._get_maniphest_app", return_value=maniphest),
# CliRunner swaps in its own stdin, so a patch of sys.stdin is lost
patch("click.testing._NamedTextIOWrapper.isatty", return_value=True),
patch.object(click_layer.NamedTextIOWrapper, "isatty", return_value=True),
patch("phabfive.cli.editor.edit_text", return_value=None),
):
result = runner.invoke(app, ["--format=rich", "maniphest", "comment", "T7"])
Expand Down
Loading