Skip to content

Commit 95ac142

Browse files
committed
Fix for click 8.2
1 parent 0e9a654 commit 95ac142

File tree

11 files changed

+117
-57
lines changed

11 files changed

+117
-57
lines changed

.github/workflows/python_ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ jobs:
3131
- {python-version: "3.7", testenvs: "py37-click{7.1,8.0,8.1}", experimental: False}
3232
- {python-version: "3.8", testenvs: "py38-click{7.1,8.0,8.1},build", experimental: False}
3333
- {python-version: "3.9", testenvs: "py39-click{7.1,8.0,8.1},build", experimental: False}
34-
- {python-version: "3.10", testenvs: "py310-click{7.1,8.0,8.1},build", experimental: False}
35-
- {python-version: "3.11", testenvs: "py311-click{7.1,8.0,8.1},build", experimental: False}
36-
- {python-version: "3.12", testenvs: "py312-click{7.1,8.0,8.1},build", experimental: False}
37-
- {python-version: "3.13", testenvs: "py313-click{7.1,8.0,8.1},build", experimental: False}
34+
- {python-version: "3.10", testenvs: "py310-click{7.1,8.0,8.1,8.2},build", experimental: False}
35+
- {python-version: "3.11", testenvs: "py311-click{7.1,8.0,8.1,8.2},build", experimental: False}
36+
- {python-version: "3.12", testenvs: "py312-click{7.1,8.0,8.1,8.2},build", experimental: False}
37+
- {python-version: "3.13", testenvs: "py313-click{7.1,8.0,8.1,8.2},build", experimental: False}
3838
- {python-version: "pypy-3.7", testenvs: "pypy37-click{7.1,8.0,8.1}", experimental: False}
3939
- {python-version: "pypy-3.8", testenvs: "pypy38-click{7.1,8.0,8.1},build", experimental: False}
4040
- {python-version: "pypy-3.9-v7.3.15", testenvs: "pypy39-click{7.1,8.0,8.1},build", experimental: True}

.github/workflows/python_ci_linux.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ jobs:
3232
- {python-version: "3.7", testenvs: "py37-click{7.1,8.0,8.1}", experimental: False}
3333
- {python-version: "3.8", testenvs: "py38-click{7.1,8.0,8.1},build", experimental: False}
3434
- {python-version: "3.9", testenvs: "py39-click{7.1,8.0,8.1},build", experimental: False}
35-
- {python-version: "3.10", testenvs: "py310-click{7.1,8.0,8.1},build", experimental: False}
36-
- {python-version: "3.11", testenvs: "py311-click{7.1,8.0,8.1},build", experimental: False}
37-
- {python-version: "3.12", testenvs: "py312-click{7.1,8.0,8.1},build", experimental: False}
38-
- {python-version: "3.13", testenvs: "py313-click{7.1,8.0,8.1},build", experimental: False}
35+
- {python-version: "3.10", testenvs: "py310-click{7.1,8.0,8.1,8.2},build", experimental: False}
36+
- {python-version: "3.11", testenvs: "py311-click{7.1,8.0,8.1,8.2},build", experimental: False}
37+
- {python-version: "3.12", testenvs: "py312-click{7.1,8.0,8.1,8.2},build", experimental: False}
38+
- {python-version: "3.13", testenvs: "py313-click{7.1,8.0,8.1,8.2},build", experimental: False}
3939
- {python-version: "pypy-3.7", testenvs: "pypy37-click{7.1,8.0,8.1}", experimental: False}
4040
- {python-version: "pypy-3.8", testenvs: "pypy38-click{7.1,8.0,8.1},build", experimental: False}
4141
- {python-version: "pypy-3.9", testenvs: "pypy39-click{7.1,8.0,8.1},build", experimental: True}

