Coverage for src / c41811 / config / abc.py: 100%

260 statements  

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

1# cython: language_level = 3 # noqa: ERA001 

2 

3 

4"""配置抽象基类""" 

5 

6import os 

7from abc import ABC 

8from abc import abstractmethod 

9from collections import OrderedDict 

10from collections.abc import Iterable 

11from collections.abc import Iterator 

12from collections.abc import Mapping 

13from collections.abc import Sequence 

14from copy import deepcopy 

15from re import Pattern 

16from typing import Any 

17from typing import Self 

18from typing import overload 

19from typing import override 

20 

21from ._protocols import Indexed 

22from ._protocols import MutableIndexed 

23 

24type AnyKey = ABCKey[Any, Any] 

25""" 

26.. versionadded:: 0.2.0 

27""" 

28 

29 

30class ABCKey[K, D](ABC): 

31 """用于获取配置的键""" 

32 

33 def __init__(self, key: K, meta: str | None = None): 

34 """ 

35 :param key: 键名 

36 :type key: K 

37 :param meta: 元信息 

38 :type meta: str | None 

39 """ # noqa: D205 

40 self._key = deepcopy(key) 

41 self._meta: str | None = meta 

42 

43 @property 

44 def key(self) -> K: 

45 """键""" 

46 return deepcopy(self._key) 

47 

48 @property 

49 def meta(self) -> str | None: 

50 """ 

51 元信息 

52 

53 .. versionadded:: 0.2.0 

54 """ 

55 return self._meta 

56 

57 @abstractmethod 

58 def unparse(self) -> str: 

59 """ 

60 还原为可被解析的字符串 

61 

62 .. versionadded:: 0.1.1 

63 """ 

64 

65 @abstractmethod 

66 def __get_inner_element__(self, data: D) -> D: 

67 """ 

68 获取内层元素 

69 

70 :param data: 配置数据 

71 :type data: D 

72 :return: 内层配置数据 

73 :rtype: D 

74 

75 .. versionadded:: 0.1.4 

76 """ 

77 

78 @abstractmethod 

79 def __set_inner_element__(self, data: D, value: Any) -> None: 

80 """ 

81 设置内层元素 

82 

83 :param data: 配置数据 

84 :type data: D 

85 :param value: 值 

86 :type value: Any 

87 

88 .. versionadded:: 0.1.4 

89 """ 

90 

91 @abstractmethod 

92 def __delete_inner_element__(self, data: D) -> None: 

93 """ 

94 删除内层元素 

95 

96 :param data: 配置数据 

97 :type data: D 

98 

99 .. versionadded:: 0.1.4 

100 """ 

101 

102 @abstractmethod 

103 def __contains_inner_element__(self, data: D) -> bool: 

104 """ 

105 是否包含内层元素 

106 

107 :param data: 配置数据 

108 :type data: D 

109 :return: 是否包含内层配置数据 

110 :rtype: bool 

111 

112 .. versionadded:: 0.1.4 

113 """ 

114 

115 @abstractmethod 

116 def __supports__(self, data: Any) -> tuple[Any, ...]: 

117 """ 

118 检查此键是否支持该配置数据 

119 

120 返回缺失的协议 

121 

122 :param data: 配置数据 

123 :type data: Any 

124 :return: 此键缺失支持的数据类型 

125 :rtype: tuple 

126 

127 .. versionadded:: 0.1.4 

128 """ 

129 

130 @abstractmethod 

131 def __supports_modify__(self, data: Any) -> tuple[Any, ...]: 

132 """ 

133 检查此键是否支持修改该配置数据 

134 

135 返回缺失的协议 

136 

137 :param data: 配置数据 

138 :type data: Any 

139 :return: 此键缺失支持的数据类型 

140 :rtype: tuple 

141 

142 .. versionadded:: 0.1.4 

143 """ 

144 

145 @override 

146 def __eq__(self, other: Any) -> bool: 

147 if not isinstance(other, type(self)): 

148 return NotImplemented 

149 

150 return all( 

151 ( 

152 self._key == other._key, 

153 self._meta == other._meta, 

154 ) 

155 ) 

156 

157 @override 

158 def __hash__(self) -> int: 

159 return hash((self._key, self._meta)) 

160 

161 def __deepcopy__(self, memo: dict[Any, Any]) -> Self: 

162 if self._meta is None: 

163 return type(self)(self._key) 

164 return type(self)(self._key, self._meta) 

165 

166 @override 

167 def __str__(self) -> str: 

168 return str(self._key) 

169 

170 @override 

171 def __repr__(self) -> str: 

172 meta = "" if self._meta is None else f", meta={self._meta}" 

173 return f"<{type(self).__name__}(key={self._key}{meta})>" 

174 

175 

176class ABCPath[K: AnyKey](ABC, Iterable[K]): 

177 """用于获取数据的路径""" 

178 

179 def __init__(self, keys: Iterable[K]): 

