Coverage for pyTooling / CLIAbstraction / Argument.py: 89%

225 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-07 17:18 +0000

1# ==================================================================================================================== # 

2# _____ _ _ ____ _ ___ _ _ _ _ _ # 

3# _ __ _ |_ _|__ ___ | (_)_ __ __ _ / ___| | |_ _| / \ | |__ ___| |_ _ __ __ _ ___| |_(_) ___ _ __ # 

4# | '_ \| | | || |/ _ \ / _ \| | | '_ \ / _` || | | | | | / _ \ | '_ \/ __| __| '__/ _` |/ __| __| |/ _ \| '_ \ # 

5# | |_) | |_| || | (_) | (_) | | | | | | (_| || |___| |___ | | / ___ \| |_) \__ \ |_| | | (_| | (__| |_| | (_) | | | | # 

6# | .__/ \__, ||_|\___/ \___/|_|_|_| |_|\__, (_)____|_____|___/_/ \_\_.__/|___/\__|_| \__,_|\___|\__|_|\___/|_| |_| # 

7# |_| |___/ |___/ # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2017-2026 Patrick Lehmann - Bötzingen, Germany # 

15# Copyright 2014-2016 Technische Universität Dresden - Germany, Chair of VLSI-Design, Diagnostics and Architecture # 

16# # 

17# Licensed under the Apache License, Version 2.0 (the "License"); # 

18# you may not use this file except in compliance with the License. # 

19# You may obtain a copy of the License at # 

20# # 

21# http://www.apache.org/licenses/LICENSE-2.0 # 

22# # 

23# Unless required by applicable law or agreed to in writing, software # 

24# distributed under the License is distributed on an "AS IS" BASIS, # 

25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

26# See the License for the specific language governing permissions and # 

27# limitations under the License. # 

28# # 

29# SPDX-License-Identifier: Apache-2.0 # 

30# ==================================================================================================================== # 

31# 

32""" 

33This module implements command line arguments without prefix character(s). 

34 

35 

36""" 

37from abc import abstractmethod 

38from pathlib import Path 

39from typing import ClassVar, List, Union, Iterable, TypeVar, Generic, Any, Optional as Nullable, Self 

40 

41from pyTooling.Decorators import export, readonly 

42from pyTooling.Common import getFullyQualifiedName 

43 

44 

45__all__ = ["ValueT"] 

46 

47 

48ValueT = TypeVar("ValueT") #: The type of value in a valued argument. 

49 

50 

51@export 

52class CommandLineArgument: 

53 """ 

54 Base-class for all *Argument* classes. 

55 

56 An argument instance can be converted via ``AsArgument`` to a single string value or a sequence of string values 

57 (tuple) usable e.g. with :class:`subprocess.Popen`. Each argument class implements at least one ``pattern`` parameter 

58 to specify how argument are formatted. 

59 

60 There are multiple derived formats supporting: 

61 

62 * commands |br| 

63 |rarr| :mod:`~pyTooling.CLIAbstraction.Command` 

64 * simple names (flags) |br| 

65 |rarr| :mod:`~pyTooling.CLIAbstraction.Flag`, :mod:`~pyTooling.CLIAbstraction.BooleanFlag` 

66 * simple values (vlaued flags) |br| 

67 |rarr| :class:`~pyTooling.CLIAbstraction.Argument.StringArgument`, :class:`~pyTooling.CLIAbstraction.Argument.PathArgument` 

68 * names and values |br| 

69 |rarr| :mod:`~pyTooling.CLIAbstraction.ValuedFlag`, :mod:`~pyTooling.CLIAbstraction.OptionalValuedFlag` 

70 * key-value pairs |br| 

71 |rarr| :mod:`~pyTooling.CLIAbstraction.NamedKeyValuePair` 

72 """ 

73 

74 _pattern: ClassVar[str] 

75 

76 def __init_subclass__(cls, *args: Any, pattern: Nullable[str] = None, **kwargs: Any) -> None: 