.github/workflows/python_ci_macos.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ jobs:
3131
- {python-version: "3.7", os-ver: "13", testenvs: "py37-click{7.1,8.0,8.1}", experimental: False}
3232
- {python-version: "3.8", os-ver: "14", testenvs: "py38-click{7.1,8.0,8.1},build", experimental: False}
3333
- {python-version: "3.9", os-ver: "14", testenvs: "py39-click{7.1,8.0,8.1},build", experimental: False}
34-
- {python-version: "3.10", os-ver: "14", testenvs: "py310-click{7.1,8.0,8.1},build", experimental: False}
35-
- {python-version: "3.11", os-ver: "14", testenvs: "py311-click{7.1,8.0,8.1},build", experimental: False}
36-
- {python-version: "3.12", os-ver: "14", testenvs: "py312-click{7.1,8.0,8.1},build", experimental: False}
37-
- {python-version: "3.13", os-ver: "14", testenvs: "py313-click{7.1,8.0,8.1},build", experimental: False}
34+
- {python-version: "3.10", os-ver: "14", testenvs: "py310-click{7.1,8.0,8.1,8.2},build", experimental: False}
35+
- {python-version: "3.11", os-ver: "14", testenvs: "py311-click{7.1,8.0,8.1,8.2},build", experimental: False}
36+
- {python-version: "3.12", os-ver: "14", testenvs: "py312-click{7.1,8.0,8.1,8.2},build", experimental: False}
37+
- {python-version: "3.13", os-ver: "14", testenvs: "py313-click{7.1,8.0,8.1,8.2},build", experimental: False}
3838
- {python-version: "pypy-3.7", os-ver: "13", testenvs: "pypy37-click{7.1,8.0,8.1}", experimental: False}
3939
- {python-version: "pypy-3.8", os-ver: "14", testenvs: "pypy38-click{7.1,8.0,8.1},build", experimental: False}
4040
- {python-version: "pypy-3.9", os-ver: "14", testenvs: "pypy39-click{7.1,8.0,8.1},build", experimental: True}

consolekit/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
# 3rd party
4747
import click
48+
from domdf_python_tools.compat import importlib_metadata
4849