180 """ 

181 :param keys: 路径的键 

182 :type keys: Iterable[K] 

183 """ # noqa: D205 

184 self._keys = deepcopy(tuple(keys)) 

185 

186 @property 

187 def keys(self) -> tuple[K, ...]: 

188 """ 

189 键列表 

190 

191 .. note:: 

192 返回的是深拷贝副本,修改不会影响路径 

193 

194 .. versionadded:: 0.2.0 

195 """ # noqa: RUF002 

196 return deepcopy(self._keys) 

197 

198 @abstractmethod 

199 def unparse(self) -> str: 

200 """ 

201 还原为可被解析的字符串 

202 

203 .. versionadded:: 0.1.1 

204 """ 

205 

206 @overload 

207 def __getitem__(self, item: slice) -> Self: ... 

208 

209 @overload 

210 def __getitem__(self, item: int) -> K: ... 

211 

212 def __getitem__(self, item: Any) -> K | Self: 

213 items: K | tuple[K, ...] = self._keys[item] 

214 if isinstance(items, tuple): 

215 return type(self)(items) 

216 return items 

217 

218 def __contains__(self, item: Any) -> bool: 

219 return item in self._keys 

220 

221 def __bool__(self) -> bool: 

222 return bool(self._keys) 

223 

224 def __len__(self) -> int: 

225 return len(self._keys) 

226 

227 @override 

228 def __iter__(self) -> Iterator[K]: 

229 return iter(self._keys) 

230 

231 @override 

232 def __hash__(self) -> int: 

233 return hash(self._keys) 

234 

235 def __deepcopy__(self, memo: dict[Any, Any]) -> Self: 

236 return type(self)(self._keys) 

237 

238 @override 

239 def __eq__(self, other: Any) -> bool: 

240 if not isinstance(other, type(self)): 

241 return NotImplemented 

242 return self._keys == other._keys 

243 

244 @override 

245 def __repr__(self) -> str: 

246 return f"<{type(self).__name__}{self._keys}>" 

247 

248 

249class ABCConfigData(ABC): 

250 """ 

251 配置数据抽象基类 

252 

253 .. versionchanged:: 0.1.5 

254 现在配置数据不再局限于Mapping 

255 """ 

256 

257 @classmethod 

258 def from_data(cls, *args: Any, **kwargs: Any) -> Self: 

259 """ 

260 提供创建同类型配置数据的快捷方式 

261 

262 :return: 新的配置数据 

263 :rtype: Self 

264 

265 .. note:: 

266 套壳 ``__init__`` 主要是为了方便内部快速创建与传入的ABCConfigData同类型的对象 

267 

268 例如: 

269 

270 .. code-block:: python 

271 

272 type(instance)(data) 

273 

274 可以简写为 

275 

276 .. code-block:: python 

277 

278 instance.from_data(data) 

279 

280 .. versionchanged:: 0.2.0 

281 现在会自适应初始化参数 

282 """ # noqa: RUF002 

283 # noinspection PyArgumentList 

284 return cls(*args, **kwargs) 

285 

286 @property 

287 @abstractmethod 

288 def data_read_only(self) -> bool | None: 

289 """ 

290 配置数据是否为只读 

291 

292 :return: 配置数据是否为只读 

293 :rtype: bool | None 

294 

295 .. versionadded:: 0.1.3 

296 

297 .. versionchanged:: 0.1.5 

298 改为抽象属性 

299 """ 

300 

301 @property 

302 @abstractmethod 

303 def read_only(self) -> bool | None: 

304 """ 

305 配置数据是否为 ``只读模式`` 

306 

307 :return: 配置数据是否为 ``只读模式`` 

308 :rtype: bool | None 

309 """ 

310 return self.data_read_only 

311 

312 @read_only.setter 

313 @abstractmethod 

314 def read_only(self, value: Any) -> None: 

315 """ 

316 设置配置数据是否为 ``只读模式`` 

317 

318 :raise ConfigDataReadOnlyError: 配置数据为只读 

319 """ 

320 

321 def freeze(self, freeze: bool | None = None) -> Self: # noqa: FBT001 

322 """ 

323 冻结配置数据 (切换只读模式) 

324 

325 :param freeze: 是否冻结配置数据, 为 :py:const:`None` 时进行切换 

326 :type freeze: bool | None 

327 :return: 返回当前实例便于链式调用 

328 :rtype: Self 

329 

330 .. versionadded:: 0.1.5 

331 """ 

332 if freeze is None: 

333 self.read_only = not self.read_only 

334 return self 

335 self.read_only = freeze 

336 return self 

337 

338 @override 

339 def __format__(self, format_spec: str) -> str: 

340 if format_spec == "r": 

341 return repr(self) 

342 return super().__format__(format_spec) 

343 

344 

345type PathLike = str | ABCPath[AnyKey] 

346""" 

347.. versionadded:: 0.2.0 

348""" 

349 

350 