77 """ 

78 This method is called when a class is derived. 

79 

80 :param args: Any positional arguments. 

81 :param pattern: This pattern is used to format an argument. |br| 

82 Default: ``None``. 

83 :param kwargs: Any keyword argument. 

84 """ 

85 super().__init_subclass__(*args, **kwargs) 

86 cls._pattern = pattern 

87 

88 # TODO: the whole class should be marked as abstract 

89 # TODO: a decorator should solve the issue and overwrite the __new__ method with that code 

90 def __new__(cls, *args: Any, **kwargs: Any) -> Self: 

91 """ 

92 Check if this class was directly instantiated without being derived to a subclass. If so, raise an error. 

93 

94 :param args: Any positional arguments. 

95 :param kwargs: Any keyword arguments. 

96 :raises TypeError: When this class gets directly instantiated without being derived to a subclass. 

97 """ 

98 if cls is CommandLineArgument: 

99 raise TypeError(f"Class '{cls.__name__}' is abstract.") 

100 

101 # TODO: not sure why parameters meant for __init__ do reach this level and distract __new__ from it's work 

102 return super().__new__(cls) 

103 

104 # TODO: Add property to read pattern 

105 

106 @abstractmethod 

107 def AsArgument(self) -> Union[str, Iterable[str]]: # type: ignore[empty-body] 

108 """ 

109 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

110 the internal name and value. 

111 

112 :return: Formatted argument. 

113 :raises NotImplementedError: This is an abstract method and must be overwritten by a subclass. 

114 """ 

115 raise NotImplementedError(f"Method 'AsArgument' is an abstract method and must be implemented by a subclass.") 

116 

117 @abstractmethod 

118 def __str__(self) -> str: # type: ignore[empty-body] 

119 """ 

120 Return a string representation of this argument instance. 

121 

122 :return: Argument formatted and enclosed in double quotes. 

123 :raises NotImplementedError: This is an abstract method and must be overwritten by a subclass. 

124 """ 

125 raise NotImplementedError(f"Method '__str__' is an abstract method and must be implemented by a subclass.") 

126 

127 @abstractmethod 

128 def __repr__(self) -> str: # type: ignore[empty-body] 

129 """ 

130 Return a string representation of this argument instance. 

131 

132 .. note:: By default, this method is identical to :meth:`__str__`. 

133 

134 :return: Argument formatted and enclosed in double quotes. 

135 :raises NotImplementedError: This is an abstract method and must be overwritten by a subclass. 

136 """ 

137 raise NotImplementedError(f"Method '__repr__' is an abstract method and must be implemented by a subclass.") 

138 

139 

140@export 

141class ExecutableArgument(CommandLineArgument): 

142 """ 

143 Represents the executable. 

144 """ 

145 

146 _executable: Path 

147 

148 def __init__(self, executable: Path) -> None: 

149 """ 

150 Initializes a ExecutableArgument instance. 

151 

152 :param executable: Path to the executable. 

153 :raises TypeError: If parameter 'executable' is not of type :class:`~pathlib.Path`. 

154 """ 

155 if not isinstance(executable, Path): 

156 ex = TypeError("Parameter 'executable' is not of type 'Path'.") 

157 ex.add_note(f"Got type '{getFullyQualifiedName(executable)}'.") 

158 raise ex 

159 

160 self._executable = executable 

161 

162 @property 

163 def Executable(self) -> Path: 

164 """ 

165 Get the internal path to the wrapped executable. 

166 

167 :return: Internal path to the executable. 

168 """ 

169 return self._executable 

170 

171 @Executable.setter 

172 def Executable(self, value: Path) -> None: 

173 """ 

174 Set the internal path to the wrapped executable. 

175 

176 :param value: Value to path to the executable. 

177 :raises TypeError: If value is not of type :class:`~pathlib.Path`. 

178 """ 

179 if not isinstance(value, Path): 

180 ex = TypeError("Parameter 'value' is not of type 'Path'.") 

181 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

182 raise ex 

183 

184 self._executable = value 

185 

186 def AsArgument(self) -> Union[str, Iterable[str]]: 

