• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

andgineer / api-db-prototype / 8766121206

20 Apr 2024 03:45PM UTC coverage: 83.956% (-2.9%) from 86.892%
8766121206

push

github

andgineer
upgrade reqs

2 of 2 new or added lines in 2 files covered. (100.0%)

89 existing lines in 23 files now uncovered.

1057 of 1259 relevant lines covered (83.96%)

0.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.18
/src/settings.py
1
import contextlib
1✔
2
import datetime
1✔
3
import os
1✔
4
import tempfile
1✔
5
import urllib.parse
1✔
6
from abc import abstractmethod
1✔
7
from datetime import timezone
1✔
8
from typing import Any, Optional
1✔
9
from unittest.mock import MagicMock
1✔
10

11
import journaling
1✔
12
from flask_server.api_app import app as flask_app
1✔
13
from openapi_server.api_app import app as connexion_app
1✔
14

15
# environment vars
16
DB_URI_ENV = "DB_URI"  # env var for DB URI (see ConfigBase.db_uri)
1✔
17
PORT_ENV = "API_PORT"  # env var for app port, default in DEFAULT_PORT
1✔
18
AUTO_DB_META_ENV = "AUTO_DB_META"  # env var, if 1 then server at start
1✔
19
# refresh DB metadata (create tables if necessary)
20

21
# const used for prod config
22
DEFAULT_PORT = 5000
1✔
23
TOKEN_EXPIRATION_HOURS = 48  # jwt lifetime
1✔
24
DEFAULT_ADMIN_EMAIL = "admin@"
1✔
25
DEFAULT_ADMIN_PASSWORD = "admin"
1✔
26
PRIVATE_JWT_KEY_FILE = "secret/jwt_private.key"
1✔
27
PUBLIC_JWT_KEY_FILE = "secret/jwt_certificate.pem"
1✔
28

29
# todo tests injections - dirty and better not be inside production code
30
TEST_LOG_CONFIG_FILE_PATH = "tests/resources/logging.yaml"
1✔
31

32

33
class ConfigBase:
1✔
34
    """Base class for config."""
35

36
    debug_mode = False
1✔
37
    jwt_secret_key_file: Optional[str] = None
1✔
38
    jwt_public_key_file: Optional[str] = None
1✔
39

40
    token_expiration_delta = datetime.timedelta(hours=TOKEN_EXPIRATION_HOURS)
1✔
41

42
    default_admin_email = DEFAULT_ADMIN_EMAIL
1✔
43
    default_admin_password = DEFAULT_ADMIN_PASSWORD
1✔
44

45
    web_enableCrossOriginRequests = False
1✔
46

47
    _port: str = str(DEFAULT_PORT)
1✔
48
    _db_uri: Optional[str] = None
1✔
49

50
    db_autometa = True  # refresh DB metadata at start
1✔
51
    db_sqltrace = False
1✔
52
    profiler_cprofile = True  # activates profiling.py#analyze() context manager
1✔
53

54
    api_host: Optional[str] = None
1✔
55
    api_root = ""
1✔
56

57
    aws_region = "us-east-1"
1✔
58

59
    def __init__(self, log_config: Optional[str] = None):
1✔
60
        """Init config."""
61
        journaling.setup(log_config)
1✔
62

63
    @property
1✔
64
    def api_url(self) -> str:
1✔
65
        """API url."""
66
        return urllib.parse.urljoin(self.api_host, self.api_root)  # type: ignore
1✔
67

68
    @property
1✔
69
    @abstractmethod
1✔
70
    def app(self) -> Any:
1✔
71
        """Flask-compatible App server."""
72

73
    @property
1✔
74
    def db_uri(self) -> str:
1✔
75
        """DB URI: engine://user:password@path.
76

77
        For example:
78
            postgres://user@example.com/template1
79
            sqlite:////data/test.sqlite
80
        """
81
        if self._db_uri:
1✔
82
            return self._db_uri
1✔
83
        raise ValueError("No DB URI specified")
1✔
84

85
    @db_uri.setter
1✔
86
    def db_uri(self, value: str) -> None:
1✔
87
        """DB URI."""
88
        self._db_uri = value
1✔
89

90
    @property
1✔
91
    def port(self) -> str:
1✔
92
        """App port."""
93
        return self._port
×
94

95
    @port.setter
1✔
96
    def port(self, value: str) -> None:
1✔
97
        """App port."""
UNCOV
98
        self._port = value
×
99

100
    @staticmethod
1✔
101
    def now() -> datetime.datetime:
1✔
102
        """To have one place to decide whether we use utc or server timezone.
103

104
        And for ease of mocking in expiration tests.
105
        """
