Source code for jgdv.structs.strang.formatter
1#!/usr/bin/env python3
2"""
3
4"""
5
6# Imports:
7from __future__ import annotations
8
9# ##-- stdlib imports
10import datetime
11import enum
12import functools as ftz
13import itertools as itz
14import logging as logmod
15import pathlib as pl
16import re
17import string
18import time
19import types
20import weakref
21from uuid import UUID, uuid1
22
23# ##-- end stdlib imports
24
25# ##-- 3rd party imports
26import sh
27
28# ##-- end 3rd party imports
29
30# ##-- 1st party imports
31from jgdv import Mixin
32from jgdv._abstract.protocols.general import SpecStruct_p
33
34# ##-- end 1st party imports
35
36from . import _interface as API # noqa: N812
37from . import errors
38
39# ##-- types
40# isort: off
41import abc
42import collections.abc
43from typing import TYPE_CHECKING, Generic, cast, assert_type, assert_never
44# Protocols:
45from typing import Protocol, runtime_checkable
46# Typing Decorators:
47from typing import no_type_check, final, override, overload
48
49if TYPE_CHECKING:
50 from jgdv import Maybe
51 from jgdv import Ident, FmtStr, Rx, RxStr, Func
52 from typing import Final
53 from typing import ClassVar, Any, LiteralString
54 from typing import Never, Self, Literal
55 from typing import TypeGuard
56 from collections.abc import Iterable, Iterator, Callable, Generator
57 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
58
59 from ._interface import Strang_p
60
61# isort: on
62# ##-- end types
63
64##-- logging
65logging = logmod.getLogger(__file__)
66##-- end logging
67
[docs]
68class StrangFormatter(string.Formatter):
69 """
70 An Expander/Formatter to extend string formatting with options useful for dkey's
71 and doot specs/state.
72
73 """
74
[docs]
75 def format(self, key:str, /, *args:Any, **kwargs:Any) -> str: # noqa: ANN401
76 """ format keys as strings """
77 match key:
78 case str():
79 fmt = key
80 case pl.Path():
81 raise NotImplementedError()
82 case _:
83 raise TypeError(errors.FormatterExpansionTypeFail, key)
84
85 result = self.vformat(fmt, args, kwargs)
86 return result
87
[docs]
88 def get_value(self, key:int|str, args:Sequence[Any], kwargs:Any) -> str: # noqa: ANN401
89 """ lowest level handling of keys being expanded """
90 # This handles when the key is something like '1968'
91 if isinstance(key, int) and 0 <= key <= len(args):
92 return args[key]
93
94 return kwargs.get(key, key)
95
[docs]
96 def convert_field(self, value:str, conversion:Maybe[str]) -> str:
97 # do any conversion on the resulting object
98 match conversion:
99 case None:
100 return value
101 case "s" | "p" | "R" | "c" | "t":
102 return str(value)
103 case "r":
104 return repr(value)
105 case "a":
106 return ascii(value)
107 case _:
108 raise ValueError(errors.FormatterConversionUnknownSpec.format(spec=conversion))
109
[docs]
110 def expanded_str(self, value:Strang_p, *, stop:Maybe[int]=None) -> str:
111 """ Create a str with generative marks replaced with generated values
112
113 eg: a.b.c.<gen-uuid> -> a.b.c.<UUID:......>
114 """
115 raise NotImplementedError()
116
[docs]
117 def format_subval(self, value:Strang_p, val:str, *, no_expansion:bool=False) -> str:
118 match val:
119 case str():
120 return val
121 case UUID() if no_expansion:
122 return "<uuid>"
123 case UUID():
124 return f"<uuid:{val}>"
125 case _:
126 raise TypeError(errors.FormatterUnkownBodyType, val)