187 """ 

188 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

189 the internal path to the wrapped executable. 

190 

191 :return: Formatted argument. 

192 """ 

193 return f"{self._executable}" 

194 

195 def __str__(self) -> str: 

196 """ 

197 Return a string representation of this argument instance. 

198 

199 :return: Argument formatted and enclosed in double quotes. 

200 """ 

201 return f"\"{self._executable}\"" 

202 

203 __repr__ = __str__ 

204 

205 

206@export 

207class DelimiterArgument(CommandLineArgument, pattern="--"): 

208 """ 

209 Represents a delimiter symbol like ``--``. 

210 """ 

211 

212 def __init_subclass__(cls, *args: Any, pattern: str = "--", **kwargs: Any) -> None: 

213 """ 

214 This method is called when a class is derived. 

215 

216 :param args: Any positional arguments. 

217 :param pattern: This pattern is used to format an argument. |br| 

218 Default: ``"--"``. 

219 :param kwargs: Any keyword argument. 

220 """ 

221 kwargs["pattern"] = pattern 

222 super().__init_subclass__(*args, **kwargs) 

223 

224 def AsArgument(self) -> Union[str, Iterable[str]]: 

225 """ 

226 Convert this argument instance to a string representation with proper escaping using the matching pattern. 

227 

228 :return: Formatted argument. 

229 """ 

230 return self._pattern 

231 

232 def __str__(self) -> str: 

233 """ 

234 Return a string representation of this argument instance. 

235 

236 :return: Argument formatted and enclosed in double quotes. 

237 """ 

238 return f"\"{self._pattern}\"" 

239 

240 __repr__ = __str__ 

241 

242 

243@export 

244class NamedArgument(CommandLineArgument, pattern="{0}"): 

245 """ 

246 Base-class for all command line arguments with a name. 

247 """ 

248 

249 _name: ClassVar[str] 

250 

251 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "{0}", **kwargs: Any) -> None: 

252 """ 

253 This method is called when a class is derived. 

254 

255 :param args: Any positional arguments. 

256 :param name: Name of the CLI argument. 

257 :param pattern: This pattern is used to format an argument. |br| 

258 Default: ``"{0}"``. 

259 :param kwargs: Any keyword argument. 

260 """ 

261 kwargs["pattern"] = pattern 

262 super().__init_subclass__(*args, **kwargs) 

263 cls._name = name 

264 

265 # TODO: the whole class should be marked as abstract 

266 # TODO: a decorator should solve the issue and overwrite the __new__ method with that code 

267 def __new__(cls, *args: Any, **kwargs: Any) -> Self: 

268 """ 

269 Check if this class was directly instantiated without being derived to a subclass. If so, raise an error. 

270 

271 :param args: Any positional arguments. 

272 :param kwargs: Any keyword arguments. 

273 :raises TypeError: When this class gets directly instantiated without being derived to a subclass. 

274 """ 

275 if cls is NamedArgument: 

276 raise TypeError(f"Class '{cls.__name__}' is abstract.") 

277 return super().__new__(cls, *args, **kwargs) 

278 

279 @readonly 

280 def Name(self) -> str: 

281 """ 

282 Get the internal name. 

283 

284 :return: Internal name. 

285 """ 

286 return self._name 

287 

288 def AsArgument(self) -> Union[str, Iterable[str]]: 

289 """ 

290 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

291 the internal name. 

292 

293 :return: Formatted argument. 

294 :raises ValueError: If internal name is None. 

295 """ 

296 if self._name is None: 296 ↛ 297line 296 didn't jump to line 297 because the condition on line 296 was never true

297 raise ValueError(f"Internal value '_name' is None.") 

298 

299 return self._pattern.format(self._name) 

300 

301 def __str__(self) -> str: 

302 """ 

303 Return a string representation of this argument instance. 

304 

305 :return: Argument formatted and enclosed in double quotes. 

306 """ 

307 return f"\"{self.AsArgument()}\"" 

308 

309 __repr__ = __str__ 

310 

311 

312@export 

313class ValuedArgument(CommandLineArgument, Generic[ValueT], pattern="{0}"): 

