Skip to content

Commit c2a908b

Browse files
authored
Merge pull request #42 from thetic/types
PEP 561 support
2 parents fa1e383 + 543a14d commit c2a908b

File tree

3 files changed

+44
-23
lines changed

3 files changed

+44
-23
lines changed

click_option_group/_core.py

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
# -*- coding: utf-8 -*-
22

3-
from typing import Optional, List, Tuple, Dict, Set
4-
53
import collections
6-
import weakref
74
import inspect
5+
import weakref
6+
from collections.abc import Callable
7+
from typing import (
8+
Any,
9+
Dict,
10+
List,
11+
Mapping,
12+
Optional,
13+
Sequence,
14+
Set,
15+
Tuple,
16+
Union,
17+
)
818

919
import click
1020
from click.core import augment_usage_errors
@@ -16,6 +26,8 @@
1626
resolve_wrappers
1727
)
1828

29+
FC = Union[Callable, click.Command]
30+
1931

2032
class GroupedOption(click.Option):
2133
"""Represents grouped (related) optional values
@@ -27,7 +39,7 @@ class GroupedOption(click.Option):
2739
:param attrs: additional option attributes
2840
"""
2941

30-
def __init__(self, param_decls=None, *, group: 'OptionGroup', **attrs):
42+
def __init__(self, param_decls: Optional[Sequence[str]] = None, *, group: 'OptionGroup', **attrs: Any):
3143
super().__init__(param_decls, **attrs)
3244

3345
for attr in group.forbidden_option_attrs:
@@ -45,13 +57,15 @@ def group(self) -> 'OptionGroup':
4557
"""
4658
return self.__group
4759

48-
def handle_parse_result(self, ctx, opts, args):
60+
def handle_parse_result(
61+
self, ctx: click.Context, opts: Mapping[str, Any], args: List[str]
62+
) -> Tuple[Any, List[str]]:
4963
with augment_usage_errors(ctx, param=self):
5064
if not ctx.resilient_parsing:
5165
self.group.handle_parse_result(self, ctx, opts)
5266
return super().handle_parse_result(ctx, opts, args)
5367

54-
def get_help_record(self, ctx: click.Context):
68+
def get_help_record(self, ctx: click.Context) -> Optional[Tuple[str, str]]:
5569
help_record = super().get_help_record(ctx)
5670
if help_record is None:
5771
# this happens if the option is hidden
@@ -69,7 +83,9 @@ class _GroupTitleFakeOption(click.Option):
6983
"""The helper `Option` class to display option group title in help
7084
"""
7185

72-
def __init__(self, param_decls=None, *, group: 'OptionGroup', **attrs):
86+
def __init__(
87+
self, param_decls: Optional[Sequence[str]] = None, *, group: 'OptionGroup', **attrs: Any
88+
) -> None:
7389
self.__group = group
7490
super().__init__(param_decls, hidden=True, expose_value=False, help=group.help, **attrs)
7591

@@ -78,7 +94,7 @@ def __init__(self, param_decls=None, *, group: 'OptionGroup', **attrs):
7894
self.opts = []
7995
self.secondary_opts = []
8096

81-
def get_help_record(self, ctx: click.Context):
97+
def get_help_record(self, ctx: click.Context) -> Optional[Tuple[str, str]]:
8298
return self.__group.get_help_record(ctx)
8399

84100

@@ -92,13 +108,14 @@ class OptionGroup:
92108
:param help: the group help text or None
93109
"""
94110

95-
def __init__(self, name: Optional[str] = None, *,
96-
hidden=False, help: Optional[str] = None) -> None: # noqa
111+
def __init__(
112+
self, name: Optional[str] = None, *, hidden: bool = False, help: Optional[str] = None
113+
) -> None:
97114
self._name = name if name else ''
98115
self._help = inspect.cleandoc(help if help else '')
99116
self._hidden = hidden
100117

101-
self._options = collections.defaultdict(weakref.WeakValueDictionary)
118+
self._options: Mapping[Any, Any] = collections.defaultdict(weakref.WeakValueDictionary)
102119
self._group_title_options = weakref.WeakValueDictionary()
103120

104121
@property
@@ -155,13 +172,13 @@ def get_help_record(self, ctx: click.Context) -> Optional[Tuple[str, str]]:
155172

156173
return name, help_
157174

158-
def option(self, *param_decls, **attrs):
175+
def option(self, *param_decls: str, **attrs: Any) -> Callable:
159176
"""Decorator attaches an grouped option to the command
160177
161178
The decorator is used for adding options to the group and to the Click-command
162179
"""
163180

