跳转至

Kayaku🔗

kayaku.Kayaku 🔗

配置管理器。

Example:

```py
from dataclasses import dataclass

from kayaku import ConfigManager

cfg_manager = ConfigManager({"{**}.connection": "./config/connection.jsonc::{**}})

@dataclass
class Connection:
    account: int | None = None
    password: str | None = None

cfg_manager.register("my_mod.config.connection", Connection)
cfg_manager.load()
```

以上代码将会将 `Connection` 类的数据存储在 `./config/connection.jsonc` 文件的 `["my_mod"]["config"]` 里.
Source code in kayaku/manager.py
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
class Kayaku:
    """配置管理器。

    Example:

        ```py
        from dataclasses import dataclass

        from kayaku import ConfigManager

        cfg_manager = ConfigManager({"{**}.connection": "./config/connection.jsonc::{**}})

        @dataclass
        class Connection:
            account: int | None = None
            password: str | None = None

        cfg_manager.register("my_mod.config.connection", Connection)
        cfg_manager.load()
        ```

        以上代码将会将 `Connection` 类的数据存储在 `./config/connection.jsonc` 文件的 `["my_mod"]["config"]` 里.
    """

    """`domain 样式 -> 路径样式` 的映射。"""
    """美化 JSONC/JSON5 文件时使用。默认根据文件后缀自动选择。"""
    """在获取 JSON Schema 时使用的生成器。"""

    def __init__(
        self,
        specs: dict[str, str],
        file_suffix: str = "json5",
        prettifier: Prettifier | None = None,
        get_schema_generator: SchemaGenCallable = SchemaGenerator,
    ) -> None:
        self.file_suffix = file_suffix
        self.get_schema_generator = get_schema_generator
        if prettifier:
            self.prettifier = prettifier
        else:
            self.prettifier: Prettifier = (
                JSON5_PRETTIFIER if self.file_suffix != "jsonc" else JSONC_PRETTIFIER
            )
        self._core = _KayakuCore(
            self.file_suffix, self.prettifier, self.get_schema_generator
        )
        exceptions = []
        for src, path in specs.items():
            try:
                src_spec = parse_source(src)
                path_spec = parse_path(path)
                self._core.insert_spec(src_spec, path_spec)
            except Exception as e:
                exceptions.append(e)
        if exceptions:
            raise ExceptionGroup(
                f"{len(exceptions)} occurred during spec initialization", exceptions
            )

    def load(self, domain_map: dict[str, type[DataClass]]) -> None:
        """加载配置类。"""
        self._core.register_batch(domain_map)

    @overload
    def get(self, cls: type[DC_T], safe: Literal[False] = False) -> DC_T: ...

    @overload
    def get(self, cls: type[DC_T], safe: Literal[True]) -> DC_T | None: ...

    def get(self, cls: type[DC_T], safe: bool = False) -> DC_T | None:
        """获取配置类的实例。"""
        res: Any = self._core.instances.get(cls)
        if res is None and not safe:
            raise ValueError(f"{cls} is not loaded!")
        return res

    def save(self, config: type[DataClass] | DataClass | DomainIdent) -> None:
        if isinstance(config, type):
            domain = self._core.cls_domains[config]
        elif isinstance(config, DataClass):
            domain = self._core.cls_domains[config.__class__]
        else:
            domain = config
        cls_entry = self._core.classes[domain]
        instance = (
            config
            if isinstance(config, DataClass) and not isinstance(config, type)
            else self.get(cls_entry.cls, safe=True)
        )
        if not instance:
            raise ValueError(f"{cls_entry.cls} is not loaded!")
        document = loads(cls_entry.path.read_text("utf-8") or "{}")
        container = document
        for sect in cls_entry.mount:
            container = container.setdefault(sect, JObject())
        update(container, instance)
        document.pop("$schema", None)
        document["$schema"] = cls_entry.path.with_suffix(".schema.json").as_uri()
        cls_entry.path.write_text(
            dumps(self._core.prettifier.prettify(document), endline=True), "utf-8"
        )
        touch_path(cls_entry.path.with_suffix(".schema.json")).with_suffix(
            ".schema.json"
        ).write_text(dumps(self._core.files[cls_entry.path].get_schema()), "utf-8")

get 🔗

get(cls: type[DC_T], safe: Literal[False] = False) -> DC_T
get(cls: type[DC_T], safe: Literal[True]) -> DC_T | None
get(cls: type[DC_T], safe: bool = False) -> DC_T | None

获取配置类的实例。

Source code in kayaku/manager.py
254
255
256
257
258
259
def get(self, cls: type[DC_T], safe: bool = False) -> DC_T | None:
    """获取配置类的实例。"""
    res: Any = self._core.instances.get(cls)
    if res is None and not safe:
        raise ValueError(f"{cls} is not loaded!")
    return res

load 🔗

load(domain_map: dict[str, type[DataClass]]) -> None

加载配置类。

Source code in kayaku/manager.py
244
245
246
def load(self, domain_map: dict[str, type[DataClass]]) -> None:
    """加载配置类。"""
    self._core.register_batch(domain_map)

kayaku.pretty.Prettifier 🔗

Prettifier(indent: int = 4, trail_comma: bool = True, key_quote: Quote | None | Literal[False] = False, string_quote: Quote | None = Quote.DOUBLE, unfold_single: bool = False)

容器格式化工具

Parameters:

  • indent (int, default: 4 ) –

    缩进数量. Defaults to 4.

  • trail_comma (bool, default: True ) –

    是否要为容器增加尾随逗号. Defaults to True.

  • key_quote (Quote | None | Literal[False], default: False ) –

    键使用的引号风格, None 为保留, Quote.DOUBLE 为双引号, Quote.SINGLE 为单引号, False 为尽可能去除引号. Defaults to False.

  • string_quote (Quote | None, default: DOUBLE ) –

    值中字符串使用的引号风格, 解释同上. Defaults to Quote.DOUBLE.

  • unfold_single (bool, default: False ) –

    单个元素的容器是否展开. Defaults to False.

Source code in kayaku/pretty.py
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def __init__(
    self,
    indent: int = 4,
    trail_comma: bool = True,
    key_quote: Quote | None | Literal[False] = False,
    string_quote: Quote | None = Quote.DOUBLE,
    unfold_single: bool = False,
):
    """

    Args:
        indent (int, optional): 缩进数量. Defaults to 4.
        trail_comma (bool, optional): 是否要为容器增加尾随逗号. Defaults to True.
        key_quote (Quote | None | Literal[False], optional): 键使用的引号风格,
            None 为保留, Quote.DOUBLE 为双引号, Quote.SINGLE 为单引号, False 为尽可能去除引号.
            Defaults to False.
        string_quote (Quote | None, optional): 值中字符串使用的引号风格, 解释同上. Defaults to Quote.DOUBLE.
        unfold_single (bool, optional): 单个元素的容器是否展开. Defaults to False.
    """
    self.indent: int = indent
    self.trail_comma: bool = trail_comma
    self.key_quote: Quote | Literal[False] | None = key_quote
    self.string_quote: Quote | None = string_quote
    self.unfold_single: bool = unfold_single
    self.layer: int = 0