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
@@ -2587,7 +2586,7 @@ def handle_parse_result(
25872586 with augment_usage_errors (ctx , param = self ):
25882587 value , source = self .consume_value (ctx , opts )
25892588
2590- ctx .set_parameter_source (self .name , source ) # type: ignore
2589+ ctx .set_parameter_source (self .name , source )
25912590
25922591 # Display a deprecation warning if necessary.
25932592 if (
@@ -2627,24 +2626,22 @@ def handle_parse_result(
26272626 # the same name to override each other.
26282627 and (self .name not in ctx .params or ctx .params [self .name ] is UNSET )
26292628 ):
2630- # Click is logically enforcing that the name is None if the parameter is
2631- # not to be exposed. We still assert it here to please the type checker.
2632- assert self .name is not None , (
2633- f"{ self !r} parameter's name should not be None when exposing value."
2634- )
26352629 ctx .params [self .name ] = value
26362630
26372631 return value , args
26382632
26392633 def get_help_record (self , ctx : Context ) -> tuple [str , str ] | None :
2640- pass
2634+ return None
26412635
26422636 def get_usage_pieces (self , ctx : Context ) -> list [str ]:
26432637 return []
26442638
2645- def get_error_hint (self , ctx : Context ) -> str :
2639+ def get_error_hint (self , ctx : Context | None ) -> str :
26462640 """Get a stringified version of the param for use in error messages to
26472641 indicate which param caused the error.
2642+
2643+ .. versionchanged:: 8.4.0
2644+ ``ctx`` can be ``None``.
26482645 """
26492646 hint_list = self .opts or [self .human_readable_name ]
26502647 return " / " .join (f"'{ x } '" for x in hint_list )
@@ -2970,15 +2967,15 @@ def get_default(
29702967
29712968 return value
29722969
2973- def get_error_hint (self , ctx : Context ) -> str :
2970+ def get_error_hint (self , ctx : Context | None ) -> str :
29742971 result = super ().get_error_hint (ctx )
29752972 if self .show_envvar and self .envvar is not None :
29762973 result += f" (env var: '{ self .envvar } ')"
29772974 return result
29782975
29792976 def _parse_decls (
29802977 self , decls : cabc .Sequence [str ], expose_value : bool
2981- ) -> tuple [str | None , list [str ], list [str ]]:
2978+ ) -> tuple [str , list [str ], list [str ]]:
29822979 opts = []
29832980 secondary_opts = []
29842981 name = None
@@ -3017,7 +3014,7 @@ def _parse_decls(
30173014
30183015 if name is None :
30193016 if not expose_value :
3020- return None , opts , secondary_opts
3017+ return "" , opts , secondary_opts
30213018 raise TypeError (
30223019 f"Could not determine name for option with declarations { decls !r} "
30233020 )
@@ -3433,14 +3430,14 @@ def __init__(
34333430 def human_readable_name (self ) -> str :
34343431 if self .metavar is not None :
34353432 return self .metavar
3436- return self .name .upper () # type: ignore
3433+ return self .name .upper ()
34373434
34383435 def make_metavar (self , ctx : Context ) -> str :
34393436 if self .metavar is not None :
34403437 return self .metavar
34413438 var = self .type .get_metavar (param = self , ctx = ctx )
34423439 if not var :
3443- var = self .name .upper () # type: ignore
3440+ var = self .name .upper ()
34443441 if self .deprecated :
34453442 var += "!"
34463443 if not self .required :
@@ -3451,10 +3448,10 @@ def make_metavar(self, ctx: Context) -> str:
34513448
34523449 def _parse_decls (
34533450 self , decls : cabc .Sequence [str ], expose_value : bool
3454- ) -> tuple [str | None , list [str ], list [str ]]:
3451+ ) -> tuple [str , list [str ], list [str ]]:
34553452 if not decls :
34563453 if not expose_value :
3457- return None , [], []
3454+ return "" , [], []
34583455 raise TypeError ("Argument is marked as exposed, but does not have a name." )
34593456 if len (decls ) == 1 :
34603457 name = arg = decls [0 ]
@@ -3469,8 +3466,10 @@ def _parse_decls(
34693466 def get_usage_pieces (self , ctx : Context ) -> list [str ]:
34703467 return [self .make_metavar (ctx )]
34713468
3472- def get_error_hint (self , ctx : Context ) -> str :
3473- return f"'{ self .make_metavar (ctx )} '"
3469+ def get_error_hint (self , ctx : Context | None ) -> str :
3470+ if ctx is not None :
3471+ return f"'{ self .make_metavar (ctx )} '"
3472+ return f"'{ self .human_readable_name } '"
34743473
34753474 def add_to_parser (self , parser : _OptionParser , ctx : Context ) -> None :
34763475 parser .add_argument (dest = self .name , nargs = self .nargs , obj = self )
0 commit comments