164-
def decorator(func):
181+
def decorator(func: FC) -> FC:
165182
option_attrs = attrs.copy()
166183
option_attrs.setdefault('cls', GroupedOption)
167184
if self._hidden:
@@ -191,7 +208,7 @@ def get_option_names(self, ctx: click.Context) -> List[str]:
191208
"""
192209
return list(reversed(list(self.get_options(ctx))))
193210

194-
def get_error_hint(self, ctx, option_names: Optional[Set[str]] = None) -> str:
211+
def get_error_hint(self, ctx: click.Context, option_names: Optional[Set[str]] = None) -> str:
195212
options = self.get_options(ctx)
196213
text = ''
197214

@@ -205,11 +222,11 @@ def get_error_hint(self, ctx, option_names: Optional[Set[str]] = None) -> str:
205222

206223
return text
207224

208-
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: dict) -> None:
225+
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: Mapping[str, Any]) -> None:
209226
"""The method should be used for adding specific behavior and relation for options in the group
210227
"""
211228

212-
def _check_mixing_decorators(self, func):
229+
def _check_mixing_decorators(self, func: Callable) -> None:
213230
func, params = get_callback_and_params(func)
214231

215232
if not params or func not in self._options:
@@ -222,7 +239,7 @@ def _check_mixing_decorators(self, func):
222239
if last_param.name != title_option.name and last_param.name not in options:
223240
raise_mixing_decorators_error(last_param, func)
224241

225-
def _add_title_fake_option(self, func):
242+
def _add_title_fake_option(self, func: FC) -> None:
226243
callback, params = get_callback_and_params(func)
227244

228245
if callback not in self._group_title_options:
@@ -240,7 +257,7 @@ def _add_title_fake_option(self, func):
240257
title_index = params.index(title_option)
241258
params[-1], params[title_index] = params[title_index], params[-1]
242259

243-
def _option_memo(self, func):
260+
def _option_memo(self, func: Callable) -> None:
244261
func, params = get_callback_and_params(func)
245262
option = params[-1]
246263
self._options[func][option.name] = option
@@ -263,7 +280,7 @@ def forbidden_option_attrs(self) -> List[str]:
263280
def name_extra(self) -> List[str]:
264281
return super().name_extra + ['required_any']
265282

266-
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: dict) -> None:
283+
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: Mapping[str, Any]) -> None:
267284
if option.name in opts:
268285
return
269286

@@ -301,7 +318,7 @@ def forbidden_option_attrs(self) -> List[str]:
301318
def name_extra(self) -> List[str]:
302319
return super().name_extra + ['required_all']
303320

304-
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: dict) -> None:
321+
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: Mapping[str, Any]) -> None:
305322
option_names = set(self.get_options(ctx))
306323

307324
if not option_names.issubset(opts):
@@ -330,7 +347,7 @@ def forbidden_option_attrs(self) -> List[str]:
330347
def name_extra(self) -> List[str]:
331348
return super().name_extra + ['mutually_exclusive']
332349

333-
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: dict) -> None:
350+
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: Mapping[str, Any]) -> None:
334351
option_names = set(self.get_options(ctx))
335352
given_option_names = option_names.intersection(opts)
336353
given_option_count = len(given_option_names)
@@ -357,7 +374,7 @@ class RequiredMutuallyExclusiveOptionGroup(MutuallyExclusiveOptionGroup):
357374
def name_extra(self) -> List[str]:
358375
return super().name_extra + ['required']
359376

360-
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: dict) -> None:
377+
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: Mapping[str, Any]) -> None:
361378
super().handle_parse_result(option, ctx, opts)
362379

363380
option_names = set(self.get_option_names(ctx))
@@ -389,7 +406,7 @@ def forbidden_option_attrs(self) -> List[str]:
389406
def name_extra(self) -> List[str]:
390407
return super().name_extra + ['all_or_none']
391408

392-
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: dict) -> None:
409+
def handle_parse_result(self, option: GroupedOption, ctx: click.Context, opts: Mapping[str, Any]) -> None:
393410
option_names = set(self.get_options(ctx))
394411

395412
if not option_names.isdisjoint(opts) and option_names.intersection(opts) != option_names:

click_option_group/py.typed

Whitespace-only changes.

setup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ def get_long_description():
2828
name='click-option-group',
2929
version=get_version(),
3030
packages=[PACKAGE_NAME],
31+
package_data={
32+
PACKAGE_NAME: ["py.typed"]
33+
},
34+
include_package_data=True,
3135
python_requires='>=3.6,<4',
3236
install_requires=[
3337
'Click>=7.0,<9',

0 commit comments

Comments
 (0)