Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/click/types.py: 35%

413 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-09 06:03 +0000

1from __future__ import annotations 

2 

3import collections.abc as cabc 

4import os 

5import stat 

6import sys 

7import typing as t 

8from datetime import datetime 

9from gettext import gettext as _ 

10from gettext import ngettext 

11 

12from ._compat import _get_argv_encoding 

13from ._compat import open_stream 

14from .exceptions import BadParameter 

15from .utils import format_filename 

16from .utils import LazyFile 

17from .utils import safecall 

18 

19if t.TYPE_CHECKING: 

20 import typing_extensions as te 

21 from .core import Context 

22 from .core import Parameter 

23 from .shell_completion import CompletionItem 

24 

25 

26class ParamType: 

27 """Represents the type of a parameter. Validates and converts values 

28 from the command line or Python into the correct type. 

29 

30 To implement a custom type, subclass and implement at least the 

31 following: 

32 

33 - The :attr:`name` class attribute must be set. 

34 - Calling an instance of the type with ``None`` must return 

35 ``None``. This is already implemented by default. 

36 - :meth:`convert` must convert string values to the correct type. 

37 - :meth:`convert` must accept values that are already the correct 

38 type. 

39 - It must be able to convert a value if the ``ctx`` and ``param`` 

40 arguments are ``None``. This can occur when converting prompt 

41 input. 

42 """ 

43 

44 is_composite: t.ClassVar[bool] = False 

45 arity: t.ClassVar[int] = 1 

46 

47 #: the descriptive name of this type 

48 name: str 

49 

50 #: if a list of this type is expected and the value is pulled from a 

51 #: string environment variable, this is what splits it up. `None` 

52 #: means any whitespace. For all parameters the general rule is that 

53 #: whitespace splits them up. The exception are paths and files which 

54 #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on 

55 #: Windows). 

56 envvar_list_splitter: t.ClassVar[str | None] = None 

57 

58 def to_info_dict(self) -> dict[str, t.Any]: 

59 """Gather information that could be useful for a tool generating 

60 user-facing documentation. 

61 

62 Use :meth:`click.Context.to_info_dict` to traverse the entire 

63 CLI structure. 

64 

65 .. versionadded:: 8.0 

66 """ 

67 # The class name without the "ParamType" suffix. 

68 param_type = type(self).__name__.partition("ParamType")[0] 

69 param_type = param_type.partition("ParameterType")[0] 

70 

71 # Custom subclasses might not remember to set a name. 

72 if hasattr(self, "name"): 

73 name = self.name 

74 else: 

75 name = param_type 

76 

77 return {"param_type": param_type, "name": name} 

78 

79 def __call__( 

80 self, 

81 value: t.Any, 

82 param: Parameter | None = None, 

83 ctx: Context | None = None, 

84 ) -> t.Any: 

85 if value is not None: 

86 return self.convert(value, param, ctx) 

87 

88 def get_metavar(self, param: Parameter) -> str | None: 

89 """Returns the metavar default for this param if it provides one.""" 

90 

91 def get_missing_message(self, param: Parameter) -> str | None: 

92 """Optionally might return extra information about a missing 

93 parameter. 

94 

95 .. versionadded:: 2.0 

96 """ 

97 

98 def convert( 

99 self, value: t.Any, param: Parameter | None, ctx: Context | None 

100 ) -> t.Any: 

101 """Convert the value to the correct type. This is not called if 

102 the value is ``None`` (the missing value). 

103 

104 This must accept string values from the command line, as well as 

105 values that are already the correct type. It may also convert 

106 other compatible types. 

107 

108 The ``param`` and ``ctx`` arguments may be ``None`` in certain 

109 situations, such as when converting prompt input. 

110 

111 If the value cannot be converted, call :meth:`fail` with a 

112 descriptive message. 

113 

114 :param value: The value to convert. 

115 :param param: The parameter that is using this type to convert 

116 its value. May be ``None``. 

117 :param ctx: The current context that arrived at this value. May 

118 be ``None``. 

119 """ 

120 return value 

121 

122 def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: 

123 """Given a value from an environment variable this splits it up 

124 into small chunks depending on the defined envvar list splitter. 

125 

126 If the splitter is set to `None`, which means that whitespace splits, 

127 then leading and trailing whitespace is ignored. Otherwise, leading 

128 and trailing splitters usually lead to empty items being included. 

129 """ 

130 return (rv or "").split(self.envvar_list_splitter) 

131 

