the1conf 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
the1conf/attr_dict.py ADDED
@@ -0,0 +1,155 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping, MutableMapping,Sequence, Iterator
4
+ from typing import (Any, Callable, Optional,
5
+ Protocol, Union, get_origin)
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+
10
+ def is_sequence(obj: Any) -> bool:
11
+ """ test if obj is a sequence (list, tuple, etc...) but not a string in thte most general way"""
12
+ try:
13
+ len(obj)
14
+ obj[0:0]
15
+ return not isinstance(obj, str)
16
+ except KeyError:
17
+ return False
18
+ except TypeError:
19
+ return False # TypeError: object is not iterable
20
+
21
+ class AttrDict(MutableMapping):
22
+ """
23
+ class which properties can be accessed like a dict or like a propertie (.x) and vis/versa:
24
+ if used like a Dict to set a value , if the key contains dots (.) it creates a hierarchy of AttrDict object.
25
+
26
+ Takes advantage of the internal __dict__ attribute of a class instance where are stored all the instance attributes.
27
+ The example bellow show that we can set and read attribute with the dot notation but also through the __dict__ attribute:
28
+
29
+ class tt:
30
+ def __init__(self):
31
+ self.a =2
32
+
33
+ vt = tt()
34
+ print(vt.__dict__) # {'a': 2}
35
+ vt.b = 3
36
+ print(vt.__dict__) # {'a': 2, 'b': 3}
37
+ vt.__dict__["c"] = 4
38
+ print(vt.__dict__) # {'a': 2, 'b': 3, 'c': 4}
39
+
40
+
41
+ class Test(AttrDict):
42
+ def __init__(self):
43
+ self.var1 = "var1"
44
+ self.__dict__["vardict"] = "vardict"
45
+ t = Test()
46
+ print (f"t['vardict'] = {t['vardict']}") # t['vardict'] = vardict
47
+ print (f"t.vardict = {t.vardict}") # t.vardict = vardict
48
+ print (f"t['var1'] = {t['var1']}") # t['var1'] = var1
49
+ print (f"t.var1 = {t.var1}") # t.var1 = var1
50
+
51
+ t.var2 = "var2"
52
+ print (f"t['var2'] = {t['var2']}") # t['var2'] = var2
53
+ print (f"t.var2 = {t.var2}") # t.var2 = var2
54
+
55
+ t["var3"] = "var3"
56
+ print (f"t['var3'] = {t['var3']}") # t['var3'] = var3
57
+ print (f"t.var3 = {t.var3}") # t.var3 = var3
58
+
59
+ t["a1.a2"] = "complexval"
60
+ print (f"t['a1'] = {t['a1']}") # t['a1'] = {'a2': 'complexval'}
61
+ print (f"t.a1 = {t.a1}") # t.a1 = {'a2': 'complexval'}
62
+ """
63
+
64
+ def __init__(self, init: Optional[Mapping[Any, Any]] = None) -> None:
65
+ if init is not None:
66
+ self.__dict__.update(init)
67
+
68
+ def __contains__(self, key: Any) -> bool:
69
+ try:
70
+ eval(f"self['{key}']")
71
+ except Exception:
72
+ return False
73
+ return True
74
+
75
+ def __getitem__(self, key: Any) -> Any:
76
+ """
77
+ Called to implement evaluation of self[key]
78
+ attributes with dots in their name are read in sub AttrDict Objects.
79
+ """
80
+ if isinstance(key, slice):
81
+ raise KeyError("slices are not supported")
82
+ parts = key.split(".")
83
+ curpart = parts[0]
84
+
85
+ if len(curpart.strip()) == 0:
86
+ raise AttributeError(f"bad attribute name: {key}")
87
+ elif len(parts) > 1:
88
+ if curpart in self.__dict__:
89
+ sub_attr = self.__dict__[curpart]
90
+ else:
91
+ raise AttributeError(f"key {curpart} not set")
92
+ return sub_attr[".".join(parts[1:])]
93
+ else:
94
+ return self.__dict__[curpart]
95
+
96
+ def __setitem__(self, key: Any, value: Any) -> None:
97
+ """
98
+ Called to implement assignment to self[key].
99
+ attributes with dots in their name are put in sub AttrDict Objects.
100
+ """
101
+ if isinstance(key, slice):
102
+ raise KeyError("slices are not supported")
103
+ parts = key.split(".")
104
+ curpart = parts[0]
105
+
106
+ if len(curpart.strip()) == 0:
107
+ raise AttributeError(f"bad attribute name: {key}")
108
+ elif len(parts) > 1:
109
+ if curpart in self.__dict__:
110
+ sub_attr = self.__dict__[curpart]
111
+ else:
112
+ sub_attr = AttrDict()
113
+ self.__dict__[curpart] = sub_attr
114
+ sub_attr[".".join(parts[1:])] = value
115
+ else:
116
+ self.__dict__[curpart] = value
117
+
118
+ def __delitem__(self, key: Any) -> None:
119
+ """Called to implement deletion of self[key]."""
120
+ del self.__dict__[key]
121
+
122
+ def __len__(self) -> int:
123
+ """Called to implement the built-in function len()"""
124
+ return len(self.__dict__)
125
+
126
+ def __iter__(self) -> Iterator:
127
+ """This method is called when an iterator is required for a container."""
128
+ return self.__dict__.__iter__()
129
+
130
+ def update( # type: ignore
131
+ self, other: Mapping[Any, Any], override: bool = False
132
+ ) -> None:
133
+ if override:
134
+ res = self.__dict__ | other # type: ignore
135
+ else:
136
+ res = other | self.__dict__ # type: ignore
137
+ self.__dict__ = res
138
+
139
+ def _repr_with_ident(self, indent: int) -> list[str]:
140
+ res = []
141
+ indent_str = "\t" * indent
142
+ for n, v in self.__dict__.items():
143
+ if issubclass(self.__class__, type(v)):
144
+ res.append(f"{indent_str}{n} :")
145
+ res.extend(v._repr_with_ident(indent + 1))
146
+ else:
147
+ res.append("{}{} : {}".format(indent_str, n, v))
148
+ return res
149
+
150
+ def __repr__(self) -> str:
151
+ res = self._repr_with_ident(0)
152
+ return "\n".join(res)
153
+
154
+ def clone(self) -> AttrDict:
155
+ return AttrDict(self.__dict__)
@@ -0,0 +1,35 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Callable
3
+
4
+ import click
5
+
6
+ from .app_config import ConfigVarDef, Undefined
7
+
8
+ def click_option(config_var: Any, **kwargs: Any) -> Callable[[Any], Any]:
9
+ """Wrappe click.option avec les métadonnées de ConfigVarDef."""
10
+ if not isinstance(config_var, ConfigVarDef):
11
+ raise TypeError(f"click_option expects a ConfigVarDef, got {type(config_var)}")
12
+
13
+
14
+ # 1. Nom du flag (ex: my_var -> --my-var)
15
+ param_name = config_var.Name
16
+ flag_name = f"--{param_name.replace('_', '-').lower()}"
17
+
18
+ # 2. Documentation
19
+ if "help" not in kwargs and config_var.Help:
20
+ kwargs["help"] = config_var.Help
21
+
22
+ # 3. Contrainte stricte : Toujours des strings
23
+ # On écrase tout type passé pour garantir que resolve_vars reçoive du string.
24
+ kwargs["type"] = click.STRING
25
+
26
+ # 4. Affichage du défaut sans l'appliquer
27
+ if "show_default" not in kwargs and config_var.Default is not Undefined and not callable(config_var.Default):
28
+ # On doit convertir en string sinon click interprete les bool/int comme des flags (True/False)
29
+ # qui lui disent "affiche le default" (qui est None ici), du coup il n'affiche rien.
30
+ kwargs["show_default"] = str(config_var.Default)
31
+
32
+ # Note: On ne passe PAS 'envvar' ni 'default'
33
+
34
+ # On force le nom de destination pour qu'il matche la clé attendue par the1conf
35
+ return click.option(flag_name, param_name, **kwargs)