351class ABCIndexedConfigData[D: Indexed[Any, Any]](ABCConfigData, MutableIndexed[Any, Any], ABC): 

352 # noinspection GrazieInspection 

353 """ 

354 支持 ``索引`` 操作的配置数据 

355 

356 .. versionadded:: 0.1.5 

357 

358 .. versionchanged:: 0.2.0 

359 重命名 ``ABCSupportsIndexConfigData`` 为 ``ABCIndexedConfigData`` 

360 """ 

361 

362 @abstractmethod 

363 def retrieve(self, path: PathLike, *, return_raw_value: bool = False) -> Any: 

364 """ 

365 获取路径的值的*快照* 

366 

367 :param path: 路径 

368 :type path: PathLike 

369 :param return_raw_value: 是否获取原始值,为 :py:const:`False` 时,会将Mapping | Sequence转换为对应类 

370 :type return_raw_value: bool 

371 

372 :return: 路径的值 

373 :rtype: Any 

374 

375 :raise ConfigDataTypeError: 配置数据类型错误 

376 :raise RequiredPathNotFoundError: 需求的键不存在 

377 

378 .. versionchanged:: 0.2.0 

379 重命名参数 ``get_raw`` 为 ``return_raw_value`` 

380 """ # noqa: RUF002 

381 

382 @abstractmethod 

383 def modify(self, path: PathLike, value: Any, *, allow_create: bool = True) -> Self: 

384 """ 

385 修改路径的值 

386 

387 :param path: 路径 

388 :type path: PathLike 

389 :param value: 值 

390 :type value: Any 

391 :param allow_create: 是否允许创建不存在的路径,默认为True 

392 :type allow_create: bool 

393 

394 :return: 返回当前实例便于链式调用 

395 :rtype: Self 

396 

397 :raise ConfigDataReadOnlyError: 配置数据为只读 

398 :raise ConfigDataTypeError: 配置数据类型错误 

399 :raise RequiredPathNotFoundError: 需求的键不存在 

400 

401 .. caution:: 

402 ``value`` 参数未默认做深拷贝,可能导致非预期行为 

403 

404 .. attention:: 

405 ``allow_create`` 时,使用与 `self.data` 一样的类型新建路径 

406 """ # noqa: RUF002 

407 

408 @abstractmethod 

409 def delete(self, path: PathLike) -> Self: 

410 """ 

411 删除路径 

412 

413 :param path: 路径 

414 :type path: PathLike 

415 

416 :return: 返回当前实例便于链式调用 

417 :rtype: Self 

418 

419 :raise ConfigDataReadOnlyError: 配置数据为只读 

420 :raise ConfigDataTypeError: 配置数据类型错误 

421 :raise RequiredPathNotFoundError: 需求的键不存在 

422 """ 

423 

424 @abstractmethod 

425 def unset(self, path: PathLike) -> Self: 

426 """ 

427 确保路径不存在 (删除路径,但是找不到路径时不会报错) 

428 

429 :param path: 路径 

430 :type path: PathLike 

431 

432 :return: 返回当前实例便于链式调用 

433 :rtype: Self 

434 

435 :raise ConfigDataReadOnlyError: 配置数据为只读 

436 :raise ConfigDataTypeError: 配置数据类型错误 

437 

438 .. versionadded:: 0.1.2 

439 """ # noqa: RUF002 

440 

441 @abstractmethod 

442 def exists(self, path: PathLike, *, ignore_wrong_type: bool = False) -> bool: 

443 """ 

444 判断路径是否存在 

445 

446 :param path: 路径 

447 :type path: PathLike 

448 :param ignore_wrong_type: 忽略配置数据类型错误 

449 :type ignore_wrong_type: bool 

450 

451 :return: 路径是否存在 

452 :rtype: bool 

453 

454 :raise ConfigDataTypeError: 配置数据类型错误 

455 """ 

456 

457 @abstractmethod 

458 def get[V](self, path: PathLike, default: V | None = None, *, return_raw_value: bool = False) -> V | Any: 

459 """ 

460 获取路径的值的*快照*,路径不存在时填充默认值 

461 

462 :param path: 路径 

463 :type path: PathLike 

464 

465 :param default: 默认值 

466 :type default: V 

467 :param return_raw_value: 是否获取原始值 

468 :type return_raw_value: bool 

469 

470 :return: 路径的值 

471 :rtype: V | Any 

472 

473 :raise ConfigDataTypeError: 配置数据类型错误 

474 

475 例子 

476 ---- 

477 

478 >>> from c41811.config import MappingConfigData 

479 >>> data = MappingConfigData({"key": "value"}) 

480 

481 路径存在时返回值 

482 

483 >>> data.get("key") 

484 'value' 

485 

486 路径不存在时返回默认值None 

487 

488 >>> print(data.get("not exists")) 

489 None 

490 

491 自定义默认值 

492 

493 >>> data.get("with default", default="default value") 

494 'default value' 

495 

496 .. versionchanged:: 0.2.0 

497 重命名参数 ``get_raw`` 为 ``return_raw_value`` 

498 """ # noqa: RUF002 

