aboutsummaryrefslogtreecommitdiff
path: root/configlib/model.py
blob: 0bc94e10b74acb1b29805c46f8e9c86a327f4da6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
"""
Abstract models and classes for the config

"""

import json
import os
from abc import abstractmethod, ABC
from typing import Type, Union, AnyStr, TextIO

from configlib.util import snake_case


class InvalidConfigEscapeException(Exception):
    """
    Some config uses an invalid escape like `$invalidescapecode:argument`
    """


class InvalidConfigTypingException(Exception):
    """
    The typing found in the given class is missing arguments.
    Example:

    >>> import typing
    >>> someting: typing.List[str, int]

    is illegal since :class:`typing.List` only takes one argument.
    """


class ConfigValueMissingException(Exception):
    """
    The given config file is missing an argument
    """


class Config(ABC):
    """
    Base class for a Config. Do NOT extend this. use :class:`configlib.BaseConfig` instead.

    """

    @classmethod
    @abstractmethod
    def get_name(cls) -> str:
        """
        Get the name for a config

        :return: the name
        """

    @classmethod
    @abstractmethod
    def parse_dict(cls: Type['Config'], data: dict) -> 'Config':
        """
        For the given data return the config instance.

        :param data: the loaded data dict
        :return: a loaded config
        """

    @classmethod
    def load(cls: Type['Config'], file: Union[AnyStr, TextIO]) -> 'Config':
        """
        Load a specified config file

        :param file: the file object or file path
        :return: the parsed config according to :func:`.parse_dict`
        """
        if hasattr(file, 'read'):
            return cls.loads(file.read())
        with open(file) as file_pointer:
            return cls.load(file_pointer)

    @classmethod
    def loads(cls: Type['Config'], text: str) -> 'Config':
        """
        Load data from text

        :param text: the text data
        :return: the parsed config
        """
        return cls.parse_dict(json.loads(text))

    @classmethod
    def get_instance(cls: Type['Config']) -> 'Config':
        """
        get a Config instance according to the matching environment variable

        :return: the parsed config
        """
        name = os.environ.get(snake_case(cls.get_name()), '').strip()
        return cls.get_instance_for_env(name)

    @classmethod
    def get_instance_for_env(cls: Type['Config'], env: str) -> 'Config':
        """
        get a Config instance for a given environment

        :param env: the wanted environment
        :return: the parsed config
        """
        if env:
            env = '-' + env
        return cls.load('config/' + snake_case(cls.get_name()) + env + '.json')