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
tests/integration/test_netrc.py
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import pytest # type: ignore
|
|
3
|
-
from urllib.parse import urlparse
|
|
4
|
-
|
|
5
|
-
from looker_sdk.sdk.api40 import methods as mtds
|
|
6
|
-
from looker_sdk.sdk.api40 import models as ml
|
|
7
|
-
|
|
8
|
-
NETRC_LOCATION = os.path.expanduser("~/.netrc")
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@pytest.fixture()
|
|
12
|
-
def sdk(sdk40) -> mtds.Looker40SDK:
|
|
13
|
-
return sdk40
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def can_create_netrc_file():
|
|
17
|
-
"""Check if netrc can be created in home directory."""
|
|
18
|
-
can = False
|
|
19
|
-
if NETRC_LOCATION.startswith("~") or os.path.exists(NETRC_LOCATION):
|
|
20
|
-
can = False
|
|
21
|
-
else:
|
|
22
|
-
can = True
|
|
23
|
-
return can
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@pytest.fixture()
|
|
27
|
-
def create_netrc_file(sdk: mtds.Looker40SDK):
|
|
28
|
-
"""Create a sample netrc meant to cause conflicts with the looker.ini file"""
|
|
29
|
-
host = urlparse(sdk.auth.settings.base_url).netloc.split(":")[0]
|
|
30
|
-
netrc_contents = (
|
|
31
|
-
f"machine {host}"
|
|
32
|
-
f"\n login netrc_client_id"
|
|
33
|
-
f"\n password netrc_client_secret"
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
with open(NETRC_LOCATION, "w") as netrc_file:
|
|
37
|
-
netrc_file.write(netrc_contents)
|
|
38
|
-
|
|
39
|
-
yield
|
|
40
|
-
|
|
41
|
-
os.remove(NETRC_LOCATION)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
@pytest.mark.skipif(
|
|
45
|
-
not can_create_netrc_file(),
|
|
46
|
-
reason="netrc file cannot be created because it already exists or $HOME is undefined", # noqa: B950
|
|
47
|
-
)
|
|
48
|
-
@pytest.mark.usefixtures("create_netrc_file")
|
|
49
|
-
def test_netrc_does_not_override_ini_creds(sdk: mtds.Looker40SDK):
|
|
50
|
-
"""The requests library overrides HTTP authorization headers if the auth= parameter
|
|
51
|
-
is not specified, resulting in an authentication error. This test makes sure this
|
|
52
|
-
does not happen when netrc files are found on the system.
|
|
53
|
-
"""
|
|
54
|
-
me = sdk.me()
|
|
55
|
-
assert isinstance(me, ml.User)
|
tests/rtl/__init__.py
DELETED
tests/rtl/test_api_methods.py
DELETED
|
@@ -1,216 +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
|
-
import datetime
|
|
24
|
-
import json
|
|
25
|
-
from typing import MutableMapping, Optional, Union
|
|
26
|
-
|
|
27
|
-
import pytest # type: ignore
|
|
28
|
-
|
|
29
|
-
from looker_sdk import error
|
|
30
|
-
from looker_sdk.rtl import auth_session
|
|
31
|
-
from looker_sdk.rtl import api_settings
|
|
32
|
-
from looker_sdk.rtl import api_methods
|
|
33
|
-
from looker_sdk.rtl import requests_transport
|
|
34
|
-
from looker_sdk.rtl import serialize
|
|
35
|
-
from looker_sdk.rtl import transport
|
|
36
|
-
from looker_sdk.sdk import constants
|
|
37
|
-
from looker_sdk.sdk.api40 import models
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@pytest.fixture(scope="module")
|
|
41
|
-
def api() -> api_methods.APIMethods:
|
|
42
|
-
settings = api_settings.ApiSettings(
|
|
43
|
-
filename="../looker.ini", env_prefix=constants.environment_prefix
|
|
44
|
-
)
|
|
45
|
-
transport = requests_transport.RequestsTransport.configure(settings)
|
|
46
|
-
auth = auth_session.AuthSession(settings, transport, serialize.deserialize40, "4.0")
|
|
47
|
-
return api_methods.APIMethods(
|
|
48
|
-
auth, serialize.deserialize40, serialize.serialize40, transport, "4.0"
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@pytest.mark.parametrize(
|
|
53
|
-
"test_query_params, expected",
|
|
54
|
-
[
|
|
55
|
-
({"a": None}, {}),
|
|
56
|
-
({"a": True}, {"a": "true"}),
|
|
57
|
-
({"a": "text"}, {"a": "text"}),
|
|
58
|
-
({"a": 1}, {"a": "1"}),
|
|
59
|
-
({"a": [1, 2, 3]}, {"a": "[1, 2, 3]"}),
|
|
60
|
-
({"a": models.DelimSequence([1, 2, 3])}, {"a": "1,2,3"}),
|
|
61
|
-
({"a": models.DelimSequence(["a", "b", "c"])}, {"a": "a,b,c"}),
|
|
62
|
-
(
|
|
63
|
-
{
|
|
64
|
-
"a": models.DelimSequence(
|
|
65
|
-
["a", "b", "c"], prefix="<", suffix=">", separator="|"
|
|
66
|
-
)
|
|
67
|
-
},
|
|
68
|
-
{"a": "<a|b|c>"},
|
|
69
|
-
),
|
|
70
|
-
({"a": ["x", "xy", "xyz"]}, {"a": '["x", "xy", "xyz"]'}),
|
|
71
|
-
({"a": datetime.datetime(2019, 8, 14, 8, 4, 2)}, {"a": "2019-08-14T08:04Z"}),
|
|
72
|
-
],
|
|
73
|
-
)
|
|
74
|
-
def test_convert_query_params(
|
|
75
|
-
api: api_methods.APIMethods,
|
|
76
|
-
test_query_params: api_methods.TQueryParams,
|
|
77
|
-
expected: MutableMapping[str, str],
|
|
78
|
-
):
|
|
79
|
-
actual = api._convert_query_params(test_query_params)
|
|
80
|
-
assert actual == expected
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@pytest.mark.parametrize(
|
|
84
|
-
"test_body, expected",
|
|
85
|
-
[
|
|
86
|
-
("some body text", b"some body text"),
|
|
87
|
-
("", b""),
|
|
88
|
-
([1, 2, 3], b"[1, 2, 3]"),
|
|
89
|
-
(["a", "b", "c"], b'["a", "b", "c"]'),
|
|
90
|
-
({"foo": "bar"}, b'{"foo": "bar"}'),
|
|
91
|
-
(None, None),
|
|
92
|
-
(models.WriteApiSession(workspace_id="dev"), b'{"workspace_id": "dev"}'),
|
|
93
|
-
(
|
|
94
|
-
[
|
|
95
|
-
models.WriteApiSession(workspace_id="dev"),
|
|
96
|
-
models.WriteApiSession(workspace_id="dev"),
|
|
97
|
-
],
|
|
98
|
-
b'[{"workspace_id": "dev"}, {"workspace_id": "dev"}]',
|
|
99
|
-
),
|
|
100
|
-
],
|
|
101
|
-
)
|
|
102
|
-
def test_get_serialized(
|
|
103
|
-
api: api_methods.APIMethods, test_body: api_methods.TBody, expected: Optional[bytes]
|
|
104
|
-
):
|
|
105
|
-
actual = api._get_serialized(test_body)
|
|
106
|
-
assert actual == expected
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
@pytest.mark.parametrize(
|
|
110
|
-
"test_response, test_structure, expected",
|
|
111
|
-
[
|
|
112
|
-
(
|
|
113
|
-
transport.Response(
|
|
114
|
-
ok=True,
|
|
115
|
-
value=bytes(range(0, 10)),
|
|
116
|
-
response_mode=transport.ResponseMode.BINARY,
|
|
117
|
-
),
|
|
118
|
-
Union[str, bytes],
|
|
119
|
-
bytes(range(0, 10)),
|
|
120
|
-
),
|
|
121
|
-
(
|
|
122
|
-
transport.Response(
|
|
123
|
-
ok=True,
|
|
124
|
-
value=b"some response text",
|
|
125
|
-
response_mode=transport.ResponseMode.STRING,
|
|
126
|
-
),
|
|
127
|
-
Union[str, bytes],
|
|
128
|
-
"some response text",
|
|
129
|
-
),
|
|
130
|
-
(
|
|
131
|
-
transport.Response(
|
|
132
|
-
ok=True,
|
|
133
|
-
value=bytes("ئ", encoding="arabic"),
|
|
134
|
-
response_mode=transport.ResponseMode.STRING,
|
|
135
|
-
encoding="arabic",
|
|
136
|
-
),
|
|
137
|
-
Union[str, bytes],
|
|
138
|
-
"ئ",
|
|
139
|
-
),
|
|
140
|
-
(
|
|
141
|
-
transport.Response(
|
|
142
|
-
ok=True, value=b"", response_mode=transport.ResponseMode.STRING
|
|
143
|
-
),
|
|
144
|
-
None,
|
|
145
|
-
None,
|
|
146
|
-
),
|
|
147
|
-
(
|
|
148
|
-
transport.Response(
|
|
149
|
-
ok=True,
|
|
150
|
-
value=bytes(
|
|
151
|
-
json.dumps(
|
|
152
|
-
{
|
|
153
|
-
"current_version": {
|
|
154
|
-
"full_version": "6.18.4",
|
|
155
|
-
"status": "fully functional",
|
|
156
|
-
"swagger_url": None,
|
|
157
|
-
"version": None,
|
|
158
|
-
},
|
|
159
|
-
"looker_release_version": "6.18",
|
|
160
|
-
"supported_versions": None,
|
|
161
|
-
}
|
|
162
|
-
),
|
|
163
|
-
encoding="utf-8",
|
|
164
|
-
),
|
|
165
|
-
response_mode=transport.ResponseMode.STRING,
|
|
166
|
-
),
|
|
167
|
-
models.ApiVersion,
|
|
168
|
-
models.ApiVersion(
|
|
169
|
-
looker_release_version="6.18",
|
|
170
|
-
current_version=models.ApiVersionElement(
|
|
171
|
-
version=None,
|
|
172
|
-
full_version="6.18.4",
|
|
173
|
-
status="fully functional",
|
|
174
|
-
swagger_url=None,
|
|
175
|
-
),
|
|
176
|
-
supported_versions=None,
|
|
177
|
-
),
|
|
178
|
-
),
|
|
179
|
-
],
|
|
180
|
-
)
|
|
181
|
-
def test_return(
|
|
182
|
-
api: api_methods.APIMethods,
|
|
183
|
-
test_response: transport.Response,
|
|
184
|
-
test_structure: api_methods.TStructure,
|
|
185
|
-
expected: api_methods.TReturn,
|
|
186
|
-
):
|
|
187
|
-
actual = api._return(test_response, test_structure)
|
|
188
|
-
assert actual == expected
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def test_return_raises_an_SDKError_for_bad_responses(api):
|
|
192
|
-
with pytest.raises(error.SDKError) as exc:
|
|
193
|
-
api._return(
|
|
194
|
-
transport.Response(
|
|
195
|
-
ok=False,
|
|
196
|
-
value=b"some error message",
|
|
197
|
-
response_mode=transport.ResponseMode.STRING,
|
|
198
|
-
),
|
|
199
|
-
str,
|
|
200
|
-
)
|
|
201
|
-
assert "some error message" in str(exc.value)
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
@pytest.mark.parametrize(
|
|
205
|
-
"method_path, expected_url",
|
|
206
|
-
[
|
|
207
|
-
("/user", "/api/4.0/user"),
|
|
208
|
-
("user", "/api/4.0/user"),
|
|
209
|
-
("/user/1", "/api/4.0/user/1"),
|
|
210
|
-
("user/1", "/api/4.0/user/1"),
|
|
211
|
-
],
|
|
212
|
-
)
|
|
213
|
-
def test_api_versioned_url_is_built_properly(
|
|
214
|
-
api: api_methods.APIMethods, method_path: str, expected_url: str
|
|
215
|
-
):
|
|
216
|
-
assert api._path(method_path).endswith(expected_url)
|
tests/rtl/test_api_settings.py
DELETED
|
@@ -1,252 +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
|
-
import configparser
|
|
24
|
-
|
|
25
|
-
import pytest # type: ignore
|
|
26
|
-
|
|
27
|
-
from looker_sdk import error
|
|
28
|
-
from looker_sdk.rtl import api_settings
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@pytest.fixture
|
|
32
|
-
def config_file(monkeypatch, tmpdir_factory):
|
|
33
|
-
"""Creates a sample looker.ini file and returns its path"""
|
|
34
|
-
monkeypatch.delenv("LOOKERSDK_BASE_URL", raising=False)
|
|
35
|
-
monkeypatch.delenv("LOOKERSDK_VERIFY_SSL", raising=False)
|
|
36
|
-
monkeypatch.delenv("LOOKERSDK_CLIENT_ID", raising=False)
|
|
37
|
-
monkeypatch.delenv("LOOKERSDK_CLIENT_SECRET", raising=False)
|
|
38
|
-
filename = tmpdir_factory.mktemp("settings").join("looker.ini")
|
|
39
|
-
filename.write(
|
|
40
|
-
"""
|
|
41
|
-
[Looker]
|
|
42
|
-
# Base URL for API. Do not include /api/* in the url
|
|
43
|
-
base_url=https://host1.looker.com:19999
|
|
44
|
-
# API client id
|
|
45
|
-
client_id=your_API_client_id
|
|
46
|
-
# API client secret
|
|
47
|
-
client_secret=your_API_client_secret
|
|
48
|
-
# Set to false if testing locally against self-signed certs. Otherwise leave True
|
|
49
|
-
verify_ssl=True
|
|
50
|
-
|
|
51
|
-
[OLD_API]
|
|
52
|
-
base_url=https://host2.looker.com:19999
|
|
53
|
-
client_id=your_API_client_id
|
|
54
|
-
client_secret=your_API_client_secret
|
|
55
|
-
verify_ssl=
|
|
56
|
-
|
|
57
|
-
[BARE_MINIMUM]
|
|
58
|
-
base_url=https://host3.looker.com:19999/
|
|
59
|
-
|
|
60
|
-
[BARE]
|
|
61
|
-
# Empty section
|
|
62
|
-
|
|
63
|
-
[BARE_MIN_NO_VALUES]
|
|
64
|
-
base_url=""
|
|
65
|
-
|
|
66
|
-
[QUOTED_CONFIG_VARS]
|
|
67
|
-
base_url="https://host4.looker.com:19999"
|
|
68
|
-
verify_ssl='false'
|
|
69
|
-
"""
|
|
70
|
-
)
|
|
71
|
-
return filename
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def test_settings_defaults_to_looker_section(config_file):
|
|
75
|
-
"""ApiSettings should retrieve settings from default (Looker) section
|
|
76
|
-
if section is not specified during instantiation.
|
|
77
|
-
"""
|
|
78
|
-
settings = api_settings.ApiSettings(filename=config_file)
|
|
79
|
-
assert settings.base_url == "https://host1.looker.com:19999"
|
|
80
|
-
# API credentials are not set as attributes in ApiSettings
|
|
81
|
-
data = vars(settings)
|
|
82
|
-
assert "client_id" not in data
|
|
83
|
-
assert "client_secret" not in data
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@pytest.mark.parametrize(
|
|
87
|
-
"test_section, expected_url",
|
|
88
|
-
[
|
|
89
|
-
("Looker", "https://host1.looker.com:19999"),
|
|
90
|
-
("OLD_API", "https://host2.looker.com:19999"),
|
|
91
|
-
],
|
|
92
|
-
ids=["section=Looker", "section=OLD_API"],
|
|
93
|
-
)
|
|
94
|
-
def test_it_retrieves_section_by_name(config_file, test_section, expected_url):
|
|
95
|
-
"""ApiSettings should return settings of specified section."""
|
|
96
|
-
settings = api_settings.ApiSettings(filename=config_file, section=test_section)
|
|
97
|
-
assert settings.base_url == expected_url
|
|
98
|
-
assert settings.verify_ssl
|
|
99
|
-
data = vars(settings)
|
|
100
|
-
assert "client_id" not in data
|
|
101
|
-
assert "client_secret" not in data
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def test_it_assigns_defaults_to_empty_settings(config_file):
|
|
105
|
-
"""ApiSettings assigns defaults to optional settings that are empty in the
|
|
106
|
-
config file.
|
|
107
|
-
"""
|
|
108
|
-
settings = api_settings.ApiSettings(filename=config_file, section="BARE_MINIMUM")
|
|
109
|
-
assert settings.base_url == "https://host3.looker.com:19999/"
|
|
110
|
-
assert settings.verify_ssl
|
|
111
|
-
data = vars(settings)
|
|
112
|
-
assert "client_id" not in data
|
|
113
|
-
assert "client_secret" not in data
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def test_it_fails_with_a_bad_section_name(config_file):
|
|
117
|
-
"""ApiSettings should raise NoSectionError section is not found."""
|
|
118
|
-
with pytest.raises(configparser.NoSectionError) as exc_info:
|
|
119
|
-
api_settings.ApiSettings(filename=config_file, section="NotAGoodLookForYou")
|
|
120
|
-
assert exc_info.match("NotAGoodLookForYou")
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def test_it_fails_with_a_bad_file_path():
|
|
124
|
-
"""ApiSettings should raise an error non-default ini path doesn't exist."""
|
|
125
|
-
api_settings.ApiSettings() # defaulting to _DEFAULT_INIS[0], no error
|
|
126
|
-
api_settings.ApiSettings(
|
|
127
|
-
filename="looker.ini"
|
|
128
|
-
) # specifying _DEFAULT_INIS[0], no error
|
|
129
|
-
with pytest.raises(FileNotFoundError) as exc_info:
|
|
130
|
-
api_settings.ApiSettings(filename="/no/such/file.ini")
|
|
131
|
-
assert exc_info.match("file.ini")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
@pytest.mark.parametrize(
|
|
135
|
-
"test_section",
|
|
136
|
-
[
|
|
137
|
-
pytest.param("BARE", id="Empty config file"),
|
|
138
|
-
pytest.param("BARE_MINIMUM", id="Overriding with env variables"),
|
|
139
|
-
],
|
|
140
|
-
)
|
|
141
|
-
def test_settings_from_env_variables_override_config_file(
|
|
142
|
-
monkeypatch, config_file, test_section
|
|
143
|
-
):
|
|
144
|
-
"""ApiSettings should read settings defined as env variables."""
|
|
145
|
-
monkeypatch.setenv("LOOKERSDK_BASE_URL", "https://host1.looker.com:19999")
|
|
146
|
-
monkeypatch.setenv("LOOKERSDK_VERIFY_SSL", "0")
|
|
147
|
-
monkeypatch.setenv("LOOKERSDK_CLIENT_ID", "id123")
|
|
148
|
-
monkeypatch.setenv("LOOKERSDK_CLIENT_SECRET", "secret123")
|
|
149
|
-
|
|
150
|
-
settings = api_settings.ApiSettings(
|
|
151
|
-
filename=config_file, section=test_section, env_prefix="LOOKERSDK"
|
|
152
|
-
)
|
|
153
|
-
assert settings.base_url == "https://host1.looker.com:19999"
|
|
154
|
-
assert not settings.verify_ssl
|
|
155
|
-
# API credentials are still not set as attributes when read from env variables
|
|
156
|
-
data = vars(settings)
|
|
157
|
-
assert "client_id" not in data
|
|
158
|
-
assert "client_secret" not in data
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
@pytest.mark.parametrize(
|
|
162
|
-
"test_value, expected",
|
|
163
|
-
[
|
|
164
|
-
("yes", True),
|
|
165
|
-
("y", True),
|
|
166
|
-
("true", True),
|
|
167
|
-
("t", True),
|
|
168
|
-
("1", True),
|
|
169
|
-
("", True),
|
|
170
|
-
("no", False),
|
|
171
|
-
("n", False),
|
|
172
|
-
("f", False),
|
|
173
|
-
("0", False),
|
|
174
|
-
],
|
|
175
|
-
)
|
|
176
|
-
def test_env_verify_ssl_maps_properly(monkeypatch, config_file, test_value, expected):
|
|
177
|
-
"""ApiSettings should map the various values that VERIFY_SSL can take to True/False
|
|
178
|
-
accordingly.
|
|
179
|
-
"""
|
|
180
|
-
monkeypatch.setenv("LOOKERSDK_VERIFY_SSL", test_value)
|
|
181
|
-
settings = api_settings.ApiSettings(
|
|
182
|
-
filename=config_file, section="BARE_MINIMUM", env_prefix="LOOKERSDK"
|
|
183
|
-
)
|
|
184
|
-
assert settings.verify_ssl == expected
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def test_configure_with_no_file(monkeypatch):
|
|
188
|
-
"""ApiSettings should be instantiated if required parameters all exist in env
|
|
189
|
-
variables.
|
|
190
|
-
"""
|
|
191
|
-
monkeypatch.setenv("LOOKERSDK_BASE_URL", "https://host1.looker.com:19999")
|
|
192
|
-
monkeypatch.setenv("LOOKERSDK_CLIENT_ID", "id123")
|
|
193
|
-
monkeypatch.setenv("LOOKERSDK_CLIENT_SECRET", "secret123")
|
|
194
|
-
|
|
195
|
-
settings = api_settings.ApiSettings(
|
|
196
|
-
filename="", env_prefix="LOOKERSDK",
|
|
197
|
-
) # explicitly setting config_file to falsey
|
|
198
|
-
assert settings.base_url == "https://host1.looker.com:19999"
|
|
199
|
-
data = vars(settings)
|
|
200
|
-
assert "client_id" not in data
|
|
201
|
-
assert "client_secret" not in data
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
@pytest.mark.parametrize(
|
|
205
|
-
"test_section",
|
|
206
|
-
[
|
|
207
|
-
pytest.param("BARE", id="Empty config file"),
|
|
208
|
-
pytest.param("BARE_MIN_NO_VALUES", id="Required settings are empty strings"),
|
|
209
|
-
],
|
|
210
|
-
)
|
|
211
|
-
def test_it_fails_if_required_settings_are_not_found(config_file, test_section):
|
|
212
|
-
"""ApiSettings should throw an error if required settings are not found."""
|
|
213
|
-
with pytest.raises(error.SDKError):
|
|
214
|
-
api_settings.ApiSettings(
|
|
215
|
-
filename=config_file, section=test_section
|
|
216
|
-
).is_configured()
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def test_it_fails_when_env_variables_are_defined_but_empty(config_file, monkeypatch):
|
|
220
|
-
"""ApiSettings should throw an error if required settings are passed as empty
|
|
221
|
-
env variables.
|
|
222
|
-
"""
|
|
223
|
-
monkeypatch.setenv("LOOKERSDK_BASE_URL", "")
|
|
224
|
-
|
|
225
|
-
with pytest.raises(error.SDKError):
|
|
226
|
-
api_settings.ApiSettings(
|
|
227
|
-
filename=config_file, section="BARE", env_prefix="LOOKERSDK"
|
|
228
|
-
).is_configured()
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def test_it_unquotes_quoted_config_file_vars(config_file):
|
|
232
|
-
"""ApiSettings should strip quotes from config file variables."""
|
|
233
|
-
settings = api_settings.ApiSettings(
|
|
234
|
-
filename=config_file, section="QUOTED_CONFIG_VARS"
|
|
235
|
-
)
|
|
236
|
-
assert settings.base_url == "https://host4.looker.com:19999"
|
|
237
|
-
assert settings.verify_ssl is False
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
def test_it_unquotes_quoted_env_var_values(monkeypatch):
|
|
241
|
-
"""ApiSettings should strip quotes from env variable values."""
|
|
242
|
-
monkeypatch.setenv("LOOKERSDK_BASE_URL", "'https://host1.looker.com:19999'")
|
|
243
|
-
monkeypatch.setenv("LOOKERSDK_TIMEOUT", "100")
|
|
244
|
-
monkeypatch.setenv("LOOKERSDK_VERIFY_SSL", '"false"')
|
|
245
|
-
|
|
246
|
-
settings = api_settings.ApiSettings(
|
|
247
|
-
env_prefix="LOOKERSDK"
|
|
248
|
-
) # _DEFAULT_INIS[0] absence doesn't raise
|
|
249
|
-
|
|
250
|
-
assert settings.base_url == "https://host1.looker.com:19999"
|
|
251
|
-
assert settings.verify_ssl is False
|
|
252
|
-
assert settings.timeout == 100
|