314 """ 

315 Base-class for all command line arguments with a value. 

316 """ 

317 

318 _value: ValueT 

319 

320 def __init_subclass__(cls, *args: Any, pattern: str = "{0}", **kwargs: Any) -> None: 

321 """ 

322 This method is called when a class is derived. 

323 

324 :param args: Any positional arguments. 

325 :param pattern: This pattern is used to format an argument. |br| 

326 Default: ``"{0}"``. 

327 :param kwargs: Any keyword argument. 

328 """ 

329 kwargs["pattern"] = pattern 

330 super().__init_subclass__(*args, **kwargs) 

331 

332 def __init__(self, value: ValueT) -> None: 

333 """ 

334 Initializes a ValuedArgument instance. 

335 

336 :param value: Value to be stored internally. 

337 :raises TypeError: If parameter 'value' is None. 

338 """ 

339 if value is None: 339 ↛ 340line 339 didn't jump to line 340 because the condition on line 339 was never true

340 raise ValueError("Parameter 'value' is None.") 

341 

342 self._value = value 

343 

344 @property 

345 def Value(self) -> ValueT: 

346 """ 

347 Get the internal value. 

348 

349 :return: Internal value. 

350 """ 

351 return self._value 

352 

353 @Value.setter 

354 def Value(self, value: ValueT) -> None: 

355 """ 

356 Set the internal value. 

357 

358 :param value: Value to set. 

359 :raises ValueError: If value to set is None. 

360 """ 

361 if value is None: 361 ↛ 362line 361 didn't jump to line 362 because the condition on line 361 was never true

362 raise ValueError(f"Value to set is None.") 

363 

364 self._value = value 

365 

366 def AsArgument(self) -> Union[str, Iterable[str]]: 

367 """ 

368 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

369 the internal value. 

370 

371 :return: Formatted argument. 

372 """ 

373 return self._pattern.format(self._value) 

374 

375 def __str__(self) -> str: 

376 """ 

377 Return a string representation of this argument instance. 

378 

379 :return: Argument formatted and enclosed in double quotes. 

380 """ 

381 return f"\"{self.AsArgument()}\"" 

382 

383 __repr__ = __str__ 

384 

385 

386class NamedAndValuedArgument(NamedArgument, ValuedArgument, Generic[ValueT], pattern="{0}={1}"): 

387 """ 

388 Base-class for all command line arguments with a name and a value. 

389 """ 

390 

391 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "{0}={1}", **kwargs: Any) -> None: 

392 """ 

393 This method is called when a class is derived. 

394 

395 :param args: Any positional arguments. 

396 :param name: Name of the CLI argument. 

397 :param pattern: This pattern is used to format an argument. |br| 

398 Default: ``"{0}={1}"``. 

399 :param kwargs: Any keyword argument. 

400 """ 

401 kwargs["name"] = name 

402 kwargs["pattern"] = pattern 

403 super().__init_subclass__(*args, **kwargs) 

404 del kwargs["name"] 

405 del kwargs["pattern"] 

406 ValuedArgument.__init_subclass__(*args, **kwargs) 

407 

408 def __init__(self, value: ValueT) -> None: 

409 ValuedArgument.__init__(self, value) 

410 

411 def AsArgument(self) -> Union[str, Iterable[str]]: 

412 """ 

413 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

414 the internal name and value. 

415 

416 :return: Formatted argument. 

417 :raises ValueError: If internal name is None. 

418 """ 

419 if self._name is None: 419 ↛ 420line 419 didn't jump to line 420 because the condition on line 419 was never true

420 raise ValueError(f"Internal value '_name' is None.") 

421 

422 return self._pattern.format(self._name, self._value) 

423 

424 def __str__(self) -> str: 

425 """ 

426 Return a string representation of this argument instance. 

427 

428 :return: Argument formatted and enclosed in double quotes. 

429 """ 

430 return f"\"{self.AsArgument()}\"" 

431 

432 __repr__ = __str__ 

433 

434 

435class NamedTupledArgument(NamedArgument, ValuedArgument, Generic[ValueT], pattern="{0}"): 

