appsettings2 2.0.7__tar.gz → 2.0.10__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.
- {appsettings2-2.0.7/src/appsettings2.egg-info → appsettings2-2.0.10}/PKG-INFO +2 -2
- {appsettings2-2.0.7 → appsettings2-2.0.10}/pyproject.toml +2 -2
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/Configuration.py +133 -3
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/ConfigurationBuilder.py +3 -2
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/__init__.py +2 -2
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/helpers.py +13 -2
- appsettings2-2.0.10/src/appsettings2/providers/EnvironmentConfigurationProvider.py +43 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10/src/appsettings2.egg-info}/PKG-INFO +2 -2
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2.egg-info/requires.txt +1 -1
- appsettings2-2.0.7/src/appsettings2/providers/EnvironmentConfigurationProvider.py +0 -14
- {appsettings2-2.0.7 → appsettings2-2.0.10}/LICENSE +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/README.md +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/setup.cfg +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/ConfigurationException.py +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/CommandLineConfigurationProvider.py +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/ConfigurationProvider.py +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/JsonConfigurationProvider.py +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/TomlConfigurationProvider.py +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/YamlConfigurationProvider.py +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/__init__.py +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/py.typed +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2.egg-info/SOURCES.txt +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2.egg-info/dependency_links.txt +0 -0
- {appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: appsettings2
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.10
|
|
4
4
|
Summary: Unifies configuration sources into a Configuration object that can be bound to complex types, or accessed directly for configuration data.
|
|
5
5
|
Author-email: Shaun Wilson <mrshaunwilson@msn.com>
|
|
6
6
|
License: MIT License
|
|
@@ -42,7 +42,7 @@ Requires-Dist: flake8; extra == "dev"
|
|
|
42
42
|
Requires-Dist: flake8-pyproject; extra == "dev"
|
|
43
43
|
Requires-Dist: mypy; extra == "dev"
|
|
44
44
|
Requires-Dist: pep8-naming; extra == "dev"
|
|
45
|
-
Requires-Dist: punit>=1.
|
|
45
|
+
Requires-Dist: punit>=1.10.8; extra == "dev"
|
|
46
46
|
Requires-Dist: twine; extra == "dev"
|
|
47
47
|
Requires-Dist: types-PyYAML; extra == "dev"
|
|
48
48
|
Dynamic: license-file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "appsettings2"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.10"
|
|
4
4
|
description = "Unifies configuration sources into a Configuration object that can be bound to complex types, or accessed directly for configuration data."
|
|
5
5
|
keywords = ["appsettings", "configuration"]
|
|
6
6
|
authors = [
|
|
@@ -25,7 +25,7 @@ dev = [
|
|
|
25
25
|
"flake8-pyproject",
|
|
26
26
|
"mypy",
|
|
27
27
|
"pep8-naming",
|
|
28
|
-
"punit (>=1.
|
|
28
|
+
"punit (>=1.10.8)",
|
|
29
29
|
"twine",
|
|
30
30
|
"types-PyYAML"
|
|
31
31
|
]
|
|
@@ -86,6 +86,8 @@ class Configuration:
|
|
|
86
86
|
def __deunionize(self, t: type) -> type:
|
|
87
87
|
if get_origin(t) is Union:
|
|
88
88
|
t = [e for e in get_args(t) if e is not NoneType][0]
|
|
89
|
+
elif get_origin(t) is types.UnionType:
|
|
90
|
+
t = [e for e in get_args(t) if e is not NoneType][0]
|
|
89
91
|
return t
|
|
90
92
|
|
|
91
93
|
def __recursive_bind(self, target: object, source: Configuration | dict[str, Any]) -> Any:
|
|
@@ -97,6 +99,14 @@ class Configuration:
|
|
|
97
99
|
)
|
|
98
100
|
else:
|
|
99
101
|
target_type_hints = get_type_hints(target)
|
|
102
|
+
|
|
103
|
+
# build scrubbed/normalized key lookup (for matching)
|
|
104
|
+
norm_source: bool | None = None
|
|
105
|
+
key_scrub_re_cfg: re.Pattern[str] | None = None
|
|
106
|
+
if isinstance(source, Configuration):
|
|
107
|
+
norm_source = source._Configuration__normalize
|
|
108
|
+
key_scrub_re_cfg = source._Configuration__key_scrub_re
|
|
109
|
+
|
|
100
110
|
names = set(dir(target) | target_type_hints.keys())
|
|
101
111
|
for aname in names:
|
|
102
112
|
if aname.startswith('_'):
|
|
@@ -107,6 +117,20 @@ class Configuration:
|
|
|
107
117
|
continue
|
|
108
118
|
ahint = target_type_hints.get(aname)
|
|
109
119
|
rval = source.get(aname)
|
|
120
|
+
# scrub/normalize-aware; look up using transformed keys
|
|
121
|
+
if rval is None and norm_source is not None:
|
|
122
|
+
raw_src_key = aname.replace(':', '__')
|
|
123
|
+
for cfg_key in source.keys(): # type: ignore[union-attr]
|
|
124
|
+
raw = cfg_key.replace('.', '_')
|
|
125
|
+
candidate = raw.upper() if norm_source else raw
|
|
126
|
+
scrubbed = candidate if key_scrub_re_cfg is None \
|
|
127
|
+
else key_scrub_re_cfg.sub(
|
|
128
|
+
lambda m: '_' if unicodedata.category(m[0]) not in ('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl', 'Mn', 'Mc', 'Nd', 'Pc') else m[0],
|
|
129
|
+
candidate)
|
|
130
|
+
compare = scrubbed.replace('-', '_')
|
|
131
|
+
if compare == raw_src_key or compare.upper() == raw_src_key.upper():
|
|
132
|
+
rval = source.get(cfg_key) # type: ignore[union-attr]
|
|
133
|
+
break
|
|
110
134
|
if ahint is None:
|
|
111
135
|
# attr has no type hints, attempt to treat as a property
|
|
112
136
|
prop = getattr(type(target), aname)
|
|
@@ -156,7 +180,37 @@ class Configuration:
|
|
|
156
180
|
lval[dk] = self.__recursive_bind_type(value_type, dv)
|
|
157
181
|
setattr(target, aname, lval)
|
|
158
182
|
continue
|
|
183
|
+
# Union/Optional types when rval missing but there's source data?
|
|
184
|
+
if get_origin(ahint) is Union or get_origin(ahint) is types.UnionType \
|
|
185
|
+
or (isinstance(ahint, type) and hasattr(ahint, '__origin__')):
|
|
186
|
+
unwrapped = self.__deunionize(ahint)
|
|
187
|
+
if unwrapped not in (str, int, float, bool, NoneType):
|
|
188
|
+
# source key overlaps with attr names?
|
|
189
|
+
src_key_overlap = False
|
|
190
|
+
for cfg_key in source.keys(): # type: ignore[union-attr]
|
|
191
|
+
raw_src_key = cfg_key.replace('.', '_')
|
|
192
|
+
candidate = raw_src_key.upper() if norm_source else raw_src_key
|
|
193
|
+
scrubbed = candidate if key_scrub_re_cfg is None \
|
|
194
|
+
else key_scrub_re_cfg.sub(
|
|
195
|
+
lambda m: '_' if unicodedata.category(m[0]) not in ('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl', 'Mn', 'Mc', 'Nd', 'Pc') else m[0],
|
|
196
|
+
candidate)
|
|
197
|
+
compare = scrubbed.replace('-', '_').replace('_', '')
|
|
198
|
+
for other_attr in names:
|
|
199
|
+
if not other_attr.startswith('_'):
|
|
200
|
+
okey = other_attr.replace(':', '__')
|
|
201
|
+
if compare == okey or compare.upper() == okey.upper():
|
|
202
|
+
src_key_overlap = True
|
|
203
|
+
break
|
|
204
|
+
if src_key_overlap:
|
|
205
|
+
break
|
|
206
|
+
if isinstance(source, Configuration) and source.keys() and not src_key_overlap: # type: ignore[union-attr]
|
|
207
|
+
lval = unwrapped()
|
|
208
|
+
setattr(target, aname, lval)
|
|
209
|
+
self.__recursive_bind(lval, source)
|
|
210
|
+
continue
|
|
159
211
|
setattr(target, aname, None)
|
|
212
|
+
elif ahint is bool:
|
|
213
|
+
setattr(target, aname, bool(rval))
|
|
160
214
|
elif ahint is float:
|
|
161
215
|
setattr(target, aname, float(rval))
|
|
162
216
|
elif ahint is int:
|
|
@@ -174,6 +228,28 @@ class Configuration:
|
|
|
174
228
|
for dk, dv in rval.items():
|
|
175
229
|
lval[dk] = self.__recursive_bind_type(value_type, dv)
|
|
176
230
|
setattr(target, aname, lval)
|
|
231
|
+
elif (
|
|
232
|
+
get_origin(ahint) is Union
|
|
233
|
+
or get_origin(ahint) is types.UnionType
|
|
234
|
+
or (isinstance(ahint, type) and hasattr(ahint, '__origin__'))
|
|
235
|
+
):
|
|
236
|
+
# Handle Optional/Union types — unwrap before instantiating
|
|
237
|
+
unwrapped = self.__deunionize(ahint)
|
|
238
|
+
if get_origin(unwrapped) is dict:
|
|
239
|
+
value_type = get_args(unwrapped)[1]
|
|
240
|
+
if value_type in (str, int, float, bool, type(None)):
|
|
241
|
+
lval = rval.to_dict()
|
|
242
|
+
setattr(target, aname, lval)
|
|
243
|
+
else:
|
|
244
|
+
lval = dict[str, Any]()
|
|
245
|
+
for dk, dv in rval.items():
|
|
246
|
+
lval[dk] = self.__recursive_bind_type(value_type, dv)
|
|
247
|
+
setattr(target, aname, lval)
|
|
248
|
+
else:
|
|
249
|
+
if lval is None:
|
|
250
|
+
lval = unwrapped()
|
|
251
|
+
setattr(target, aname, lval)
|
|
252
|
+
self.__recursive_bind(lval, rval)
|
|
177
253
|
else:
|
|
178
254
|
if lval is None:
|
|
179
255
|
ahint = self.__deunionize(ahint)
|
|
@@ -262,12 +338,66 @@ class Configuration:
|
|
|
262
338
|
source = self.get(key)
|
|
263
339
|
if source is not None:
|
|
264
340
|
source_type = type(source)
|
|
265
|
-
if source_type
|
|
341
|
+
if source_type in (Configuration, dict):
|
|
266
342
|
return self.__recursive_bind(target, source)
|
|
343
|
+
elif source_type is list:
|
|
344
|
+
return self.__bind_list_source(target, key, source)
|
|
267
345
|
else:
|
|
268
|
-
|
|
269
|
-
|
|
346
|
+
# Scalar source: convert to matching typed attribute(s) on target
|
|
347
|
+
return self.__bind_scalar_to_target(target, key, source)
|
|
348
|
+
else:
|
|
349
|
+
return target
|
|
350
|
+
|
|
351
|
+
def __bind_list_source(self, target: object, key: str, source: list[Any]) -> Any:
|
|
352
|
+
"""Bind a Configuration- or dict-wrapped list source to *target*."""
|
|
353
|
+
if not hasattr(target, '__class__'):
|
|
270
354
|
return target
|
|
355
|
+
hints = get_type_hints(type(target))
|
|
356
|
+
raw_key = self.__scrub_key(key.replace(':', '__'))
|
|
357
|
+
for attr_name, ahint in hints.items():
|
|
358
|
+
if raw_key == self.__scrub_key(attr_name) or key.upper() == attr_name.upper():
|
|
359
|
+
element_type = ahint.__args__[0] if get_origin(ahint) is list else None
|
|
360
|
+
if element_type is not None and source:
|
|
361
|
+
lval = []
|
|
362
|
+
for e in source:
|
|
363
|
+
lval.append(self.__recursive_bind_type(element_type, e))
|
|
364
|
+
setattr(target, attr_name, lval)
|
|
365
|
+
return target
|
|
366
|
+
# taking object/untyped attr from normalized
|
|
367
|
+
for attr_name, ahint in hints.items():
|
|
368
|
+
if raw_key == self.__scrub_key(attr_name) or key.upper() == attr_name.upper():
|
|
369
|
+
if ahint is object:
|
|
370
|
+
setattr(target, attr_name, source)
|
|
371
|
+
return target
|
|
372
|
+
return target
|
|
373
|
+
|
|
374
|
+
def __bind_scalar_to_target(self, target: object, key: str, value: Any) -> Any:
|
|
375
|
+
"""Bind a scalar config value to the typed attribute on *target* matching the key."""
|
|
376
|
+
if not hasattr(target, '__class__'):
|
|
377
|
+
return target
|
|
378
|
+
hints = get_type_hints(type(target))
|
|
379
|
+
# Normalize / scrub exactly as :py:meth:`set` does so we can match back.
|
|
380
|
+
raw_key = self.__scrub_key(key.replace(':', '__'))
|
|
381
|
+
for attr_name, ahint in hints.items():
|
|
382
|
+
if raw_key == self.__scrub_key(attr_name):
|
|
383
|
+
converted = self.__convert_to_type(value, ahint)
|
|
384
|
+
setattr(target, attr_name, converted)
|
|
385
|
+
return target
|
|
386
|
+
|
|
387
|
+
@staticmethod
|
|
388
|
+
def __convert_to_type(value: Any, target_type: type) -> Any:
|
|
389
|
+
"""Convert *value* to *target_type* using primitive coercion rules."""
|
|
390
|
+
if target_type is float:
|
|
391
|
+
return float(value)
|
|
392
|
+
elif target_type is int:
|
|
393
|
+
return int(value)
|
|
394
|
+
elif target_type is str:
|
|
395
|
+
return str(value)
|
|
396
|
+
elif target_type is bool:
|
|
397
|
+
return bool(value)
|
|
398
|
+
else:
|
|
399
|
+
# Complex type or Any — nothing we can do for a scalar source
|
|
400
|
+
return value
|
|
271
401
|
|
|
272
402
|
def clear(self) -> None:
|
|
273
403
|
"""Clear all configuration data."""
|
|
@@ -65,13 +65,14 @@ class ConfigurationBuilder:
|
|
|
65
65
|
addCommandLine = add_command_line
|
|
66
66
|
"""⚠️ DEPRECATED: use ``add_command_line(...)`` instead."""
|
|
67
67
|
|
|
68
|
-
def add_environment(self) -> 'ConfigurationBuilder':
|
|
68
|
+
def add_environment(self, required_prefix: str | None = None) -> 'ConfigurationBuilder':
|
|
69
69
|
"""
|
|
70
70
|
Add a :py:class:`~appsettings2.providers.EnvironmentConfigurationProvider`.
|
|
71
71
|
|
|
72
|
+
:param required_prefix: Optional prefix used to filter which environment variables are included. Only variables whose names start with this prefix (followed by ``_`` or ``__``) will be loaded. When ``None``, all environment variables are included. Defaults to None.
|
|
72
73
|
:return: Returns :py:class:`~appsettings2.ConfigurationBuilder` for method chaining.
|
|
73
74
|
"""
|
|
74
|
-
return self.add_provider(EnvironmentConfigurationProvider())
|
|
75
|
+
return self.add_provider(EnvironmentConfigurationProvider(required_prefix=required_prefix))
|
|
75
76
|
|
|
76
77
|
addEnvironment = add_environment
|
|
77
78
|
"""⚠️ DEPRECATED: use ``add_environment(...)`` instead."""
|
|
@@ -8,7 +8,17 @@ from .Configuration import Configuration
|
|
|
8
8
|
from .ConfigurationBuilder import ConfigurationBuilder
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def get_configuration(
|
|
11
|
+
def get_configuration(
|
|
12
|
+
basename: str | pathlib.PosixPath | pathlib.Path = 'appsettings',
|
|
13
|
+
*,
|
|
14
|
+
json: bool = True,
|
|
15
|
+
toml: bool = True,
|
|
16
|
+
yaml: bool = True,
|
|
17
|
+
cli: bool = True,
|
|
18
|
+
environment: bool = True,
|
|
19
|
+
variations: Optional[list[str | None]] = ['', 'prod', 'production', 'stage', 'staging', 'qa', 'dev', 'development', 'local'],
|
|
20
|
+
env_prefix: str | None = None
|
|
21
|
+
) -> Configuration:
|
|
12
22
|
"""
|
|
13
23
|
Get a ``Configuration`` instance by loading from a set of well-known providers and their variations.
|
|
14
24
|
|
|
@@ -19,6 +29,7 @@ def get_configuration(basename: str | pathlib.PosixPath | pathlib.Path = 'appset
|
|
|
19
29
|
:param cli: ``True`` to load configuration from Command-Line, defaults to True
|
|
20
30
|
:param environment: ``True`` to load configuration from process Environment, defaults to True
|
|
21
31
|
:param variations: A set of variations to apply to use with file-based Configuration Providers, defaults to ['', 'prod', 'production', 'stage', 'staging', 'qa', 'dev', 'development', 'local']
|
|
32
|
+
:param env_prefix: (OPTIONAL) When specified, only env vars having the specified prefix are bound as configuration settings, the prefix is stripped from the resulting setting name.
|
|
22
33
|
:return: An ``appsettings2.Configuration`` instance.
|
|
23
34
|
"""
|
|
24
35
|
if type(basename) is pathlib.Path or type(basename) is pathlib.PosixPath:
|
|
@@ -36,7 +47,7 @@ def get_configuration(basename: str | pathlib.PosixPath | pathlib.Path = 'appset
|
|
|
36
47
|
if cli:
|
|
37
48
|
builder.add_command_line()
|
|
38
49
|
if environment:
|
|
39
|
-
builder.add_environment()
|
|
50
|
+
builder.add_environment(required_prefix=env_prefix)
|
|
40
51
|
return builder.build()
|
|
41
52
|
|
|
42
53
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: © 2025 Shaun Wilson
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ..Configuration import Configuration
|
|
8
|
+
from .ConfigurationProvider import ConfigurationProvider
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EnvironmentConfigurationProvider(ConfigurationProvider):
|
|
12
|
+
"""A ``ConfigurationProvider`` that populates configuration data from Environment variables."""
|
|
13
|
+
|
|
14
|
+
__required_prefix: str | None
|
|
15
|
+
|
|
16
|
+
def __init__(self, /, required_prefix: str | None = None, **kwargs: Any) -> None:
|
|
17
|
+
self.__required_prefix = required_prefix.upper() if required_prefix is not None else None
|
|
18
|
+
|
|
19
|
+
def populate_configuration(self, configuration: Configuration) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Populate the provided :py:class:`~appsettings2.Configuration` from environment variables.
|
|
22
|
+
|
|
23
|
+
Usage::
|
|
24
|
+
|
|
25
|
+
# All env vars become config keys:
|
|
26
|
+
provider = EnvironmentConfigurationProvider()
|
|
27
|
+
provider.populate_configuration(config)
|
|
28
|
+
|
|
29
|
+
# Only keys with a specific prefix, stripped in output:
|
|
30
|
+
provider = EnvironmentConfigurationProvider(required_prefix="APP_")
|
|
31
|
+
# APP_DATABASE_URL=postgres://... → config["DATABASE_URL"] == "postgres://..."
|
|
32
|
+
provider.populate_configuration(config)
|
|
33
|
+
|
|
34
|
+
When ``required_prefix`` is set, only keys starting with that prefix are included,
|
|
35
|
+
and the prefix is stripped from each key in the output configuration.
|
|
36
|
+
"""
|
|
37
|
+
for k in os.environ:
|
|
38
|
+
key = (
|
|
39
|
+
k
|
|
40
|
+
if self.__required_prefix is None
|
|
41
|
+
else k[len(self.__required_prefix):]
|
|
42
|
+
)
|
|
43
|
+
configuration.set(key, os.environ[k])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: appsettings2
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.10
|
|
4
4
|
Summary: Unifies configuration sources into a Configuration object that can be bound to complex types, or accessed directly for configuration data.
|
|
5
5
|
Author-email: Shaun Wilson <mrshaunwilson@msn.com>
|
|
6
6
|
License: MIT License
|
|
@@ -42,7 +42,7 @@ Requires-Dist: flake8; extra == "dev"
|
|
|
42
42
|
Requires-Dist: flake8-pyproject; extra == "dev"
|
|
43
43
|
Requires-Dist: mypy; extra == "dev"
|
|
44
44
|
Requires-Dist: pep8-naming; extra == "dev"
|
|
45
|
-
Requires-Dist: punit>=1.
|
|
45
|
+
Requires-Dist: punit>=1.10.8; extra == "dev"
|
|
46
46
|
Requires-Dist: twine; extra == "dev"
|
|
47
47
|
Requires-Dist: types-PyYAML; extra == "dev"
|
|
48
48
|
Dynamic: license-file
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: © 2025 Shaun Wilson
|
|
2
|
-
# SPDX-License-Identifier: MIT
|
|
3
|
-
|
|
4
|
-
from .ConfigurationProvider import ConfigurationProvider
|
|
5
|
-
from ..Configuration import Configuration
|
|
6
|
-
import os
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class EnvironmentConfigurationProvider(ConfigurationProvider):
|
|
10
|
-
"""A ``ConfigurationProvider`` that populates configuration data from Environment variables."""
|
|
11
|
-
|
|
12
|
-
def populate_configuration(self, configuration: Configuration) -> None: # noqa: D102
|
|
13
|
-
for k in os.environ:
|
|
14
|
-
configuration.set(k, os.environ[k])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/ConfigurationProvider.py
RENAMED
|
File without changes
|
{appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/JsonConfigurationProvider.py
RENAMED
|
File without changes
|
{appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/TomlConfigurationProvider.py
RENAMED
|
File without changes
|
{appsettings2-2.0.7 → appsettings2-2.0.10}/src/appsettings2/providers/YamlConfigurationProvider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|