132 def fail( 

133 self, 

134 message: str, 

135 param: Parameter | None = None, 

136 ctx: Context | None = None, 

137 ) -> t.NoReturn: 

138 """Helper method to fail with an invalid value message.""" 

139 raise BadParameter(message, ctx=ctx, param=param) 

140 

141 def shell_complete( 

142 self, ctx: Context, param: Parameter, incomplete: str 

143 ) -> list[CompletionItem]: 

144 """Return a list of 

145 :class:`~click.shell_completion.CompletionItem` objects for the 

146 incomplete value. Most types do not provide completions, but 

147 some do, and this allows custom types to provide custom 

148 completions as well. 

149 

150 :param ctx: Invocation context for this command. 

151 :param param: The parameter that is requesting completion. 

152 :param incomplete: Value being completed. May be empty. 

153 

154 .. versionadded:: 8.0 

155 """ 

156 return [] 

157 

158 

159class CompositeParamType(ParamType): 

160 is_composite = True 

161 

162 @property 

163 def arity(self) -> int: # type: ignore 

164 raise NotImplementedError() 

165 

166 

167class FuncParamType(ParamType): 

168 def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: 

169 self.name: str = func.__name__ 

170 self.func = func 

171 

172 def to_info_dict(self) -> dict[str, t.Any]: 

173 info_dict = super().to_info_dict() 

174 info_dict["func"] = self.func 

175 return info_dict 

176 

177 def convert( 

178 self, value: t.Any, param: Parameter | None, ctx: Context | None 

179 ) -> t.Any: 

180 try: 

181 return self.func(value) 

182 except ValueError: 

183 try: 

184 value = str(value) 

185 except UnicodeError: 

186 value = value.decode("utf-8", "replace") 

187 

188 self.fail(value, param, ctx) 

189 

190 

191class UnprocessedParamType(ParamType): 

192 name = "text" 

193 

194 def convert( 

195 self, value: t.Any, param: Parameter | None, ctx: Context | None 

196 ) -> t.Any: 

197 return value 

198 

199 def __repr__(self) -> str: 

200 return "UNPROCESSED" 

201 

202 

203class StringParamType(ParamType): 

204 name = "text" 

205 

206 def convert( 

207 self, value: t.Any, param: Parameter | None, ctx: Context | None 

208 ) -> t.Any: 

209 if isinstance(value, bytes): 

210 enc = _get_argv_encoding() 

211 try: 

212 value = value.decode(enc) 

213 except UnicodeError: 

214 fs_enc = sys.getfilesystemencoding() 

215 if fs_enc != enc: 

216 try: 

217 value = value.decode(fs_enc) 

218 except UnicodeError: 

219 value = value.decode("utf-8", "replace") 

220 else: 

221 value = value.decode("utf-8", "replace") 

222 return value 

223 return str(value) 

224 

225 def __repr__(self) -> str: 

226 return "STRING" 

227 

228 

229class Choice(ParamType): 

230 """The choice type allows a value to be checked against a fixed set 

231 of supported values. All of these values have to be strings. 

232 

233 You should only pass a list or tuple of choices. Other iterables 

234 (like generators) may lead to surprising results. 

235 

236 The resulting value will always be one of the originally passed choices 

237 regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` 

238 being specified. 

239 

240 See :ref:`choice-opts` for an example. 

241 

242 :param case_sensitive: Set to false to make choices case 

243 insensitive. Defaults to true. 

244 """ 

245 

246 name = "choice" 

247 

248 def __init__( 

249 self, choices: cabc.Sequence[str], case_sensitive: bool = True 

250 ) -> None: 

251 self.choices = choices 

252 self.case_sensitive = case_sensitive 

253 

254 def to_info_dict(self) -> dict[str, t.Any]: 

255 info_dict = super().to_info_dict() 

256 info_dict["choices"] = self.choices 

257 info_dict["case_sensitive"] = self.case_sensitive 

258 return info_dict 

259 

260 def get_metavar(self, param: Parameter) -> str: 

261 choices_str = "|".join(self.choices) 

262 

263 # Use curly braces to indicate a required argument. 

264 if param.required and param.param_type_name == "argument": 

265 return f"{{{choices_str}}}" 

266 

267 # Use square braces to indicate an option or optional argument. 

268 return f"[{choices_str}]" 

269 

270 def get_missing_message(self, param: Parameter) -> str: 

271 return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) 

272 

273 def convert( 

274 self, value: t.Any, param: Parameter | None, ctx: Context | None 

275 ) -> t.Any: 

276 # Match through normalization and case sensitivity 

