77import os
88import sys
99import typing as t
10+ from abc import ABC
11+ from abc import abstractmethod
1012from collections import abc
1113from collections import Counter
1214from contextlib import AbstractContextManager
@@ -838,9 +840,7 @@ def invoke(
838840 # https://github.com/pallets/click/pull/3068
839841 if default_value is UNSET :
840842 default_value = None
841- kwargs [param .name ] = param .type_cast_value ( # type: ignore
842- ctx , default_value
843- )
843+ kwargs [param .name ] = param .type_cast_value (ctx , default_value )
844844
845845 # Track all kwargs as params, so that forward() will pass
846846 # them on in subsequent calls.
@@ -1320,7 +1320,7 @@ def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]:
13201320 or param .hidden
13211321 or (
13221322 not param .multiple
1323- and ctx .get_parameter_source (param .name ) # type: ignore
1323+ and ctx .get_parameter_source (param .name )
13241324 is ParameterSource .COMMANDLINE
13251325 )
13261326 ):
@@ -2053,7 +2053,7 @@ def _check_iter(value: t.Any) -> cabc.Iterator[t.Any]:
20532053 return iter (value )
20542054
20552055
2056- class Parameter :
2056+ class Parameter ( ABC ) :
20572057 r"""A parameter to a command comes in two versions: they are either
20582058 :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently
20592059 not supported by design as some of the internals for parsing are
@@ -2175,7 +2175,7 @@ def __init__(
21752175 | None = None ,
21762176 deprecated : bool | str = False ,
21772177 ) -> None :
2178- self .name : str | None
2178+ self .name : str
21792179 self .opts : list [str ]
21802180 self .secondary_opts : list [str ]
21812181 self .name , self .opts , self .secondary_opts = self ._parse_decls (
@@ -2248,17 +2248,17 @@ def to_info_dict(self) -> dict[str, t.Any]:
22482248 def __repr__ (self ) -> str :
22492249 return f"<{ self .__class__ .__name__ } { self .name } >"
22502250
2251+ @abstractmethod
22512252 def _parse_decls (
22522253 self , decls : cabc .Sequence [str ], expose_value : bool
2253- ) -> tuple [str | None , list [str ], list [str ]]:
2254- raise NotImplementedError ()
2254+ ) -> tuple [str , list [str ], list [str ]]: ...
22552255
22562256 @property
22572257 def human_readable_name (self ) -> str :
22582258 """Returns the human readable name of this parameter. This is the
22592259 same as the name for options, but the metavar for arguments.
22602260 """
2261- return self .name # type: ignore
2261+ return self .name
22622262
22632263 def make_metavar (self , ctx : Context ) -> str :
22642264 if self .metavar is not None :
@@ -2307,19 +2307,18 @@ def get_default(
23072307 .. versionchanged:: 8.0
23082308 Added the ``call`` parameter.
23092309 """
2310- name = self .name
2311- value = ctx .lookup_default (name , call = False ) if name is not None else None
2310+ value = ctx .lookup_default (self .name , call = False )
23122311
2313- if value is None and not ctx ._default_map_has (name ):
2312+ if value is None and not ctx ._default_map_has (self . name ):
23142313 value = self .default
23152314
23162315 if call and callable (value ):
23172316 value = value ()
23182317
23192318 return value
23202319
2321- def add_to_parser ( self , parser : _OptionParser , ctx : Context ) -> None :
2322- raise NotImplementedError ()
2320+ @ abstractmethod
2321+ def add_to_parser ( self , parser : _OptionParser , ctx : Context ) -> None : ...
23232322
23242323 def consume_value (
23252324 self , ctx : Context , opts : cabc .Mapping [str , t .Any ]
@@ -2335,7 +2334,7 @@ def consume_value(
23352334 :meta private:
23362335 """
23372336 # Collect from the parse the value passed by the user to the CLI.
2338- value = opts .get (self .name , UNSET ) # type: ignore
2337+ value = opts .get (self .name , UNSET )
23392338 # If the value is set, it means it was sourced from the command line by the
23402339 # parser, otherwise it left unset by default.
23412340 source = (
@@ -2351,7 +2350,7 @@ def consume_value(
23512350 source = ParameterSource .ENVIRONMENT
23522351
23532352 if value is UNSET :
2354- default_map_value = ctx .lookup_default (self .name ) # type: ignore[arg-type]
2353+ default_map_value = ctx .lookup_default (self .name )
23552354 if default_map_value is not None or ctx ._default_map_has (self .name ):
23562355 value = default_map_value
23572356 source = ParameterSource .DEFAULT_MAP
@@ -2582,7 +2581,7 @@ def handle_parse_result(
25822581 with augment_usage_errors (ctx , param = self ):
25832582 value , source = self .consume_value (ctx , opts )
25842583
2585- ctx .set_parameter_source (self .name , source ) # type: ignore
2584+ ctx .set_parameter_source (self .name , source )
25862585
25872586 # Display a deprecation warning if necessary.
25882587 if (
@@ -2622,24 +2621,22 @@ def handle_parse_result(
26222621 # the same name to override each other.
26232622 and (self .name not in ctx .params or ctx .params [self .name ] is UNSET )
26242623 ):
2625- # Click is logically enforcing that the name is None if the parameter is
2626- # not to be exposed. We still assert it here to please the type checker.
2627- assert self .name is not None , (
2628- f"{ self !r} parameter's name should not be None when exposing value."
2629- )
26302624 ctx .params [self .name ] = value
26312625
26322626 return value , args
26332627
26342628 def get_help_record (self , ctx : Context ) -> tuple [str , str ] | None :
2635- pass
2629+ return None
26362630
26372631 def get_usage_pieces (self , ctx : Context ) -> list [str ]:
26382632 return []
26392633
2640- def get_error_hint (self , ctx : Context ) -> str :
2634+ def get_error_hint (self , ctx : Context | None ) -> str :
26412635 """Get a stringified version of the param for use in error messages to
26422636 indicate which param caused the error.
2637+
2638+ .. versionchanged:: 8.4.0
2639+ ``ctx`` can be ``None``.
26432640 """
26442641 hint_list = self .opts or [self .human_readable_name ]
26452642 return " / " .join (f"'{ x } '" for x in hint_list )
@@ -2946,15 +2943,15 @@ def get_default(
29462943
29472944 return value
29482945
2949- def get_error_hint (self , ctx : Context ) -> str :
2946+ def get_error_hint (self , ctx : Context | None ) -> str :
29502947 result = super ().get_error_hint (ctx )
29512948 if self .show_envvar and self .envvar is not None :
29522949 result += f" (env var: '{ self .envvar } ')"
29532950 return result
29542951
29552952 def _parse_decls (
29562953 self , decls : cabc .Sequence [str ], expose_value : bool
2957- ) -> tuple [str | None , list [str ], list [str ]]:
2954+ ) -> tuple [str , list [str ], list [str ]]:
29582955 opts = []
29592956 secondary_opts = []
29602957 name = None
@@ -2993,7 +2990,7 @@ def _parse_decls(
29932990
29942991 if name is None :
29952992 if not expose_value :
2996- return None , opts , secondary_opts
2993+ return "" , opts , secondary_opts
29972994 raise TypeError (
29982995 f"Could not determine name for option with declarations { decls !r} "
29992996 )
@@ -3409,14 +3406,14 @@ def __init__(
34093406 def human_readable_name (self ) -> str :
34103407 if self .metavar is not None :
34113408 return self .metavar
3412- return self .name .upper () # type: ignore
3409+ return self .name .upper ()
34133410
34143411 def make_metavar (self , ctx : Context ) -> str :
34153412 if self .metavar is not None :
34163413 return self .metavar
34173414 var = self .type .get_metavar (param = self , ctx = ctx )
34183415 if not var :
3419- var = self .name .upper () # type: ignore
3416+ var = self .name .upper ()
34203417 if self .deprecated :
34213418 var += "!"
34223419 if not self .required :
@@ -3427,10 +3424,10 @@ def make_metavar(self, ctx: Context) -> str:
34273424
34283425 def _parse_decls (
34293426 self , decls : cabc .Sequence [str ], expose_value : bool
3430- ) -> tuple [str | None , list [str ], list [str ]]:
3427+ ) -> tuple [str , list [str ], list [str ]]:
34313428 if not decls :
34323429 if not expose_value :
3433- return None , [], []
3430+ return "" , [], []
34343431 raise TypeError ("Argument is marked as exposed, but does not have a name." )
34353432 if len (decls ) == 1 :
34363433 name = arg = decls [0 ]
@@ -3445,8 +3442,10 @@ def _parse_decls(
34453442 def get_usage_pieces (self , ctx : Context ) -> list [str ]:
34463443 return [self .make_metavar (ctx )]
34473444
3448- def get_error_hint (self , ctx : Context ) -> str :
3449- return f"'{ self .make_metavar (ctx )} '"
3445+ def get_error_hint (self , ctx : Context | None ) -> str :
3446+ if ctx is not None :
3447+ return f"'{ self .make_metavar (ctx )} '"
3448+ return f"'{ self .human_readable_name } '"
34503449
34513450 def add_to_parser (self , parser : _OptionParser , ctx : Context ) -> None :
34523451 parser .add_argument (dest = self .name , nargs = self .nargs , obj = self )
0 commit comments