436 """ 

437 Class and base-class for all TupleFlag classes, which represents an argument with separate value. 

438 

439 A tuple argument is a command line argument followed by a separate value. Name and value are passed as two arguments 

440 to the executable. 

441 

442 **Example: ** 

443 

444 * `width 100`` 

445 """ 

446 

447 _valuePattern: ClassVar[str] 

448 

449 def __init_subclass__(cls, *args: Any, name: Nullable[str] = None, pattern: str = "{0}", valuePattern: str = "{0}", **kwargs: Any) -> None: 

450 """ 

451 This method is called when a class is derived. 

452 

453 :param args: Any positional arguments. 

454 :param name: Name of the CLI argument. 

455 :param pattern: This pattern is used to format the CLI argument name. |br| 

456 Default: ``"{0}"``. 

457 :param valuePattern: This pattern is used to format the value. |br| 

458 Default: ``"{0}"``. 

459 :param kwargs: Any keyword argument. 

460 """ 

461 kwargs["name"] = name 

462 kwargs["pattern"] = pattern 

463 super().__init_subclass__(*args, **kwargs) 

464 cls._valuePattern = valuePattern 

465 

466 # TODO: the whole class should be marked as abstract 

467 # TODO: a decorator should solve the issue and overwrite the __new__ method with that code 

468 def __new__(cls, *args: Any, **kwargs: Any) -> Self: 

469 """ 

470 Check if this class was directly instantiated without being derived to a subclass. If so, raise an error. 

471 

472 :param args: Any positional arguments. 

473 :param kwargs: Any keyword arguments. 

474 :raises TypeError: When this class gets directly instantiated without being derived to a subclass. 

475 """ 

476 if cls is NamedTupledArgument: 

477 raise TypeError(f"Class '{cls.__name__}' is abstract.") 

478 return super().__new__(cls, *args, **kwargs) 

479 

480 def __init__(self, value: ValueT) -> None: 

481 ValuedArgument.__init__(self, value) 

482 

483 # TODO: Add property to read value pattern 

484 

485 # @property 

486 # def ValuePattern(self) -> str: 

487 # if self._valuePattern is None: 

488 # raise ValueError(f"") # XXX: add message 

489 # 

490 # return self._valuePattern 

491 

492 def AsArgument(self) -> Union[str, Iterable[str]]: 

493 """ 

494 Convert this argument instance to a sequence of string representations with proper escaping using the matching 

495 pattern based on the internal name and value. 

496 

497 :return: Formatted argument as tuple of strings. 

498 :raises ValueError: If internal name is None. 

499 """ 

500 if self._name is None: 500 ↛ 501line 500 didn't jump to line 501 because the condition on line 500 was never true

501 raise ValueError(f"Internal value '_name' is None.") 

502 

503 return ( 

504 self._pattern.format(self._name), 

505 self._valuePattern.format(self._value) 

506 ) 

507 

508 def __str__(self) -> str: 

509 """ 

510 Return a string representation of this argument instance. 

511 

512 :return: Space separated sequence of arguments formatted and each enclosed in double quotes. 

513 """ 

514 return " ".join([f"\"{item}\"" for item in self.AsArgument()]) 

515 

516 def __repr__(self) -> str: 

517 """ 

518 Return a string representation of this argument instance. 

519 

520 :return: Comma separated sequence of arguments formatted and each enclosed in double quotes. 

521 """ 

522 return ", ".join([f"\"{item}\"" for item in self.AsArgument()]) 

523 

524 

525@export 

526class StringArgument(ValuedArgument, pattern="{0}"): 

527 """ 

528 Represents a simple string argument. 

529 

530 A list of strings is available as :class:`~pyTooling.CLIAbstraction.Argument.StringListArgument`. 

531 """ 

532 

533 def __init_subclass__(cls, *args: Any, pattern: str = "{0}", **kwargs: Any) -> None: 