277 # first do token_normalize_func, then lowercase 

278 # preserve original `value` to produce an accurate message in 

279 # `self.fail` 

280 normed_value = value 

281 normed_choices = {choice: choice for choice in self.choices} 

282 

283 if ctx is not None and ctx.token_normalize_func is not None: 

284 normed_value = ctx.token_normalize_func(value) 

285 normed_choices = { 

286 ctx.token_normalize_func(normed_choice): original 

287 for normed_choice, original in normed_choices.items() 

288 } 

289 

290 if not self.case_sensitive: 

291 normed_value = normed_value.casefold() 

292 normed_choices = { 

293 normed_choice.casefold(): original 

294 for normed_choice, original in normed_choices.items() 

295 } 

296 

297 if normed_value in normed_choices: 

298 return normed_choices[normed_value] 

299 

300 choices_str = ", ".join(map(repr, self.choices)) 

301 self.fail( 

302 ngettext( 

303 "{value!r} is not {choice}.", 

304 "{value!r} is not one of {choices}.", 

305 len(self.choices), 

306 ).format(value=value, choice=choices_str, choices=choices_str), 

307 param, 

308 ctx, 

309 ) 

310 

311 def __repr__(self) -> str: 

312 return f"Choice({list(self.choices)})" 

313 

314 def shell_complete( 

315 self, ctx: Context, param: Parameter, incomplete: str 

316 ) -> list[CompletionItem]: 

317 """Complete choices that start with the incomplete value. 

318 

319 :param ctx: Invocation context for this command. 

320 :param param: The parameter that is requesting completion. 

321 :param incomplete: Value being completed. May be empty. 

322 

323 .. versionadded:: 8.0 

324 """ 

325 from click.shell_completion import CompletionItem 

326 

327 str_choices = map(str, self.choices) 

328 

329 if self.case_sensitive: 

330 matched = (c for c in str_choices if c.startswith(incomplete)) 

331 else: 

332 incomplete = incomplete.lower() 

333 matched = (c for c in str_choices if c.lower().startswith(incomplete)) 

334 

335 return [CompletionItem(c) for c in matched] 

336 

337 

338class DateTime(ParamType): 

339 """The DateTime type converts date strings into `datetime` objects. 

340 

341 The format strings which are checked are configurable, but default to some 

342 common (non-timezone aware) ISO 8601 formats. 

343 

344 When specifying *DateTime* formats, you should only pass a list or a tuple. 

345 Other iterables, like generators, may lead to surprising results. 

346 

347 The format strings are processed using ``datetime.strptime``, and this 

348 consequently defines the format strings which are allowed. 

349 

350 Parsing is tried using each format, in order, and the first format which 

351 parses successfully is used. 

352 

353 :param formats: A list or tuple of date format strings, in the order in 

354 which they should be tried. Defaults to 

355 ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, 

356 ``'%Y-%m-%d %H:%M:%S'``. 

357 """ 

358 

359 name = "datetime" 

360 

361 def __init__(self, formats: cabc.Sequence[str] | None = None): 

362 self.formats: cabc.Sequence[str] = formats or [ 

363 "%Y-%m-%d", 

364 "%Y-%m-%dT%H:%M:%S", 

365 "%Y-%m-%d %H:%M:%S", 

366 ] 

367 

368 def to_info_dict(self) -> dict[str, t.Any]: 

369 info_dict = super().to_info_dict() 

370 info_dict["formats"] = self.formats 

371 return info_dict 

372 

373 def get_metavar(self, param: Parameter) -> str: 

374 return f"[{'|'.join(self.formats)}]" 

375 

376 def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: 

377 try: 

378 return datetime.strptime(value, format) 

379 except ValueError: 

380 return None 

381 

382 def convert( 

383 self, value: t.Any, param: Parameter | None, ctx: Context | None 

384 ) -> t.Any: 

385 if isinstance(value, datetime): 

386 return value 

387 

388 for format in self.formats: 

389 converted = self._try_to_convert_date(value, format) 

390 

391 if converted is not None: 

392 return converted 

393 

394 formats_str = ", ".join(map(repr, self.formats)) 

395 self.fail( 

396 ngettext( 

397 "{value!r} does not match the format {format}.", 

398 "{value!r} does not match the formats {formats}.", 

399 len(self.formats), 

400 ).format(value=value, format=formats_str, formats=formats_str), 

401 param, 

402 ctx, 

403 ) 

404 

405 def __repr__(self) -> str: 

406 return "DateTime" 

407 

408 

409class _NumberParamTypeBase(ParamType): 