4950
# this package
5051
from consolekit import _readline, commands, input, terminal_colours, tracebacks, utils # noqa: F401
@@ -145,4 +146,5 @@ def option(
145146
click.Context.__module__ = "click"
146147
click.HelpFormatter.__module__ = "click"
147148
click.Group.__module__ = "click"
148-
click.OptionParser.__module__ = "click"
149+
if tuple(map(int, (importlib_metadata.version("click").split('.')))) < (8, 2):
150+
click.OptionParser.__module__ = "click"

consolekit/commands.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464
# 3rd party
6565
import click
6666
from click.core import iter_params_for_processing
67-
from click.parser import split_opt
6867
from click.utils import make_str
6968
from domdf_python_tools.stringlist import DelimitedList
7069
from domdf_python_tools.words import Plural
@@ -88,6 +87,18 @@
8887
_argument = Plural("argument", "arguments")
8988

9089

90+
def _split_opt(opt: str) -> Tuple[str, str]:
91+
first = opt[:1]
92+
93+
if first.isalnum():
94+
return '', opt
95+
96+
if opt[1:2] == first:
97+
return opt[:2], opt[2:]
98+
99+
return first, opt[1:]
100+
101+
91102
class RawHelpMixin:
92103
"""
93104
Mixin class for :class:`click.Command` and :class:`click.Group` which leaves the help text unformatted.
@@ -172,7 +183,7 @@ def get_params(self, ctx: click.Context) -> List[click.Parameter]:
172183

173184
raise NotImplementedError
174185

175-
def make_parser(self, ctx: click.Context) -> click.OptionParser:
186+
def make_parser(self, ctx: click.Context) -> "click.OptionParser":
176187
"""
177188
Creates the underlying option parser for this command.
178189
@@ -399,7 +410,7 @@ def resolve_command(
399410
# if the first argument looks like an option we want to kick off parsing again
400411
# for arguments to resolve things like --help which now should go to the main place.
401412
if cmd is None and not ctx.resilient_parsing:
402-
if split_opt(cmd_name)[0]:
413+
if _split_opt(cmd_name)[0]:
403414
self.parse_args(ctx, ctx.args)
404415

405416
closest = difflib.get_close_matches(original_cmd_name, self.commands, n=1)

consolekit/options.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
# 3rd party
6666
import click
6767
from click.decorators import _param_memo
68+
from domdf_python_tools.compat import importlib_metadata
6869

6970
# this package
7071
import consolekit.input
@@ -377,7 +378,7 @@ def __init__(
377378
self._previous_parser_process: Optional[Callable] = None
378379
self._eat_all_parser: Optional[click.parser.Option] = None
379380

380-
def add_to_parser(self, parser: click.OptionParser, ctx: click.Context) -> Any:
381+
def add_to_parser(self, parser: "click.OptionParser", ctx: click.Context) -> Any:
381382
"""
382383
Add the :class:`~.MultiValueOption` to the given parser.
383384
@@ -444,7 +445,7 @@ def process_value(self, ctx: click.Context, value: Any) -> Optional[Tuple]:
444445
else:
445446
return None
446447

447-
if int(click.__version__.split('.')[0]) == 7: # pragma: nocover
448+
if int(importlib_metadata.version("click").split('.')[0]) == 7: # pragma: nocover
448449

449450
def get_default(self, ctx): # noqa: MAN001,MAN002,D102
450451
if callable(self.default):

consolekit/testing.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,13 @@
6565
import click.testing
6666
import pytest # nodep
6767
from coincidence.regressions import check_file_regression # nodep
68+
from domdf_python_tools.compat import importlib_metadata
6869
from pytest_regressions.file_regression import FileRegressionFixture # nodep
6970
from typing_extensions import Literal
7071

7172
__all__ = ("CliRunner", "Result", "cli_runner")
7273

73-
_click_major = int(click.__version__.split('.')[0])
74+
_click_version = tuple(map(int, importlib_metadata.version("click").split('.')))
7475

7576

7677
class Result(click.testing.Result):
@@ -101,9 +102,21 @@ def __init__(
101102
exit_code: int,
102103
exception: Optional[BaseException],
103104
exc_info: Optional[Tuple[Type[BaseException], BaseException, TracebackType]] = None,
105+
output_bytes: Optional[bytes] = None,
104106
) -> None:
105107

106-
if _click_major >= 8:
108+
if _click_version >= (8, 2):
109+
super().__init__(
110+
runner=runner,
111+
stdout_bytes=stdout_bytes,
112+
stderr_bytes=stderr_bytes,
113+
output_bytes=output_bytes, # type: ignore[call-arg]
114+
exit_code=exit_code,
115+
exception=exception,
116+
exc_info=exc_info,
117+
return_value=None,
118+
)
119+
elif _click_version[0] >= 8:
107120
super().__init__(
108121
runner=runner,
109122
stdout_bytes=stdout_bytes,
@@ -129,6 +142,10 @@ def output(self) -> str:
129142
The (standard) output as a string.
130143
"""
131144

145+
if _click_version >= (8, 2):
146+
ob = self.output_bytes # type: ignore[attr-defined]
147+
return ob.decode(self.runner.charset, "replace").replace("\r\n", '\n')
148+
132149
return super().output
133150

134151
@property
@@ -149,13 +166,19 @@ def stderr(self) -> str:
149166

150167
@classmethod
151168
def _from_click_result(cls, result: click.testing.Result) -> "Result":
169+
if _click_version >= (8, 2):
170+
output_bytes = result.output_bytes # type: ignore[attr-defined]
171+
else:
172+
output_bytes = None
173+
152174
return cls(
153175
runner=result.runner,
154176
stdout_bytes=result.stdout_bytes,
155177
stderr_bytes=result.stderr_bytes,
156178
exit_code=result.exit_code,
157179
exception=result.exception,
158180
exc_info=result.exc_info,
181+
output_bytes=output_bytes,
159182
)
160183

161184
def check_stdout(
@@ -174,7 +197,10 @@ def check_stdout(
174197

175198
__tracebackhide__ = True
176199

177-
check_file_regression(self.stdout.rstrip(), file_regression, extension=extension, **kwargs)
200+
if _click_version >= (8, 2) and self.runner.mix_stderr:
201+
check_file_regression(self.output.rstrip(), file_regression, extension=extension, **kwargs)
202+
else:
203+
check_file_regression(self.stdout.rstrip(), file_regression, extension=extension, **kwargs)
178204

179205
return True
180206

@@ -206,11 +232,15 @@ def __init__(
206232
echo_stdin: bool = False,
207233
mix_stderr: bool = True,
208234
) -> None:
209-
super().__init__(charset, env, echo_stdin, mix_stderr)
235+
if _click_version >= (8, 2):
236+
super().__init__(charset, env, echo_stdin)
237+
self.mix_stderr = mix_stderr
238+
else:
239+
super().__init__(charset, env, echo_stdin, mix_stderr)
210240

211241
def invoke( # type: ignore[override]
212242
self,
213-
cli: click.BaseCommand,
243+
cli: click.Command,
214244
args: Optional[Union[str, Iterable[str]]] = None,
215245
input: Optional[Union[bytes, str, IO]] = None, # noqa: A002 # pylint: disable=redefined-builtin
216246
env: Optional[Mapping[str, str]] = None,

repo_helper.yml

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,34 @@ conda_extras:
1919
- none
2020

2121
python_versions:
22-
- 3.7
23-
- 3.8
24-
- 3.9
25-
- "3.10"
26-
- "3.11"
27-
- "3.12"
28-
- "3.13"
29-
- pypy37
30-
- pypy38
31-
- pypy39
22+
3.7:
23+
matrix_exclude:
24+
click:
25+
- 8.2
26+
3.8:
27+
matrix_exclude:
28+
click:
29+
- 8.2
30+
3.9:
31+
matrix_exclude:
32+
click:
33+
- 8.2
34+
"3.10":
35+
"3.11":
36+
"3.12":
37+
"3.13":
38+
pypy37:
39+
matrix_exclude:
40+
click:
41+
- 8.2
42+
pypy38:
43+
matrix_exclude:
44+
click:
45+
- 8.2
46+
pypy39:
47+
matrix_exclude:
48+
click:
49+
- 8.2
3250

3351
classifiers:
3452
- 'Development Status :: 5 - Production/Stable'
@@ -59,6 +77,7 @@ third_party_version_matrix:
5977
- 7.1
6078
- 8.0
6179
- 8.1
80+
- 8.2
6281

6382
extra_sphinx_extensions:
6483
- sphinx_autofixture

tests/test_input.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
# this package
1212
from consolekit.input import choice, confirm, prompt
13-
from consolekit.testing import _click_major
13+
from consolekit.testing import _click_version
1414

1515

1616
def test_choice_letters(
@@ -48,11 +48,11 @@ def fake_input(prompt: str) -> str:
4848
[
4949
pytest.param(
5050
'7',
51-
marks=pytest.mark.skipif(_click_major == 8, reason="Output differs on click 8"),
51+
marks=pytest.mark.skipif(_click_version[0] == 8, reason="Output differs on click 8"),
5252
),
5353
pytest.param(
5454
'8',
55-
marks=pytest.mark.skipif(_click_major != 8, reason="Output differs on click 8"),
55+
marks=pytest.mark.skipif(_click_version[0] != 8, reason="Output differs on click 8"),
5656
),
5757
]
5858
)

tests/test_tracebacks.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
# this package
1212
from consolekit import click_command
13-
from consolekit.testing import CliRunner, Result, _click_major
13+
from consolekit.testing import CliRunner, Result, _click_version
1414
from consolekit.tracebacks import TracebackHandler, handle_tracebacks, traceback_handler, traceback_option
1515

1616
exceptions = pytest.mark.parametrize(
@@ -88,7 +88,7 @@ def demo() -> None:
8888

8989
result: Result = cli_runner.invoke(demo, catch_exceptions=False)
9090

91-
assert result.stdout.strip() == "Aborted!"
91+
assert result.output.strip() == "Aborted!"
9292
assert result.exit_code == 1
9393

9494

@@ -114,13 +114,13 @@ def test_handle_tracebacks_ignored_exceptions(
114114
click.FileError("Message"),
115115
1,
116116
id="click.FileError",
117-
marks=pytest.mark.skipif(_click_major == 8, reason="Output differs on Click 8")
117+
marks=pytest.mark.skipif(_click_version[0] == 8, reason="Output differs on Click 8")
118118
),
119119
pytest.param(
120120
click.FileError("Message"),
121121
1,
122122
id="click.FileError_8",
123-
marks=pytest.mark.skipif(_click_major != 8, reason="Output differs on Click 8")
123+
marks=pytest.mark.skipif(_click_version[0] != 8, reason="Output differs on Click 8")
124124
),
125125
pytest.param(click.ClickException("Message"), 1, id="click.ClickException"),
126126
]
@@ -131,11 +131,11 @@ def test_handle_tracebacks_ignored_exceptions(
131131
[
132132
pytest.param(
133133
'7',
134-
marks=pytest.mark.skipif(_click_major == 8, reason="Output differs on click 8"),
134+
marks=pytest.mark.skipif(_click_version[0] == 8, reason="Output differs on click 8"),
135135
),
136136
pytest.param(
137137
'8',
138-
marks=pytest.mark.skipif(_click_major != 8, reason="Output differs on click 8"),
138+
marks=pytest.mark.skipif(_click_version[0] != 8, reason="Output differs on click 8"),
139139
),
140140
]
141141
)

0 commit comments

Comments
 (0)