499 

500 @abstractmethod 

501 def setdefault[V](self, path: PathLike, default: V | None = None, *, return_raw_value: bool = False) -> V | Any: 

502 """ 

503 如果路径不在配置数据中则填充默认值到配置数据并返回 

504 

505 :param path: 路径 

506 :type path: PathLike 

507 :param default: 默认值 

508 :type default: V 

509 :param return_raw_value: 是否获取原始值 

510 :type return_raw_value: bool 

511 

512 :return: 路径的值 

513 :rtype: V | Any 

514 

515 :raise ConfigDataReadOnlyError: 配置数据为只读 

516 :raise ConfigDataTypeError: 配置数据类型错误 

517 

518 例子 

519 ---- 

520 

521 >>> from c41811.config import MappingConfigData 

522 >>> data = MappingConfigData({"key": "value"}) 

523 

524 路径存在时返回值 

525 

526 >>> data.setdefault("key") 

527 'value' 

528 

529 路径不存在时返回默认值None并填充到原始数据 

530 

531 >>> print(data.setdefault("not exists")) 

532 None 

533 >>> data 

534 MappingConfigData({'key': 'value', 'not exists': None}) 

535 

536 自定义默认值 

537 

538 >>> data.setdefault("with default", default="default value") 

539 'default value' 

540 >>> data 

541 MappingConfigData({'key': 'value', 'not exists': None, 'with default': 'default value'}) 

542 

543 .. versionchanged:: 0.2.0 

544 重命名参数 ``get_raw`` 为 ``return_raw_value`` 

545 

546 重命名 ``set_default`` 为 ``setdefault`` 

547 """ 

548 

549 @abstractmethod 

550 def __contains__(self, key: Any) -> bool: ... 

551 

552 @abstractmethod 

553 def __iter__(self) -> Iterator[Any]: ... 

554 

555 @abstractmethod 

556 def __len__(self) -> int: ... 

557 

558 @override 

559 @abstractmethod 

560 def __getitem__(self, index: Any) -> Any: ... 

561 

562 @override 

563 @abstractmethod 

564 def __setitem__(self, index: Any, value: Any) -> None: ... 

565 

566 @override 

567 @abstractmethod 

568 def __delitem__(self, index: Any) -> None: ... 

569 

570 

571class ABCProcessorHelper(ABC): # noqa: B024 

572 """ 

573 辅助SL处理器 

574 

575 .. versionadded:: 0.2.0 

576 """ 

577 

578 @staticmethod 

579 def calc_path( 

580 root_path: str, 

581 namespace: str, 

582 file_name: str | None = None, 

583 ) -> str: 

584 """ 

585 处理配置文件对应的文件路径 

586 

587 file_name为None时,返回文件所在的目录 

588 

589 :param root_path: 保存的根目录 

590 :type root_path: str 

591 :param namespace: 配置的命名空间 

592 :type namespace: str 

593 :param file_name: 配置文件名 

594 :type file_name: str | None 

595 

596 :return: 配置文件路径 

597 :rtype: str 

598 """ # noqa: RUF002 

599 if file_name is None: 

600 file_name = "" 

601 

602 return os.path.normpath(os.path.join(root_path, namespace, file_name)) 

603 

604 

605class ABCSLProcessorPool(ABC): 

606 """SL处理器池""" 

607 

608 def __init__(self, root_path: str = "./.config"): 

609 """ 

610 :param root_path: 保存的根目录 

611 :type root_path: str 

612 """ # noqa: D205 

613 self.SLProcessors: dict[str, ABCConfigSL] = {} 

614 """ 

615 处理器注册表 

616 

617 数据结构: ``{处理器注册名: 处理器实例}}`` 

618 

619 .. versionchanged:: 0.2.0 

620 重命名 ``SLProcessor`` 为 ``SLProcessors`` 

621 """ 

622 self.FileNameProcessors: OrderedDict[str | Pattern[str], list[str]] = ( 

623 OrderedDict() 

624 ) # {FileNameMatch: [RegName]} 

625 # noinspection SpellCheckingInspection 

626 """ 

627 文件名处理器注册表 

628 

629 .. caution:: 

630 此字典是顺序敏感的,越靠前越优先被检查 

631 

632 数据结构: ``{文件名匹配: [处理器注册名]}`` 

633 

634 文件名匹配: 

635 - 为字符串时会使用 ``endswith`` 进行匹配 

636 - 为 ``re.Pattern`` 时会使用 ``Pattern.fullmatch`` 进行匹配 

637 

638 .. versionchanged:: 0.2.0 

639 重命名 ``FileExtProcessor`` 为 ``FileNameProcessors`` 

640 

641 现在是顺序敏感的 

642 """ # noqa: RUF001 

643 self._root_path = root_path 

644 

645 @property 

646 @abstractmethod 