410 _number_class: t.ClassVar[type[t.Any]] 

411 

412 def convert( 

413 self, value: t.Any, param: Parameter | None, ctx: Context | None 

414 ) -> t.Any: 

415 try: 

416 return self._number_class(value) 

417 except ValueError: 

418 self.fail( 

419 _("{value!r} is not a valid {number_type}.").format( 

420 value=value, number_type=self.name 

421 ), 

422 param, 

423 ctx, 

424 ) 

425 

426 

427class _NumberRangeBase(_NumberParamTypeBase): 

428 def __init__( 

429 self, 

430 min: float | None = None, 

431 max: float | None = None, 

432 min_open: bool = False, 

433 max_open: bool = False, 

434 clamp: bool = False, 

435 ) -> None: 

436 self.min = min 

437 self.max = max 

438 self.min_open = min_open 

439 self.max_open = max_open 

440 self.clamp = clamp 

441 

442 def to_info_dict(self) -> dict[str, t.Any]: 

443 info_dict = super().to_info_dict() 

444 info_dict.update( 

445 min=self.min, 

446 max=self.max, 

447 min_open=self.min_open, 

448 max_open=self.max_open, 

449 clamp=self.clamp, 

450 ) 

451 return info_dict 

452 

453 def convert( 

454 self, value: t.Any, param: Parameter | None, ctx: Context | None 

455 ) -> t.Any: 

456 import operator 

457 

458 rv = super().convert(value, param, ctx) 

459 lt_min: bool = self.min is not None and ( 

460 operator.le if self.min_open else operator.lt 

461 )(rv, self.min) 

462 gt_max: bool = self.max is not None and ( 

463 operator.ge if self.max_open else operator.gt 

464 )(rv, self.max) 

465 

466 if self.clamp: 

467 if lt_min: 

468 return self._clamp(self.min, 1, self.min_open) # type: ignore 

469 

470 if gt_max: 

471 return self._clamp(self.max, -1, self.max_open) # type: ignore 

472 

473 if lt_min or gt_max: 

474 self.fail( 

475 _("{value} is not in the range {range}.").format( 

476 value=rv, range=self._describe_range() 

477 ), 

478 param, 

479 ctx, 

480 ) 

481 

482 return rv 

483 

484 def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: 

485 """Find the valid value to clamp to bound in the given 

486 direction. 

487 

488 :param bound: The boundary value. 

489 :param dir: 1 or -1 indicating the direction to move. 

490 :param open: If true, the range does not include the bound. 

491 """ 

492 raise NotImplementedError 

493 

494 def _describe_range(self) -> str: 

495 """Describe the range for use in help text.""" 

496 if self.min is None: 

497 op = "<" if self.max_open else "<=" 

498 return f"x{op}{self.max}" 

499 

500 if self.max is None: 

501 op = ">" if self.min_open else ">=" 

502 return f"x{op}{self.min}" 

503 

504 lop = "<" if self.min_open else "<=" 

505 rop = "<" if self.max_open else "<=" 

506 return f"{self.min}{lop}x{rop}{self.max}" 

507 

508 def __repr__(self) -> str: 

509 clamp = " clamped" if self.clamp else "" 

510 return f"<{type(self).__name__} {self._describe_range()}{clamp}>" 

511 

512 

513class IntParamType(_NumberParamTypeBase): 

514 name = "integer" 

515 _number_class = int 

516 

517 def __repr__(self) -> str: 

518 return "INT" 

519 

520 

521class IntRange(_NumberRangeBase, IntParamType): 

522 """Restrict an :data:`click.INT` value to a range of accepted 

523 values. See :ref:`ranges`. 

524 

525 If ``min`` or ``max`` are not passed, any value is accepted in that 

526 direction. If ``min_open`` or ``max_open`` are enabled, the 

527 corresponding boundary is not included in the range. 

528 

529 If ``clamp`` is enabled, a value outside the range is clamped to the 

530 boundary instead of failing. 

531 

532 .. versionchanged:: 8.0 

533 Added the ``min_open`` and ``max_open`` parameters. 

534 """ 

535 

536 name = "integer range" 

537 

538 def _clamp( # type: ignore 

539 self, bound: int, dir: t.Literal[1, -1], open: bool 

540 ) -> int: 

541 if not open: 

542 return bound 

543 

544 return bound + dir 

545 

546 

547class FloatParamType(_NumberParamTypeBase): 

548 name = "float" 

549 _number_class = float 

550 

551 def __repr__(self) -> str: 

