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
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-09 01:06 +0000
1# cython: language_level = 3 # noqa: ERA001
4"""配置抽象基类"""
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
21from ._protocols import Indexed
22from ._protocols import MutableIndexed
24type AnyKey = ABCKey[Any, Any]
25"""
26.. versionadded:: 0.2.0
27"""
30class ABCKey[K, D](ABC):
31 """用于获取配置的键"""
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
43 @property
44 def key(self) -> K:
45 """键"""
46 return deepcopy(self._key)
48 @property
49 def meta(self) -> str | None:
50 """
51 元信息
53 .. versionadded:: 0.2.0
54 """
55 return self._meta
57 @abstractmethod
58 def unparse(self) -> str:
59 """
60 还原为可被解析的字符串
62 .. versionadded:: 0.1.1
63 """
65 @abstractmethod
66 def __get_inner_element__(self, data: D) -> D:
67 """
68 获取内层元素
70 :param data: 配置数据
71 :type data: D
72 :return: 内层配置数据
73 :rtype: D
75 .. versionadded:: 0.1.4
76 """
78 @abstractmethod
79 def __set_inner_element__(self, data: D, value: Any) -> None:
80 """
81 设置内层元素
83 :param data: 配置数据
84 :type data: D
85 :param value: 值
86 :type value: Any
88 .. versionadded:: 0.1.4
89 """
91 @abstractmethod
92 def __delete_inner_element__(self, data: D) -> None:
93 """
94 删除内层元素
96 :param data: 配置数据
97 :type data: D
99 .. versionadded:: 0.1.4
100 """
102 @abstractmethod
103 def __contains_inner_element__(self, data: D) -> bool:
104 """
105 是否包含内层元素
107 :param data: 配置数据
108 :type data: D
109 :return: 是否包含内层配置数据
110 :rtype: bool
112 .. versionadded:: 0.1.4
113 """
115 @abstractmethod
116 def __supports__(self, data: Any) -> tuple[Any, ...]:
117 """
118 检查此键是否支持该配置数据
120 返回缺失的协议
122 :param data: 配置数据
123 :type data: Any
124 :return: 此键缺失支持的数据类型
125 :rtype: tuple
127 .. versionadded:: 0.1.4
128 """
130 @abstractmethod
131 def __supports_modify__(self, data: Any) -> tuple[Any, ...]:
132 """
133 检查此键是否支持修改该配置数据
135 返回缺失的协议
137 :param data: 配置数据
138 :type data: Any
139 :return: 此键缺失支持的数据类型
140 :rtype: tuple
142 .. versionadded:: 0.1.4
143 """
145 @override
146 def __eq__(self, other: Any) -> bool:
147 if not isinstance(other, type(self)):
148 return NotImplemented
150 return all(
151 (
152 self._key == other._key,
153 self._meta == other._meta,
154 )
155 )
157 @override
158 def __hash__(self) -> int:
159 return hash((self._key, self._meta))
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)
166 @override
167 def __str__(self) -> str:
168 return str(self._key)
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})>"
176class ABCPath[K: AnyKey](ABC, Iterable[K]):
177 """用于获取数据的路径"""
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))
186 @property
187 def keys(self) -> tuple[K, ...]:
188 """
189 键列表
191 .. note::
192 返回的是深拷贝副本,修改不会影响路径
194 .. versionadded:: 0.2.0
195 """ # noqa: RUF002
196 return deepcopy(self._keys)
198 @abstractmethod
199 def unparse(self) -> str:
200 """
201 还原为可被解析的字符串
203 .. versionadded:: 0.1.1
204 """
206 @overload
207 def __getitem__(self, item: slice) -> Self: ...
209 @overload
210 def __getitem__(self, item: int) -> K: ...
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
218 def __contains__(self, item: Any) -> bool:
219 return item in self._keys
221 def __bool__(self) -> bool:
222 return bool(self._keys)
224 def __len__(self) -> int:
225 return len(self._keys)
227 @override
228 def __iter__(self) -> Iterator[K]:
229 return iter(self._keys)
231 @override
232 def __hash__(self) -> int:
233 return hash(self._keys)
235 def __deepcopy__(self, memo: dict[Any, Any]) -> Self:
236 return type(self)(self._keys)
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
244 @override
245 def __repr__(self) -> str:
246 return f"<{type(self).__name__}{self._keys}>"
249class ABCConfigData(ABC):
250 """
251 配置数据抽象基类
253 .. versionchanged:: 0.1.5
254 现在配置数据不再局限于Mapping
255 """
257 @classmethod
258 def from_data(cls, *args: Any, **kwargs: Any) -> Self:
259 """
260 提供创建同类型配置数据的快捷方式
262 :return: 新的配置数据
263 :rtype: Self
265 .. note::
266 套壳 ``__init__`` 主要是为了方便内部快速创建与传入的ABCConfigData同类型的对象
268 例如:
270 .. code-block:: python
272 type(instance)(data)
274 可以简写为
276 .. code-block:: python
278 instance.from_data(data)
280 .. versionchanged:: 0.2.0
281 现在会自适应初始化参数
282 """ # noqa: RUF002
283 # noinspection PyArgumentList
284 return cls(*args, **kwargs)
286 @property
287 @abstractmethod
288 def data_read_only(self) -> bool | None:
289 """
290 配置数据是否为只读
292 :return: 配置数据是否为只读
293 :rtype: bool | None
295 .. versionadded:: 0.1.3
297 .. versionchanged:: 0.1.5
298 改为抽象属性
299 """
301 @property
302 @abstractmethod
303 def read_only(self) -> bool | None:
304 """
305 配置数据是否为 ``只读模式``
307 :return: 配置数据是否为 ``只读模式``
308 :rtype: bool | None
309 """
310 return self.data_read_only
312 @read_only.setter
313 @abstractmethod
314 def read_only(self, value: Any) -> None:
315 """
316 设置配置数据是否为 ``只读模式``
318 :raise ConfigDataReadOnlyError: 配置数据为只读
319 """
321 def freeze(self, freeze: bool | None = None) -> Self: # noqa: FBT001
322 """
323 冻结配置数据 (切换只读模式)
325 :param freeze: 是否冻结配置数据, 为 :py:const:`None` 时进行切换
326 :type freeze: bool | None
327 :return: 返回当前实例便于链式调用
328 :rtype: Self
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
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)
345type PathLike = str | ABCPath[AnyKey]
346"""
347.. versionadded:: 0.2.0
348"""
351class ABCIndexedConfigData[D: Indexed[Any, Any]](ABCConfigData, MutableIndexed[Any, Any], ABC):
352 # noinspection GrazieInspection
353 """
354 支持 ``索引`` 操作的配置数据
356 .. versionadded:: 0.1.5
358 .. versionchanged:: 0.2.0
359 重命名 ``ABCSupportsIndexConfigData`` 为 ``ABCIndexedConfigData``
360 """
362 @abstractmethod
363 def retrieve(self, path: PathLike, *, return_raw_value: bool = False) -> Any:
364 """
365 获取路径的值的*快照*
367 :param path: 路径
368 :type path: PathLike
369 :param return_raw_value: 是否获取原始值,为 :py:const:`False` 时,会将Mapping | Sequence转换为对应类
370 :type return_raw_value: bool
372 :return: 路径的值
373 :rtype: Any
375 :raise ConfigDataTypeError: 配置数据类型错误
376 :raise RequiredPathNotFoundError: 需求的键不存在
378 .. versionchanged:: 0.2.0
379 重命名参数 ``get_raw`` 为 ``return_raw_value``
380 """ # noqa: RUF002
382 @abstractmethod
383 def modify(self, path: PathLike, value: Any, *, allow_create: bool = True) -> Self:
384 """
385 修改路径的值
387 :param path: 路径
388 :type path: PathLike
389 :param value: 值
390 :type value: Any
391 :param allow_create: 是否允许创建不存在的路径,默认为True
392 :type allow_create: bool
394 :return: 返回当前实例便于链式调用
395 :rtype: Self
397 :raise ConfigDataReadOnlyError: 配置数据为只读
398 :raise ConfigDataTypeError: 配置数据类型错误
399 :raise RequiredPathNotFoundError: 需求的键不存在
401 .. caution::
402 ``value`` 参数未默认做深拷贝,可能导致非预期行为
404 .. attention::
405 ``allow_create`` 时,使用与 `self.data` 一样的类型新建路径
406 """ # noqa: RUF002
408 @abstractmethod
409 def delete(self, path: PathLike) -> Self:
410 """
411 删除路径
413 :param path: 路径
414 :type path: PathLike
416 :return: 返回当前实例便于链式调用
417 :rtype: Self
419 :raise ConfigDataReadOnlyError: 配置数据为只读
420 :raise ConfigDataTypeError: 配置数据类型错误
421 :raise RequiredPathNotFoundError: 需求的键不存在
422 """
424 @abstractmethod
425 def unset(self, path: PathLike) -> Self:
426 """
427 确保路径不存在 (删除路径,但是找不到路径时不会报错)
429 :param path: 路径
430 :type path: PathLike
432 :return: 返回当前实例便于链式调用
433 :rtype: Self
435 :raise ConfigDataReadOnlyError: 配置数据为只读
436 :raise ConfigDataTypeError: 配置数据类型错误
438 .. versionadded:: 0.1.2
439 """ # noqa: RUF002
441 @abstractmethod
442 def exists(self, path: PathLike, *, ignore_wrong_type: bool = False) -> bool:
443 """
444 判断路径是否存在
446 :param path: 路径
447 :type path: PathLike
448 :param ignore_wrong_type: 忽略配置数据类型错误
449 :type ignore_wrong_type: bool
451 :return: 路径是否存在
452 :rtype: bool
454 :raise ConfigDataTypeError: 配置数据类型错误
455 """
457 @abstractmethod
458 def get[V](self, path: PathLike, default: V | None = None, *, return_raw_value: bool = False) -> V | Any:
459 """
460 获取路径的值的*快照*,路径不存在时填充默认值
462 :param path: 路径
463 :type path: PathLike
465 :param default: 默认值
466 :type default: V
467 :param return_raw_value: 是否获取原始值
468 :type return_raw_value: bool
470 :return: 路径的值
471 :rtype: V | Any
473 :raise ConfigDataTypeError: 配置数据类型错误
475 例子
476 ----
478 >>> from c41811.config import MappingConfigData
479 >>> data = MappingConfigData({"key": "value"})
481 路径存在时返回值
483 >>> data.get("key")
484 'value'
486 路径不存在时返回默认值None
488 >>> print(data.get("not exists"))
489 None
491 自定义默认值
493 >>> data.get("with default", default="default value")
494 'default value'
496 .. versionchanged:: 0.2.0
497 重命名参数 ``get_raw`` 为 ``return_raw_value``
498 """ # noqa: RUF002
500 @abstractmethod
501 def setdefault[V](self, path: PathLike, default: V | None = None, *, return_raw_value: bool = False) -> V | Any:
502 """
503 如果路径不在配置数据中则填充默认值到配置数据并返回
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
512 :return: 路径的值
513 :rtype: V | Any
515 :raise ConfigDataReadOnlyError: 配置数据为只读
516 :raise ConfigDataTypeError: 配置数据类型错误
518 例子
519 ----
521 >>> from c41811.config import MappingConfigData
522 >>> data = MappingConfigData({"key": "value"})
524 路径存在时返回值
526 >>> data.setdefault("key")
527 'value'
529 路径不存在时返回默认值None并填充到原始数据
531 >>> print(data.setdefault("not exists"))
532 None
533 >>> data
534 MappingConfigData({'key': 'value', 'not exists': None})
536 自定义默认值
538 >>> data.setdefault("with default", default="default value")
539 'default value'
540 >>> data
541 MappingConfigData({'key': 'value', 'not exists': None, 'with default': 'default value'})
543 .. versionchanged:: 0.2.0
544 重命名参数 ``get_raw`` 为 ``return_raw_value``
546 重命名 ``set_default`` 为 ``setdefault``
547 """
549 @abstractmethod
550 def __contains__(self, key: Any) -> bool: ...
552 @abstractmethod
553 def __iter__(self) -> Iterator[Any]: ...
555 @abstractmethod
556 def __len__(self) -> int: ...
558 @override
559 @abstractmethod
560 def __getitem__(self, index: Any) -> Any: ...
562 @override
563 @abstractmethod
564 def __setitem__(self, index: Any, value: Any) -> None: ...
566 @override
567 @abstractmethod
568 def __delitem__(self, index: Any) -> None: ...
571class ABCProcessorHelper(ABC): # noqa: B024
572 """
573 辅助SL处理器
575 .. versionadded:: 0.2.0
576 """
578 @staticmethod
579 def calc_path(
580 root_path: str,
581 namespace: str,
582 file_name: str | None = None,
583 ) -> str:
584 """
585 处理配置文件对应的文件路径
587 file_name为None时,返回文件所在的目录
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
596 :return: 配置文件路径
597 :rtype: str
598 """ # noqa: RUF002
599 if file_name is None:
600 file_name = ""
602 return os.path.normpath(os.path.join(root_path, namespace, file_name))
605class ABCSLProcessorPool(ABC):
606 """SL处理器池"""
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 处理器注册表
617 数据结构: ``{处理器注册名: 处理器实例}}``
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 文件名处理器注册表
629 .. caution::
630 此字典是顺序敏感的,越靠前越优先被检查
632 数据结构: ``{文件名匹配: [处理器注册名]}``
634 文件名匹配:
635 - 为字符串时会使用 ``endswith`` 进行匹配
636 - 为 ``re.Pattern`` 时会使用 ``Pattern.fullmatch`` 进行匹配
638 .. versionchanged:: 0.2.0
639 重命名 ``FileExtProcessor`` 为 ``FileNameProcessors``
641 现在是顺序敏感的
642 """ # noqa: RUF001
643 self._root_path = root_path
645 @property
646 @abstractmethod
647 def helper(self) -> ABCProcessorHelper:
648 """处理器助手"""
650 @property
651 def root_path(self) -> str:
652 """配置文件根目录"""
653 return self._root_path
656class ABCConfigFile[D: ABCConfigData](ABC):
657 """配置文件类"""
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
666 .. caution::
667 ``initial_config`` 参数未默认做深拷贝,可能导致非预期行为
669 .. versionchanged:: 0.2.0
670 重命名参数 ``config_data`` 为 ``initial_config``
671 """ # noqa: RUF002, D205
672 self._config: D = initial_config
674 self._config_format: str | None = config_format
676 @property
677 def config(self) -> D:
678 """
679 :return: 配置数据
681 .. caution::
682 未默认做深拷贝,可能导致非预期行为
684 .. versionchanged:: 0.2.0
685 重命名属性 ``data`` 为 ``config``
686 """ # noqa: RUF002
687 return self._config
689 @property
690 def config_format(self) -> str | None:
691 """配置文件的格式"""
692 return self._config_format
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处理保存配置
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
716 :raise UnsupportedConfigFormatError: 不支持的配置格式
718 .. versionchanged:: 0.2.0
719 重命名 ``config_pool`` 为 ``processor_pool``
720 """
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处理器加载配置
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
745 :return: 配置对象
746 :rtype: Self
748 :raise UnsupportedConfigFormatError: 不支持的配置格式
750 .. versionchanged:: 0.2.0
751 重命名 ``config_pool`` 为 ``processor_pool``
752 """
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处理器支持的配置文件
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
777 :return: 配置对象
778 :rtype: Self
780 :raise UnsupportedConfigFormatError: 不支持的配置格式
782 .. versionadded:: 0.2.0
783 """
785 def __bool__(self) -> bool:
786 return bool(self._config)
788 @override
789 def __eq__(self, other: Any) -> bool:
790 if not isinstance(other, type(self)):
791 return NotImplemented
793 return all(getattr(self, field) == getattr(other, field) for field in ["_config_format", "_config"])
795 __hash__ = None # type: ignore[assignment]
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
805 repr_parts.append(f"{field[1:]}={field_value!r}")
807 fmt_str = ", ".join(repr_parts)
808 return f"{self.__class__.__name__}({fmt_str})"
811class ABCConfigPool(ABCSLProcessorPool):
812 """配置池抽象类"""
814 @overload
815 def get(self, namespace: str) -> dict[str, ABCConfigFile[Any]] | None: ...
817 @overload
818 def get(self, namespace: str, file_name: str) -> ABCConfigFile[Any] | None: ...
820 @overload
821 def get(
822 self,
823 namespace: str,
824 file_name: str | None = None,
825 ) -> dict[str, ABCConfigFile[Any]] | ABCConfigFile[Any] | None: ...
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 获取配置
836 如果配置不存在则返回None
838 :param namespace: 命名空间
839 :type namespace: str
840 :param file_name: 文件名
841 :type file_name: Optional[str]
843 :return: 配置
844 :rtype: dict[str, ABCConfigFile] | ABCConfigFile | None
845 """
847 @abstractmethod
848 def set(self, namespace: str, file_name: str, config: ABCConfigFile[Any]) -> Self:
849 """
850 设置配置
852 :param namespace: 命名空间
853 :type namespace: str
854 :param file_name: 文件名
855 :type file_name: str
856 :param config: 配置
857 :type config: ABCConfigFile
859 :return: 返回当前实例便于链式调用
860 :rtype: Self
862 .. versionchanged:: 0.2.0
863 返回当前实例便于链式调用
864 """
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 保存配置
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
888 :return: 返回当前实例便于链式调用
889 :rtype: Self
891 .. versionchanged:: 0.1.2
892 添加参数 ``config_formats``
893 添加参数 ``config``
895 .. versionchanged:: 0.2.0
896 返回当前实例便于链式调用
897 """ # noqa: RUF002
899 @abstractmethod
900 def save_all(
901 self, *, ignore_err: bool = False
902 ) -> dict[str, dict[str, tuple[ABCConfigFile[Any], Exception]]] | None:
903 """
904 保存所有配置
906 :param ignore_err: 是否忽略保存导致的错误
907 :type ignore_err: bool
909 :return: ignore_err为True时返回{Namespace: {FileName: (ConfigObj, Exception)}},否则返回None
910 :rtype: dict[str, dict[str, tuple[ABCConfigFile, Exception]]] | None
912 .. versionchanged:: 0.3.0
913 更改参数 ``ignore_err`` 为仅关键字参数
914 """ # noqa: RUF002
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 初始化配置文件到指定命名空间并返回
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
935 :return: 配置对象
936 :rtype: ABCConfigFile
938 .. versionadded:: 0.2.0
939 """
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 加载配置到指定命名空间并返回
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
963 :return: 配置对象
964 :rtype: ABCConfigFile
966 .. versionchanged:: 0.2.0
967 现在会像 :py:meth:`save` 一样接收并传递额外参数
969 删除参数 ``config_file_cls``
971 重命名参数 ``allow_create`` 为 ``allow_initialize``
972 """
974 @abstractmethod
975 def remove(self, namespace: str, file_name: str | None = None) -> Self:
976 """
977 从配置池移除配置文件
979 :param namespace: 命名空间
980 :type namespace: str
981 :param file_name: 文件名
982 :type file_name: str | None
984 :return: 返回当前实例便于链式调用
985 :rtype: Self
987 .. versionchanged:: 0.2.0
988 返回当前实例便于链式调用
990 重命名 ``delete`` 为 ``remove``
991 """
993 @abstractmethod
994 def discard(self, namespace: str, file_name: str | None = None) -> Self:
995 """
996 确保配置文件不存在于配置池
998 :param namespace: 命名空间
999 :type namespace: str
1000 :param file_name: 文件名
1001 :type file_name: str | None
1003 :return: 返回当前实例便于链式调用
1004 :rtype: Self
1006 .. versionadded:: 0.2.0
1007 """
1010type SLArgumentType = Sequence[Any] | Mapping[str, Any] | tuple[Sequence[Any], Mapping[str, Any]] | None
1011"""
1012.. versionchanged:: 0.3.0
1013 重命名 ``SLArgument`` 为 ``SLArgumentType``
1014"""
1017class ABCConfigSL(ABC):
1018 """
1019 配置SaveLoad处理器抽象类
1021 .. versionchanged:: 0.2.0
1022 移动 ``保存加载器参数`` 相关至 :py:class:`BasicLocalFileConfigSL`
1023 """
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
1036 @property
1037 @abstractmethod
1038 def processor_reg_name(self) -> str:
1039 """SL处理器的默认注册名"""
1041 @property
1042 @abstractmethod
1043 def supported_file_classes(self) -> list[type[ABCConfigFile[Any]]]:
1044 """
1045 :return: 支持的配置文件类
1047 .. versionadded:: 0.2.0
1048 """
1050 @property
1051 def reg_alias(self) -> str | None:
1052 """处理器的别名"""
1053 return self._reg_alias
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
1060 @property
1061 @abstractmethod
1062 def supported_file_patterns(self) -> tuple[str | Pattern[Any], ...]:
1063 """
1064 :return: 支持的文件名匹配
1066 .. versionchanged:: 0.2.0
1067 重命名 ``file_ext`` 为 ``supported_file_patterns``
1068 """
1070 def register_to(self, config_pool: ABCSLProcessorPool) -> Self:
1071 """
1072 注册到配置池中
1074 :param config_pool: 配置池
1075 :type config_pool: ABCSLProcessorPool
1077 :return: 返回当前实例便于链式调用
1078 :rtype: Self
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
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 保存处理器
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
1113 :raise FailedProcessConfigFileError: 处理配置文件失败
1115 .. versionchanged:: 0.2.0
1116 添加参数 ``processor_pool``
1117 """
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 加载处理器
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
1141 :return: 配置对象
1142 :rtype: ABCConfigFile
1144 :raise FailedProcessConfigFileError: 处理配置文件失败
1146 .. versionchanged:: 0.2.0
1147 删除参数 ``config_file_cls``
1149 添加参数 ``processor_pool``
1150 """
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处理器支持的配置文件
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
1174 :return: 配置对象
1175 :rtype: ABCConfigFile
1177 .. versionadded:: 0.2.0
1178 """
1180 @override
1181 def __eq__(self, other: Any) -> bool:
1182 if not isinstance(other, type(self)):
1183 return NotImplemented
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
1189 return all(
1190 (
1191 processor_reg_name,
1192 reg_alias,
1193 file_match_eq,
1194 )
1195 )
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 )
1208class ABCMetaParser[D: ABCConfigData, M](ABC):
1209 """
1210 元信息解析器抽象类
1212 .. versionadded:: 0.2.0
1213 """
1215 @abstractmethod
1216 def convert_config2meta(self, meta_config: D) -> M:
1217 """
1218 解析元配置
1220 :param meta_config: 元配置
1221 :type meta_config: D
1223 :return: 元数据
1224 :rtype: M
1225 """
1227 @abstractmethod
1228 def convert_meta2config(self, meta: M) -> D:
1229 """
1230 解析元数据
1232 :param meta: 元数据
1233 :type meta: M
1235 :return: 元配置
1236 :rtype: D
1237 """
1239 @abstractmethod
1240 def validator(self, meta: M, *args: Any) -> M:
1241 """元数据验证器"""
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)