1#!/usr/bin/env python3
2"""
3
4"""
5
6# Imports:
7from __future__ import annotations
8
9# ##-- stdlib imports
10import collections
11import contextlib
12import datetime
13import enum
14import faulthandler
15import functools as ftz
16import hashlib
17import itertools as itz
18import logging as logmod
19import pathlib as pl
20import re
21import time
22import types
23import weakref
24from copy import deepcopy
25from dataclasses import InitVar, dataclass, field
26from time import sleep
27from uuid import UUID, uuid1
28from weakref import ref
29
30# ##-- end stdlib imports
31
32# ##-- 1st party imports
33from jgdv.structs.chainguard.errors import GuardedAccessError
34
35# ##-- end 1st party imports
36
37# ##-- types
38# isort: off
39import abc
40import collections.abc
41from typing import TYPE_CHECKING, cast, assert_type, assert_never
42from typing import Generic, NewType
43# Protocols:
44from typing import Protocol, runtime_checkable
45# Typing Decorators:
46from typing import no_type_check, final, override, overload
47
48if TYPE_CHECKING:
49 from jgdv import Maybe
50 from typing import Final
51 from typing import ClassVar, Any, LiteralString
52 from typing import Never, Self, Literal
53 from typing import TypeGuard
54 from collections.abc import Iterable, Iterator, Callable, Generator
55 from collections.abc import Sequence, Mapping, MutableMapping, Hashable
56
57 from .._interface import ChainGuard_i, TomlTypes
58 from .._base import GuardBase
59# isort: on
60# ##-- end types
61
62##-- logging
63logging = logmod.getLogger(__name__)
64##-- end logging
65
66super_get = object.__getattribute__
67super_set = object.__setattr__
68USCORE : Final[str] = "_"
69DASH : Final[str] = "-"
70MUTABLE : Final[str] = "__mutable"
71##--|
72
[docs]
73class TomlAccess_m:
74 """ Mixing for dynamic attribute access """
75
76 @override
77 def __setattr__(self:ChainGuard_i, attr:str, value:Any) -> None:
78 if not getattr(self, MUTABLE):
79 raise TypeError()
80 super_set(self, attr, value)
81
82 def __getattr__(self:ChainGuard_i, attr:str) -> Any: # noqa: ANN401
83 index : list[str]
84 index_s : str
85 table : dict = self._table() # type: ignore[operator,assignment]
86
87 if attr not in table and attr.replace(USCORE, DASH) not in table:
88 index = [*self._index(), attr] # type: ignore[operator,misc]
89 index_s = ".".join(index)
90 available = " ".join(self.keys())
91 msg = f"{index_s} not found, available: [{available}]"
92 raise GuardedAccessError(msg)
93
94 match table.get(attr, None) or table.get(attr.replace(USCORE, DASH), None):
95 case dict() as result:
96 return type(self)(result, index=[*self._index(), attr])
97 case list() as result if all(isinstance(x, dict) for x in result):
98 index = self._index()
99 return [type(self)(x, index=index[:]) for x in result if isinstance(x, dict)]
100 case _ as result:
101 return result
102
103 def __getitem__(self:ChainGuard_i, keys:str|list[str]|tuple[str]) -> Any: # noqa: ANN401
104 curr : ChainGuard_i|TomlTypes = self
105 match keys:
106 case tuple():
107 for key in keys:
108 curr = getattr(curr, key)
109 case str():
110 curr = getattr(self, keys)
111 case _:
112 pass
113
114 return curr
115
[docs]
116 def get(self:ChainGuard_i, key:str, default:Maybe=None) -> Maybe:
117 if key in self:
118 return self[key]
119
120 return default