552 return "FLOAT" 

553 

554 

555class FloatRange(_NumberRangeBase, FloatParamType): 

556 """Restrict a :data:`click.FLOAT` value to a range of accepted 

557 values. See :ref:`ranges`. 

558 

559 If ``min`` or ``max`` are not passed, any value is accepted in that 

560 direction. If ``min_open`` or ``max_open`` are enabled, the 

561 corresponding boundary is not included in the range. 

562 

563 If ``clamp`` is enabled, a value outside the range is clamped to the 

564 boundary instead of failing. This is not supported if either 

565 boundary is marked ``open``. 

566 

567 .. versionchanged:: 8.0 

568 Added the ``min_open`` and ``max_open`` parameters. 

569 """ 

570 

571 name = "float range" 

572 

573 def __init__( 

574 self, 

575 min: float | None = None, 

576 max: float | None = None, 

577 min_open: bool = False, 

578 max_open: bool = False, 

579 clamp: bool = False, 

580 ) -> None: 

581 super().__init__( 

582 min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp 

583 ) 

584 

585 if (min_open or max_open) and clamp: 

586 raise TypeError("Clamping is not supported for open bounds.") 

587 

588 def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: 

589 if not open: 

590 return bound 

591 

592 # Could use Python 3.9's math.nextafter here, but clamping an 

593 # open float range doesn't seem to be particularly useful. It's 

594 # left up to the user to write a callback to do it if needed. 

595 raise RuntimeError("Clamping is not supported for open bounds.") 

596 

597 

598class BoolParamType(ParamType): 

599 name = "boolean" 

600 

601 def convert( 

602 self, value: t.Any, param: Parameter | None, ctx: Context | None 

603 ) -> t.Any: 

604 if value in {False, True}: 

605 return bool(value) 

606 

607 norm = value.strip().lower() 

608 

609 if norm in {"1", "true", "t", "yes", "y", "on"}: 

610 return True 

611 

612 if norm in {"0", "false", "f", "no", "n", "off"}: 

613 return False 

614 

615 self.fail( 

616 _("{value!r} is not a valid boolean.").format(value=value), param, ctx 

617 ) 

618 

619 def __repr__(self) -> str: 

620 return "BOOL" 

621 

622 

623class UUIDParameterType(ParamType): 

624 name = "uuid" 

625 

626 def convert( 

627 self, value: t.Any, param: Parameter | None, ctx: Context | None 

628 ) -> t.Any: 

629 import uuid 

630 

631 if isinstance(value, uuid.UUID): 

632 return value 

633 

634 value = value.strip() 

635 

636 try: 

637 return uuid.UUID(value) 

638 except ValueError: 

639 self.fail( 

640 _("{value!r} is not a valid UUID.").format(value=value), param, ctx 

641 ) 

642 

643 def __repr__(self) -> str: 

644 return "UUID" 

645 

646 

647class File(ParamType): 

648 """Declares a parameter to be a file for reading or writing. The file 

649 is automatically closed once the context tears down (after the command 

650 finished working). 

651 

652 Files can be opened for reading or writing. The special value ``-`` 

653 indicates stdin or stdout depending on the mode. 

654 

655 By default, the file is opened for reading text data, but it can also be 

656 opened in binary mode or for writing. The encoding parameter can be used 

657 to force a specific encoding. 

658 

659 The `lazy` flag controls if the file should be opened immediately or upon 

660 first IO. The default is to be non-lazy for standard input and output 

661 streams as well as files opened for reading, `lazy` otherwise. When opening a 

662 file lazily for reading, it is still opened temporarily for validation, but 

663 will not be held open until first IO. lazy is mainly useful when opening 

664 for writing to avoid creating the file until it is needed. 

665 

666 Starting with Click 2.0, files can also be opened atomically in which 

667 case all writes go into a separate file in the same folder and upon 

668 completion the file will be moved over to the original location. This 

669 is useful if a file regularly read by other users is modified. 

670 

671 See :ref:`file-args` for more information. 

672 """ 

673 

674 name = "filename" 

675 envvar_list_splitter: t.ClassVar[str] = os.path.pathsep 

676 

677 def __init__( 

678 self, 

679 mode: str = "r", 

680 encoding: str | None = None, 

681 errors: str | None = "strict", 

682 lazy: bool | None = None, 

683 atomic: bool = False, 

684 ) -> None: 

685 self.mode = mode 

686 self.encoding = encoding 

687 self.errors = errors 

688 self.lazy = lazy 

689 self.atomic = atomic 

