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

226 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-28 12:48 +0000

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

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

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

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

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

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

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

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

14# Copyright 2017-2025 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 

41try: 

42 from pyTooling.Decorators import export, readonly 

43 from pyTooling.Common import getFullyQualifiedName 

44except (ImportError, ModuleNotFoundError): # pragma: no cover 

45 print("[pyTooling.Versioning] Could not import from 'pyTooling.*'!") 

46 

47 try: 

48 from Decorators import export, readonly 

49 from Common import getFullyQualifiedName 

50 except (ImportError, ModuleNotFoundError) as ex: # pragma: no cover 

51 print("[pyTooling.Versioning] Could not import directly!") 

52 raise ex 

53 

54 

55__all__ = ["ValueT"] 

56 

57 

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

59 

60 

61@export 

62class CommandLineArgument: 

63 """ 

64 Base-class for all *Argument* classes. 

65 

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

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

68 to specify how argument are formatted. 

69 

70 There are multiple derived formats supporting: 

71 

72 * commands |br| 

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

74 * simple names (flags) |br| 

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

76 * simple values (vlaued flags) |br| 

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

78 * names and values |br| 

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

80 * key-value pairs |br| 

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

82 """ 

83 

84 _pattern: ClassVar[str] 

85 

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

87 """ 

88 This method is called when a class is derived. 

89 

90 :param args: Any positional arguments. 

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

92 Default: ``None``. 

93 :param kwargs: Any keyword argument. 

94 """ 

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

96 cls._pattern = pattern 

97 

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

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

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

101 """ 

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

103 

104 :param args: Any positional arguments. 

105 :param kwargs: Any keyword arguments. 

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

107 """ 

108 if cls is CommandLineArgument: 

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

110 

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

112 return super().__new__(cls) 

113 

114 # TODO: Add property to read pattern 

115 

116 @abstractmethod 

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

118 """ 

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

120 the internal name and value. 

121 

122 :return: Formatted argument. 

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

124 """ 

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

126 

127 @abstractmethod 

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

129 """ 

130 Return a string representation of this argument instance. 

131 

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

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

134 """ 

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

136 

137 @abstractmethod 

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

139 """ 

140 Return a string representation of this argument instance. 

141 

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

143 

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

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

146 """ 

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

148 

149 

150@export 

151class ExecutableArgument(CommandLineArgument): 

152 """ 

153 Represents the executable. 

154 """ 

155 

156 _executable: Path 

157 

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

159 """ 

160 Initializes a ExecutableArgument instance. 

161 

162 :param executable: Path to the executable. 

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

164 """ 

165 if not isinstance(executable, Path): 

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

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

168 raise ex 

169 

170 self._executable = executable 

171 

172 @property 

173 def Executable(self) -> Path: 

174 """ 

175 Get the internal path to the wrapped executable. 

176 

177 :return: Internal path to the executable. 

178 """ 

179 return self._executable 

180 

181 @Executable.setter 

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

183 """ 

184 Set the internal path to the wrapped executable. 

185 

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

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

188 """ 

189 if not isinstance(value, Path): 

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

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

192 raise ex 

193 

194 self._executable = value 

195 

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

197 """ 

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

199 the internal path to the wrapped executable. 

200 

201 :return: Formatted argument. 

202 """ 

203 return f"{self._executable}" 

204 

205 def __str__(self) -> str: 

206 """ 

207 Return a string representation of this argument instance. 

208 

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

210 """ 

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

212 

213 __repr__ = __str__ 

214 

215 

216@export 

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

218 """ 

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

220 """ 

221 

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

223 """ 

224 This method is called when a class is derived. 

225 

226 :param args: Any positional arguments. 

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

228 Default: ``"--"``. 

229 :param kwargs: Any keyword argument. 

230 """ 

231 kwargs["pattern"] = pattern 

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

233 

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

235 """ 

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

237 

238 :return: Formatted argument. 

239 """ 

240 return self._pattern 

241 

242 def __str__(self) -> str: 

243 """ 

244 Return a string representation of this argument instance. 

245 

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

247 """ 

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

249 

250 __repr__ = __str__ 

251 

252 

253@export 

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

255 """ 

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

257 """ 

258 

259 _name: ClassVar[str] 

260 

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

262 """ 

263 This method is called when a class is derived. 

264 

265 :param args: Any positional arguments. 

266 :param name: Name of the CLI argument. 

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

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

269 :param kwargs: Any keyword argument. 

270 """ 

271 kwargs["pattern"] = pattern 

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

273 cls._name = name 

274 

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

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

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

278 """ 

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

280 

281 :param args: Any positional arguments. 

282 :param kwargs: Any keyword arguments. 

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

284 """ 

285 if cls is NamedArgument: 

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

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

288 

289 @readonly 

290 def Name(self) -> str: 

291 """ 

292 Get the internal name. 

293 

294 :return: Internal name. 

295 """ 

296 return self._name 

297 

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

299 """ 

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

301 the internal name. 

302 

303 :return: Formatted argument. 

304 :raises ValueError: If internal name is None. 

305 """ 

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

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

308 

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

310 

311 def __str__(self) -> str: 

312 """ 

313 Return a string representation of this argument instance. 

314 

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

316 """ 

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

318 

319 __repr__ = __str__ 

320 

321 

322@export 

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

324 """ 

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

326 """ 

327 

328 _value: ValueT 

329 

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

331 """ 

332 This method is called when a class is derived. 

333 

334 :param args: Any positional arguments. 

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

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

337 :param kwargs: Any keyword argument. 

338 """ 

339 kwargs["pattern"] = pattern 

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

341 

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

343 """ 

344 Initializes a ValuedArgument instance. 

345 

346 :param value: Value to be stored internally. 

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

348 """ 

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

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

351 

352 self._value = value 

353 

354 @property 

355 def Value(self) -> ValueT: 

356 """ 

357 Get the internal value. 

358 

359 :return: Internal value. 

360 """ 

361 return self._value 

362 

363 @Value.setter 

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

365 """ 

366 Set the internal value. 

367 

368 :param value: Value to set. 

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

370 """ 

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

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

373 

374 self._value = value 

375 

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

377 """ 

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

379 the internal value. 

380 

381 :return: Formatted argument. 

382 """ 

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

384 

385 def __str__(self) -> str: 

386 """ 

387 Return a string representation of this argument instance. 

388 

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

390 """ 

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

392 

393 __repr__ = __str__ 

394 

395 

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

397 """ 

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

399 """ 

400 

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

402 """ 

403 This method is called when a class is derived. 

404 

405 :param args: Any positional arguments. 

406 :param name: Name of the CLI argument. 

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

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

409 :param kwargs: Any keyword argument. 

410 """ 

411 kwargs["name"] = name 

412 kwargs["pattern"] = pattern 

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

414 del kwargs["name"] 

415 del kwargs["pattern"] 

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

417 

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

419 ValuedArgument.__init__(self, value) 

420 

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

422 """ 

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

424 the internal name and value. 

425 

426 :return: Formatted argument. 

427 :raises ValueError: If internal name is None. 

428 """ 

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

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

431 

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

433 

434 def __str__(self) -> str: 

435 """ 

436 Return a string representation of this argument instance. 

437 

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

439 """ 

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

441 

442 __repr__ = __str__ 

443 

444 

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

446 """ 

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

448 

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

450 to the executable. 

451 

452 **Example: ** 

453 

454 * `width 100`` 

455 """ 

456 

457 _valuePattern: ClassVar[str] 

458 

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

460 """ 

461 This method is called when a class is derived. 

462 

463 :param args: Any positional arguments. 

464 :param name: Name of the CLI argument. 

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

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

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

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

469 :param kwargs: Any keyword argument. 

470 """ 

471 kwargs["name"] = name 

472 kwargs["pattern"] = pattern 

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

474 cls._valuePattern = valuePattern 

475 

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

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

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

479 """ 

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

481 

482 :param args: Any positional arguments. 

483 :param kwargs: Any keyword arguments. 

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

485 """ 

486 if cls is NamedTupledArgument: 

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

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

489 

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

491 ValuedArgument.__init__(self, value) 

492 

493 # TODO: Add property to read value pattern 

494 

495 # @property 

496 # def ValuePattern(self) -> str: 

497 # if self._valuePattern is None: 

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

499 # 

500 # return self._valuePattern 

501 

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

503 """ 

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

505 pattern based on the internal name and value. 

506 

507 :return: Formatted argument as tuple of strings. 

508 :raises ValueError: If internal name is None. 

509 """ 

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

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

