Skip to content

Reference

python-configuration module.

DotEnvConfiguration

Bases: FileConfiguration

Configuration from a .env type file input.

Source code in src/config/__init__.py
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
class DotEnvConfiguration(FileConfiguration):
    """Configuration from a .env type file input."""

    def __init__(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
        prefix: str = "",
        separator: str = "__",
        *,
        strip_prefix: bool = True,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
        ignore_missing_paths: bool = False,
    ):
        """Class Constructor."""
        self._prefix = prefix
        self._strip_prefix = strip_prefix
        self._separator = separator

        super().__init__(
            data=data,
            read_from_file=read_from_file,
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
            ignore_missing_paths=ignore_missing_paths,
        )

    def _reload(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
    ) -> None:
        """Reload the .env data."""
        if read_from_file:
            if isinstance(data, (str, Path)):
                with open(data, "rt") as f:
                    data = f.read()
            else:
                data = data.read()
        data = cast(str, data)
        result: Dict[str, Any] = dict(
            parse_env_line(x) for x in data.splitlines() if x and not x.startswith("#")
        )

        n = len(self._prefix) if self._strip_prefix else 0
        result = {
            k[n:].replace(self._separator, ".").strip("."): v
            for k, v in result.items()
            if k.startswith(self._prefix)
        }

        self._config = self._flatten_dict(result)