690 

691 def to_info_dict(self) -> dict[str, t.Any]: 

692 info_dict = super().to_info_dict() 

693 info_dict.update(mode=self.mode, encoding=self.encoding) 

694 return info_dict 

695 

696 def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: 

697 if self.lazy is not None: 

698 return self.lazy 

699 if os.fspath(value) == "-": 

700 return False 

701 elif "w" in self.mode: 

702 return True 

703 return False 

704 

705 def convert( 

706 self, 

707 value: str | os.PathLike[str] | t.IO[t.Any], 

708 param: Parameter | None, 

709 ctx: Context | None, 

710 ) -> t.IO[t.Any]: 

711 if _is_file_like(value): 

712 return value 

713 

714 value = t.cast("str | os.PathLike[str]", value) 

715 

716 try: 

717 lazy = self.resolve_lazy_flag(value) 

718 

719 if lazy: 

720 lf = LazyFile( 

721 value, self.mode, self.encoding, self.errors, atomic=self.atomic 

722 ) 

723 

724 if ctx is not None: 

725 ctx.call_on_close(lf.close_intelligently) 

726 

727 return t.cast("t.IO[t.Any]", lf) 

728 

729 f, should_close = open_stream( 

730 value, self.mode, self.encoding, self.errors, atomic=self.atomic 

731 ) 

732 

733 # If a context is provided, we automatically close the file 

734 # at the end of the context execution (or flush out). If a 

735 # context does not exist, it's the caller's responsibility to 

736 # properly close the file. This for instance happens when the 

737 # type is used with prompts. 

738 if ctx is not None: 

739 if should_close: 

740 ctx.call_on_close(safecall(f.close)) 

741 else: 

742 ctx.call_on_close(safecall(f.flush)) 

743 

744 return f 

745 except OSError as e: # noqa: B014 

746 self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) 

747 

748 def shell_complete( 

749 self, ctx: Context, param: Parameter, incomplete: str 

750 ) -> list[CompletionItem]: 

751 """Return a special completion marker that tells the completion 

752 system to use the shell to provide file path completions. 

753 

754 :param ctx: Invocation context for this command. 

755 :param param: The parameter that is requesting completion. 

756 :param incomplete: Value being completed. May be empty. 

757 

758 .. versionadded:: 8.0 

759 """ 

760 from click.shell_completion import CompletionItem 

761 

762 return [CompletionItem(incomplete, type="file")] 

763 

764 

765def _is_file_like(value: t.Any) -> te.TypeGuard[t.IO[t.Any]]: 

766 return hasattr(value, "read") or hasattr(value, "write") 

767 

768 

769class Path(ParamType): 

770 """The ``Path`` type is similar to the :class:`File` type, but 

771 returns the filename instead of an open file. Various checks can be 

772 enabled to validate the type of file and permissions. 

773 

774 :param exists: The file or directory needs to exist for the value to 

775 be valid. If this is not set to ``True``, and the file does not 

776 exist, then all further checks are silently skipped. 

777 :param file_okay: Allow a file as a value. 

778 :param dir_okay: Allow a directory as a value. 

779 :param readable: if true, a readable check is performed. 

780 :param writable: if true, a writable check is performed. 

781 :param executable: if true, an executable check is performed. 

782 :param resolve_path: Make the value absolute and resolve any 

783 symlinks. A ``~`` is not expanded, as this is supposed to be 

784 done by the shell only. 

785 :param allow_dash: Allow a single dash as a value, which indicates 

786 a standard stream (but does not open it). Use 

787 :func:`~click.open_file` to handle opening this value. 

788 :param path_type: Convert the incoming path value to this type. If 

789 ``None``, keep Python's default, which is ``str``. Useful to 

790 convert to :class:`pathlib.Path`. 

791 

792 .. versionchanged:: 8.1 

793 Added the ``executable`` parameter. 

794 

795 .. versionchanged:: 8.0 

796 Allow passing ``path_type=pathlib.Path``. 

797 

798 .. versionchanged:: 6.0 

799 Added the ``allow_dash`` parameter. 

800 """ 

801 

802 envvar_list_splitter: t.ClassVar[str] = os.path.pathsep 

803 

804 def __init__( 

805 self, 

806 exists: bool = False, 

807 file_okay: bool = True, 

808 dir_okay: bool = True, 

809 writable: bool = False, 

810 readable: bool = True, 

811 resolve_path: bool = False, 

812 allow_dash: bool = False, 

813 path_type: type[t.Any] | None = None, 

814 executable: bool = False, 

815 ): 

