the1conf 1.3.0__tar.gz → 1.3.1__tar.gz
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-1.3.0 → the1conf-1.3.1}/PKG-INFO +1 -1
- {the1conf-1.3.0 → the1conf-1.3.1}/pyproject.toml +1 -1
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/app_config.py +19 -7
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/click_option.py +25 -3
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/config_var.py +12 -13
- {the1conf-1.3.0 → the1conf-1.3.1}/LICENSE +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/README.md +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/__init__.py +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/app_config_meta.py +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/attr_dict.py +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/auto_prolog.py +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/flags.py +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/py.typed +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/solver.py +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/utils.py +0 -0
- {the1conf-1.3.0 → the1conf-1.3.1}/python/main/the1conf/var_substitution.py +0 -0
|
@@ -389,19 +389,31 @@ class AppConfig(AttrDict, AutoProlog, metaclass=AppConfigMeta):
|
|
|
389
389
|
self, vardef_to_serialize: Iterable[ConfigVarDef], for_file: bool = False
|
|
390
390
|
) -> dict[str, Any]:
|
|
391
391
|
"""
|
|
392
|
-
Serialize the given variable definitions to a dictionary
|
|
393
|
-
|
|
394
|
-
|
|
392
|
+
Serialize the given variable definitions to a dictionary **that have a value**.
|
|
393
|
+
|
|
394
|
+
for_file is used to specify if we serialize for storing in a file or for display
|
|
395
|
+
|
|
396
|
+
if for file is True we serialize only variables that have no_conffile_search set to False and used
|
|
397
|
+
the first key in file_key as the key in the dict, otherwise the key is the variable name. In this case we don't
|
|
398
|
+
serialize variables whose type_info is None and their real type is not string because we would not be able to
|
|
399
|
+
read them back from the file and get the same value.
|
|
400
|
+
|
|
401
|
+
We use str() to serialize configuration variables .
|
|
395
402
|
To detect list we need to look at the split_to_list attribute of the ConfigVarDef and call str() on
|
|
396
403
|
each element of the list, then join them with the separator used to create the list.
|
|
397
|
-
If for_file is True we serialize only variables that have no_conffile_search set to False and
|
|
398
|
-
used file_key as the key in the dict, otherwise the key is the variable name.
|
|
399
404
|
"""
|
|
400
405
|
# we are going to take advantage of the AttrDict to accept dotted keys in order to create nested dicts.
|
|
401
406
|
dumper = AttrDict()
|
|
402
407
|
for var in vardef_to_serialize:
|
|
403
|
-
if
|
|
404
|
-
|
|
408
|
+
if not self.has_value(var.name):
|
|
409
|
+
# we skip variables that don't have a value, surely their scope hasn't been resolved yet.
|
|
410
|
+
continue
|
|
411
|
+
stringifiable = True
|
|
412
|
+
if var._type_info is None and not isinstance(self[var.name], str):
|
|
413
|
+
# we don't know how to put this varialbe in a file so that we can read it afterward and get back the same value.
|
|
414
|
+
stringifiable = False
|
|
415
|
+
if for_file and var.file_key is not None and stringifiable:
|
|
416
|
+
key = var.file_key[0]
|
|
405
417
|
elif not for_file:
|
|
406
418
|
key = var.name
|
|
407
419
|
else:
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any, Callable
|
|
4
4
|
|
|
5
5
|
import click
|
|
6
|
+
from click.types import BoolParamType
|
|
6
7
|
|
|
7
8
|
from .app_config import ConfigVarDef
|
|
8
9
|
from .utils import Undefined, _undef
|
|
@@ -17,6 +18,15 @@ class StringOrUndefined(click.ParamType):
|
|
|
17
18
|
return click.STRING.convert(value, param, ctx)
|
|
18
19
|
|
|
19
20
|
|
|
21
|
+
class BoolOrUndefined(BoolParamType):
|
|
22
|
+
name = "boolean"
|
|
23
|
+
|
|
24
|
+
def convert(self, value: Any, param: Any, ctx: Any) -> Any:
|
|
25
|
+
if value is _undef:
|
|
26
|
+
return value
|
|
27
|
+
return super().convert(value, param, ctx)
|
|
28
|
+
|
|
29
|
+
|
|
20
30
|
def click_option(config_var: Any, **kwargs: Any) -> Callable[[Any], Any]:
|
|
21
31
|
"""Wrapper for click.option with the metadata from ConfigVarDef."""
|
|
22
32
|
if not isinstance(config_var, ConfigVarDef):
|
|
@@ -33,15 +43,24 @@ def click_option(config_var: Any, **kwargs: Any) -> Callable[[Any], Any]:
|
|
|
33
43
|
else:
|
|
34
44
|
keys = config_var.value_key
|
|
35
45
|
|
|
46
|
+
is_bool = config_var._type_info is bool
|
|
47
|
+
|
|
36
48
|
for key in keys:
|
|
37
49
|
if len(key) == 1:
|
|
38
50
|
param_decls.append(f"-{key}")
|
|
39
51
|
else:
|
|
40
|
-
|
|
52
|
+
param_name_str = key.replace("_", "-").lower()
|
|
53
|
+
if is_bool:
|
|
54
|
+
param_decls.append(f"--{param_name_str}/--no-{param_name_str}")
|
|
55
|
+
else:
|
|
56
|
+
param_decls.append(f"--{param_name_str}")
|
|
41
57
|
|
|
42
58
|
# Used as destination in the dict returned by click
|
|
43
59
|
param_name = keys[0]
|
|
44
60
|
|
|
61
|
+
if is_bool:
|
|
62
|
+
kwargs["is_flag"] = True
|
|
63
|
+
|
|
45
64
|
# 2. Documentation
|
|
46
65
|
if "help" not in kwargs and config_var.help:
|
|
47
66
|
kwargs["help"] = config_var.help
|
|
@@ -49,7 +68,10 @@ def click_option(config_var: Any, **kwargs: Any) -> Callable[[Any], Any]:
|
|
|
49
68
|
# 3. Strict constraint: Always strings
|
|
50
69
|
# We overwrite any passed type to ensure that resolve_vars receives a string.
|
|
51
70
|
# We use a custom type to handle the `_undef` default value without converting it to string.
|
|
52
|
-
|
|
71
|
+
if not is_bool:
|
|
72
|
+
kwargs["type"] = StringOrUndefined()
|
|
73
|
+
else:
|
|
74
|
+
kwargs["type"] = BoolOrUndefined()
|
|
53
75
|
|
|
54
76
|
# We set default to `_undef` to distinguish between "option not provided" (_undef)
|
|
55
77
|
# and "option provided with no value" (which shouldn't happen with string) or None.
|
|
@@ -69,4 +91,4 @@ def click_option(config_var: Any, **kwargs: Any) -> Callable[[Any], Any]:
|
|
|
69
91
|
# Note: We do NOT pass 'envvar' nor 'default'
|
|
70
92
|
|
|
71
93
|
# We force the destination name to match the key expected by the1conf
|
|
72
|
-
return click.option(*param_decls,
|
|
94
|
+
return click.option(*param_decls, **kwargs)
|
|
@@ -209,7 +209,7 @@ class ConfigVarDef(Generic[_T]):
|
|
|
209
209
|
_name: Optional[str] = None
|
|
210
210
|
_split_to_list: Optional[bool | str] = None
|
|
211
211
|
_transform: Optional[Union[Callable[[str, Any, Any], Any], str]] = None
|
|
212
|
-
_type_info: Any =
|
|
212
|
+
_type_info: Any = _undef
|
|
213
213
|
_value_key: Optional[Sequence[str]] = None
|
|
214
214
|
|
|
215
215
|
def __init__(
|
|
@@ -233,7 +233,7 @@ class ConfigVarDef(Generic[_T]):
|
|
|
233
233
|
no_value_search: Optional[bool] = None,
|
|
234
234
|
split_to_list: Optional[bool | str] = None,
|
|
235
235
|
transform: Optional[Union[Callable[[str, Any, Any], Any], str]] = None,
|
|
236
|
-
type_info: Any =
|
|
236
|
+
type_info: Any = _undef,
|
|
237
237
|
value_key: Optional[str | Sequence[str]] = None,
|
|
238
238
|
) -> None:
|
|
239
239
|
"""Initialize the configuration variable definition.
|
|
@@ -289,6 +289,7 @@ class ConfigVarDef(Generic[_T]):
|
|
|
289
289
|
no_conffile_search=no_conffile_search,
|
|
290
290
|
click_key_conversion=click_key_conversion,
|
|
291
291
|
allow_override=allow_override,
|
|
292
|
+
no_search=no_search,
|
|
292
293
|
)
|
|
293
294
|
|
|
294
295
|
def __set_name__(self, owner: type, name: str) -> None:
|
|
@@ -347,17 +348,15 @@ class ConfigVarDef(Generic[_T]):
|
|
|
347
348
|
"Please check that the type is imported and available."
|
|
348
349
|
)
|
|
349
350
|
|
|
350
|
-
type_info_directive
|
|
351
|
-
if self._type_info is not None:
|
|
352
|
-
type_info_directive = self._type_info
|
|
351
|
+
type_info_directive = self._type_info
|
|
353
352
|
|
|
354
|
-
if annotated_type is not None and type_info_directive
|
|
353
|
+
if annotated_type is not None and type_info_directive != _undef:
|
|
355
354
|
# both type hint and type_info directive are defined, use type_info directive
|
|
356
355
|
self._type_info = type_info_directive
|
|
357
356
|
elif annotated_type is not None:
|
|
358
357
|
# only type hint is defined, use it
|
|
359
358
|
self._type_info = annotated_type
|
|
360
|
-
elif type_info_directive
|
|
359
|
+
elif type_info_directive != _undef:
|
|
361
360
|
# only type_info directive is defined, use it
|
|
362
361
|
self._type_info = type_info_directive
|
|
363
362
|
else:
|
|
@@ -428,14 +427,14 @@ class ConfigVarDef(Generic[_T]):
|
|
|
428
427
|
if self.flags.no_search or self.flags.no_env_search:
|
|
429
428
|
return None
|
|
430
429
|
else:
|
|
431
|
-
return self._env_name or self.name
|
|
430
|
+
return self._env_name or [self.name]
|
|
432
431
|
|
|
433
432
|
@property
|
|
434
|
-
def file_key(self) -> Optional[
|
|
433
|
+
def file_key(self) -> Optional[Sequence[str]]:
|
|
435
434
|
if self.flags.no_search or self.flags.no_conffile_search:
|
|
436
435
|
return None
|
|
437
436
|
else:
|
|
438
|
-
return self._file_key or self.name
|
|
437
|
+
return self._file_key or [self.name]
|
|
439
438
|
|
|
440
439
|
@property
|
|
441
440
|
def help(self) -> str:
|
|
@@ -470,13 +469,13 @@ class ConfigVarDef(Generic[_T]):
|
|
|
470
469
|
return self._transform
|
|
471
470
|
|
|
472
471
|
@property
|
|
473
|
-
def value_key(self) -> Optional[
|
|
472
|
+
def value_key(self) -> Optional[Sequence[str]]:
|
|
474
473
|
"""Note: we can't compute the final value here because it depends on the click_key_conversion
|
|
475
474
|
flag that can be set globally or in resolve_vars."""
|
|
476
475
|
if self.flags.no_search or self.flags.no_value_search:
|
|
477
476
|
return None
|
|
478
477
|
else:
|
|
479
|
-
return self._value_key or self.name
|
|
478
|
+
return self._value_key or [self.name]
|
|
480
479
|
|
|
481
480
|
|
|
482
481
|
def configvar(
|
|
@@ -499,7 +498,7 @@ def configvar(
|
|
|
499
498
|
no_value_search: Optional[bool] = None,
|
|
500
499
|
split_to_list: Optional[bool | str] = None,
|
|
501
500
|
transform: Optional[Union[Callable[[str, Any, Any], Any], str]] = None,
|
|
502
|
-
type_info: Any =
|
|
501
|
+
type_info: Any = _undef,
|
|
503
502
|
value_key: Optional[str | Sequence[str]] = None,
|
|
504
503
|
) -> Any:
|
|
505
504
|
"""Create a declarative configuration variable definition.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|