looker-sdk 24.16.2__py3-none-any.whl → 24.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- looker_sdk/version.py +1 -1
- {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/METADATA +1 -1
- looker_sdk-24.18.0.dist-info/RECORD +9 -0
- {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/top_level.txt +0 -1
- looker_sdk/rtl/__init__.py +0 -22
- looker_sdk/rtl/api_methods.py +0 -247
- looker_sdk/rtl/api_settings.py +0 -194
- looker_sdk/rtl/auth_session.py +0 -353
- looker_sdk/rtl/auth_token.py +0 -101
- looker_sdk/rtl/constants.py +0 -31
- looker_sdk/rtl/hooks.py +0 -86
- looker_sdk/rtl/model.py +0 -230
- looker_sdk/rtl/requests_transport.py +0 -110
- looker_sdk/rtl/serialize.py +0 -120
- looker_sdk/rtl/transport.py +0 -137
- looker_sdk/sdk/__init__.py +0 -0
- looker_sdk/sdk/api40/__init__.py +0 -1
- looker_sdk/sdk/api40/methods.py +0 -13283
- looker_sdk/sdk/api40/models.py +0 -15641
- looker_sdk/sdk/constants.py +0 -24
- looker_sdk-24.16.2.dist-info/RECORD +0 -38
- tests/__init__.py +0 -0
- tests/conftest.py +0 -133
- tests/integration/__init__.py +0 -2
- tests/integration/test_methods.py +0 -681
- tests/integration/test_netrc.py +0 -55
- tests/rtl/__init__.py +0 -2
- tests/rtl/test_api_methods.py +0 -216
- tests/rtl/test_api_settings.py +0 -252
- tests/rtl/test_auth_session.py +0 -284
- tests/rtl/test_auth_token.py +0 -70
- tests/rtl/test_requests_transport.py +0 -171
- tests/rtl/test_serialize.py +0 -770
- tests/rtl/test_transport.py +0 -34
- {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/LICENSE.txt +0 -0
- {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/WHEEL +0 -0
looker_sdk/version.py
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
looker_sdk/__init__.py,sha256=0UOw2v-BP1bNoBIIm-BnyKUpGQB3Zx-JZRmpYyLiIuY,2589
|
|
2
|
+
looker_sdk/error.py,sha256=XTKuy1zEyhSVd-VCWHKB2zVjj0X7VUzVwq9y9L22Bo0,4941
|
|
3
|
+
looker_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
looker_sdk/version.py,sha256=yXV-fBxVicsLoKDd9IOghQocwVxB_xDkPB65URlYiF0,1156
|
|
5
|
+
looker_sdk-24.18.0.dist-info/LICENSE.txt,sha256=N4Rmmbuo5EryYSCXcvjuXL1ZXwyXanRzuGP-dJzwsoE,1094
|
|
6
|
+
looker_sdk-24.18.0.dist-info/METADATA,sha256=dICNCD4P_hznPEaK-jOitIUoitWyMiFR91ufqVT7HP0,7022
|
|
7
|
+
looker_sdk-24.18.0.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
|
8
|
+
looker_sdk-24.18.0.dist-info/top_level.txt,sha256=xviIw22PmtLgfOpj_Hhv_CyPTEHXPD3dJdzYTlloICU,11
|
|
9
|
+
looker_sdk-24.18.0.dist-info/RECORD,,
|
looker_sdk/rtl/__init__.py
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# The MIT License (MIT)
|
|
2
|
-
#
|
|
3
|
-
# Copyright (c) 2019 Looker Data Sciences, Inc.
|
|
4
|
-
#
|
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
# furnished to do so, subject to the following conditions:
|
|
11
|
-
#
|
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
|
13
|
-
# all copies or substantial portions of the Software.
|
|
14
|
-
#
|
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
# THE SOFTWARE.
|
|
22
|
-
|
looker_sdk/rtl/api_methods.py
DELETED
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
# The MIT License (MIT)
|
|
2
|
-
#
|
|
3
|
-
# Copyright (c) 2019 Looker Data Sciences, Inc.
|
|
4
|
-
#
|
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
# furnished to do so, subject to the following conditions:
|
|
11
|
-
#
|
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
|
13
|
-
# all copies or substantial portions of the Software.
|
|
14
|
-
#
|
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
# THE SOFTWARE.
|
|
22
|
-
|
|
23
|
-
"""Functionality for making authenticated API calls
|
|
24
|
-
"""
|
|
25
|
-
import datetime
|
|
26
|
-
import json
|
|
27
|
-
from typing import Any, MutableMapping, Optional, Sequence, Type, Union
|
|
28
|
-
import urllib.parse
|
|
29
|
-
|
|
30
|
-
from looker_sdk import error
|
|
31
|
-
from looker_sdk.rtl import model
|
|
32
|
-
from looker_sdk.rtl import serialize
|
|
33
|
-
from looker_sdk.rtl import transport
|
|
34
|
-
from looker_sdk.rtl import auth_session
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
TBody = Optional[
|
|
38
|
-
Union[
|
|
39
|
-
str,
|
|
40
|
-
MutableMapping[str, str],
|
|
41
|
-
Sequence[str],
|
|
42
|
-
Sequence[int],
|
|
43
|
-
model.Model,
|
|
44
|
-
Sequence[model.Model],
|
|
45
|
-
]
|
|
46
|
-
]
|
|
47
|
-
TStructure = Optional[Union[Any, Type[str], serialize.TStructure]]
|
|
48
|
-
TReturn = Optional[Union[str, bytes, serialize.TDeserializeReturn]]
|
|
49
|
-
TQueryParams = MutableMapping[
|
|
50
|
-
str, Union[None, bool, str, int, Sequence[int], Sequence[str], datetime.datetime]
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class APIMethods:
|
|
55
|
-
"""Functionality for making authenticated API calls"""
|
|
56
|
-
|
|
57
|
-
def __init__(
|
|
58
|
-
self,
|
|
59
|
-
auth: auth_session.AuthSession,
|
|
60
|
-
deserialize: serialize.TDeserialize,
|
|
61
|
-
serialize: serialize.TSerialize,
|
|
62
|
-
transport: transport.Transport,
|
|
63
|
-
api_version: str,
|
|
64
|
-
):
|
|
65
|
-
self.auth = auth
|
|
66
|
-
self.api_path = urllib.parse.urljoin(
|
|
67
|
-
auth.settings.base_url, f"/api/{api_version}/"
|
|
68
|
-
)
|
|
69
|
-
self.deserialize = deserialize
|
|
70
|
-
self.serialize = serialize
|
|
71
|
-
self.transport = transport
|
|
72
|
-
|
|
73
|
-
def _path(self, path: str) -> str:
|
|
74
|
-
if path[0] == "/":
|
|
75
|
-
path = path[1:]
|
|
76
|
-
return urllib.parse.urljoin(self.api_path, path)
|
|
77
|
-
|
|
78
|
-
def __enter__(self) -> "APIMethods":
|
|
79
|
-
return self
|
|
80
|
-
|
|
81
|
-
def __exit__(self, *exc) -> None:
|
|
82
|
-
self.auth.logout()
|
|
83
|
-
|
|
84
|
-
def _return(self, response: transport.Response, structure: TStructure) -> TReturn:
|
|
85
|
-
encoding = response.encoding
|
|
86
|
-
if not response.ok:
|
|
87
|
-
value = response.value.decode(encoding=encoding)
|
|
88
|
-
sdk_error: error.SDKError
|
|
89
|
-
try:
|
|
90
|
-
sdk_error = self.deserialize(data=value, structure=error.SDKError) # type: ignore
|
|
91
|
-
helper = error.ErrorDocHelper()
|
|
92
|
-
(sdk_error.error_doc_url, sdk_error.error_doc) = (
|
|
93
|
-
helper.parse_and_lookup(sdk_error.documentation_url)
|
|
94
|
-
)
|
|
95
|
-
for e in sdk_error.errors:
|
|
96
|
-
(e.error_doc_url, e.error_doc) = helper.parse_and_lookup(
|
|
97
|
-
e.documentation_url
|
|
98
|
-
)
|
|
99
|
-
except serialize.DeserializeError:
|
|
100
|
-
raise error.SDKError(value)
|
|
101
|
-
raise sdk_error
|
|
102
|
-
ret: TReturn
|
|
103
|
-
if structure is None:
|
|
104
|
-
ret = None
|
|
105
|
-
elif response.response_mode == transport.ResponseMode.BINARY:
|
|
106
|
-
ret = response.value
|
|
107
|
-
else:
|
|
108
|
-
value = response.value.decode(encoding=encoding)
|
|
109
|
-
if structure is Union[str, bytes] or structure is str or value == "": # type: ignore
|
|
110
|
-
ret = value
|
|
111
|
-
else:
|
|
112
|
-
# ignore type: mypy bug doesn't recognized kwarg
|
|
113
|
-
# `structure` to partial func
|
|
114
|
-
ret = self.deserialize(data=value, structure=structure) # type: ignore
|
|
115
|
-
return ret
|
|
116
|
-
|
|
117
|
-
def _convert_query_params(
|
|
118
|
-
self, query_params: TQueryParams
|
|
119
|
-
) -> MutableMapping[str, str]:
|
|
120
|
-
params: MutableMapping[str, str] = {}
|
|
121
|
-
for k, v in query_params.items():
|
|
122
|
-
if v is None:
|
|
123
|
-
continue
|
|
124
|
-
if isinstance(v, datetime.datetime):
|
|
125
|
-
params[k] = f'{v.isoformat(timespec="minutes")}Z'
|
|
126
|
-
elif isinstance(v, str):
|
|
127
|
-
params[k] = v
|
|
128
|
-
elif isinstance(v, model.DelimSequence):
|
|
129
|
-
params[k] = str(v)
|
|
130
|
-
else:
|
|
131
|
-
params[k] = json.dumps(v)
|
|
132
|
-
return params
|
|
133
|
-
|
|
134
|
-
@staticmethod
|
|
135
|
-
def encode_path_param(value: str) -> str:
|
|
136
|
-
if value == urllib.parse.unquote(value):
|
|
137
|
-
value = urllib.parse.quote(value, safe="")
|
|
138
|
-
return value
|
|
139
|
-
|
|
140
|
-
def get(
|
|
141
|
-
self,
|
|
142
|
-
path: str,
|
|
143
|
-
structure: TStructure,
|
|
144
|
-
query_params: Optional[TQueryParams] = None,
|
|
145
|
-
transport_options: Optional[transport.TransportOptions] = None,
|
|
146
|
-
) -> TReturn:
|
|
147
|
-
"""GET method"""
|
|
148
|
-
params = self._convert_query_params(query_params) if query_params else None
|
|
149
|
-
response = self.transport.request(
|
|
150
|
-
transport.HttpMethod.GET,
|
|
151
|
-
self._path(path),
|
|
152
|
-
query_params=params,
|
|
153
|
-
body=None,
|
|
154
|
-
authenticator=self.auth.authenticate,
|
|
155
|
-
transport_options=transport_options,
|
|
156
|
-
)
|
|
157
|
-
return self._return(response, structure)
|
|
158
|
-
|
|
159
|
-
def _get_serialized(self, body: TBody) -> Optional[bytes]:
|
|
160
|
-
serialized: Optional[bytes]
|
|
161
|
-
if isinstance(body, str):
|
|
162
|
-
serialized = body.encode("utf-8")
|
|
163
|
-
elif isinstance(body, (list, dict, model.Model)):
|
|
164
|
-
serialized = self.serialize(api_model=body) # type: ignore
|
|
165
|
-
else:
|
|
166
|
-
serialized = None
|
|
167
|
-
return serialized
|
|
168
|
-
|
|
169
|
-
def post(
|
|
170
|
-
self,
|
|
171
|
-
path: str,
|
|
172
|
-
structure: TStructure,
|
|
173
|
-
query_params: Optional[TQueryParams] = None,
|
|
174
|
-
body: TBody = None,
|
|
175
|
-
transport_options: Optional[transport.TransportOptions] = None,
|
|
176
|
-
) -> TReturn:
|
|
177
|
-
"""POST method"""
|
|
178
|
-
params = self._convert_query_params(query_params) if query_params else None
|
|
179
|
-
serialized = self._get_serialized(body)
|
|
180
|
-
response = self.transport.request(
|
|
181
|
-
transport.HttpMethod.POST,
|
|
182
|
-
self._path(path),
|
|
183
|
-
query_params=params,
|
|
184
|
-
body=serialized,
|
|
185
|
-
authenticator=self.auth.authenticate,
|
|
186
|
-
transport_options=transport_options,
|
|
187
|
-
)
|
|
188
|
-
return self._return(response, structure)
|
|
189
|
-
|
|
190
|
-
def patch(
|
|
191
|
-
self,
|
|
192
|
-
path: str,
|
|
193
|
-
structure: TStructure,
|
|
194
|
-
query_params: Optional[TQueryParams] = None,
|
|
195
|
-
body: TBody = None,
|
|
196
|
-
transport_options: Optional[transport.TransportOptions] = None,
|
|
197
|
-
) -> TReturn:
|
|
198
|
-
"""PATCH method"""
|
|
199
|
-
params = self._convert_query_params(query_params) if query_params else None
|
|
200
|
-
serialized = self._get_serialized(body)
|
|
201
|
-
response = self.transport.request(
|
|
202
|
-
transport.HttpMethod.PATCH,
|
|
203
|
-
self._path(path),
|
|
204
|
-
query_params=params,
|
|
205
|
-
body=serialized,
|
|
206
|
-
authenticator=self.auth.authenticate,
|
|
207
|
-
transport_options=transport_options,
|
|
208
|
-
)
|
|
209
|
-
return self._return(response, structure)
|
|
210
|
-
|
|
211
|
-
def put(
|
|
212
|
-
self,
|
|
213
|
-
path: str,
|
|
214
|
-
structure: TStructure = None,
|
|
215
|
-
query_params: Optional[TQueryParams] = None,
|
|
216
|
-
body: TBody = None,
|
|
217
|
-
transport_options: Optional[transport.TransportOptions] = None,
|
|
218
|
-
) -> TReturn:
|
|
219
|
-
"""PUT method"""
|
|
220
|
-
params = self._convert_query_params(query_params) if query_params else None
|
|
221
|
-
serialized = self._get_serialized(body)
|
|
222
|
-
response = self.transport.request(
|
|
223
|
-
transport.HttpMethod.PUT,
|
|
224
|
-
self._path(path),
|
|
225
|
-
query_params=params,
|
|
226
|
-
body=serialized,
|
|
227
|
-
authenticator=self.auth.authenticate,
|
|
228
|
-
transport_options=transport_options,
|
|
229
|
-
)
|
|
230
|
-
return self._return(response, structure)
|
|
231
|
-
|
|
232
|
-
def delete(
|
|
233
|
-
self,
|
|
234
|
-
path: str,
|
|
235
|
-
structure: TStructure = None,
|
|
236
|
-
query_params: Optional[TQueryParams] = None,
|
|
237
|
-
transport_options: Optional[transport.TransportOptions] = None,
|
|
238
|
-
) -> TReturn:
|
|
239
|
-
"""DELETE method"""
|
|
240
|
-
response = self.transport.request(
|
|
241
|
-
transport.HttpMethod.DELETE,
|
|
242
|
-
self._path(path),
|
|
243
|
-
body=None,
|
|
244
|
-
authenticator=self.auth.authenticate,
|
|
245
|
-
transport_options=transport_options,
|
|
246
|
-
)
|
|
247
|
-
return self._return(response, structure)
|
looker_sdk/rtl/api_settings.py
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
# The MIT License (MIT)
|
|
2
|
-
#
|
|
3
|
-
# Copyright (c) 2019 Looker Data Sciences, Inc.
|
|
4
|
-
#
|
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
# furnished to do so, subject to the following conditions:
|
|
11
|
-
#
|
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
|
13
|
-
# all copies or substantial portions of the Software.
|
|
14
|
-
#
|
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
# THE SOFTWARE.
|
|
22
|
-
|
|
23
|
-
"""Load settings from .ini file and create an ApiSettings object
|
|
24
|
-
with the settings as attributes
|
|
25
|
-
"""
|
|
26
|
-
import configparser as cp
|
|
27
|
-
import os
|
|
28
|
-
import sys
|
|
29
|
-
from typing import Dict, Optional, Set, cast
|
|
30
|
-
import warnings
|
|
31
|
-
|
|
32
|
-
from looker_sdk.rtl import transport
|
|
33
|
-
|
|
34
|
-
if sys.version_info >= (3, 8):
|
|
35
|
-
from typing import Protocol, TypedDict
|
|
36
|
-
else:
|
|
37
|
-
from typing_extensions import Protocol, TypedDict
|
|
38
|
-
from typing_extensions import Required
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class SettingsConfig(TypedDict, total=False):
|
|
42
|
-
client_id: Required[str]
|
|
43
|
-
client_secret: Required[str]
|
|
44
|
-
base_url: str
|
|
45
|
-
verify_ssl: str
|
|
46
|
-
timeout: str
|
|
47
|
-
redirect_uri: str
|
|
48
|
-
looker_url: str
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class PApiSettings(transport.PTransportSettings, Protocol):
|
|
52
|
-
def read_config(self) -> SettingsConfig:
|
|
53
|
-
...
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
_DEFAULT_INIS = ["looker.ini", "../looker.ini"]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class ApiSettings(PApiSettings):
|
|
60
|
-
deprecated_settings: Set[str] = {"api_version", "embed_secret", "user_id"}
|
|
61
|
-
|
|
62
|
-
def __init__(
|
|
63
|
-
self,
|
|
64
|
-
*,
|
|
65
|
-
filename: str = _DEFAULT_INIS[0],
|
|
66
|
-
section: Optional[str] = None,
|
|
67
|
-
sdk_version: Optional[str] = "",
|
|
68
|
-
env_prefix: Optional[str] = None,
|
|
69
|
-
):
|
|
70
|
-
"""Configure using a config file and/or environment variables.
|
|
71
|
-
|
|
72
|
-
Environment variables will override config file settings. Neither
|
|
73
|
-
is necessary but some combination must supply the minimum to
|
|
74
|
-
instantiate ApiSettings.
|
|
75
|
-
|
|
76
|
-
ENV variables map like this:
|
|
77
|
-
<package-prefix>_BASE_URL -> base_url
|
|
78
|
-
<package-prefix>_VERIFY_SSL -> verify_ssl
|
|
79
|
-
|
|
80
|
-
Args:
|
|
81
|
-
filename (str): config file. If specified, the file must exist.
|
|
82
|
-
If not specified and the default value of "looker.ini" does not
|
|
83
|
-
exist then no error is raised.
|
|
84
|
-
section (str): section in config file. If not supplied default to
|
|
85
|
-
reading first section.
|
|
86
|
-
"""
|
|
87
|
-
if not os.path.isfile(filename):
|
|
88
|
-
if filename and filename not in _DEFAULT_INIS:
|
|
89
|
-
raise FileNotFoundError(f"No config file found: '{filename}'")
|
|
90
|
-
|
|
91
|
-
self.filename = filename
|
|
92
|
-
self.section = section
|
|
93
|
-
self.env_prefix = env_prefix
|
|
94
|
-
data = self.read_config()
|
|
95
|
-
verify_ssl = data.get("verify_ssl")
|
|
96
|
-
if verify_ssl is None:
|
|
97
|
-
self.verify_ssl = True
|
|
98
|
-
else:
|
|
99
|
-
self.verify_ssl = self._bool(verify_ssl)
|
|
100
|
-
self.base_url = data.get("base_url", "")
|
|
101
|
-
self.timeout = int(data.get("timeout", 120))
|
|
102
|
-
self.headers = {"Content-Type": "application/json"}
|
|
103
|
-
self.agent_tag = f"{transport.AGENT_PREFIX}"
|
|
104
|
-
if sdk_version:
|
|
105
|
-
self.agent_tag += f" {sdk_version}"
|
|
106
|
-
|
|
107
|
-
def read_config(self) -> SettingsConfig:
|
|
108
|
-
cfg_parser = cp.ConfigParser()
|
|
109
|
-
data: SettingsConfig = {
|
|
110
|
-
"client_id": "",
|
|
111
|
-
"client_secret": "",
|
|
112
|
-
}
|
|
113
|
-
try:
|
|
114
|
-
config_file = open(self.filename)
|
|
115
|
-
except FileNotFoundError:
|
|
116
|
-
pass
|
|
117
|
-
else:
|
|
118
|
-
cfg_parser.read_file(config_file)
|
|
119
|
-
config_file.close()
|
|
120
|
-
# If section is not specified, use first section in file
|
|
121
|
-
section = self.section or cfg_parser.sections()[0]
|
|
122
|
-
if not cfg_parser.has_section(section):
|
|
123
|
-
raise cp.NoSectionError(section)
|
|
124
|
-
self._override_settings(data, dict(cfg_parser[section]))
|
|
125
|
-
|
|
126
|
-
if self.env_prefix:
|
|
127
|
-
self._override_settings(data, self._override_from_env())
|
|
128
|
-
return self._clean_input(data)
|
|
129
|
-
|
|
130
|
-
@staticmethod
|
|
131
|
-
def _bool(val: str) -> bool:
|
|
132
|
-
if val.lower() in ("yes", "y", "true", "t", "1"):
|
|
133
|
-
converted = True
|
|
134
|
-
elif val.lower() in ("", "no", "n", "false", "f", "0"):
|
|
135
|
-
converted = False
|
|
136
|
-
else:
|
|
137
|
-
raise TypeError
|
|
138
|
-
return converted
|
|
139
|
-
|
|
140
|
-
def _override_settings(
|
|
141
|
-
self, data: SettingsConfig, overrides: Dict[str, str]
|
|
142
|
-
) -> SettingsConfig:
|
|
143
|
-
# https://github.com/python/mypy/issues/6262
|
|
144
|
-
for setting in SettingsConfig.__annotations__.keys(): # type: ignore
|
|
145
|
-
if setting in overrides:
|
|
146
|
-
data[setting] = overrides[setting] # type: ignore
|
|
147
|
-
return data
|
|
148
|
-
|
|
149
|
-
def _override_from_env(self) -> Dict[str, str]:
|
|
150
|
-
overrides = {}
|
|
151
|
-
base_url = os.getenv(f"{self.env_prefix}_BASE_URL")
|
|
152
|
-
if base_url:
|
|
153
|
-
overrides["base_url"] = base_url
|
|
154
|
-
|
|
155
|
-
verify_ssl = os.getenv(f"{self.env_prefix}_VERIFY_SSL")
|
|
156
|
-
if verify_ssl:
|
|
157
|
-
overrides["verify_ssl"] = verify_ssl
|
|
158
|
-
|
|
159
|
-
timeout = os.getenv(f"{self.env_prefix}_TIMEOUT")
|
|
160
|
-
if timeout:
|
|
161
|
-
overrides["timeout"] = timeout
|
|
162
|
-
|
|
163
|
-
client_id = os.getenv(f"{self.env_prefix}_CLIENT_ID")
|
|
164
|
-
if client_id:
|
|
165
|
-
overrides["client_id"] = client_id
|
|
166
|
-
|
|
167
|
-
client_secret = os.getenv(f"{self.env_prefix}_CLIENT_SECRET")
|
|
168
|
-
if client_secret:
|
|
169
|
-
overrides["client_secret"] = client_secret
|
|
170
|
-
|
|
171
|
-
return overrides
|
|
172
|
-
|
|
173
|
-
def _clean_input(self, data: SettingsConfig) -> SettingsConfig:
|
|
174
|
-
"""Remove surrounding quotes and discard empty strings.
|
|
175
|
-
"""
|
|
176
|
-
cleaned = {}
|
|
177
|
-
for setting, value in data.items():
|
|
178
|
-
if setting in self.deprecated_settings:
|
|
179
|
-
warnings.warn(
|
|
180
|
-
message=DeprecationWarning(
|
|
181
|
-
f"'{setting}' config setting is deprecated"
|
|
182
|
-
)
|
|
183
|
-
)
|
|
184
|
-
if not isinstance(value, str):
|
|
185
|
-
continue
|
|
186
|
-
# Remove empty setting values
|
|
187
|
-
if value in ['""', "''", ""]:
|
|
188
|
-
continue
|
|
189
|
-
# Strip quotes from setting values
|
|
190
|
-
elif value.startswith(('"', "'")) or value.endswith(('"', "'")):
|
|
191
|
-
cleaned[setting] = value.strip("\"'")
|
|
192
|
-
else:
|
|
193
|
-
cleaned[setting] = value
|
|
194
|
-
return cast(SettingsConfig, cleaned)
|