647 def helper(self) -> ABCProcessorHelper: 

648 """处理器助手""" 

649 

650 @property 

651 def root_path(self) -> str: 

652 """配置文件根目录""" 

653 return self._root_path 

654 

655 

656class ABCConfigFile[D: ABCConfigData](ABC): 

657 """配置文件类""" 

658 

659 def __init__(self, initial_config: D, *, config_format: str | None = None): 

660 """ 

661 :param initial_config: 配置数据 

662 :type initial_config: D 

663 :param config_format: 配置文件的格式 

664 :type config_format: str | None 

665 

666 .. caution:: 

667 ``initial_config`` 参数未默认做深拷贝,可能导致非预期行为 

668 

669 .. versionchanged:: 0.2.0 

670 重命名参数 ``config_data`` 为 ``initial_config`` 

671 """ # noqa: RUF002, D205 

672 self._config: D = initial_config 

673 

674 self._config_format: str | None = config_format 

675 

676 @property 

677 def config(self) -> D: 

678 """ 

679 :return: 配置数据 

680 

681 .. caution:: 

682 未默认做深拷贝,可能导致非预期行为 

683 

684 .. versionchanged:: 0.2.0 

685 重命名属性 ``data`` 为 ``config`` 

686 """ # noqa: RUF002 

687 return self._config 

688 

689 @property 

690 def config_format(self) -> str | None: 

691 """配置文件的格式""" 

692 return self._config_format 

693 

694 @abstractmethod 

695 def save( 

696 self, 

697 processor_pool: ABCSLProcessorPool, 

698 namespace: str, 

699 file_name: str, 

700 config_format: str | None = None, 

701 *processor_args: Any, 

702 **processor_kwargs: Any, 

703 ) -> None: 

704 """ 

705 使用SL处理保存配置 

706 

707 :param processor_pool: 配置池 

708 :type processor_pool: ABCSLProcessorPool 

709 :param namespace: 文件命名空间 

710 :type namespace: str 

711 :param file_name: 文件名 

712 :type file_name: str 

713 :param config_format: 配置文件的格式 

714 :type config_format: str | None 

715 

716 :raise UnsupportedConfigFormatError: 不支持的配置格式 

717 

718 .. versionchanged:: 0.2.0 

719 重命名 ``config_pool`` 为 ``processor_pool`` 

720 """ 

721 

722 @classmethod 

723 @abstractmethod 

724 def load( 

725 cls, 

726 processor_pool: ABCSLProcessorPool, 

727 namespace: str, 

728 file_name: str, 

729 config_format: str, 

730 *processor_args: Any, 

731 **processor_kwargs: Any, 

732 ) -> Self: 

733 """ 

734 从SL处理器加载配置 

735 

736 :param processor_pool: 配置池 

737 :type processor_pool: ABCSLProcessorPool 

738 :param namespace: 文件命名空间 

739 :type namespace: str 

740 :param file_name: 文件名 

741 :type file_name: str 

742 :param config_format: 配置文件的格式 

743 :type config_format: str 

744 

745 :return: 配置对象 

746 :rtype: Self 

747 

748 :raise UnsupportedConfigFormatError: 不支持的配置格式 

749 

750 .. versionchanged:: 0.2.0 

751 重命名 ``config_pool`` 为 ``processor_pool`` 

752 """ 

753 

754 @classmethod 

755 @abstractmethod 

756 def initialize( 

757 cls, 

758 processor_pool: ABCSLProcessorPool, 

759 namespace: str, 

760 file_name: str, 

761 config_format: str, 

762 *processor_args: Any, 

763 **processor_kwargs: Any, 

764 ) -> Self: 

765 """ 

766 初始化一个受SL处理器支持的配置文件 

767 

768 :param processor_pool: 配置池 

769 :type processor_pool: ABCSLProcessorPool 

770 :param namespace: 文件命名空间 

771 :type namespace: str 

772 :param file_name: 文件名 

773 :type file_name: str 

774 :param config_format: 配置文件的格式 

775 :type config_format: str 

776 

777 :return: 配置对象 

778 :rtype: Self 

779 

780 :raise UnsupportedConfigFormatError: 不支持的配置格式 

781 

782 .. versionadded:: 0.2.0 

783 """ 

784 

785 def __bool__(self) -> bool: 

786 return bool(self._config) 

787 

788 @override 

789 def __eq__(self, other: Any) -> bool: 

790 if not isinstance(other, type(self)): 

791 return NotImplemented 

792 

793 return all(getattr(self, field) == getattr(other, field) for field in ["_config_format", "_config"]) 

794 

795 __hash__ = None # type: ignore[assignment] 

796 

797 @override 

798 def __repr__(self) -> str: 

799 repr_parts: list[str] = [] 

800 for field in ["_config_format", "_config"]: 

801 field_value = getattr(self, field) 

802 if field_value is None: 

803 continue 

804 

805 repr_parts.append(f"{field[1:]}={field_value!r}") 

806 

807 fmt_str = ", ".join(repr_parts) 

808 return f"{self.__class__.__name__}({fmt_str})" 

809 

810 

811class ABCConfigPool(ABCSLProcessorPool): 

812 """配置池抽象类""" 

813 

814 @overload 

815 def get(self, namespace: str) -> dict[str, ABCConfigFile[Any]] | None: ... 

816 

817 @overload 

818 def get(self, namespace: str, file_name: str) -> ABCConfigFile[Any] | None: ... 

819 

820 @overload 

821 def get( 

822 self, 

823 namespace: str, 

824 file_name: str | None = None, 

825 ) -> dict[str, ABCConfigFile[Any]] | ABCConfigFile[Any] | None: ... 

826 

827 @abstractmethod 

828 def get( 

829 self, 

830 namespace: str, 

831 file_name: str | None = None, 

832 ) -> dict[str, ABCConfigFile[Any]] | ABCConfigFile[Any] | None: 

833 """ 

834 获取配置 

835 

836 如果配置不存在则返回None 

837 

838 :param namespace: 命名空间 

839 :type namespace: str 

840 :param file_name: 文件名 

841 :type file_name: Optional[str] 

842 

843 :return: 配置 

844 :rtype: dict[str, ABCConfigFile] | ABCConfigFile | None 

845 """ 

846 

847 @abstractmethod 

848 def set(self, namespace: str, file_name: str, config: ABCConfigFile[Any]) -> Self: 

849 """ 

850 设置配置 

851 

852 :param namespace: 命名空间 

853 :type namespace: str 

854 :param file_name: 文件名 

855 :type file_name: str 

856 :param config: 配置 

857 :type config: ABCConfigFile 

858 

859 :return: 返回当前实例便于链式调用 

860 :rtype: Self 

861 

862 .. versionchanged:: 0.2.0 

863 返回当前实例便于链式调用 

864 """ 

865 

866 @abstractmethod 

867 def save( 

868 self, 

869 namespace: str, 

870 file_name: str, 

871 config_formats: str | Iterable[str] | None = None, 

872 config: ABCConfigFile[Any] | None = None, 

873 *args: Any, 

874 **kwargs: Any, 

875 ) -> Self: 

876 """ 

877 保存配置 

878 

879 :param namespace: 命名空间 

880 :type namespace: str 

881 :param file_name: 文件名 

882 :type file_name: str 

883 :param config_formats: 配置格式 

884 :type config_formats: str | Iterable[str] | None 

885 :param config: 配置文件,可选,提供此参数相当于自动调用了一遍pool.set 

886 :type config: ABCConfigFile | None 

887 

888 :return: 返回当前实例便于链式调用 

889 :rtype: Self 

890 

891 .. versionchanged:: 0.1.2 

892 添加参数 ``config_formats`` 

893 添加参数 ``config`` 

894 

895 .. versionchanged:: 0.2.0 

896 返回当前实例便于链式调用 

897 """ # noqa: RUF002 

898 

899 @abstractmethod 

900 def save_all( 

901 self, *, ignore_err: bool = False 

902 ) -> dict[str, dict[str, tuple[ABCConfigFile[Any], Exception]]] | None: 

903 """ 

904 保存所有配置 

905 

906 :param ignore_err: 是否忽略保存导致的错误 

907 :type ignore_err: bool 

908 

909 :return: ignore_err为True时返回{Namespace: {FileName: (ConfigObj, Exception)}},否则返回None 

910 :rtype: dict[str, dict[str, tuple[ABCConfigFile, Exception]]] | None 

911 

912 .. versionchanged:: 0.3.0 

913 更改参数 ``ignore_err`` 为仅关键字参数 

914 """ # noqa: RUF002 

915 

916 @abstractmethod 

917 def initialize( 

918 self, 

919 namespace: str, 

920 file_name: str, 

921 *args: Any, 

922 config_formats: str | Iterable[str] | None = None, 

923 **kwargs: Any, 

924 ) -> ABCConfigFile[Any]: 

925 """ 

926 初始化配置文件到指定命名空间并返回 

927 

928 :param namespace: 命名空间 

929 :type namespace: str 

930 :param file_name: 文件名 

931 :type file_name: str 

932 :param config_formats: 配置格式 

933 :type config_formats: str | Iterable[str] | None 

934 

935 :return: 配置对象 

936 :rtype: ABCConfigFile 

937 

938 .. versionadded:: 0.2.0 

939 """ 

940 

941 @abstractmethod 

942 def load( 

943 self, 

944 namespace: str, 

945 file_name: str, 

946 *args: Any, 

947 config_formats: str | Iterable[str] | None = None, 

948 allow_initialize: bool = False, 

949 **kwargs: Any, 

950 ) -> ABCConfigFile[Any]: 

