fivetran-cli 0.1.0__tar.gz → 0.1.1__tar.gz
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.
- {fivetran_cli-0.1.0/src/fivetran_cli.egg-info → fivetran_cli-0.1.1}/PKG-INFO +4 -4
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/README.md +3 -3
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/pyproject.toml +1 -1
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli/cli.py +3 -11
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli/client.py +13 -7
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1/src/fivetran_cli.egg-info}/PKG-INFO +4 -4
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/tests/test_cli.py +1 -36
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/tests/test_client.py +33 -4
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/LICENSE +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/MANIFEST.in +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/setup.cfg +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli/__init__.py +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli/__main__.py +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli/output.py +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli.egg-info/SOURCES.txt +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli.egg-info/dependency_links.txt +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli.egg-info/entry_points.txt +0 -0
- {fivetran_cli-0.1.0 → fivetran_cli-0.1.1}/src/fivetran_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fivetran-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Command line wrapper for the Fivetran REST API
|
|
5
5
|
Author: Fivetran
|
|
6
6
|
License-Expression: MIT
|
|
@@ -22,10 +22,10 @@ Thin command line wrapper around the Fivetran REST API.
|
|
|
22
22
|
fivetran [global-options] <resource> <operation> [arguments] [options]
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Credentials default to `FIVETRAN_API_KEY
|
|
25
|
+
Credentials default to `FIVETRAN_API_KEY`. Set it to the single Base64-encoded API key shown by Fivetran.
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
fivetran --api-key "$FIVETRAN_API_KEY"
|
|
28
|
+
fivetran --api-key "$FIVETRAN_API_KEY" connection list
|
|
29
29
|
fivetran connection create --data-file connection.json
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ fivetran connection create --data-file connection.json
|
|
|
34
34
|
Global options may be placed before or after the resource command.
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
fivetran connection list --api-key "$FIVETRAN_API_KEY"
|
|
37
|
+
fivetran connection list --api-key "$FIVETRAN_API_KEY"
|
|
38
38
|
fivetran connection-schema get connection_id
|
|
39
39
|
fivetran connector-metadata get google_ads
|
|
40
40
|
fivetran public-connector list
|
|
@@ -6,10 +6,10 @@ Thin command line wrapper around the Fivetran REST API.
|
|
|
6
6
|
fivetran [global-options] <resource> <operation> [arguments] [options]
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Credentials default to `FIVETRAN_API_KEY
|
|
9
|
+
Credentials default to `FIVETRAN_API_KEY`. Set it to the single Base64-encoded API key shown by Fivetran.
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
fivetran --api-key "$FIVETRAN_API_KEY"
|
|
12
|
+
fivetran --api-key "$FIVETRAN_API_KEY" connection list
|
|
13
13
|
fivetran connection create --data-file connection.json
|
|
14
14
|
```
|
|
15
15
|
|
|
@@ -18,7 +18,7 @@ fivetran connection create --data-file connection.json
|
|
|
18
18
|
Global options may be placed before or after the resource command.
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
fivetran connection list --api-key "$FIVETRAN_API_KEY"
|
|
21
|
+
fivetran connection list --api-key "$FIVETRAN_API_KEY"
|
|
22
22
|
fivetran connection-schema get connection_id
|
|
23
23
|
fivetran connector-metadata get google_ads
|
|
24
24
|
fivetran public-connector list
|
|
@@ -18,7 +18,6 @@ from .output import emit_output
|
|
|
18
18
|
Handler = Callable[[argparse.Namespace, FivetranClient], Any]
|
|
19
19
|
GLOBAL_OPTIONS_WITH_VALUES = {
|
|
20
20
|
"--api-key",
|
|
21
|
-
"--api-secret",
|
|
22
21
|
"--profile",
|
|
23
22
|
"--base-url",
|
|
24
23
|
"--format",
|
|
@@ -26,7 +25,7 @@ GLOBAL_OPTIONS_WITH_VALUES = {
|
|
|
26
25
|
}
|
|
27
26
|
GLOBAL_FLAG_OPTIONS = {"--quiet", "--verbose"}
|
|
28
27
|
OPERATION_EPILOG = (
|
|
29
|
-
"Credentials default to FIVETRAN_API_KEY
|
|
28
|
+
"Credentials default to FIVETRAN_API_KEY, which should contain the Base64-encoded API key. "
|
|
30
29
|
"FIVETRAN_BASE_URL overrides the default API base URL. "
|
|
31
30
|
"Global options may be placed before or after the resource command."
|
|
32
31
|
)
|
|
@@ -121,10 +120,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
121
120
|
|
|
122
121
|
|
|
123
122
|
def _add_global_options(parser: argparse.ArgumentParser) -> None:
|
|
124
|
-
parser.add_argument("--api-key", help="Fivetran API key. Defaults to FIVETRAN_API_KEY.")
|
|
125
123
|
parser.add_argument(
|
|
126
|
-
"--api-
|
|
127
|
-
help="Fivetran API
|
|
124
|
+
"--api-key",
|
|
125
|
+
help="Base64-encoded Fivetran API key. Defaults to FIVETRAN_API_KEY.",
|
|
128
126
|
)
|
|
129
127
|
parser.add_argument("--profile", help="Named credential profile.")
|
|
130
128
|
parser.add_argument(
|
|
@@ -1413,11 +1411,6 @@ def _confirm_destructive(args: argparse.Namespace) -> None:
|
|
|
1413
1411
|
def resolve_config(args: argparse.Namespace) -> ClientConfig:
|
|
1414
1412
|
profile = _load_profile(args.profile) if args.profile else {}
|
|
1415
1413
|
api_key = args.api_key or profile.get("api_key") or os.environ.get("FIVETRAN_API_KEY")
|
|
1416
|
-
api_secret = (
|
|
1417
|
-
args.api_secret
|
|
1418
|
-
or profile.get("api_secret")
|
|
1419
|
-
or os.environ.get("FIVETRAN_API_SECRET")
|
|
1420
|
-
)
|
|
1421
1414
|
base_url = (
|
|
1422
1415
|
args.base_url
|
|
1423
1416
|
or profile.get("base_url")
|
|
@@ -1426,7 +1419,6 @@ def resolve_config(args: argparse.Namespace) -> ClientConfig:
|
|
|
1426
1419
|
)
|
|
1427
1420
|
return ClientConfig(
|
|
1428
1421
|
api_key=api_key,
|
|
1429
|
-
api_secret=api_secret,
|
|
1430
1422
|
base_url=base_url,
|
|
1431
1423
|
verbose=args.verbose,
|
|
1432
1424
|
)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import base64
|
|
4
3
|
import json
|
|
5
4
|
import urllib.error
|
|
6
5
|
import urllib.parse
|
|
@@ -19,7 +18,6 @@ class CliError(Exception):
|
|
|
19
18
|
@dataclass(frozen=True)
|
|
20
19
|
class ClientConfig:
|
|
21
20
|
api_key: str | None
|
|
22
|
-
api_secret: str | None
|
|
23
21
|
base_url: str = DEFAULT_BASE_URL
|
|
24
22
|
verbose: bool = False
|
|
25
23
|
|
|
@@ -38,10 +36,10 @@ class FivetranClient:
|
|
|
38
36
|
body: Any = None,
|
|
39
37
|
auth_required: bool = True,
|
|
40
38
|
) -> Any:
|
|
41
|
-
if auth_required and
|
|
39
|
+
if auth_required and not self.config.api_key:
|
|
42
40
|
raise CliError(
|
|
43
|
-
"Missing Fivetran API
|
|
44
|
-
"
|
|
41
|
+
"Missing Fivetran API key. Set FIVETRAN_API_KEY to the "
|
|
42
|
+
"Base64-encoded API key, pass --api-key, or use --profile."
|
|
45
43
|
)
|
|
46
44
|
|
|
47
45
|
url = self._url(path, query)
|
|
@@ -52,8 +50,7 @@ class FivetranClient:
|
|
|
52
50
|
headers["Content-Type"] = "application/json"
|
|
53
51
|
|
|
54
52
|
if auth_required:
|
|
55
|
-
|
|
56
|
-
headers["Authorization"] = "Basic " + base64.b64encode(token).decode("ascii")
|
|
53
|
+
headers["Authorization"] = _authorization_header(self.config.api_key)
|
|
57
54
|
|
|
58
55
|
request = urllib.request.Request(url, data=data, headers=headers, method=method)
|
|
59
56
|
|
|
@@ -157,3 +154,12 @@ def _next_cursor(page: Any) -> str | None:
|
|
|
157
154
|
cursor = data.get("next_cursor")
|
|
158
155
|
return str(cursor) if cursor else None
|
|
159
156
|
return None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _authorization_header(api_key: str | None) -> str:
|
|
160
|
+
if api_key is None:
|
|
161
|
+
raise CliError("Missing Fivetran API key.")
|
|
162
|
+
api_key = api_key.strip()
|
|
163
|
+
if api_key.lower().startswith("basic "):
|
|
164
|
+
return api_key
|
|
165
|
+
return f"Basic {api_key}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fivetran-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Command line wrapper for the Fivetran REST API
|
|
5
5
|
Author: Fivetran
|
|
6
6
|
License-Expression: MIT
|
|
@@ -22,10 +22,10 @@ Thin command line wrapper around the Fivetran REST API.
|
|
|
22
22
|
fivetran [global-options] <resource> <operation> [arguments] [options]
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Credentials default to `FIVETRAN_API_KEY
|
|
25
|
+
Credentials default to `FIVETRAN_API_KEY`. Set it to the single Base64-encoded API key shown by Fivetran.
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
fivetran --api-key "$FIVETRAN_API_KEY"
|
|
28
|
+
fivetran --api-key "$FIVETRAN_API_KEY" connection list
|
|
29
29
|
fivetran connection create --data-file connection.json
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ fivetran connection create --data-file connection.json
|
|
|
34
34
|
Global options may be placed before or after the resource command.
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
fivetran connection list --api-key "$FIVETRAN_API_KEY"
|
|
37
|
+
fivetran connection list --api-key "$FIVETRAN_API_KEY"
|
|
38
38
|
fivetran connection-schema get connection_id
|
|
39
39
|
fivetran connector-metadata get google_ads
|
|
40
40
|
fivetran public-connector list
|
|
@@ -51,8 +51,6 @@ class CliTests(unittest.TestCase):
|
|
|
51
51
|
[
|
|
52
52
|
"--api-key",
|
|
53
53
|
"key",
|
|
54
|
-
"--api-secret",
|
|
55
|
-
"secret",
|
|
56
54
|
"connection",
|
|
57
55
|
"list",
|
|
58
56
|
"--group-id",
|
|
@@ -88,8 +86,6 @@ class CliTests(unittest.TestCase):
|
|
|
88
86
|
[
|
|
89
87
|
"--api-key",
|
|
90
88
|
"key",
|
|
91
|
-
"--api-secret",
|
|
92
|
-
"secret",
|
|
93
89
|
"connection",
|
|
94
90
|
"create",
|
|
95
91
|
"--data",
|
|
@@ -113,8 +109,6 @@ class CliTests(unittest.TestCase):
|
|
|
113
109
|
"connection_id",
|
|
114
110
|
"--api-key",
|
|
115
111
|
"key",
|
|
116
|
-
"--api-secret",
|
|
117
|
-
"secret",
|
|
118
112
|
"--format",
|
|
119
113
|
"table",
|
|
120
114
|
]
|
|
@@ -129,8 +123,6 @@ class CliTests(unittest.TestCase):
|
|
|
129
123
|
[
|
|
130
124
|
"--api-key",
|
|
131
125
|
"key",
|
|
132
|
-
"--api-secret",
|
|
133
|
-
"secret",
|
|
134
126
|
"group",
|
|
135
127
|
"delete",
|
|
136
128
|
"group_id",
|
|
@@ -146,8 +138,6 @@ class CliTests(unittest.TestCase):
|
|
|
146
138
|
[
|
|
147
139
|
"--api-key",
|
|
148
140
|
"key",
|
|
149
|
-
"--api-secret",
|
|
150
|
-
"secret",
|
|
151
141
|
"group",
|
|
152
142
|
"delete",
|
|
153
143
|
"group_id",
|
|
@@ -162,7 +152,7 @@ class CliTests(unittest.TestCase):
|
|
|
162
152
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
163
153
|
config_path = Path(tmpdir) / "config.toml"
|
|
164
154
|
config_path.write_text(
|
|
165
|
-
'[profiles.dev]\napi_key = "profile-key"\
|
|
155
|
+
'[profiles.dev]\napi_key = "profile-key"\nbase_url = "https://example.test"\n',
|
|
166
156
|
encoding="utf-8",
|
|
167
157
|
)
|
|
168
158
|
with patch.dict(os.environ, {"FIVETRAN_CONFIG": str(config_path)}, clear=False):
|
|
@@ -170,7 +160,6 @@ class CliTests(unittest.TestCase):
|
|
|
170
160
|
|
|
171
161
|
self.assertEqual(code, 0, stderr)
|
|
172
162
|
self.assertEqual(client.config.api_key, "profile-key")
|
|
173
|
-
self.assertEqual(client.config.api_secret, "profile-secret")
|
|
174
163
|
self.assertEqual(client.config.base_url, "https://example.test")
|
|
175
164
|
self.assertEqual(client.calls[0][0:2], ("GET", "/v1/account/info"))
|
|
176
165
|
|
|
@@ -179,8 +168,6 @@ class CliTests(unittest.TestCase):
|
|
|
179
168
|
[
|
|
180
169
|
"--api-key",
|
|
181
170
|
"key",
|
|
182
|
-
"--api-secret",
|
|
183
|
-
"secret",
|
|
184
171
|
"user",
|
|
185
172
|
"connection",
|
|
186
173
|
"update",
|
|
@@ -208,8 +195,6 @@ class CliTests(unittest.TestCase):
|
|
|
208
195
|
[
|
|
209
196
|
"--api-key",
|
|
210
197
|
"key",
|
|
211
|
-
"--api-secret",
|
|
212
|
-
"secret",
|
|
213
198
|
"team",
|
|
214
199
|
"connection",
|
|
215
200
|
"add",
|
|
@@ -228,8 +213,6 @@ class CliTests(unittest.TestCase):
|
|
|
228
213
|
[
|
|
229
214
|
"--api-key",
|
|
230
215
|
"key",
|
|
231
|
-
"--api-secret",
|
|
232
|
-
"secret",
|
|
233
216
|
"system-key",
|
|
234
217
|
"rotate",
|
|
235
218
|
"key_id",
|
|
@@ -245,8 +228,6 @@ class CliTests(unittest.TestCase):
|
|
|
245
228
|
[
|
|
246
229
|
"--api-key",
|
|
247
230
|
"key",
|
|
248
|
-
"--api-secret",
|
|
249
|
-
"secret",
|
|
250
231
|
"group",
|
|
251
232
|
"public-key",
|
|
252
233
|
"get",
|
|
@@ -262,8 +243,6 @@ class CliTests(unittest.TestCase):
|
|
|
262
243
|
[
|
|
263
244
|
"--api-key",
|
|
264
245
|
"key",
|
|
265
|
-
"--api-secret",
|
|
266
|
-
"secret",
|
|
267
246
|
"--output",
|
|
268
247
|
"/missing-directory/output.json",
|
|
269
248
|
"account",
|
|
@@ -280,8 +259,6 @@ class CliTests(unittest.TestCase):
|
|
|
280
259
|
[
|
|
281
260
|
"--api-key",
|
|
282
261
|
"key",
|
|
283
|
-
"--api-secret",
|
|
284
|
-
"secret",
|
|
285
262
|
"connection-schema",
|
|
286
263
|
"column",
|
|
287
264
|
"drop-blocked",
|
|
@@ -309,8 +286,6 @@ class CliTests(unittest.TestCase):
|
|
|
309
286
|
[
|
|
310
287
|
"--api-key",
|
|
311
288
|
"key",
|
|
312
|
-
"--api-secret",
|
|
313
|
-
"secret",
|
|
314
289
|
"connection-schema",
|
|
315
290
|
"column",
|
|
316
291
|
"update",
|
|
@@ -337,8 +312,6 @@ class CliTests(unittest.TestCase):
|
|
|
337
312
|
[
|
|
338
313
|
"--api-key",
|
|
339
314
|
"key",
|
|
340
|
-
"--api-secret",
|
|
341
|
-
"secret",
|
|
342
315
|
"connector-metadata",
|
|
343
316
|
"get",
|
|
344
317
|
"google_ads",
|
|
@@ -360,8 +333,6 @@ class CliTests(unittest.TestCase):
|
|
|
360
333
|
[
|
|
361
334
|
"--api-key",
|
|
362
335
|
"key",
|
|
363
|
-
"--api-secret",
|
|
364
|
-
"secret",
|
|
365
336
|
"hybrid-deployment-agent",
|
|
366
337
|
"list",
|
|
367
338
|
"--group-id",
|
|
@@ -388,8 +359,6 @@ class CliTests(unittest.TestCase):
|
|
|
388
359
|
[
|
|
389
360
|
"--api-key",
|
|
390
361
|
"key",
|
|
391
|
-
"--api-secret",
|
|
392
|
-
"secret",
|
|
393
362
|
"proxy-agent",
|
|
394
363
|
"connection",
|
|
395
364
|
"list",
|
|
@@ -405,8 +374,6 @@ class CliTests(unittest.TestCase):
|
|
|
405
374
|
[
|
|
406
375
|
"--api-key",
|
|
407
376
|
"key",
|
|
408
|
-
"--api-secret",
|
|
409
|
-
"secret",
|
|
410
377
|
"private-link",
|
|
411
378
|
"update",
|
|
412
379
|
"private_link_id",
|
|
@@ -424,8 +391,6 @@ class CliTests(unittest.TestCase):
|
|
|
424
391
|
[
|
|
425
392
|
"--api-key",
|
|
426
393
|
"key",
|
|
427
|
-
"--api-secret",
|
|
428
|
-
"secret",
|
|
429
394
|
"transformation",
|
|
430
395
|
"list",
|
|
431
396
|
"--all",
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import unittest
|
|
4
|
+
from unittest.mock import MagicMock, patch
|
|
4
5
|
|
|
5
6
|
from fivetran_cli.client import CliError, ClientConfig, FivetranClient
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class PagingClient(FivetranClient):
|
|
9
10
|
def __init__(self) -> None:
|
|
10
|
-
super().__init__(ClientConfig(api_key="key"
|
|
11
|
+
super().__init__(ClientConfig(api_key="encoded-key"))
|
|
11
12
|
self.calls = []
|
|
12
13
|
|
|
13
14
|
def request(self, method, path, *, query=None, body=None, auth_required=True):
|
|
@@ -37,16 +38,44 @@ class ClientTests(unittest.TestCase):
|
|
|
37
38
|
)
|
|
38
39
|
|
|
39
40
|
def test_request_requires_credentials_for_authenticated_endpoints(self):
|
|
40
|
-
client = FivetranClient(ClientConfig(api_key=None
|
|
41
|
+
client = FivetranClient(ClientConfig(api_key=None))
|
|
41
42
|
|
|
42
43
|
with self.assertRaises(CliError) as context:
|
|
43
44
|
client.request("GET", "/v1/connections")
|
|
44
45
|
|
|
45
|
-
self.assertIn("Missing Fivetran API
|
|
46
|
+
self.assertIn("Missing Fivetran API key", str(context.exception))
|
|
47
|
+
|
|
48
|
+
def test_request_uses_encoded_api_key_directly_in_basic_auth_header(self):
|
|
49
|
+
client = FivetranClient(
|
|
50
|
+
ClientConfig(api_key="already-base64", base_url="https://api.example.test")
|
|
51
|
+
)
|
|
52
|
+
response = MagicMock()
|
|
53
|
+
response.read.return_value = b'{"data":{"ok":true}}'
|
|
54
|
+
response.__enter__.return_value = response
|
|
55
|
+
|
|
56
|
+
with patch("urllib.request.urlopen", return_value=response) as urlopen:
|
|
57
|
+
client.request("GET", "/v1/account/info")
|
|
58
|
+
|
|
59
|
+
request = urlopen.call_args.args[0]
|
|
60
|
+
self.assertEqual(request.headers["Authorization"], "Basic already-base64")
|
|
61
|
+
|
|
62
|
+
def test_request_accepts_api_key_with_basic_prefix(self):
|
|
63
|
+
client = FivetranClient(
|
|
64
|
+
ClientConfig(api_key="Basic already-base64", base_url="https://api.example.test")
|
|
65
|
+
)
|
|
66
|
+
response = MagicMock()
|
|
67
|
+
response.read.return_value = b'{"data":{"ok":true}}'
|
|
68
|
+
response.__enter__.return_value = response
|
|
69
|
+
|
|
70
|
+
with patch("urllib.request.urlopen", return_value=response) as urlopen:
|
|
71
|
+
client.request("GET", "/v1/account/info")
|
|
72
|
+
|
|
73
|
+
request = urlopen.call_args.args[0]
|
|
74
|
+
self.assertEqual(request.headers["Authorization"], "Basic already-base64")
|
|
46
75
|
|
|
47
76
|
def test_url_omits_empty_query_values(self):
|
|
48
77
|
client = FivetranClient(
|
|
49
|
-
ClientConfig(api_key="key",
|
|
78
|
+
ClientConfig(api_key="encoded-key", base_url="https://api.example.test/")
|
|
50
79
|
)
|
|
51
80
|
|
|
52
81
|
self.assertEqual(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|