534 """ 

535 This method is called when a class is derived. 

536 

537 :param args: Any positional arguments. 

538 :param pattern: This pattern is used to format an argument. |br| 

539 Default: ``"{0}"``. 

540 :param kwargs: Any keyword argument. 

541 """ 

542 kwargs["pattern"] = pattern 

543 super().__init_subclass__(*args, **kwargs) 

544 

545 

546@export 

547class StringListArgument(ValuedArgument): 

548 """ 

549 Represents a list of string argument (:class:`~pyTooling.CLIAbstraction.Argument.StringArgument`).""" 

550 

551 def __init__(self, values: Iterable[str]) -> None: 

552 """ 

553 Initializes a StringListArgument instance. 

554 

555 :param values: An iterable of str instances. 

556 :raises TypeError: If iterable parameter 'values' contains elements not of type :class:`str`. 

557 """ 

558 self._values = [] 

559 for value in values: 

560 if not isinstance(value, str): 560 ↛ 561line 560 didn't jump to line 561 because the condition on line 560 was never true

561 ex = TypeError(f"Parameter 'values' contains elements which are not of type 'str'.") 

562 ex.add_note(f"Got type '{getFullyQualifiedName(values)}'.") 

563 raise ex 

564 

565 self._values.append(value) 

566 

567 @property 

568 def Value(self) -> List[str]: 

569 """ 

570 Get the internal list of str objects. 

571 

572 :return: Reference to the internal list of str objects. 

573 """ 

574 return self._values 

575 

576 @Value.setter 

577 def Value(self, value: Iterable[str]) -> None: 

578 """ 

579 Overwrite all elements in the internal list of str objects. 

580 

581 .. note:: The list object is not replaced, but cleared and then reused by adding the given elements in the iterable. 

582 

583 :param value: List of str objects to set. 

584 :raises TypeError: If value contains elements, which are not of type :class:`str`. 

585 """ 

586 self._values.clear() 

587 for value in value: 

588 if not isinstance(value, str): 

589 ex = TypeError(f"Value contains elements which are not of type 'str'.") 

590 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

591 raise ex 

592 self._values.append(value) 

593 

594 def AsArgument(self) -> Union[str, Iterable[str]]: 

595 """ 

596 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

597 the internal value. 

598 

599 :return: Sequence of formatted arguments. 

600 """ 

601 return [f"{value}" for value in self._values] 

602 

603 def __str__(self) -> str: 

604 """ 

605 Return a string representation of this argument instance. 

606 

607 :return: Space separated sequence of arguments formatted and each enclosed in double quotes. 

608 """ 

609 return " ".join([f"\"{value}\"" for value in self.AsArgument()]) 

610 

611 def __repr__(self) -> str: 

612 """ 

613 Return a string representation of this argument instance. 

614 

615 :return: Comma separated sequence of arguments formatted and each enclosed in double quotes. 

616 """ 

617 return ", ".join([f"\"{value}\"" for value in self.AsArgument()]) 

618 

619 

620# TODO: Add option to class if path should be checked for existence 

621@export 

622class PathArgument(CommandLineArgument): 

623 """ 

624 Represents a single path argument. 

625 

626 A list of paths is available as :class:`~pyTooling.CLIAbstraction.Argument.PathListArgument`. 

627 """ 

628 # The output format can be forced to the POSIX format with :py:data:`_PosixFormat`. 

629 _path: Path 

630 

631 def __init__(self, path: Path) -> None: 

632 """ 

633 Initializes a PathArgument instance. 

634 

635 :param path: Path to a filesystem object. 

636 :raises TypeError: If parameter 'path' is not of type :class:`~pathlib.Path`. 

637 """ 

638 if not isinstance(path, Path): 638 ↛ 639line 638 didn't jump to line 639 because the condition on line 638 was never true

639 ex = TypeError("Parameter 'path' is not of type 'Path'.") 

640 ex.add_note(f"Got type '{getFullyQualifiedName(path)}'.") 

641 raise ex 

642 self._path = path 

643 

644 @property 

645 def Value(self) -> Path: 

646 """ 

647 Get the internal path object. 

648 

649 :return: Internal path object. 

650 """ 