106
        return datetime.datetime.now(timezone.utc)
1✔
107

108
    def from_date_str(self, date_str: str) -> datetime.datetime:
1✔
109
        """Convert date string into datetime."""
UNCOV
110
        return self.rfc3339_to_date(date_str)
×
111

112
    @staticmethod
1✔
113
    def date_to_rfc3339(date: datetime.datetime) -> str:
1✔
114
        """Date as 'yyyy-mm-dd'."""
115
        return date.isoformat(sep="T").split("T")[0]
1✔
116

117
    @staticmethod
1✔
118
    def rfc3339_to_date(date_str: str) -> datetime.datetime:
1✔
119
        """'yyyy-mm-dd' (UTC) to datetime."""
120
        return datetime.datetime.strptime(date_str, "%Y-%m-%d").replace(tzinfo=timezone.utc)
1✔
121

122

123
class ConfigTest(ConfigBase):
1✔
124
    """Creates temp sqlite db."""
125

126
    debug_mode = True
1✔
127

128
    def __init__(self) -> None:
1✔
129
        """Init."""
130
        super().__init__(TEST_LOG_CONFIG_FILE_PATH)
1✔
131
        self.db_file_object, self.db_file_name = tempfile.mkstemp()
1✔
132
        self.db_uri = f"sqlite:///{self.db_file_name}"
1✔
133
        self.jwt_public_key_file = "src/secret/jwt_certificate.pem"
1✔
134
        self.jwt_secret_key_file = "src/secret/jwt_private.key"
1✔
135
        self.api_host = "http://localhost:5000"
1✔
136

137
    def __del__(self) -> None:
1✔
138
        """Remove temp db file."""
139
        if os is not None:
1✔
140
            with contextlib.suppress(PermissionError):
1✔
141
                os.close(self.db_file_object)
1✔
142
                os.remove(self.db_file_name)
1✔
143

144
    @property
1✔
145
    def app(self) -> Any:
1✔
146
        """Flask-compatible App server."""
147
        return MagicMock()
1✔
148

149

150
class ConfigTestPureFlask(ConfigTest):
1✔
151
    """Creates temp sqlite db."""
152

153
    @property
1✔
154
    def app(self) -> Any:
1✔
155
        """Flask-compatible App server."""
156
        return flask_app
1✔
157

158

159
class ConfigTestConnexion(ConfigTest):
1✔
160
    """Creates temp sqlite db."""
161

162
    @property
1✔
163
    def app(self) -> Any:
1✔
164
        """Flask-compatible App server."""
165
        return connexion_app
1✔
166

167

168
class ConfigDev(ConfigBase):
1✔
169
    """Development environment.
170

171
    Local sqlite DB.
172
    """
173

174
    debug_mode = True
1✔
175

176
    def __init__(self) -> None:
1✔
177
        """Init."""
UNCOV
178
        super().__init__()
×
UNCOV
179
        self.db_uri = "sqlite:///../debug_db.sqlite"
×
UNCOV
180
        self.jwt_public_key_file = PUBLIC_JWT_KEY_FILE
×
UNCOV
181
        self.jwt_secret_key_file = PRIVATE_JWT_KEY_FILE
×
182

183
    @property
1✔
184
    def app(self) -> Any:
1✔
185
        """Flask-compatible App server."""
186
        return flask_app
×
187

188

189
class ConfigProd(ConfigBase):
1✔
190
    """Production."""
191

192
    def __init__(self) -> None:
1✔
193
        """Init."""
194
        super().__init__()
×
195
        self.db_uri = os.environ.get(DB_URI_ENV, "sqlite:///../debug_db.sqlite")
×
196
        self.port = os.environ.get(PORT_ENV, self.port)
×
197
        self.auto_db_meta = int(os.environ.get(AUTO_DB_META_ENV, 0))
×
198
        self.jwt_public_key_file = PUBLIC_JWT_KEY_FILE
×
199
        self.jwt_secret_key_file = PRIVATE_JWT_KEY_FILE
×
200
        self.api_host = "https://example.com"
×
201

202
    @property
1✔
203
    def app(self) -> Any:
1✔
204
        """Flask-compatible App server."""
UNCOV
205
        return connexion_app
×
206

207

208
class ConfigTestWrong(ConfigBase):
1✔
209
    """To test wrong config."""
210

211
    @property
1✔
212
    def app(self) -> Any:
1✔
213
        """Flask-compatible App server."""
UNCOV
214
        return flask_app
×
215

216

217
config: Optional[ConfigBase] = None  # Convenient config injection
1✔
218
# app is responsible to populate this var with config object
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc