Skip to content

Commit ffbd890

Browse files
authored
Minor improvements to dependency reporting (#88)
* More verbose dependency reporting for optional classes * Minor improvements to README to clarify features/dependencies
1 parent 5ee55a6 commit ffbd890

File tree

2 files changed

+138
-111
lines changed

2 files changed

+138
-111
lines changed

README.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,27 @@
99
[![codecov](https://codecov.io/gh/tr11/python-configuration/branch/main/graph/badge.svg?token=5zRYlGnDs7)](https://codecov.io/gh/tr11/python-configuration)
1010
[![Documentation Status](https://readthedocs.org/projects/python-configuration/badge/?version=latest)](https://python-configuration.readthedocs.io/en/latest/?badge=latest)
1111

12-
This library is intended as a helper mechanism to load configuration files hierarchically. Supported format types are:
12+
This library is intended as a helper mechanism to load configuration files hierarchically.
1313

14-
* Python files
15-
* Dictionaries
16-
* Environment variables
17-
* Filesystem paths
18-
* JSON files
19-
* INI files
20-
* dotenv type files
14+
## Supported Formats
2115

22-
and optionally
16+
The `python-configuration` library supports the following configuration formats and sources:
17+
18+
- Python files: ...
19+
- Dictionaries: ...
20+
- Environment variables: ...
21+
- Filesystem paths: ...
22+
- JSON files: ...
23+
- INI files: ...
24+
- dotenv type files: ...
25+
- Optional support for:
26+
- YAML files: requires `yaml`
27+
- TOML files: requires `toml`
28+
- Azure Key Vault credentials: ...
29+
- AWS Secrets Manager credentials: ...
30+
- GCP Secret Manager credentials: ...
31+
- Hashicorp Vault credentials: ...
2332

24-
* YAML files
25-
* TOML files
26-
* Azure Key Vault credentials
27-
* AWS Secrets Manager credentials
28-
* GCP Secret Manager credentials
29-
* Hashicorp Vault credentials
3033

3134
## Installing
3235

@@ -42,6 +45,8 @@ To include the optional TOML and/or YAML loaders, install the optional dependenc
4245
pip install python-configuration[toml,yaml]
4346
```
4447

48+
Without the optional dependencies, the TOML and YAML loaders will not be available,
49+
and attempting to use them will raise an exception.
4550
## Getting started
4651

4752
`python-configuration` converts the various config types into dictionaries with dotted-based keys. For example, given this JSON configuration

config/__init__.py

Lines changed: 118 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -763,101 +763,77 @@ def create_path_from_config(
763763
return cfg
764764

765765

766-
if yaml is not None: # pragma: no branch
766+
class YAMLConfiguration(FileConfiguration):
767+
"""Configuration from a YAML input."""
767768

768-
class YAMLConfiguration(FileConfiguration):
769-
"""Configuration from a YAML input."""
770-
771-
def _reload(
772-
self, data: Union[str, TextIO], read_from_file: bool = False
773-
) -> None:
774-
"""Reload the YAML data."""
775-
if read_from_file and isinstance(data, str):
776-
loaded = yaml.load(open(data, "rt"), Loader=yaml.FullLoader)
777-
else:
778-
loaded = yaml.load(data, Loader=yaml.FullLoader)
779-
if not isinstance(loaded, Mapping):
780-
raise ValueError("Data should be a dictionary")
781-
self._config = self._flatten_dict(loaded)
782-
783-
def config_from_yaml(
784-
data: Union[str, TextIO],
785-
read_from_file: bool = False,
786-
*,
787-
lowercase_keys: bool = False,
788-
interpolate: InterpolateType = False,
789-
interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
790-
ignore_missing_paths: bool = False,
791-
) -> Configuration:
792-
"""
793-
Return a Configuration instance from YAML files.
794-
795-
:param data: string or file
796-
:param read_from_file: whether `data` is a file or a YAML formatted string
797-
:param lowercase_keys: whether to convert every key to lower case.
798-
:param interpolate: whether to apply string interpolation when looking for items
799-
:param ignore_missing_paths: if true it will not throw on missing paths
800-
:return: a Configuration instance
801-
"""
802-
return YAMLConfiguration(
803-
data,
804-
read_from_file,
805-
lowercase_keys=lowercase_keys,
806-
interpolate=interpolate,
807-
interpolate_type=interpolate_type,
808-
ignore_missing_paths=ignore_missing_paths,
809-
)
810-
811-
812-
if toml is not None: # pragma: no branch
813-
814-
class TOMLConfiguration(FileConfiguration):
815-
"""Configuration from a TOML input."""
816-
817-
def __init__(
769+
def __init__(
818770
self,
819771
data: Union[str, TextIO],
820772
read_from_file: bool = False,
821773
*,
822-
section_prefix: str = "",
823774
lowercase_keys: bool = False,
824775
interpolate: InterpolateType = False,
825776
interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
826777
ignore_missing_paths: bool = False,
827-
):
828-
self._section_prefix = section_prefix
829-
super().__init__(
830-
data=data,
831-
read_from_file=read_from_file,
832-
lowercase_keys=lowercase_keys,
833-
interpolate=interpolate,
834-
interpolate_type=interpolate_type,
835-
ignore_missing_paths=ignore_missing_paths,
836-
)
778+
):
779+
if yaml is None:
780+
raise ImportError("Dependency <yaml> is not found, but required by this class.")
781+
super().__init__(
782+
data=data,
783+
read_from_file=read_from_file,
784+
lowercase_keys=lowercase_keys,
785+
interpolate=interpolate,
786+
interpolate_type=interpolate_type,
787+
ignore_missing_paths=ignore_missing_paths,
788+
)
837789

838-
def _reload(
839-
self, data: Union[str, TextIO], read_from_file: bool = False
840-
) -> None:
841-
"""Reload the TOML data."""
842-
if read_from_file:
843-
if isinstance(data, str):
844-
loaded = toml.load(open(data, "rt"))
845-
else:
846-
loaded = toml.load(data)
847-
else:
848-
data = cast(str, data)
849-
loaded = toml.loads(data)
850-
loaded = cast(dict, loaded)
790+
def _reload(
791+
self, data: Union[str, TextIO], read_from_file: bool = False
792+
) -> None:
793+
"""Reload the YAML data."""
794+
if read_from_file and isinstance(data, str):
795+
loaded = yaml.load(open(data, "rt"), Loader=yaml.FullLoader)
796+
else:
797+
loaded = yaml.load(data, Loader=yaml.FullLoader)
798+
if not isinstance(loaded, Mapping):
799+
raise ValueError("Data should be a dictionary")
800+
self._config = self._flatten_dict(loaded)
801+
802+
803+
def config_from_yaml(
804+
data: Union[str, TextIO],
805+
read_from_file: bool = False,
806+
*,
807+
lowercase_keys: bool = False,
808+
interpolate: InterpolateType = False,
809+
interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
810+
ignore_missing_paths: bool = False,
811+
) -> Configuration:
812+
"""
813+
Return a Configuration instance from YAML files.
814+
815+
:param data: string or file
816+
:param read_from_file: whether `data` is a file or a YAML formatted string
817+
:param lowercase_keys: whether to convert every key to lower case.
818+
:param interpolate: whether to apply string interpolation when looking for items
819+
:param ignore_missing_paths: if true it will not throw on missing paths
820+
:return: a Configuration instance
821+
"""
822+
return YAMLConfiguration(
823+
data,
824+
read_from_file,
825+
lowercase_keys=lowercase_keys,
826+
interpolate=interpolate,
827+
interpolate_type=interpolate_type,
828+
ignore_missing_paths=ignore_missing_paths,
829+
)
851830

852-
result = {
853-
k[len(self._section_prefix) :]: v
854-
for k, v in self._flatten_dict(loaded).items()
855-
if k.startswith(self._section_prefix)
856-
}
857831

858-
self._config = result
832+
class TOMLConfiguration(FileConfiguration):
833+
"""Configuration from a TOML input."""
859834

860-
def config_from_toml(
835+
def __init__(
836+
self,
861837
data: Union[str, TextIO],
862838
read_from_file: bool = False,
863839
*,
@@ -866,23 +842,69 @@ def config_from_toml(
866842
interpolate: InterpolateType = False,
867843
interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
868844
ignore_missing_paths: bool = False,
869-
) -> Configuration:
870-
"""
871-
Return a Configuration instance from TOML files.
845+
):
846+
if toml is None:
847+
raise ImportError("Dependency <toml> is not found, but required by this class.")
872848

873-
:param data: string or file
874-
:param read_from_file: whether `data` is a file or a TOML formatted string
875-
:param lowercase_keys: whether to convert every key to lower case.
876-
:param interpolate: whether to apply string interpolation when looking for items
877-
:param ignore_missing_paths: if true it will not throw on missing paths
878-
:return: a Configuration instance
879-
"""
880-
return TOMLConfiguration(
881-
data,
882-
read_from_file,
883-
section_prefix=section_prefix,
849+
self._section_prefix = section_prefix
850+
super().__init__(
851+
data=data,
852+
read_from_file=read_from_file,
884853
lowercase_keys=lowercase_keys,
885854
interpolate=interpolate,
886855
interpolate_type=interpolate_type,
887856
ignore_missing_paths=ignore_missing_paths,
888857
)
858+
859+
def _reload(
860+
self, data: Union[str, TextIO], read_from_file: bool = False
861+
) -> None:
862+
"""Reload the TOML data."""
863+
if read_from_file:
864+
if isinstance(data, str):
865+
loaded = toml.load(open(data, "rt"))
866+
else:
867+
loaded = toml.load(data)
868+
else:
869+
data = cast(str, data)
870+
loaded = toml.loads(data)
871+
loaded = cast(dict, loaded)
872+
873+
result = {
874+
k[len(self._section_prefix) :]: v
875+
for k, v in self._flatten_dict(loaded).items()
876+
if k.startswith(self._section_prefix)
877+
}
878+
879+
self._config = result
880+
881+
882+
def config_from_toml(
883+
data: Union[str, TextIO],
884+
read_from_file: bool = False,
885+
*,
886+
section_prefix: str = "",
887+
lowercase_keys: bool = False,
888+
interpolate: InterpolateType = False,
889+
interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
890+
ignore_missing_paths: bool = False,
891+
) -> Configuration:
892+
"""
893+
Return a Configuration instance from TOML files.
894+
895+
:param data: string or file
896+
:param read_from_file: whether `data` is a file or a TOML formatted string
897+
:param lowercase_keys: whether to convert every key to lower case.
898+
:param interpolate: whether to apply string interpolation when looking for items
899+
:param ignore_missing_paths: if true it will not throw on missing paths
900+
:return: a Configuration instance
901+
"""
902+
return TOMLConfiguration(
903+
data,
904+
read_from_file,
905+
section_prefix=section_prefix,
906+
lowercase_keys=lowercase_keys,
907+
interpolate=interpolate,
908+
interpolate_type=interpolate_type,
909+
ignore_missing_paths=ignore_missing_paths,
910+
)

0 commit comments

Comments
 (0)