816 self.exists = exists 

817 self.file_okay = file_okay 

818 self.dir_okay = dir_okay 

819 self.readable = readable 

820 self.writable = writable 

821 self.executable = executable 

822 self.resolve_path = resolve_path 

823 self.allow_dash = allow_dash 

824 self.type = path_type 

825 

826 if self.file_okay and not self.dir_okay: 

827 self.name: str = _("file") 

828 elif self.dir_okay and not self.file_okay: 

829 self.name = _("directory") 

830 else: 

831 self.name = _("path") 

832 

833 def to_info_dict(self) -> dict[str, t.Any]: 

834 info_dict = super().to_info_dict() 

835 info_dict.update( 

836 exists=self.exists, 

837 file_okay=self.file_okay, 

838 dir_okay=self.dir_okay, 

839 writable=self.writable, 

840 readable=self.readable, 

841 allow_dash=self.allow_dash, 

842 ) 

843 return info_dict 

844 

845 def coerce_path_result( 

846 self, value: str | os.PathLike[str] 

847 ) -> str | bytes | os.PathLike[str]: 

848 if self.type is not None and not isinstance(value, self.type): 

849 if self.type is str: 

850 return os.fsdecode(value) 

851 elif self.type is bytes: 

852 return os.fsencode(value) 

853 else: 

854 return t.cast("os.PathLike[str]", self.type(value)) 

855 

856 return value 

857 

858 def convert( 

859 self, 

860 value: str | os.PathLike[str], 

861 param: Parameter | None, 

862 ctx: Context | None, 

863 ) -> str | bytes | os.PathLike[str]: 

864 rv = value 

865 

866 is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") 

867 

868 if not is_dash: 

869 if self.resolve_path: 

870 rv = os.path.realpath(rv) 

871 

872 try: 

873 st = os.stat(rv) 

874 except OSError: 

875 if not self.exists: 

876 return self.coerce_path_result(rv) 

877 self.fail( 

878 _("{name} {filename!r} does not exist.").format( 

879 name=self.name.title(), filename=format_filename(value) 

880 ), 

881 param, 

882 ctx, 

883 ) 

884 

885 if not self.file_okay and stat.S_ISREG(st.st_mode): 

886 self.fail( 

887 _("{name} {filename!r} is a file.").format( 

888 name=self.name.title(), filename=format_filename(value) 

889 ), 

890 param, 

891 ctx, 

892 ) 

893 if not self.dir_okay and stat.S_ISDIR(st.st_mode): 

894 self.fail( 

895 _("{name} '{filename}' is a directory.").format( 

896 name=self.name.title(), filename=format_filename(value) 

897 ), 

898 param, 

899 ctx, 

900 ) 

901 

902 if self.readable and not os.access(rv, os.R_OK): 

903 self.fail( 

904 _("{name} {filename!r} is not readable.").format( 

905 name=self.name.title(), filename=format_filename(value) 

906 ), 

907 param, 

908 ctx, 

909 ) 

910 

911 if self.writable and not os.access(rv, os.W_OK): 

912 self.fail( 

913 _("{name} {filename!r} is not writable.").format( 

914 name=self.name.title(), filename=format_filename(value) 

915 ), 

916 param, 

917 ctx, 

918 ) 

919 

920 if self.executable and not os.access(value, os.X_OK): 

921 self.fail( 

922 _("{name} {filename!r} is not executable.").format( 

923 name=self.name.title(), filename=format_filename(value) 

924 ), 

925 param, 

926 ctx, 

927 ) 

928 

929 return self.coerce_path_result(rv) 

930 

931 def shell_complete( 

932 self, ctx: Context, param: Parameter, incomplete: str 

933 ) -> list[CompletionItem]: 

934 """Return a special completion marker that tells the completion 

935 system to use the shell to provide path completions for only 

936 directories or any paths. 

937 

938 :param ctx: Invocation context for this command. 

939 :param param: The parameter that is requesting completion. 

940 :param incomplete: Value being completed. May be empty. 

941 

942 .. versionadded:: 8.0 

943 """ 

944 from click.shell_completion import CompletionItem 

945 

946 type = "dir" if self.dir_okay and not self.file_okay else "file" 

947 return [CompletionItem(incomplete, type=type)] 

948 

949 

950class Tuple(CompositeParamType): 