__init__(data, read_from_file=False, prefix='', separator='__', *, strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Class Constructor.

Source code in src/config/__init__.py
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
def __init__(
    self,
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    prefix: str = "",
    separator: str = "__",
    *,
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
):
    """Class Constructor."""
    self._prefix = prefix
    self._strip_prefix = strip_prefix
    self._separator = separator

    super().__init__(
        data=data,
        read_from_file=read_from_file,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

EnvConfiguration

Bases: Configuration

Configuration from Environment variables.

Source code in src/config/__init__.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
class EnvConfiguration(Configuration):
    """Configuration from Environment variables."""

    def __init__(
        self,
        prefix: str = "",
        separator: str = "__",
        *,
        strip_prefix: bool = True,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ):
        """Class Constructor.

        prefix: prefix to filter environment variables with
        separator: separator to replace by dots
        strip_prefix: whether to include the prefix
        lowercase_keys: whether to convert every key to lower case.
        """
        self._prefix = prefix
        self._strip_prefix = strip_prefix
        self._separator = separator
        super().__init__(
            {},
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
        )
        self.reload()

    def reload(self) -> None:
        """Reload the environment values."""
        result = {}
        for key, value in os.environ.items():
            if not key.startswith(self._prefix + self._separator):
                continue
            if self._strip_prefix:
                result[
                    key[len(self._prefix) :].replace(self._separator, ".").strip(".")
                ] = value
            else:
                result[key.replace(self._separator, ".").strip(".")] = value
        super().__init__(
            result,
            lowercase_keys=self._lowercase,
            interpolate=self._interpolate,
            interpolate_type=self._interpolate_type,
        )

__init__(prefix='', separator='__', *, strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD)

Class Constructor.

prefix: prefix to filter environment variables with separator: separator to replace by dots strip_prefix: whether to include the prefix lowercase_keys: whether to convert every key to lower case.

Source code in src/config/__init__.py
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
def __init__(
    self,
    prefix: str = "",
    separator: str = "__",
    *,
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
):
    """Class Constructor.

    prefix: prefix to filter environment variables with
    separator: separator to replace by dots
    strip_prefix: whether to include the prefix
    lowercase_keys: whether to convert every key to lower case.
    """
    self._prefix = prefix
    self._strip_prefix = strip_prefix
    self._separator = separator
    super().__init__(
        {},
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
    )
    self.reload()

reload()

Reload the environment values.

Source code in src/config/__init__.py
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def reload(self) -> None:
    """Reload the environment values."""
    result = {}
    for key, value in os.environ.items():
        if not key.startswith(self._prefix + self._separator):
            continue
        if self._strip_prefix:
            result[
                key[len(self._prefix) :].replace(self._separator, ".").strip(".")
            ] = value
        else:
            result[key.replace(self._separator, ".").strip(".")] = value
    super().__init__(
        result,
        lowercase_keys=self._lowercase,
        interpolate=self._interpolate,
        interpolate_type=self._interpolate_type,
    )

FileConfiguration

Bases: Configuration

Configuration from a file input.

Source code in src/config/__init__.py
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
class FileConfiguration(Configuration):
    """Configuration from a file input."""

    def __init__(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
        *,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
        ignore_missing_paths: bool = False,
    ):
        """Class Constructor.

        data: path to a config file, or its contents
        read_from_file: whether to read from a file path or to interpret
            the `data` as the contents of the file.
        lowercase_keys: whether to convert every key to lower case.
        """
        super().__init__(
            {},
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
        )
        self._filename = (
            data if read_from_file and isinstance(data, (str, Path)) else None
        )
        self._ignore_missing_paths = ignore_missing_paths
        self._reload_with_check(data, read_from_file)

    def _reload_with_check(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
    ) -> None:  # pragma: no cover
        try:
            self._reload(data, read_from_file)
        except FileNotFoundError:
            if not self._ignore_missing_paths:
                raise
            self._config = self._flatten_dict({})

    def _reload(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
    ) -> None:  # pragma: no cover
        raise NotImplementedError()

    def reload(self) -> None:
        """Reload the configuration."""
        if self._filename:  # pragma: no branch
            self._reload_with_check(self._filename, True)

__init__(data, read_from_file=False, *, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Class Constructor.

data: path to a config file, or its contents read_from_file: whether to read from a file path or to interpret the data as the contents of the file. lowercase_keys: whether to convert every key to lower case.

Source code in src/config/__init__.py
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
def __init__(
    self,
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
):
    """Class Constructor.

    data: path to a config file, or its contents
    read_from_file: whether to read from a file path or to interpret
        the `data` as the contents of the file.
    lowercase_keys: whether to convert every key to lower case.
    """
    super().__init__(
        {},
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
    )
    self._filename = (
        data if read_from_file and isinstance(data, (str, Path)) else None
    )
    self._ignore_missing_paths = ignore_missing_paths
    self._reload_with_check(data, read_from_file)

reload()

Reload the configuration.

Source code in src/config/__init__.py
423
424
425
426
def reload(self) -> None:
    """Reload the configuration."""
    if self._filename:  # pragma: no branch
        self._reload_with_check(self._filename, True)

INIConfiguration

Bases: FileConfiguration

Configuration from an INI file input.

Source code in src/config/__init__.py
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
class INIConfiguration(FileConfiguration):
    """Configuration from an INI file input."""

    def __init__(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
        *,
        section_prefix: str = "",
        strip_prefix: bool = True,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
        ignore_missing_paths: bool = False,
    ):
        """Class Constructor."""
        self._section_prefix = section_prefix
        self._strip_prefix = strip_prefix
        super().__init__(
            data=data,
            read_from_file=read_from_file,
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
            ignore_missing_paths=ignore_missing_paths,
        )

    def _reload(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
    ) -> None:
        """Reload the INI data."""
        import configparser

        lowercase = self._lowercase

        class ConfigParser(configparser.RawConfigParser):
            def optionxform(self, optionstr: str) -> str:
                return super().optionxform(optionstr) if lowercase else optionstr

        if read_from_file:
            if isinstance(data, (str, Path)):
                with open(data, "rt") as f:
                    data = f.read()
            else:
                data = data.read()
        data = cast(str, data)
        cfg = ConfigParser()
        cfg.read_string(data)
        n = len(self._section_prefix) if self._strip_prefix else 0
        result = {
            section[n:] + "." + k: v
            for section, values in cfg.items()
            for k, v in values.items()
            if section.startswith(self._section_prefix)
        }
        self._config = self._flatten_dict(result)

__init__(data, read_from_file=False, *, section_prefix='', strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Class Constructor.

Source code in src/config/__init__.py
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
def __init__(
    self,
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    section_prefix: str = "",
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
):
    """Class Constructor."""
    self._section_prefix = section_prefix
    self._strip_prefix = strip_prefix
    super().__init__(
        data=data,
        read_from_file=read_from_file,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

JSONConfiguration

Bases: FileConfiguration

Configuration from a JSON input.

Source code in src/config/__init__.py
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
class JSONConfiguration(FileConfiguration):
    """Configuration from a JSON input."""

    def _reload(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
    ) -> None:
        """Reload the JSON data."""
        if read_from_file:
            if isinstance(data, (str, Path)):
                with open(data, "rt") as f:
                    result = json.load(f)
            else:
                result = json.load(data)
        else:
            result = json.loads(cast(str, data))
        self._config = self._flatten_dict(result)

PathConfiguration

Bases: Configuration

Configuration from a filesytem path.

Source code in src/config/__init__.py
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
class PathConfiguration(Configuration):
    """Configuration from a filesytem path."""

    def __init__(
        self,
        path: str,
        remove_level: int = 1,
        *,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
        ignore_missing_paths: bool = False,
    ):
        """Class Constructor.

        path: path to read from
        remove_level: how many levels to remove from the resulting config
        lowercase_keys: whether to convert every key to lower case.
        """
        self._path = path
        self._remove_level = remove_level
        super().__init__(
            {},
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
        )
        self._ignore_missing_paths = ignore_missing_paths
        self.reload()

    def reload(self) -> None:
        """Reload the path."""
        try:
            path = os.path.normpath(self._path)
            if not os.path.exists(path) or not os.path.isdir(path):
                raise FileNotFoundError()

            dotted_path_levels = len(path.split("/"))
            files_keys = (
                (
                    os.path.join(x[0], y),
                    ".".join(
                        (x[0].split("/") + [y])[
                            (dotted_path_levels + self._remove_level) :
                        ],
                    ),
                )
                for x in os.walk(path)
                for y in x[2]
                if not x[0].split("/")[-1].startswith("..")
            )

            result = {}
            for filename, key in files_keys:
                with open(filename) as f:
                    result[key] = f.read()
        except FileNotFoundError:
            if self._ignore_missing_paths:
                result = {}
            else:
                raise
        super().__init__(
            result,
            lowercase_keys=self._lowercase,
            interpolate=self._interpolate,
            interpolate_type=self._interpolate_type,
        )

__init__(path, remove_level=1, *, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Class Constructor.

path: path to read from remove_level: how many levels to remove from the resulting config lowercase_keys: whether to convert every key to lower case.

Source code in src/config/__init__.py
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
def __init__(
    self,
    path: str,
    remove_level: int = 1,
    *,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
):
    """Class Constructor.

    path: path to read from
    remove_level: how many levels to remove from the resulting config
    lowercase_keys: whether to convert every key to lower case.
    """
    self._path = path
    self._remove_level = remove_level
    super().__init__(
        {},
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
    )
    self._ignore_missing_paths = ignore_missing_paths
    self.reload()

reload()

Reload the path.

Source code in src/config/__init__.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
def reload(self) -> None:
    """Reload the path."""
    try:
        path = os.path.normpath(self._path)
        if not os.path.exists(path) or not os.path.isdir(path):
            raise FileNotFoundError()

        dotted_path_levels = len(path.split("/"))
        files_keys = (
            (
                os.path.join(x[0], y),
                ".".join(
                    (x[0].split("/") + [y])[
                        (dotted_path_levels + self._remove_level) :
                    ],
                ),
            )
            for x in os.walk(path)
            for y in x[2]
            if not x[0].split("/")[-1].startswith("..")
        )

        result = {}
        for filename, key in files_keys:
            with open(filename) as f:
                result[key] = f.read()
    except FileNotFoundError:
        if self._ignore_missing_paths:
            result = {}
        else:
            raise
    super().__init__(
        result,
        lowercase_keys=self._lowercase,
        interpolate=self._interpolate,
        interpolate_type=self._interpolate_type,
    )

PythonConfiguration

Bases: Configuration

Configuration from a python module.

Source code in src/config/__init__.py
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
class PythonConfiguration(Configuration):
    """Configuration from a python module."""

    def __init__(
        self,
        module: Union[str, Path, ModuleType],
        prefix: str = "",
        separator: str = "_",
        *,
        strip_prefix: bool = True,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
        ignore_missing_paths: bool = False,
    ):
        """Class Constructor.

        module: a module or path string
        prefix: prefix to use to filter object names
        separator: separator to replace by dots
        lowercase_keys: whether to convert every key to lower case.
        """
        try:
            if isinstance(module, (str, Path)):
                module = str(module)
                if module.endswith(".py"):
                    import importlib.util
                    from importlib import machinery

                    spec = cast(
                        machinery.ModuleSpec,
                        importlib.util.spec_from_file_location(module, module),
                    )
                    module = importlib.util.module_from_spec(spec)
                    spec.loader = cast(InspectLoader, spec.loader)
                    spec.loader.exec_module(module)
                else:
                    import importlib

                    module = importlib.import_module(module)
            self._module: Optional[ModuleType] = module
            self._prefix = prefix
            self._strip_prefix = strip_prefix
            self._separator = separator
        except (FileNotFoundError, ModuleNotFoundError):
            if not ignore_missing_paths:
                raise
            self._module = None

        super().__init__(
            {},
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
        )
        self.reload()

    def reload(self) -> None:
        """Reload the path."""
        if self._module is not None:
            variables = [
                x
                for x in dir(self._module)
                if not x.startswith("__") and x.startswith(self._prefix)
            ]
            n = len(self._prefix) if self._strip_prefix else 0
            result = {
                k[n:].replace(self._separator, ".").strip("."): getattr(self._module, k)
                for k in variables
            }
        else:
            result = {}
        super().__init__(
            result,
            lowercase_keys=self._lowercase,
            interpolate=self._interpolate,
            interpolate_type=self._interpolate_type,
        )

__init__(module, prefix='', separator='_', *, strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Class Constructor.

module: a module or path string prefix: prefix to use to filter object names separator: separator to replace by dots lowercase_keys: whether to convert every key to lower case.

Source code in src/config/__init__.py
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
def __init__(
    self,
    module: Union[str, Path, ModuleType],
    prefix: str = "",
    separator: str = "_",
    *,
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
):
    """Class Constructor.

    module: a module or path string
    prefix: prefix to use to filter object names
    separator: separator to replace by dots
    lowercase_keys: whether to convert every key to lower case.
    """
    try:
        if isinstance(module, (str, Path)):
            module = str(module)
            if module.endswith(".py"):
                import importlib.util
                from importlib import machinery

                spec = cast(
                    machinery.ModuleSpec,
                    importlib.util.spec_from_file_location(module, module),
                )
                module = importlib.util.module_from_spec(spec)
                spec.loader = cast(InspectLoader, spec.loader)
                spec.loader.exec_module(module)
            else:
                import importlib

                module = importlib.import_module(module)
        self._module: Optional[ModuleType] = module
        self._prefix = prefix
        self._strip_prefix = strip_prefix
        self._separator = separator
    except (FileNotFoundError, ModuleNotFoundError):
        if not ignore_missing_paths:
            raise
        self._module = None

    super().__init__(
        {},
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
    )
    self.reload()

reload()

Reload the path.

Source code in src/config/__init__.py
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
def reload(self) -> None:
    """Reload the path."""
    if self._module is not None:
        variables = [
            x
            for x in dir(self._module)
            if not x.startswith("__") and x.startswith(self._prefix)
        ]
        n = len(self._prefix) if self._strip_prefix else 0
        result = {
            k[n:].replace(self._separator, ".").strip("."): getattr(self._module, k)
            for k in variables
        }
    else:
        result = {}
    super().__init__(
        result,
        lowercase_keys=self._lowercase,
        interpolate=self._interpolate,
        interpolate_type=self._interpolate_type,
    )

TOMLConfiguration

Bases: FileConfiguration

Configuration from a TOML input.

Source code in src/config/__init__.py
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
class TOMLConfiguration(FileConfiguration):
    """Configuration from a TOML input."""

    def __init__(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
        *,
        section_prefix: str = "",
        strip_prefix: bool = True,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
        ignore_missing_paths: bool = False,
    ):
        """Class Constructor."""
        if toml is None:  # pragma: no cover
            raise ImportError(
                "Dependency <toml> is not found, but required by this class.",
            )

        self._section_prefix = section_prefix
        self._strip_prefix = strip_prefix
        super().__init__(
            data=data,
            read_from_file=read_from_file,
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
            ignore_missing_paths=ignore_missing_paths,
        )

    def _reload(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
    ) -> None:
        """Reload the TOML data."""
        if read_from_file:
            if isinstance(data, (str, Path)):
                with open(data, "rb") as f:
                    loaded = toml.load(f)
            else:
                loaded = toml.load(data)  # type: ignore [arg-type,unused-ignore]
        else:
            data = cast(str, data)
            loaded = toml.loads(data)
        loaded = cast(dict, loaded)

        n = len(self._section_prefix) if self._section_prefix else 0
        result = {
            k[n:]: v
            for k, v in self._flatten_dict(loaded).items()
            if k.startswith(self._section_prefix)
        }

        self._config = result

__init__(data, read_from_file=False, *, section_prefix='', strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Class Constructor.

Source code in src/config/__init__.py
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
def __init__(
    self,
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    section_prefix: str = "",
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
):
    """Class Constructor."""
    if toml is None:  # pragma: no cover
        raise ImportError(
            "Dependency <toml> is not found, but required by this class.",
        )

    self._section_prefix = section_prefix
    self._strip_prefix = strip_prefix
    super().__init__(
        data=data,
        read_from_file=read_from_file,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

YAMLConfiguration

Bases: FileConfiguration

Configuration from a YAML input.

Source code in src/config/__init__.py
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
class YAMLConfiguration(FileConfiguration):
    """Configuration from a YAML input."""

    def __init__(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
        *,
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
        ignore_missing_paths: bool = False,
    ):
        """Class Constructor."""
        if yaml is None:  # pragma: no cover
            raise ImportError(
                "Dependency <yaml> is not found, but required by this class.",
            )
        super().__init__(
            data=data,
            read_from_file=read_from_file,
            lowercase_keys=lowercase_keys,
            interpolate=interpolate,
            interpolate_type=interpolate_type,
            ignore_missing_paths=ignore_missing_paths,
        )

    def _reload(
        self,
        data: Union[str, Path, TextIO],
        read_from_file: bool = False,
    ) -> None:
        """Reload the YAML data."""
        if read_from_file and isinstance(data, (str, Path)):
            with open(data, "rt") as f:
                loaded = yaml.load(f, Loader=yaml.FullLoader)
        else:
            loaded = yaml.load(data, Loader=yaml.FullLoader)
        if not isinstance(loaded, Mapping):
            raise ValueError("Data should be a dictionary")
        self._config = self._flatten_dict(loaded)

__init__(data, read_from_file=False, *, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Class Constructor.

Source code in src/config/__init__.py
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
def __init__(
    self,
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
):
    """Class Constructor."""
    if yaml is None:  # pragma: no cover
        raise ImportError(
            "Dependency <yaml> is not found, but required by this class.",
        )
    super().__init__(
        data=data,
        read_from_file=read_from_file,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

config(*configs, prefix='', strip_prefix=True, separator=None, remove_level=1, lowercase_keys=False, ignore_missing_paths=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD)

Create a ConfigurationSet instance from an iterable of configs.

Parameters:

Name Type Description Default
configs Iterable

iterable of configurations

()
prefix str

prefix to filter environment variables with

''
strip_prefix bool

whether to strip the prefix

True
remove_level int

how many levels to remove from the resulting config

1
lowercase_keys bool

whether to convert every key to lower case.

False
ignore_missing_paths bool

whether to ignore failures from missing files/folders.

False
separator Optional[str]

separator for Python modules and environment variables.

None
interpolate InterpolateType

whether to apply string interpolation when looking for items

False

Note that the separator parameter impacts Python modules and environment variables at the same time. To pass different separators to Python modules and environments, use the longer version ('python', 'path-to-module', prefix, separator) and ('env', prefix, separator) .

Source code in src/config/__init__.py
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
def config(
    *configs: Iterable,
    prefix: str = "",
    strip_prefix: bool = True,
    separator: Optional[str] = None,
    remove_level: int = 1,
    lowercase_keys: bool = False,
    ignore_missing_paths: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
) -> ConfigurationSet:
    """Create a [ConfigurationSet][config.configuration_set.ConfigurationSet] instance from an iterable of configs.

    Params:
       configs: iterable of configurations
       prefix: prefix to filter environment variables with
       strip_prefix: whether to strip the prefix
       remove_level: how many levels to remove from the resulting config
       lowercase_keys: whether to convert every key to lower case.
       ignore_missing_paths: whether to ignore failures from missing files/folders.
       separator: separator for Python modules and environment variables.
       interpolate: whether to apply string interpolation when looking for items

    Note that the `separator` parameter  impacts Python modules and
    environment variables at the same time. To pass different separators to Python
    modules and environments, use the longer version
    ``('python', 'path-to-module', prefix, separator)``
    and ``('env', prefix, separator)`` .
    """  # noqa: E501
    instances = []
    default_args: List[str] = [prefix]
    if separator is not None:
        default_args.append(separator)
    default_kwargs: Dict[Any, Any] = {
        "lowercase_keys": lowercase_keys,
        # for Configuration Sets, interpolate parameters should be at the Set level
        "interpolate": False,
        "interpolate_type": InterpolateEnumType.STANDARD,
    }

    for config_ in configs:
        if isinstance(config_, Mapping):
            instances.append(config_from_dict(config_, **default_kwargs))
            continue
        elif isinstance(config_, Configuration):
            instances.append(config_)
            continue
        elif isinstance(config_, str):
            if config_.endswith(".py"):
                config_ = ("python", config_, *default_args)
            elif config_.endswith(".json"):
                config_ = ("json", config_, True)
            elif yaml and config_.endswith(".yaml"):
                config_ = ("yaml", config_, True)
            elif toml and config_.endswith(".toml"):
                config_ = ("toml", config_, True)
            elif config_.endswith(".ini"):
                config_ = ("ini", config_, True)
            elif config_.endswith(".env") or config_.startswith(".env"):
                config_ = ("dotenv", config_, True, *default_args)
            elif os.path.isdir(config_):
                config_ = ("path", config_, remove_level)
            elif config_ in ("env", "environment"):
                config_ = ("env", *default_args)
            elif all(s and s.isidentifier() for s in config_.split(".")):
                config_ = ("python", config_, *default_args)
            else:
                raise ValueError(f'Cannot determine config type from "{config_}"')

        if not isinstance(config_, (tuple, list)) or len(config_) == 0:
            raise ValueError(
                "configuration parameters must be a list of dictionaries,"
                " strings, or non-empty tuples/lists",
            )
        type_ = config_[0]
        if type_ == "dict":
            instances.append(config_from_dict(*config_[1:], **default_kwargs))
        elif type_ in ("env", "environment"):
            params = list(config_[1:]) + default_args[(len(config_) - 1) :]
            instances.append(
                config_from_env(
                    *params,
                    **default_kwargs,
                    strip_prefix=strip_prefix,
                ),
            )
        elif type_ == "python":
            if len(config_) < 2:
                raise ValueError("No path specified for python module")
            params = list(config_[1:]) + default_args[(len(config_) - 2) :]
            instances.append(
                config_from_python(
                    *params,
                    **default_kwargs,
                    ignore_missing_paths=ignore_missing_paths,
                    strip_prefix=strip_prefix,
                ),
            )
        elif type_ == "json":
            instances.append(
                config_from_json(
                    *config_[1:],
                    **default_kwargs,
                    ignore_missing_paths=ignore_missing_paths,
                ),
            )
        elif yaml and type_ == "yaml":
            instances.append(
                config_from_yaml(
                    *config_[1:],
                    **default_kwargs,
                    ignore_missing_paths=ignore_missing_paths,
                ),
            )
        elif toml and type_ == "toml":
            instances.append(
                config_from_toml(
                    *config_[1:],
                    **default_kwargs,
                    ignore_missing_paths=ignore_missing_paths,
                    strip_prefix=strip_prefix,
                ),
            )
        elif type_ == "ini":
            instances.append(
                config_from_ini(
                    *config_[1:],
                    **default_kwargs,
                    ignore_missing_paths=ignore_missing_paths,
                    strip_prefix=strip_prefix,
                ),
            )
        elif type_ == "dotenv":
            instances.append(
                config_from_dotenv(
                    *config_[1:],
                    **default_kwargs,
                    ignore_missing_paths=ignore_missing_paths,
                    strip_prefix=strip_prefix,
                ),
            )
        elif type_ == "path":
            instances.append(
                config_from_path(
                    *config_[1:],
                    **default_kwargs,
                    ignore_missing_paths=ignore_missing_paths,
                ),
            )
        else:
            raise ValueError(f'Unknown configuration type "{type_}"')

    return ConfigurationSet(
        *instances,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
    )

config_from_dict(data, *, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD)

Create a Configuration instance from a dictionary.

Parameters:

Name Type Description Default
data Mapping

dictionary with string keys.

required
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
def config_from_dict(
    data: Mapping,
    *,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
) -> Configuration:
    """Create a [Configuration][config.configuration.Configuration] instance from a dictionary.

    Params:
        data: dictionary with string keys.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.

    Returns:
        a [Configuration][config.configuration.Configuration] instance.
    """  # noqa: E501
    return Configuration(
        data,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
    )

config_from_dotenv(data, read_from_file=False, prefix='', separator='__', *, strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Create a Configuration instance from a .env type file.

Lines starting with a # are ignored and treated as comments.

Parameters:

Name Type Description Default
data Union[str, Path, TextIO]

path to a .env type file or contents.

required
read_from_file bool

whether to read from a file path or to interpret. the data as the contents of the INI file.

False
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False
ignore_missing_paths bool

if true it will not throw on missing paths.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
def config_from_dotenv(
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    prefix: str = "",
    separator: str = "__",
    *,
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
) -> Configuration:
    """Create a [Configuration][config.configuration.Configuration] instance from a .env type file.

    Lines starting with a # are ignored and treated as comments.

    Params:
        data: path to a .env type file or contents.
        read_from_file: whether to read from a file path or to interpret.
            the `data` as the contents of the INI file.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.
        ignore_missing_paths: if true it will not throw on missing paths.

    Returns:
        a [Configuration][config.configuration.Configuration] instance.
    """  # noqa: E501
    return DotEnvConfiguration(
        data,
        read_from_file,
        prefix=prefix,
        separator=separator,
        strip_prefix=strip_prefix,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

config_from_env(prefix, separator='__', *, strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD)

Create a EnvConfiguration instance from environment variables.

Parameters:

Name Type Description Default
prefix str

prefix to filter environment variables with.

required
separator str

separator to replace by dots.

'__'
strip_prefix bool

whether to include the prefix

True
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
def config_from_env(
    prefix: str,
    separator: str = "__",
    *,
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
) -> Configuration:
    """Create a [EnvConfiguration][config.EnvConfiguration] instance from environment variables.

    Params:
        prefix: prefix to filter environment variables with.
        separator: separator to replace by dots.
        strip_prefix: whether to include the prefix
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.

    Returns:
        a [Configuration][config.configuration.Configuration] instance.
    """  # noqa: E501
    return EnvConfiguration(
        prefix,
        separator,
        strip_prefix=strip_prefix,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
    )

config_from_ini(data, read_from_file=False, *, section_prefix='', strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Create a Configuration instance from an INI file.

Parameters:

Name Type Description Default
data Union[str, Path, TextIO]

path to an INI file or contents.

required
read_from_file bool

whether to read from a file path or to interpret. the data as the contents of the INI file.

False
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False
ignore_missing_paths bool

if true it will not throw on missing paths.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
def config_from_ini(
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    section_prefix: str = "",
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
) -> Configuration:
    """Create a [Configuration][config.configuration.Configuration] instance from an INI file.

    Params:
        data: path to an INI file or contents.
        read_from_file: whether to read from a file path or to interpret.
            the `data` as the contents of the INI file.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.
        ignore_missing_paths: if true it will not throw on missing paths.

    Returns:
        a [Configuration][config.configuration.Configuration] instance.
    """  # noqa: E501
    return INIConfiguration(
        data,
        read_from_file,
        section_prefix=section_prefix,
        strip_prefix=strip_prefix,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

config_from_json(data, read_from_file=False, *, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Create a Configuration instance from a JSON file.

Parameters:

Name Type Description Default
data Union[str, Path, TextIO]

path to a JSON file or contents.

required
read_from_file bool

whether to read from a file path or to interpret. the data as the contents of the JSON file.

False
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False
ignore_missing_paths bool

if true it will not throw on missing paths.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
def config_from_json(
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
) -> Configuration:
    """Create a [Configuration][config.configuration.Configuration] instance from a JSON file.

    Params:
        data: path to a JSON file or contents.
        read_from_file: whether to read from a file path or to interpret.
            the `data` as the contents of the JSON file.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.
        ignore_missing_paths: if true it will not throw on missing paths.

    Returns:
        a [Configuration][config.configuration.Configuration] instance.
    """  # noqa: E501
    return JSONConfiguration(
        data,
        read_from_file,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

config_from_path(path, remove_level=1, *, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Create a Configuration instance from filesystem path.

Parameters:

Name Type Description Default
path str

path to read from.

required
remove_level int

how many levels to remove from the resulting config.

1
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
def config_from_path(
    path: str,
    remove_level: int = 1,
    *,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
) -> Configuration:
    """Create a [Configuration][config.configuration.Configuration] instance from filesystem path.

    Params:
        path: path to read from.
        remove_level: how many levels to remove from the resulting config.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.

    Returns:
        a [Configuration][config.configuration.Configuration] instance.
    """  # noqa: E501
    return PathConfiguration(
        path,
        remove_level,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

config_from_python(module, prefix='', separator='_', *, strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Create a Configuration instance from the objects in a Python module.

Parameters:

Name Type Description Default
module Union[str, Path, ModuleType]

a module or path string.

required
prefix str

prefix to use to filter object names.

''
separator str

separator to replace by dots.

'_'
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
def config_from_python(
    module: Union[str, Path, ModuleType],
    prefix: str = "",
    separator: str = "_",
    *,
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
) -> Configuration:
    """Create a [Configuration][config.configuration.Configuration] instance from the objects in a Python module.

    Params:
        module: a module or path string.
        prefix: prefix to use to filter object names.
        separator: separator to replace by dots.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.

    Returns:
        a [Configuration][config.configuration.Configuration] instance.
    """  # noqa: E501
    return PythonConfiguration(
        module,
        prefix,
        separator,
        strip_prefix=strip_prefix,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

config_from_toml(data, read_from_file=False, *, section_prefix='', strip_prefix=True, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Return a Configuration instance from TOML files.

Parameters:

Name Type Description Default
data Union[str, Path, TextIO]

string or file.

required
read_from_file bool

whether data is a file or a TOML formatted string.

False
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False
ignore_missing_paths bool

if true it will not throw on missing paths.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
def config_from_toml(
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    section_prefix: str = "",
    strip_prefix: bool = True,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
) -> Configuration:
    """Return a Configuration instance from TOML files.

    Params:
        data: string or file.
        read_from_file: whether `data` is a file or a TOML formatted string.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.
        ignore_missing_paths: if true it will not throw on missing paths.

    Returns:
        a Configuration instance.
    """
    return TOMLConfiguration(
        data,
        read_from_file,
        section_prefix=section_prefix,
        strip_prefix=strip_prefix,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

config_from_yaml(data, read_from_file=False, *, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD, ignore_missing_paths=False)

Return a Configuration instance from YAML files.

Parameters:

Name Type Description Default
data Union[str, Path, TextIO]

string or file.

required
read_from_file bool

whether data is a file or a YAML formatted string.

False
lowercase_keys bool

whether to convert every key to lower case.

False
interpolate InterpolateType

whether to apply string interpolation when looking for items.

False
ignore_missing_paths bool

if true it will not throw on missing paths.

False

Returns:

Type Description
Configuration

a Configuration instance.

Source code in src/config/__init__.py
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
def config_from_yaml(
    data: Union[str, Path, TextIO],
    read_from_file: bool = False,
    *,
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ignore_missing_paths: bool = False,
) -> Configuration:
    """Return a Configuration instance from YAML files.

    Params:
        data: string or file.
        read_from_file: whether `data` is a file or a YAML formatted string.
        lowercase_keys: whether to convert every key to lower case.
        interpolate: whether to apply string interpolation when looking for items.
        ignore_missing_paths: if true it will not throw on missing paths.

    Returns:
        a Configuration instance.
    """
    return YAMLConfiguration(
        data,
        read_from_file,
        lowercase_keys=lowercase_keys,
        interpolate=interpolate,
        interpolate_type=interpolate_type,
        ignore_missing_paths=ignore_missing_paths,
    )

create_path_from_config(path, cfg, remove_level=1)

Output a path configuration from a Configuration instance.

Parameters:

Name Type Description Default
path str

path to create the config files in.

required
cfg Configuration

Configuration instance.

required
remove_level int

how many levels to remove.

1
Source code in src/config/__init__.py
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
def create_path_from_config(
    path: str,
    cfg: Configuration,
    remove_level: int = 1,
) -> Configuration:
    """
    Output a path configuration from a [Configuration][config.Configuration] instance.

    Args:
        path: path to create the config files in.
        cfg: [Configuration][config.Configuration] instance.
        remove_level: how many levels to remove.
    """
    import os.path

    assert os.path.isdir(path)

    d = cfg.as_dict()
    for k, v in d.items():
        with open(os.path.join(path, k), "wb") as f:
            f.write(str(v).encode())

        cfg = config_from_path(path, remove_level=remove_level)
    return cfg

Configuration class.

Configuration

Configuration class.

The Configuration class takes a dictionary input with keys such as

- ``a1.b1.c1``
- ``a1.b1.c2``
- ``a1.b2.c1``
- ``a1.b2.c2``
- ``a2.b1.c1``
- ``a2.b1.c2``
- ``a2.b2.c1``
- ``a2.b2.c2``
Source code in src/config/configuration.py
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
class Configuration:
    """Configuration class.

    The Configuration class takes a dictionary input with keys such as

        - ``a1.b1.c1``
        - ``a1.b1.c2``
        - ``a1.b2.c1``
        - ``a1.b2.c2``
        - ``a2.b1.c1``
        - ``a2.b1.c2``
        - ``a2.b2.c1``
        - ``a2.b2.c2``
    """

    def __init__(
        self,
        config_: Mapping[str, Any],
        lowercase_keys: bool = False,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ):
        """Class Constructor.

        Params:
            config_: a mapping of configuration values. Keys need to be strings.
            lowercase_keys: whether to convert every key to lower case.
        """
        self._lowercase = lowercase_keys
        self._interpolate = {} if interpolate is True else interpolate
        self._interpolate_type = interpolate_type
        self._config: Dict[str, Any] = self._flatten_dict(config_)
        self._default_levels: Optional[int] = 1

    def __eq__(self, other):  # type: ignore
        """Equality operator."""
        if not isinstance(other, (Configuration, Mapping)):
            return False
        return self.as_dict() == Configuration(other).as_dict()

    def _filter_dict(self, d: Dict[str, Any], prefix: str) -> Dict[str, Any]:
        """Filter a dictionary and return the items that are prefixed by `prefix`.

        Params:
            d: dictionary.
            prefix: prefix to filter on.
        """
        if self._lowercase:
            return {
                k[(len(prefix) + 1) :].lower(): v
                for k, v in d.items()
                for k, v in d.items()
                if k.startswith(prefix + ".")
            }
        else:
            return {
                k[(len(prefix) + 1) :]: v
                for k, v in d.items()
                if k.startswith(prefix + ".")
            }

    def _flatten_dict(self, d: Mapping[str, Any]) -> Dict[str, Any]:
        """Flatten one level of a dictionary.

        Params:
            d: dict.

        Returns:
            a flattened dict.
        """
        nested = {k for k, v in d.items() if isinstance(v, (Mapping, Configuration))}
        if self._lowercase:
            result = {
                k.lower() + "." + ki: vi
                for k in nested
                for ki, vi in self._flatten_dict(d[k]).items()
            }
            result.update(
                (k.lower(), v)
                for k, v in d.items()
                if not isinstance(v, (Mapping, Configuration))
            )
        else:
            result = {
                k + "." + ki: vi
                for k in nested
                for ki, vi in self._flatten_dict(d[k]).items()
            }
            result.update(
                (k, v)
                for k, v in d.items()
                if not isinstance(v, (Mapping, Configuration))
            )
        return result

    def _get_subset(self, prefix: str) -> Union[Dict[str, Any], Any]:
        """Return the subset of the config dictionary whose keys start with `prefix`.

        Params:
            prefix: string.

        Returns:
            dict.
        """  # noqa: E501
        d = {
            k[(len(prefix) + 1) :]: v
            for k, v in self._config.items()
            if k.startswith(prefix + ".")
        }
        if not d:
            prefixes = prefix.split(".")
            if len(prefixes) == 1:
                return deepcopy(self._config.get(prefix, {}))
            d = self._config
            while prefixes:  # pragma: no branches
                p = prefixes[0]
                new_d = self._filter_dict(d, p)
                if new_d == {}:
                    return deepcopy(d.get(p, {}) if len(prefixes) == 1 else {})
                d = new_d
                prefixes = prefixes[1:]
        return deepcopy(d)

    def __getitem__(self, item: str) -> Union["Configuration", Any]:  # noqa: D105
        v = self._get_subset(item)

        if v == {}:
            raise KeyError(item)
        if isinstance(v, Mapping):
            return Configuration(v)
        elif self._interpolate is not False:
            d = self.as_dict()
            d.update(self._interpolate)
            return interpolate_object(item, v, [d], self._interpolate_type)
        else:
            return v

    def __getattr__(self, item: str) -> Any:  # noqa: D105
        try:
            return self[item]
        except KeyError:
            raise AttributeError(item) from None

    def get(self, key: str, default: Any = None) -> Union[dict, Any]:
        """Get the configuration values corresponding to `key`.

        Params:
            key: key to retrieve.
            default: default value in case the key is missing.

        Returns:
            the value found or a default.
        """
        return self.as_dict().get(key, default)

    def as_dict(self) -> dict:
        """Return the representation as a dictionary."""
        return self._config

    def as_attrdict(self) -> AttributeDict:
        """Return the representation as an attribute dictionary."""
        return AttributeDict(
            {
                x: Configuration(v).as_attrdict() if isinstance(v, Mapping) else v
                for x, v in self.items(levels=1)
            },
        )

    def get_bool(self, item: str) -> bool:
        """Get the item value as a bool.

        Params:
            item: key
        """
        return as_bool(self[item])

    def get_str(self, item: str, fmt: str = "{}") -> str:
        """Get the item value as an int.

        Params:
            item: key
            fmt: format to use
        """
        return fmt.format(self[item])

    def get_int(self, item: str) -> int:
        """Get the item value as an int.

        Params:
            item: key
        """
        return int(self[item])

    def get_float(self, item: str) -> float:
        """Get the item value as a float.

        Params:
            item: key
        """
        return float(self[item])

    def get_list(self, item: str) -> List[Any]:
        """Get the item value as a list.

        Params:
            item: key
        """
        return list(self[item])

    def get_dict(self, item: str) -> dict:
        """Get the item values as a dictionary.

        Params:
            item: key
        """
        return dict(self._get_subset(item))

    def base64encode(self, item: str) -> bytes:
        """Get the item value as a Base64 encoded bytes instance.

        Params:
            item: key
        """
        b = self[item]
        b = b if isinstance(b, bytes) else b.encode()
        return base64.b64encode(b)

    def base64decode(self, item: str) -> bytes:
        """Get the item value as a Base64 decoded bytes instance.

        Params:
            item: key
        """
        b = self[item]
        b = b if isinstance(b, bytes) else b.encode()
        return base64.b64decode(b, validate=True)

    def keys(
        self,
        levels: Optional[int] = None,
    ) -> Union["Configuration", Any, KeysView[str]]:
        """Return a set-like object providing a view on the configuration keys."""
        assert levels is None or levels > 0
        levels = self._default_levels if levels is None else levels
        try:
            return self["keys"]  # don't filter levels, existing attribute
        except KeyError:
            return cast(
                KeysView[str],
                list(
                    {
                        ".".join(x.split(".")[:levels])
                        for x in set(self.as_dict().keys())
                    },
                ),
            )

    def values(
        self,
        levels: Optional[int] = None,
    ) -> Union["Configuration", Any, ValuesView[Any]]:
        """Return a set-like object providing a view on the configuration values."""
        assert levels is None or levels > 0
        levels = self._default_levels if levels is None else levels
        try:
            return self["values"]
        except KeyError:
            return dict(self.items(levels=levels)).values()

    def items(
        self,
        levels: Optional[int] = None,
    ) -> Union["Configuration", Any, ItemsView[str, Any]]:
        """Return a set-like object providing a view on the configuration items."""
        assert levels is None or levels > 0
        levels = self._default_levels if levels is None else levels
        try:
            return self["items"]
        except KeyError:
            keys = cast(KeysView[str], self.keys(levels=levels))
            return {k: self._get_subset(k) for k in keys}.items()

    def __iter__(self) -> Iterator[Tuple[str, Any]]:  # noqa: D105
        return iter(dict(self.items()))  # type: ignore

    def __reversed__(self) -> Iterator[Tuple[str, Any]]:  # noqa: D105
        if version_info < (3, 8):
            return OrderedDict(
                reversed(list(self.items())),
            )  # type: ignore  # pragma: no cover
        else:
            return reversed(dict(self.items()))  # type: ignore

    def __len__(self) -> int:  # noqa: D105
        return len(self.keys())

    def __setitem__(self, key: str, value: Any) -> None:  # noqa: D105
        self.update({key: value})

    def __delitem__(self, prefix: str) -> None:  # noqa: D105
        """Filter a dictionary and delete the items that are prefixed by `prefix`.

        Params:
            prefix: prefix to filter on to delete keys
        """
        remove = []
        for k in self._config:
            kl = k.lower() if self._lowercase else k
            if kl == prefix or kl.startswith(prefix + "."):
                remove.append(k)
        if not remove:
            raise KeyError("No key with prefix '%s' found." % prefix)
        for k in remove:
            del self._config[k]

    def __contains__(self, prefix: str) -> bool:  # noqa: D105
        try:
            self[prefix]
            return True
        except KeyError:
            return False

    def clear(self) -> None:
        """Remove all items."""
        self._config.clear()

    def copy(self) -> "Configuration":
        """Return shallow copy."""
        return Configuration(self._config)

    def pop(self, prefix: str, value: Any = None) -> Any:
        """Remove keys with the specified prefix and return the corresponding value.

        If the prefix is not found a KeyError is raised.
        """
        try:
            value = self[prefix]
            del self[prefix]
        except KeyError:
            if value is None:
                raise
        return value

    def setdefault(self, key: str, default: Any = None) -> Any:
        """Insert key with a value of default if key is not in the Configuration.

        Return the value for key if key is in the Configuration, else default.
        """
        try:
            return self[key]
        except KeyError:
            self[key] = default
        return self[key]

    def update(self, other: Mapping[str, Any]) -> None:
        """Update the Configuration with another Configuration object or Mapping."""
        self._config.update(self._flatten_dict(other))

    def reload(self) -> None:  # pragma: no cover
        """Reload the configuration.

        This method is not implemented for simple Configuration objects and is
        intended only to be used in subclasses.
        """
        raise NotImplementedError()

    def validate(
        self,
        schema: Any,
        raise_on_error: bool = False,
        nested: bool = False,
        **kwargs: Mapping[str, Any],
    ) -> bool:
        """Validate the current config using JSONSchema."""
        try:
            from jsonschema import ValidationError, validate
        except ImportError:  # pragma: no cover
            raise RuntimeError(
                "Validation requires the `jsonschema` library.",
            ) from None
        try:
            validate(self.as_attrdict() if nested else self.as_dict(), schema, **kwargs)
        except ValidationError as err:
            if raise_on_error:
                raise err
            return False
        return True

    @contextmanager
    def dotted_iter(self) -> Iterator["Configuration"]:
        """
        Context manager for dotted iteration.

        This context manager changes all the iterator-related functions
        to include every nested (dotted) key instead of just the top level.
        """
        self._default_levels = None
        try:
            yield self
        finally:
            self._default_levels = 1

    def __repr__(self) -> str:  # noqa: D105
        return "<%s: %s>" % (type(self).__name__, hex(id(self)))

    def __str__(self) -> str:  # noqa: D105
        return str({k: clean(k, v) for k, v in sorted(self.as_dict().items())})

__delitem__(prefix)

Filter a dictionary and delete the items that are prefixed by prefix.

Parameters:

Name Type Description Default
prefix str

prefix to filter on to delete keys

required
Source code in src/config/configuration.py
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
def __delitem__(self, prefix: str) -> None:  # noqa: D105
    """Filter a dictionary and delete the items that are prefixed by `prefix`.

    Params:
        prefix: prefix to filter on to delete keys
    """
    remove = []
    for k in self._config:
        kl = k.lower() if self._lowercase else k
        if kl == prefix or kl.startswith(prefix + "."):
            remove.append(k)
    if not remove:
        raise KeyError("No key with prefix '%s' found." % prefix)
    for k in remove:
        del self._config[k]

__eq__(other)

Equality operator.

Source code in src/config/configuration.py
69
70
71
72
73
def __eq__(self, other):  # type: ignore
    """Equality operator."""
    if not isinstance(other, (Configuration, Mapping)):
        return False
    return self.as_dict() == Configuration(other).as_dict()

__init__(config_, lowercase_keys=False, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD)

Class Constructor.

Parameters:

Name Type Description Default
config_ Mapping[str, Any]

a mapping of configuration values. Keys need to be strings.

required
lowercase_keys bool

whether to convert every key to lower case.

False
Source code in src/config/configuration.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def __init__(
    self,
    config_: Mapping[str, Any],
    lowercase_keys: bool = False,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
):
    """Class Constructor.

    Params:
        config_: a mapping of configuration values. Keys need to be strings.
        lowercase_keys: whether to convert every key to lower case.
    """
    self._lowercase = lowercase_keys
    self._interpolate = {} if interpolate is True else interpolate
    self._interpolate_type = interpolate_type
    self._config: Dict[str, Any] = self._flatten_dict(config_)
    self._default_levels: Optional[int] = 1

as_attrdict()

Return the representation as an attribute dictionary.

Source code in src/config/configuration.py
194
195
196
197
198
199
200
201
def as_attrdict(self) -> AttributeDict:
    """Return the representation as an attribute dictionary."""
    return AttributeDict(
        {
            x: Configuration(v).as_attrdict() if isinstance(v, Mapping) else v
            for x, v in self.items(levels=1)
        },
    )

as_dict()

Return the representation as a dictionary.

Source code in src/config/configuration.py
190
191
192
def as_dict(self) -> dict:
    """Return the representation as a dictionary."""
    return self._config

base64decode(item)

Get the item value as a Base64 decoded bytes instance.

Parameters:

Name Type Description Default
item str

key

required
Source code in src/config/configuration.py
262
263
264
265
266
267
268
269
270
def base64decode(self, item: str) -> bytes:
    """Get the item value as a Base64 decoded bytes instance.

    Params:
        item: key
    """
    b = self[item]
    b = b if isinstance(b, bytes) else b.encode()
    return base64.b64decode(b, validate=True)

base64encode(item)

Get the item value as a Base64 encoded bytes instance.

Parameters:

Name Type Description Default
item str

key

required
Source code in src/config/configuration.py
252
253
254
255
256
257
258
259
260
def base64encode(self, item: str) -> bytes:
    """Get the item value as a Base64 encoded bytes instance.

    Params:
        item: key
    """
    b = self[item]
    b = b if isinstance(b, bytes) else b.encode()
    return base64.b64encode(b)

clear()

Remove all items.

Source code in src/config/configuration.py
357
358
359
def clear(self) -> None:
    """Remove all items."""
    self._config.clear()

copy()

Return shallow copy.

Source code in src/config/configuration.py
361
362
363
def copy(self) -> "Configuration":
    """Return shallow copy."""
    return Configuration(self._config)

dotted_iter()

Context manager for dotted iteration.

This context manager changes all the iterator-related functions to include every nested (dotted) key instead of just the top level.

Source code in src/config/configuration.py
423
424
425
426
427
428
429
430
431
432
433
434
435
@contextmanager
def dotted_iter(self) -> Iterator["Configuration"]:
    """
    Context manager for dotted iteration.

    This context manager changes all the iterator-related functions
    to include every nested (dotted) key instead of just the top level.
    """
    self._default_levels = None
    try:
        yield self
    finally:
        self._default_levels = 1

get(key, default=None)

Get the configuration values corresponding to key.

Parameters:

Name Type Description Default
key str

key to retrieve.

required
default Any

default value in case the key is missing.

None

Returns:

Type Description
Union[dict, Any]

the value found or a default.

Source code in src/config/configuration.py
178
179
180
181
182
183
184
185
186
187
188
def get(self, key: str, default: Any = None) -> Union[dict, Any]:
    """Get the configuration values corresponding to `key`.

    Params:
        key: key to retrieve.
        default: default value in case the key is missing.

    Returns:
        the value found or a default.
    """
    return self.as_dict().get(key, default)

get_bool(item)

Get the item value as a bool.

Parameters:

Name Type Description Default
item str

key

required
Source code in src/config/configuration.py
203
204
205
206
207
208
209
def get_bool(self, item: str) -> bool:
    """Get the item value as a bool.

    Params:
        item: key
    """
    return as_bool(self[item])

get_dict(item)

Get the item values as a dictionary.

Parameters:

Name Type Description Default
item str

key

required
Source code in src/config/configuration.py
244
245
246
247
248
249
250
def get_dict(self, item: str) -> dict:
    """Get the item values as a dictionary.

    Params:
        item: key
    """
    return dict(self._get_subset(item))

get_float(item)

Get the item value as a float.

Parameters:

Name Type Description Default
item str

key

required
Source code in src/config/configuration.py
228
229
230
231
232
233
234
def get_float(self, item: str) -> float:
    """Get the item value as a float.

    Params:
        item: key
    """
    return float(self[item])

get_int(item)

Get the item value as an int.

Parameters:

Name Type Description Default
item str

key

required
Source code in src/config/configuration.py
220
221
222
223
224
225
226
def get_int(self, item: str) -> int:
    """Get the item value as an int.

    Params:
        item: key
    """
    return int(self[item])

get_list(item)

Get the item value as a list.

Parameters:

Name Type Description Default
item str

key

required
Source code in src/config/configuration.py
236
237
238
239
240
241
242
def get_list(self, item: str) -> List[Any]:
    """Get the item value as a list.

    Params:
        item: key
    """
    return list(self[item])

get_str(item, fmt='{}')

Get the item value as an int.

Parameters:

Name Type Description Default
item str

key

required
fmt str

format to use

'{}'
Source code in src/config/configuration.py
211
212
213
214
215
216
217
218
def get_str(self, item: str, fmt: str = "{}") -> str:
    """Get the item value as an int.

    Params:
        item: key
        fmt: format to use
    """
    return fmt.format(self[item])

items(levels=None)

Return a set-like object providing a view on the configuration items.

Source code in src/config/configuration.py
304
305
306
307
308
309
310
311
312
313
314
315
def items(
    self,
    levels: Optional[int] = None,
) -> Union["Configuration", Any, ItemsView[str, Any]]:
    """Return a set-like object providing a view on the configuration items."""
    assert levels is None or levels > 0
    levels = self._default_levels if levels is None else levels
    try:
        return self["items"]
    except KeyError:
        keys = cast(KeysView[str], self.keys(levels=levels))
        return {k: self._get_subset(k) for k in keys}.items()

keys(levels=None)

Return a set-like object providing a view on the configuration keys.

Source code in src/config/configuration.py
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
def keys(
    self,
    levels: Optional[int] = None,
) -> Union["Configuration", Any, KeysView[str]]:
    """Return a set-like object providing a view on the configuration keys."""
    assert levels is None or levels > 0
    levels = self._default_levels if levels is None else levels
    try:
        return self["keys"]  # don't filter levels, existing attribute
    except KeyError:
        return cast(
            KeysView[str],
            list(
                {
                    ".".join(x.split(".")[:levels])
                    for x in set(self.as_dict().keys())
                },
            ),
        )

pop(prefix, value=None)

Remove keys with the specified prefix and return the corresponding value.

If the prefix is not found a KeyError is raised.

Source code in src/config/configuration.py
365
366
367
368
369
370
371
372
373
374
375
376
def pop(self, prefix: str, value: Any = None) -> Any:
    """Remove keys with the specified prefix and return the corresponding value.

    If the prefix is not found a KeyError is raised.
    """
    try:
        value = self[prefix]
        del self[prefix]
    except KeyError:
        if value is None:
            raise
    return value

reload()

Reload the configuration.

This method is not implemented for simple Configuration objects and is intended only to be used in subclasses.

Source code in src/config/configuration.py
393
394
395
396
397
398
399
def reload(self) -> None:  # pragma: no cover
    """Reload the configuration.

    This method is not implemented for simple Configuration objects and is
    intended only to be used in subclasses.
    """
    raise NotImplementedError()

setdefault(key, default=None)

Insert key with a value of default if key is not in the Configuration.

Return the value for key if key is in the Configuration, else default.

Source code in src/config/configuration.py
378
379
380
381
382
383
384
385
386
387
def setdefault(self, key: str, default: Any = None) -> Any:
    """Insert key with a value of default if key is not in the Configuration.

    Return the value for key if key is in the Configuration, else default.
    """
    try:
        return self[key]
    except KeyError:
        self[key] = default
    return self[key]

update(other)

Update the Configuration with another Configuration object or Mapping.

Source code in src/config/configuration.py
389
390
391
def update(self, other: Mapping[str, Any]) -> None:
    """Update the Configuration with another Configuration object or Mapping."""
    self._config.update(self._flatten_dict(other))

validate(schema, raise_on_error=False, nested=False, **kwargs)

Validate the current config using JSONSchema.

Source code in src/config/configuration.py
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
def validate(
    self,
    schema: Any,
    raise_on_error: bool = False,
    nested: bool = False,
    **kwargs: Mapping[str, Any],
) -> bool:
    """Validate the current config using JSONSchema."""
    try:
        from jsonschema import ValidationError, validate
    except ImportError:  # pragma: no cover
        raise RuntimeError(
            "Validation requires the `jsonschema` library.",
        ) from None
    try:
        validate(self.as_attrdict() if nested else self.as_dict(), schema, **kwargs)
    except ValidationError as err:
        if raise_on_error:
            raise err
        return False
    return True

values(levels=None)

Return a set-like object providing a view on the configuration values.

Source code in src/config/configuration.py
292
293
294
295
296
297
298
299
300
301
302
def values(
    self,
    levels: Optional[int] = None,
) -> Union["Configuration", Any, ValuesView[Any]]:
    """Return a set-like object providing a view on the configuration values."""
    assert levels is None or levels > 0
    levels = self._default_levels if levels is None else levels
    try:
        return self["values"]
    except KeyError:
        return dict(self.items(levels=levels)).values()

ConfigurationSet class.

ConfigurationSet

Bases: Configuration

Configuration Sets.

A class that combines multiple Configuration instances in a hierarchical manner.

Source code in src/config/configuration_set.py
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
class ConfigurationSet(Configuration):
    """Configuration Sets.

    A class that combines multiple [Configuration][config.configuration.Configuration]
    instances in a hierarchical manner.
    """

    def __init__(
        self,
        *configs: Configuration,
        interpolate: InterpolateType = False,
        interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
    ):  # noqa: D107
        """Class Constructor."""
        self._interpolate = {} if interpolate is True else interpolate
        self._interpolate_type = interpolate_type
        try:
            self._configs: List[Configuration] = list(configs)
        except Exception:  # pragma: no cover
            raise ValueError(
                "configs should be a non-empty iterable of Configuration objects",
            ) from None
        if not self._configs:  # pragma: no cover
            raise ValueError(
                "configs should be a non-empty iterable of Configuration objects",
            )
        if not all(
            isinstance(x, Configuration) for x in self._configs
        ):  # pragma: no cover
            raise ValueError(
                "configs should be a non-empty iterable of Configuration objects",
            )
        self._writable = False
        self._default_levels = 1

    def _from_configs(self, attr: str, *args: Any, **kwargs: dict) -> Any:
        last_err = Exception()
        values = []
        for config_ in self._configs:
            try:
                values.append(getattr(config_, attr)(*args, **kwargs))
            except Exception as err:
                last_err = err
                continue
        if not values:
            # raise the last error
            raise last_err
        if all(isinstance(v, Configuration) for v in values):
            result: dict = {}
            for v in values[::-1]:
                result.update(v.as_dict())
            return Configuration(result)
        elif isinstance(values[0], Configuration):
            result = {}
            for v in values[::-1]:
                if not isinstance(v, Configuration):
                    continue
                result.update(v)
            return Configuration(result)
        elif self._interpolate is not False:
            d = [d.as_dict() for d in self._configs]
            d[0].update(self._interpolate)
            return interpolate_object(args[0], values[0], d, self._interpolate_type)
        else:
            return values[0]

    def _writable_config(self) -> Configuration:
        if not self._writable:
            lowercase = bool(self._configs and self._configs[0]._lowercase)
            self._configs.insert(0, Configuration({}, lowercase_keys=lowercase))
            self._writable = True
        return self._configs[0]

    @property
    def configs(self) -> List[Configuration]:
        """List of underlying configuration objects."""
        if self._writable:
            return self._configs[1:]
        else:
            return list(self._configs)

    @configs.setter
    def configs(self, iterable: Iterable[Configuration]) -> None:
        if self._writable:
            self._configs = [self._configs[0]] + list(iterable)
        else:
            self._configs = list(iterable)

    def __getitem__(self, item: str) -> Union[Configuration, Any]:  # noqa: D105
        return self._from_configs("__getitem__", item)

    def __getattr__(self, item: str) -> Union[Configuration, Any]:  # noqa: D105
        return self._from_configs("__getattr__", item)

    def get(self, key: str, default: Any = None) -> Union[dict, Any]:
        """Get the configuration values corresponding to `key`.

        Params:
            key: key to retrieve.
            default: default value in case the key is missing.

        Returns:
            the value found or a default
        """
        try:
            return self[key]
        except Exception:
            return default

    def as_dict(self) -> dict:
        """Return the representation as a dictionary."""
        result = {}
        for config_ in self._configs[::-1]:
            result.update(config_.as_dict())
        return result

    def get_dict(self, item: str) -> dict:
        """Get the item values as a dictionary.

        item: key
        """
        return Configuration(dict(dict(self[item]).items())).as_dict()

    def keys(
        self,
        levels: Optional[int] = None,
    ) -> Union["Configuration", Any, KeysView[str]]:
        """Return a set-like object providing a view on the configuration keys."""
        if self._default_levels:
            return Configuration(self.as_dict()).keys(levels or self._default_levels)
        with Configuration(self.as_dict()).dotted_iter() as cfg:
            return cfg.keys(levels)

    def values(
        self,
        levels: Optional[int] = None,
    ) -> Union["Configuration", Any, ValuesView[Any]]:
        """Return a set-like object providing a view on the configuration values."""
        if self._default_levels:
            return Configuration(self.as_dict()).values(levels or self._default_levels)
        with Configuration(self.as_dict()).dotted_iter() as cfg:
            return cfg.values(levels)

    def items(
        self,
        levels: Optional[int] = None,
    ) -> Union["Configuration", Any, ItemsView[str, Any]]:
        """Return a set-like object providing a view on the configuration items."""
        if self._default_levels:
            return Configuration(self.as_dict()).items(levels or self._default_levels)
        with Configuration(self.as_dict()).dotted_iter() as cfg:
            return cfg.items(levels)

    def __setitem__(self, key: str, value: Any) -> None:  # noqa: D105
        cfg = self._writable_config()
        cfg[key] = value

    def __delitem__(self, prefix: str) -> None:  # noqa: D105
        removed = False
        for cfg in self._configs:
            try:
                del cfg[prefix]
                removed = True
            except KeyError:
                continue
        if not removed:
            raise KeyError()

    def __contains__(self, prefix: str) -> bool:  # noqa: D105
        return any(prefix in cfg for cfg in self._configs)

    def clear(self) -> None:
        """Remove all items."""
        for cfg in self._configs:
            cfg.clear()

    def copy(self) -> "Configuration":
        """Return shallow copy."""
        return ConfigurationSet(*self._configs)

    def update(self, other: Mapping[str, Any]) -> None:
        """Update the ConfigurationSet with another Configuration object or Mapping."""
        cfg = self._writable_config()
        cfg.update(other)

    def reload(self) -> None:
        """Reload the underlying configuration instances."""
        for cfg in self._configs:
            with contextlib.suppress(NotImplementedError):
                cfg.reload()

    def __repr__(self) -> str:  # noqa: D105
        return "<ConfigurationSet: %s>" % hex(id(self))

    def __str__(self) -> str:  # noqa: D105
        return str({k: clean(k, v) for k, v in sorted(self.as_dict().items())})

configs: List[Configuration] property writable

List of underlying configuration objects.

__init__(*configs, interpolate=False, interpolate_type=InterpolateEnumType.STANDARD)

Class Constructor.

Source code in src/config/configuration_set.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
def __init__(
    self,
    *configs: Configuration,
    interpolate: InterpolateType = False,
    interpolate_type: InterpolateEnumType = InterpolateEnumType.STANDARD,
):  # noqa: D107
    """Class Constructor."""
    self._interpolate = {} if interpolate is True else interpolate
    self._interpolate_type = interpolate_type
    try:
        self._configs: List[Configuration] = list(configs)
    except Exception:  # pragma: no cover
        raise ValueError(
            "configs should be a non-empty iterable of Configuration objects",
        ) from None
    if not self._configs:  # pragma: no cover
        raise ValueError(
            "configs should be a non-empty iterable of Configuration objects",
        )
    if not all(
        isinstance(x, Configuration) for x in self._configs
    ):  # pragma: no cover
        raise ValueError(
            "configs should be a non-empty iterable of Configuration objects",
        )
    self._writable = False
    self._default_levels = 1

as_dict()

Return the representation as a dictionary.

Source code in src/config/configuration_set.py
129
130
131
132
133
134
def as_dict(self) -> dict:
    """Return the representation as a dictionary."""
    result = {}
    for config_ in self._configs[::-1]:
        result.update(config_.as_dict())
    return result

clear()

Remove all items.

Source code in src/config/configuration_set.py
191
192
193
194
def clear(self) -> None:
    """Remove all items."""
    for cfg in self._configs:
        cfg.clear()

copy()

Return shallow copy.

Source code in src/config/configuration_set.py
196
197
198
def copy(self) -> "Configuration":
    """Return shallow copy."""
    return ConfigurationSet(*self._configs)

get(key, default=None)

Get the configuration values corresponding to key.

Parameters:

Name Type Description Default
key str

key to retrieve.

required
default Any

default value in case the key is missing.

None

Returns:

Type Description
Union[dict, Any]

the value found or a default

Source code in src/config/configuration_set.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def get(self, key: str, default: Any = None) -> Union[dict, Any]:
    """Get the configuration values corresponding to `key`.

    Params:
        key: key to retrieve.
        default: default value in case the key is missing.

    Returns:
        the value found or a default
    """
    try:
        return self[key]
    except Exception:
        return default

get_dict(item)

Get the item values as a dictionary.

item: key

Source code in src/config/configuration_set.py
136
137
138
139
140
141
def get_dict(self, item: str) -> dict:
    """Get the item values as a dictionary.

    item: key
    """
    return Configuration(dict(dict(self[item]).items())).as_dict()

items(levels=None)

Return a set-like object providing a view on the configuration items.

Source code in src/config/configuration_set.py
163
164
165
166
167
168
169
170
171
def items(
    self,
    levels: Optional[int] = None,
) -> Union["Configuration", Any, ItemsView[str, Any]]:
    """Return a set-like object providing a view on the configuration items."""
    if self._default_levels:
        return Configuration(self.as_dict()).items(levels or self._default_levels)
    with Configuration(self.as_dict()).dotted_iter() as cfg:
        return cfg.items(levels)

keys(levels=None)

Return a set-like object providing a view on the configuration keys.

Source code in src/config/configuration_set.py
143
144
145
146
147
148
149
150
151
def keys(
    self,
    levels: Optional[int] = None,
) -> Union["Configuration", Any, KeysView[str]]:
    """Return a set-like object providing a view on the configuration keys."""
    if self._default_levels:
        return Configuration(self.as_dict()).keys(levels or self._default_levels)
    with Configuration(self.as_dict()).dotted_iter() as cfg:
        return cfg.keys(levels)

reload()

Reload the underlying configuration instances.

Source code in src/config/configuration_set.py
205
206
207
208
209
def reload(self) -> None:
    """Reload the underlying configuration instances."""
    for cfg in self._configs:
        with contextlib.suppress(NotImplementedError):
            cfg.reload()

update(other)

Update the ConfigurationSet with another Configuration object or Mapping.

Source code in src/config/configuration_set.py
200
201
202
203
def update(self, other: Mapping[str, Any]) -> None:
    """Update the ConfigurationSet with another Configuration object or Mapping."""
    cfg = self._writable_config()
    cfg.update(other)

values(levels=None)

Return a set-like object providing a view on the configuration values.

Source code in src/config/configuration_set.py
153
154
155
156
157
158
159
160
161
def values(
    self,
    levels: Optional[int] = None,
) -> Union["Configuration", Any, ValuesView[Any]]:
    """Return a set-like object providing a view on the configuration values."""
    if self._default_levels:
        return Configuration(self.as_dict()).values(levels or self._default_levels)
    with Configuration(self.as_dict()).dotted_iter() as cfg:
        return cfg.values(levels)