Coverage for src/tomcli/cli/set.py: 71%
68 statements
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-13 11:39 +0300
« prev ^ index » next coverage.py v7.2.3, created at 2023-04-13 11:39 +0300
1# Copyright (C) 2023 Maxwell G <maxwell@gtmx.me>
2#
3# SPDX-License-Identifier: MIT
5# ruff: noqa: UP007
7from __future__ import annotations
9import dataclasses
10from collections.abc import Mapping, MutableMapping
11import sys
12from typing import Any, Optional
14from typer import Argument, Context, Exit, Option, Typer
16from tomcli.cli._util import _std_cm
17from tomcli.toml import Reader, Writer, dump, load
19app = Typer()
22def get_part(data: MutableMapping[str, Any], selector: str) -> Any:
23 if selector == ".":
24 return data
26 cur = data
27 parts = selector.split(".")
28 idx = 0
29 try:
30 for idx, part in enumerate(parts): # noqa: B007
31 cur = cur[part]
32 except (IndexError, KeyError):
33 up_to = ".".join(parts[: idx + 1])
34 msg = f"Invalid selector {selector!r}: could not find {up_to!r}"
35 raise Exit(msg) from None
36 return cur
39@dataclasses.dataclass()
40class ModderCtx:
41 path: str
42 out: str
43 reader: str | None = None
44 writer: str | None = None
45 allow_fallback_r: bool = True
46 allow_fallback_w: bool = True
48 def set_default_rw(self, reader: Reader, writer: Writer):
49 if self.reader is None:
50 self.reader = reader
51 else:
52 self.allow_fallback_r = False
53 if self.writer is None:
54 self.writer = writer
55 else:
56 self.allow_fallback_w = False
58 def load(self) -> MutableMapping[str, Any]:
59 with _std_cm(self.path, sys.stdin.buffer, "rb") as fp:
60 return load(fp, self.reader, self.allow_fallback_r)
62 def dump(self, __data: Mapping[str, Any]) -> None:
63 with _std_cm(self.out, sys.stdout.buffer, "wb") as fp:
64 dump(__data, fp, self.writer, self.allow_fallback_w)
67@app.callback()
68def callback(
69 ctx: Context,
70 path: str = Argument(...),
71 output: Optional[str] = Option(None, "-o", "--output"),
72 reader: Optional[Reader] = None,
73 writer: Optional[Writer] = None,
74):
75 ctx.obj = ModderCtx(path, output or path, reader, writer)
78@app.command(name="del")
79def delete(
80 ctx: Context,
81 selector: str = Argument(...),
82):
83 modder: ModderCtx = ctx.find_object(ModderCtx)
84 modder.set_default_rw(Reader.TOMLKIT, Writer.TOMLKIT)
85 data = modder.load()
86 if selector == ".":
87 raise Exit("Thank you for your patronage, but we won't delete the whole file.")
88 parts = selector.split(".")
89 idx = 0
90 cur = data
91 try:
92 for idx, part in enumerate(parts):
93 if idx + 1 == len(parts):
94 del cur[part]
95 break
96 cur = cur[part]
97 except (IndexError, KeyError):
98 up_to = ".".join(parts[: idx + 1])
99 msg = f"Invalid selector {selector!r}: could not find {up_to!r}"
100 raise Exit(msg) from None
101 modder.dump(data)