512 

513 return ( 

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

515 self._valuePattern.format(self._value) 

516 ) 

517 

518 def __str__(self) -> str: 

519 """ 

520 Return a string representation of this argument instance. 

521 

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

523 """ 

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

525 

526 def __repr__(self) -> str: 

527 """ 

528 Return a string representation of this argument instance. 

529 

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

531 """ 

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

533 

534 

535@export 

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

537 """ 

538 Represents a simple string argument. 

539 

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

541 """ 

542 

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

544 """ 

545 This method is called when a class is derived. 

546 

547 :param args: Any positional arguments. 

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

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

550 :param kwargs: Any keyword argument. 

551 """ 

552 kwargs["pattern"] = pattern 

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

554 

555 

556@export 

557class StringListArgument(ValuedArgument): 

558 """ 

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

560 

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

562 """ 

563 Initializes a StringListArgument instance. 

564 

565 :param values: An iterable of str instances. 

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

567 """ 

568 self._values = [] 

569 for value in values: 

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

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

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

573 raise ex 

574 

575 self._values.append(value) 

576 

577 @property 

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

579 """ 

580 Get the internal list of str objects. 

581 

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

583 """ 

584 return self._values 

585 

586 @Value.setter 

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

588 """ 

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

590 

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

592 

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

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

595 """ 

596 self._values.clear() 

597 for value in value: 

598 if not isinstance(value, str): 

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

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

601 raise ex 

602 self._values.append(value) 

603 

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

605 """ 

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

607 the internal value. 

608 

609 :return: Sequence of formatted arguments. 

610 """ 

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

612 

613 def __str__(self) -> str: 

614 """ 

615 Return a string representation of this argument instance. 

616 

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

618 """ 

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

620 

621 def __repr__(self) -> str: 

622 """ 

623 Return a string representation of this argument instance. 

624 

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

626 """ 

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

628 

629 

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

631@export 

632class PathArgument(CommandLineArgument): 

633 """ 

634 Represents a single path argument. 

635 

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

637 """ 

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

639 _path: Path 

640 

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

642 """ 

643 Initializes a PathArgument instance. 

644 

645 :param path: Path to a filesystem object. 

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

647 """ 

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

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

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

651 raise ex 

652 self._path = path 

653 

654 @property 

655 def Value(self) -> Path: 

656 """ 

657 Get the internal path object. 

658 

659 :return: Internal path object. 

660 """ 

661 return self._path 

662 

663 @Value.setter 

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

665 """ 

666 Set the internal path object. 

667 

668 :param value: Value to set. 

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

670 """ 

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

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

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

674 raise ex 

675 

676 self._path = value 

677 

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

679 """ 

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

681 the internal value. 

682 

683 :return: Formatted argument. 

684 """ 

685 return f"{self._path}" 

686 

687 def __str__(self) -> str: 

688 """ 

689 Return a string representation of this argument instance. 

690 

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

692 """ 

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

694 

695 __repr__ = __str__ 

696 

697 

698@export 

699class PathListArgument(CommandLineArgument): 

700 """ 

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

702 """ 

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

704 _paths: List[Path] 

705 

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

707 """ 

708 Initializes a PathListArgument instance. 

709 

710 :param paths: An iterable os Path instances. 

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

712 """ 

713 self._paths = [] 

714 for path in paths: 

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

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

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

718 raise ex 

719 

720 self._paths.append(path) 

721 

722 @property 

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

724 """ 

725 Get the internal list of path objects. 

726 

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

728 """ 

729 return self._paths 

730 

731 @Value.setter 

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

733 """ 

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

735 

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

737 

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

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

740 """ 

741 self._paths.clear() 

742 for path in value: 

743 if not isinstance(path, Path): 

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

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

746 raise ex 

747 self._paths.append(path) 

748 

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

750 """ 

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

752 the internal value. 

753 

754 :return: Sequence of formatted arguments. 

755 """ 

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

757 

758 def __str__(self) -> str: 

759 """ 

760 Return a string representation of this argument instance. 

761 

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

763 """ 

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

765 

766 def __repr__(self) -> str: 

767 """ 

768 Return a string representation of this argument instance. 

769 

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

771 """ 

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