651 return self._path 

652 

653 @Value.setter 

654 def Value(self, value: Path) -> None: 

655 """ 

656 Set the internal path object. 

657 

658 :param value: Value to set. 

659 :raises TypeError: If value is not of type :class:`~pathlib.Path`. 

660 """ 

661 if not isinstance(value, Path): 661 ↛ 662line 661 didn't jump to line 662 because the condition on line 661 was never true

662 ex = TypeError("Value is not of type 'Path'.") 

663 ex.add_note(f"Got type '{getFullyQualifiedName(value)}'.") 

664 raise ex 

665 

666 self._path = value 

667 

668 def AsArgument(self) -> Union[str, Iterable[str]]: 

669 """ 

670 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

671 the internal value. 

672 

673 :return: Formatted argument. 

674 """ 

675 return f"{self._path}" 

676 

677 def __str__(self) -> str: 

678 """ 

679 Return a string representation of this argument instance. 

680 

681 :return: Argument formatted and enclosed in double quotes. 

682 """ 

683 return f"\"{self._path}\"" 

684 

685 __repr__ = __str__ 

686 

687 

688@export 

689class PathListArgument(CommandLineArgument): 

690 """ 

691 Represents a list of path arguments (:class:`~pyTooling.CLIAbstraction.Argument.PathArgument`). 

692 """ 

693 # The output format can be forced to the POSIX format with :py:data:`_PosixFormat`. 

694 _paths: List[Path] 

695 

696 def __init__(self, paths: Iterable[Path]) -> None: 

697 """ 

698 Initializes a PathListArgument instance. 

699 

700 :param paths: An iterable os Path instances. 

701 :raises TypeError: If iterable parameter 'paths' contains elements not of type :class:`~pathlib.Path`. 

702 """ 

703 self._paths = [] 

704 for path in paths: 

705 if not isinstance(path, Path): 705 ↛ 706line 705 didn't jump to line 706 because the condition on line 705 was never true

706 ex = TypeError(f"Parameter 'paths' contains elements which are not of type 'Path'.") 

707 ex.add_note(f"Got type '{getFullyQualifiedName(path)}'.") 

708 raise ex 

709 

710 self._paths.append(path) 

711 

712 @property 

713 def Value(self) -> List[Path]: 

714 """ 

715 Get the internal list of path objects. 

716 

717 :return: Reference to the internal list of path objects. 

718 """ 

719 return self._paths 

720 

721 @Value.setter 

722 def Value(self, value: Iterable[Path]) -> None: 

723 """ 

724 Overwrite all elements in the internal list of path objects. 

725 

726 .. note:: The list object is not replaced, but cleared and then reused by adding the given elements in the iterable. 

727 

728 :param value: List of path objects to set. 

729 :raises TypeError: If value contains elements, which are not of type :class:`~pathlib.Path`. 

730 """ 

731 self._paths.clear() 

732 for path in value: 

733 if not isinstance(path, Path): 

734 ex = TypeError(f"Value contains elements which are not of type 'Path'.") 

735 ex.add_note(f"Got type '{getFullyQualifiedName(path)}'.") 

736 raise ex 

737 self._paths.append(path) 

738 

739 def AsArgument(self) -> Union[str, Iterable[str]]: 

740 """ 

741 Convert this argument instance to a string representation with proper escaping using the matching pattern based on 

742 the internal value. 

743 

744 :return: Sequence of formatted arguments. 

745 """ 

746 return [f"{path}" for path in self._paths] 

747 

748 def __str__(self) -> str: 

749 """ 

750 Return a string representation of this argument instance. 

751 

752 :return: Space separated sequence of arguments formatted and each enclosed in double quotes. 

753 """ 

754 return " ".join([f"\"{value}\"" for value in self.AsArgument()]) 

755 

756 def __repr__(self) -> str: 

757 """ 

758 Return a string representation of this argument instance. 

759 

760 :return: Comma separated sequence of arguments formatted and each enclosed in double quotes. 

761 """ 

762 return ", ".join([f"\"{value}\"" for value in self.AsArgument()])