951 """ 

952 加载配置到指定命名空间并返回 

953 

954 :param namespace: 命名空间 

955 :type namespace: str 

956 :param file_name: 文件名 

957 :type file_name: str 

958 :param config_formats: 配置格式 

959 :type config_formats: str | Iterable[str] | None 

960 :param allow_initialize: 是否允许初始化配置文件 

961 :type allow_initialize: bool 

962 

963 :return: 配置对象 

964 :rtype: ABCConfigFile 

965 

966 .. versionchanged:: 0.2.0 

967 现在会像 :py:meth:`save` 一样接收并传递额外参数 

968 

969 删除参数 ``config_file_cls`` 

970 

971 重命名参数 ``allow_create`` 为 ``allow_initialize`` 

972 """ 

973 

974 @abstractmethod 

975 def remove(self, namespace: str, file_name: str | None = None) -> Self: 

976 """ 

977 从配置池移除配置文件 

978 

979 :param namespace: 命名空间 

980 :type namespace: str 

981 :param file_name: 文件名 

982 :type file_name: str | None 

983 

984 :return: 返回当前实例便于链式调用 

985 :rtype: Self 

986 

987 .. versionchanged:: 0.2.0 

988 返回当前实例便于链式调用 

989 

990 重命名 ``delete`` 为 ``remove`` 

991 """ 

992 

993 @abstractmethod 

994 def discard(self, namespace: str, file_name: str | None = None) -> Self: 

995 """ 

996 确保配置文件不存在于配置池 

997 

998 :param namespace: 命名空间 

999 :type namespace: str 

1000 :param file_name: 文件名 

1001 :type file_name: str | None 

1002 

1003 :return: 返回当前实例便于链式调用 

1004 :rtype: Self 

1005 

1006 .. versionadded:: 0.2.0 

1007 """ 

1008 

1009 

1010type SLArgumentType = Sequence[Any] | Mapping[str, Any] | tuple[Sequence[Any], Mapping[str, Any]] | None 

1011""" 

1012.. versionchanged:: 0.3.0 

1013 重命名 ``SLArgument`` 为 ``SLArgumentType`` 

1014""" 

1015 

1016 

1017class ABCConfigSL(ABC): 

1018 """ 

1019 配置SaveLoad处理器抽象类 

1020 

1021 .. versionchanged:: 0.2.0 

1022 移动 ``保存加载器参数`` 相关至 :py:class:`BasicLocalFileConfigSL` 

1023 """ 

1024 

1025 def __init__( 

1026 self, 

1027 *, 

1028 reg_alias: str | None = None, 

1029 ): 

1030 """ 

1031 :param reg_alias: sl处理器注册别名 

1032 :type reg_alias: Optional[str] 

1033 """ # noqa: D205 

1034 self._reg_alias: str | None = reg_alias 

1035 

1036 @property 

1037 @abstractmethod 

1038 def processor_reg_name(self) -> str: 

1039 """SL处理器的默认注册名""" 

1040 

1041 @property 

1042 @abstractmethod 

1043 def supported_file_classes(self) -> list[type[ABCConfigFile[Any]]]: 

1044 """ 

1045 :return: 支持的配置文件类 

1046 

1047 .. versionadded:: 0.2.0 

1048 """ 

1049 

1050 @property 

1051 def reg_alias(self) -> str | None: 

1052 """处理器的别名""" 

1053 return self._reg_alias 

1054 

1055 @property 

1056 def reg_name(self) -> str: 

1057 """处理器的注册名""" 

1058 return self.processor_reg_name if self._reg_alias is None else self._reg_alias 

1059 

1060 @property 

1061 @abstractmethod 

1062 def supported_file_patterns(self) -> tuple[str | Pattern[Any], ...]: 

1063 """ 

1064 :return: 支持的文件名匹配 

1065 

1066 .. versionchanged:: 0.2.0 

1067 重命名 ``file_ext`` 为 ``supported_file_patterns`` 

1068 """ 

1069 

1070 def register_to(self, config_pool: ABCSLProcessorPool) -> Self: 

1071 """ 

1072 注册到配置池中 

1073 

1074 :param config_pool: 配置池 

1075 :type config_pool: ABCSLProcessorPool 

1076 

1077 :return: 返回当前实例便于链式调用 

1078 :rtype: Self 

1079 

1080 .. versionchanged:: 0.3.0 

1081 返回当前实例便于链式调用 

1082 """ 

1083 config_pool.SLProcessors[self.reg_name] = self 

1084 for match in self.supported_file_patterns: 

1085 config_pool.FileNameProcessors.setdefault(match, []).append(self.reg_name) 

1086 return self 

1087 

1088 @abstractmethod 

1089 def save( 

1090 self, 

1091 processor_pool: ABCSLProcessorPool, 

1092 config_file: ABCConfigFile[Any], 

1093 root_path: str, 

1094 namespace: str, 

1095 file_name: str, 

1096 *args: Any, 

1097 **kwargs: Any, 

1098 ) -> None: 

1099 """ 

1100 保存处理器 

1101 

1102 :param processor_pool: 配置池 

1103 :type processor_pool: ABCSLProcessorPool 

1104 :param config_file: 待保存配置 

1105 :type config_file: ABCConfigFile 

1106 :param root_path: 保存的根目录 

1107 :type root_path: str 

1108 :param namespace: 配置的命名空间 

1109 :type namespace: str 

1110 :param file_name: 配置文件名 

1111 :type file_name: str 

1112 

1113 :raise FailedProcessConfigFileError: 处理配置文件失败 

1114 

1115 .. versionchanged:: 0.2.0 

1116 添加参数 ``processor_pool`` 

1117 """ 

1118 

1119 @abstractmethod 

1120 def load( 

1121 self, 

1122 processor_pool: ABCSLProcessorPool, 

1123 root_path: str, 

1124 namespace: str, 

1125 file_name: str, 

1126 *args: Any, 

1127 **kwargs: Any, 

1128 ) -> ABCConfigFile[Any]: 

1129 """ 

1130 加载处理器 

1131 

1132 :param processor_pool: 配置池 

1133 :type processor_pool: ABCSLProcessorPool 

1134 :param root_path: 保存的根目录 

1135 :type root_path: str 

1136 :param namespace: 配置的命名空间 

1137 :type namespace: str 

1138 :param file_name: 配置文件名 

1139 :type file_name: str 

1140 

1141 :return: 配置对象 

1142 :rtype: ABCConfigFile 

1143 

1144 :raise FailedProcessConfigFileError: 处理配置文件失败 

1145 

1146 .. versionchanged:: 0.2.0 

1147 删除参数 ``config_file_cls`` 

1148 

1149 添加参数 ``processor_pool`` 

1150 """ 

1151 

1152 @abstractmethod 

1153 def initialize( 

1154 self, 

1155 processor_pool: ABCSLProcessorPool, 

1156 root_path: str, 

1157 namespace: str, 

1158 file_name: str, 

1159 *args: Any, 

1160 **kwargs: Any, 

1161 ) -> ABCConfigFile[Any]: 

1162 """ 

1163 初始化一个受SL处理器支持的配置文件 

1164 

1165 :param processor_pool: 配置池 

1166 :type processor_pool: ABCSLProcessorPool 

1167 :param root_path: 保存的根目录 

1168 :type root_path: str 

1169 :param namespace: 配置的命名空间 

1170 :type namespace: str 

1171 :param file_name: 配置文件名 

1172 :type file_name: str 

1173 

1174 :return: 配置对象 

1175 :rtype: ABCConfigFile 

1176 

1177 .. versionadded:: 0.2.0 

1178 """ 

1179 

1180 @override 

1181 def __eq__(self, other: Any) -> bool: 

1182 if not isinstance(other, type(self)): 

1183 return NotImplemented 

1184 

1185 processor_reg_name = self.processor_reg_name == other.processor_reg_name 

1186 reg_alias = self.reg_alias == other.reg_alias 

1187 file_match_eq = self.supported_file_patterns == other.supported_file_patterns 

1188 

1189 return all( 

1190 ( 

1191 processor_reg_name, 

1192 reg_alias, 

1193 file_match_eq, 

1194 ) 

1195 ) 

1196 

1197 @override 

1198 def __hash__(self) -> int: 

1199 return hash( 

1200 ( 

1201 self.processor_reg_name, 

1202 self.reg_alias, 

1203 self.supported_file_patterns, 

1204 ) 

1205 ) 

1206 

1207 

1208class ABCMetaParser[D: ABCConfigData, M](ABC): 

1209 """ 

1210 元信息解析器抽象类 

1211 

1212 .. versionadded:: 0.2.0 

1213 """ 

1214 

1215 @abstractmethod 

1216 def convert_config2meta(self, meta_config: D) -> M: 

1217 """ 

1218 解析元配置 

1219 

1220 :param meta_config: 元配置 

1221 :type meta_config: D 

1222 

1223 :return: 元数据 

1224 :rtype: M 

1225 """ 

1226 

1227 @abstractmethod 

1228 def convert_meta2config(self, meta: M) -> D: 

1229 """ 

1230 解析元数据 

1231 

1232 :param meta: 元数据 

1233 :type meta: M 

1234 

1235 :return: 元配置 

1236 :rtype: D 

1237 """ 

1238 

1239 @abstractmethod 

1240 def validator(self, meta: M, *args: Any) -> M: 

1241 """元数据验证器""" 

1242 

1243 

1244__all__ = ( 

1245 "ABCConfigData", 

1246 "ABCConfigFile", 

1247 "ABCConfigPool", 

1248 "ABCConfigSL", 

1249 "ABCIndexedConfigData", 

1250 "ABCKey", 

1251 "ABCMetaParser", 

1252 "ABCPath", 

1253 "ABCProcessorHelper", 

1254 "ABCSLProcessorPool", 

1255 "AnyKey", 

1256 "PathLike", 

1257 "SLArgumentType", 

1258)