951 """The default behavior of Click is to apply a type on a value directly. 

952 This works well in most cases, except for when `nargs` is set to a fixed 

953 count and different types should be used for different items. In this 

954 case the :class:`Tuple` type can be used. This type can only be used 

955 if `nargs` is set to a fixed number. 

956 

957 For more information see :ref:`tuple-type`. 

958 

959 This can be selected by using a Python tuple literal as a type. 

960 

961 :param types: a list of types that should be used for the tuple items. 

962 """ 

963 

964 def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType]) -> None: 

965 self.types: cabc.Sequence[ParamType] = [convert_type(ty) for ty in types] 

966 

967 def to_info_dict(self) -> dict[str, t.Any]: 

968 info_dict = super().to_info_dict() 

969 info_dict["types"] = [t.to_info_dict() for t in self.types] 

970 return info_dict 

971 

972 @property 

973 def name(self) -> str: # type: ignore 

974 return f"<{' '.join(ty.name for ty in self.types)}>" 

975 

976 @property 

977 def arity(self) -> int: # type: ignore 

978 return len(self.types) 

979 

980 def convert( 

981 self, value: t.Any, param: Parameter | None, ctx: Context | None 

982 ) -> t.Any: 

983 len_type = len(self.types) 

984 len_value = len(value) 

985 

986 if len_value != len_type: 

987 self.fail( 

988 ngettext( 

989 "{len_type} values are required, but {len_value} was given.", 

990 "{len_type} values are required, but {len_value} were given.", 

991 len_value, 

992 ).format(len_type=len_type, len_value=len_value), 

993 param=param, 

994 ctx=ctx, 

995 ) 

996 

997 return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) 

998 

999 

1000def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType: 

1001 """Find the most appropriate :class:`ParamType` for the given Python 

1002 type. If the type isn't provided, it can be inferred from a default 

1003 value. 

1004 """ 

1005 guessed_type = False 

1006 

1007 if ty is None and default is not None: 

1008 if isinstance(default, (tuple, list)): 

1009 # If the default is empty, ty will remain None and will 

1010 # return STRING. 

1011 if default: 

1012 item = default[0] 

1013 

1014 # A tuple of tuples needs to detect the inner types. 

1015 # Can't call convert recursively because that would 

1016 # incorrectly unwind the tuple to a single type. 

1017 if isinstance(item, (tuple, list)): 

1018 ty = tuple(map(type, item)) 

1019 else: 

1020 ty = type(item) 

1021 else: 

1022 ty = type(default) 

1023 

1024 guessed_type = True 

1025 

1026 if isinstance(ty, tuple): 

1027 return Tuple(ty) 

1028 

1029 if isinstance(ty, ParamType): 

1030 return ty 

1031 

1032 if ty is str or ty is None: 

1033 return STRING 

1034 

1035 if ty is int: 

1036 return INT 

1037 

1038 if ty is float: 

1039 return FLOAT 

1040 

1041 if ty is bool: 

1042 return BOOL 

1043 

1044 if guessed_type: 

1045 return STRING 

1046 

1047 if __debug__: 

1048 try: 

1049 if issubclass(ty, ParamType): 

1050 raise AssertionError( 

1051 f"Attempted to use an uninstantiated parameter type ({ty})." 

1052 ) 

1053 except TypeError: 

1054 # ty is an instance (correct), so issubclass fails. 

1055 pass 

1056 

1057 return FuncParamType(ty) 

1058 

1059 

1060#: A dummy parameter type that just does nothing. From a user's 

1061#: perspective this appears to just be the same as `STRING` but 

1062#: internally no string conversion takes place if the input was bytes. 

1063#: This is usually useful when working with file paths as they can 

1064#: appear in bytes and unicode. 

1065#: 

1066#: For path related uses the :class:`Path` type is a better choice but 

1067#: there are situations where an unprocessed type is useful which is why 

1068#: it is is provided. 

1069#: 

1070#: .. versionadded:: 4.0 

1071UNPROCESSED = UnprocessedParamType() 

1072 

1073#: A unicode string parameter type which is the implicit default. This 

1074#: can also be selected by using ``str`` as type. 

1075STRING = StringParamType() 

1076 

1077#: An integer parameter. This can also be selected by using ``int`` as 

1078#: type. 

1079INT = IntParamType() 

1080 

1081#: A floating point value parameter. This can also be selected by using 

1082#: ``float`` as type. 

1083FLOAT = FloatParamType() 

1084 

1085#: A boolean parameter. This is the default for boolean flags. This can 

1086#: also be selected by using ``bool`` as a type. 

1087BOOL = BoolParamType() 

1088 

1089#: A UUID parameter. 

1090UUID = UUIDParameterType()