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.
Files changed (36) hide show
  1. looker_sdk/version.py +1 -1
  2. {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/METADATA +1 -1
  3. looker_sdk-24.18.0.dist-info/RECORD +9 -0
  4. {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/top_level.txt +0 -1
  5. looker_sdk/rtl/__init__.py +0 -22
  6. looker_sdk/rtl/api_methods.py +0 -247
  7. looker_sdk/rtl/api_settings.py +0 -194
  8. looker_sdk/rtl/auth_session.py +0 -353
  9. looker_sdk/rtl/auth_token.py +0 -101
  10. looker_sdk/rtl/constants.py +0 -31
  11. looker_sdk/rtl/hooks.py +0 -86
  12. looker_sdk/rtl/model.py +0 -230
  13. looker_sdk/rtl/requests_transport.py +0 -110
  14. looker_sdk/rtl/serialize.py +0 -120
  15. looker_sdk/rtl/transport.py +0 -137
  16. looker_sdk/sdk/__init__.py +0 -0
  17. looker_sdk/sdk/api40/__init__.py +0 -1
  18. looker_sdk/sdk/api40/methods.py +0 -13283
  19. looker_sdk/sdk/api40/models.py +0 -15641
  20. looker_sdk/sdk/constants.py +0 -24
  21. looker_sdk-24.16.2.dist-info/RECORD +0 -38
  22. tests/__init__.py +0 -0
  23. tests/conftest.py +0 -133
  24. tests/integration/__init__.py +0 -2
  25. tests/integration/test_methods.py +0 -681
  26. tests/integration/test_netrc.py +0 -55
  27. tests/rtl/__init__.py +0 -2
  28. tests/rtl/test_api_methods.py +0 -216
  29. tests/rtl/test_api_settings.py +0 -252
  30. tests/rtl/test_auth_session.py +0 -284
  31. tests/rtl/test_auth_token.py +0 -70
  32. tests/rtl/test_requests_transport.py +0 -171
  33. tests/rtl/test_serialize.py +0 -770
  34. tests/rtl/test_transport.py +0 -34
  35. {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/LICENSE.txt +0 -0
  36. {looker_sdk-24.16.2.dist-info → looker_sdk-24.18.0.dist-info}/WHEEL +0 -0
@@ -1,681 +0,0 @@
1
- import datetime
2
- import io
3
- import json
4
- import re
5
- from operator import itemgetter
6
- from typing import Any, cast, Dict, List, Optional, Union, Sequence
7
-
8
- import pytest # type: ignore
9
- from PIL import Image # type: ignore
10
-
11
- from looker_sdk.sdk.api40 import methods as mtds
12
- from looker_sdk.sdk.api40 import models as ml
13
-
14
-
15
- @pytest.fixture(scope="module")
16
- def sdk(sdk40) -> mtds.Looker40SDK:
17
- return sdk40
18
-
19
-
20
- TEST_FIRST_NAME = "Rudolphontronix"
21
- TEST_LAST_NAME = "Doe"
22
-
23
-
24
- def test_crud_user(sdk: mtds.Looker40SDK):
25
- """Test creating, retrieving, updating and deleting a user."""
26
-
27
- # Create user
28
- user = sdk.create_user(
29
- ml.WriteUser(
30
- first_name=TEST_FIRST_NAME,
31
- last_name=TEST_LAST_NAME,
32
- is_disabled=False,
33
- locale="fr",
34
- )
35
- )
36
- assert isinstance(user, ml.User)
37
- assert isinstance(user.id, str)
38
- assert user.first_name == TEST_FIRST_NAME
39
- assert user.last_name == TEST_LAST_NAME
40
- assert not user.is_disabled
41
- assert user.locale == "fr"
42
-
43
- # sudo checks
44
- user_id = user.id
45
- sudo_auth = sdk.login_user(user_id)
46
- assert isinstance(sudo_auth.access_token, str)
47
- assert sudo_auth.access_token != ""
48
- sdk.auth.login_user(user_id)
49
- user = sdk.me()
50
- assert user.first_name == TEST_FIRST_NAME
51
- assert user.last_name == TEST_LAST_NAME
52
- sdk.auth.logout()
53
- user = sdk.me()
54
- assert user.first_name != TEST_FIRST_NAME
55
- assert user.last_name != TEST_LAST_NAME
56
-
57
- # Update user and check fields we didn't intend to change didn't change
58
- update_user = ml.WriteUser(is_disabled=True, locale="uk")
59
- sdk.update_user(user_id, update_user)
60
- user = sdk.user(user_id)
61
- assert user.first_name == TEST_FIRST_NAME
62
- assert user.last_name == TEST_LAST_NAME
63
- assert user.locale == "uk"
64
- assert user.is_disabled
65
-
66
- # Update user and check fields we intended to wipe out are now None
67
- # first way to specify nulling out a field
68
- update_user = ml.WriteUser(first_name=ml.EXPLICIT_NULL)
69
- # second way
70
- update_user.last_name = ml.EXPLICIT_NULL
71
- sdk.update_user(user_id, update_user)
72
- user = sdk.user(user_id)
73
- assert user.first_name == ""
74
- assert user.last_name == ""
75
-
76
- # Try adding email creds
77
- sdk.create_user_credentials_email(
78
- user_id, ml.WriteCredentialsEmail(email="john.doe@looker.com")
79
- )
80
- user = sdk.user(user_id)
81
- assert isinstance(user.credentials_email, ml.CredentialsEmail)
82
- assert user.credentials_email.email == "john.doe@looker.com"
83
-
84
- # Delete user
85
- resp = sdk.delete_user(user_id)
86
- assert resp == ""
87
-
88
-
89
- def test_crud_user_dict(sdk): # no typing
90
- """Test creating, retrieving, updating and deleting a user."""
91
-
92
- # Create user
93
- new_user = sdk.create_user(
94
- dict(
95
- first_name=TEST_FIRST_NAME,
96
- last_name=TEST_LAST_NAME,
97
- is_disabled=False,
98
- locale="fr",
99
- )
100
- )
101
- assert new_user["first_name"] == TEST_FIRST_NAME
102
- assert new_user["last_name"] == TEST_LAST_NAME
103
- assert not new_user["is_disabled"]
104
- assert new_user["locale"] == "fr"
105
-
106
- # sudo checks
107
- user_id = new_user["id"]
108
- sdk.auth.login_user(user_id)
109
- sudo_user = sdk.me()
110
- assert sudo_user["first_name"] == TEST_FIRST_NAME
111
- assert sudo_user["last_name"] == TEST_LAST_NAME
112
- sdk.auth.logout()
113
- me_user = sdk.me()
114
- assert me_user["first_name"] != TEST_FIRST_NAME
115
- assert me_user["last_name"] != TEST_LAST_NAME
116
-
117
- # Update user and check fields we didn't intend to change didn't change
118
- new_user["is_disabled"] = True
119
- new_user["locale"] = "uk"
120
- # sdk.update_user(user_id, update_user)
121
- sdk.update_user(user_id, new_user)
122
- updated_user = sdk.user(user_id)
123
- assert updated_user["first_name"] == TEST_FIRST_NAME
124
- assert updated_user["last_name"] == TEST_LAST_NAME
125
- assert updated_user["locale"] == "uk"
126
- assert updated_user["is_disabled"]
127
-
128
- update_user = dict(first_name=None)
129
- update_user["last_name"] = None
130
- sdk.update_user(user_id, update_user)
131
- user = sdk.user(user_id)
132
- assert user["first_name"] == ""
133
- assert user["last_name"] == ""
134
-
135
- # Try adding email creds
136
- sdk.create_user_credentials_email(user_id, dict(email="john.doe@looker.com"))
137
- user = sdk.user(user_id)
138
- assert user["credentials_email"]["email"] == "john.doe@looker.com"
139
-
140
- # Delete user
141
- resp = sdk.delete_user(user_id)
142
- assert resp == ""
143
-
144
-
145
- def test_me_returns_correct_result(sdk: mtds.Looker40SDK):
146
- """me() should return the current authenticated user"""
147
- me = sdk.me()
148
- assert isinstance(me, ml.User)
149
- assert isinstance(me.credentials_api3, list)
150
- assert len(me.credentials_api3) > 0
151
- assert isinstance(me.credentials_api3[0], ml.CredentialsApi3)
152
-
153
-
154
- def test_me_field_filters(sdk: mtds.Looker40SDK):
155
- """me() should return only the requested fields."""
156
- me = sdk.me("id, first_name, last_name")
157
- assert isinstance(me, ml.User)
158
- assert isinstance(me.id, str)
159
- assert isinstance(me.first_name, str)
160
- assert me.first_name != ""
161
- assert isinstance(me.last_name, str)
162
- assert me.last_name != ""
163
- assert not me.display_name
164
- assert not me.email
165
- assert not me.personal_folder_id
166
-
167
-
168
- @pytest.mark.usefixtures("test_users")
169
- def test_bad_user_search_returns_no_results(sdk: mtds.Looker40SDK):
170
- """search_users() should return an empty list when no match is found."""
171
- resp = sdk.search_users(first_name="Bad", last_name="News")
172
- assert isinstance(resp, list)
173
- assert len(resp) == 0
174
-
175
-
176
- @pytest.mark.usefixtures("test_users")
177
- def test_search_users_matches_pattern(
178
- sdk: mtds.Looker40SDK, users: List[Dict[str, str]], email_domain: str
179
- ):
180
- """search_users should return a list of all matches."""
181
- user = users[0]
182
-
183
- # Search by full email
184
- search_email = f'{user["first_name"]}.{user["last_name"]}{email_domain}'
185
- search_results = sdk.search_users_names(pattern=search_email)
186
- assert len(search_results) == 1
187
- assert search_results[0].first_name == user["first_name"]
188
- assert search_results[0].last_name == user["last_name"]
189
- assert search_results[0].email == search_email
190
-
191
- # Search by first name
192
- search_results = sdk.search_users_names(pattern=user["first_name"])
193
- assert len(search_results) > 0
194
- assert search_results[0].first_name == user["first_name"]
195
-
196
- # First name with spaces
197
- u = sdk.create_user(ml.WriteUser(first_name="John Allen", last_name="Smith"))
198
- if u.id:
199
- search_results = sdk.search_users_names(pattern="John Allen")
200
- assert len(search_results) == 1
201
- assert search_results[0].first_name == "John Allen"
202
- assert search_results[0].last_name == "Smith"
203
-
204
- # Delete user
205
- resp = sdk.delete_user(u.id)
206
- assert resp == ""
207
-
208
-
209
- def test_csv_user_id_list(sdk: mtds.Looker40SDK):
210
- """all_users() should accept a delimited array of ids."""
211
- users = sdk.all_users()
212
- assert len(users) > 1
213
- ids = [user.id for user in users]
214
- all_users = sdk.all_users(ids=ml.DelimSequence(cast(Sequence[int], ids)))
215
- assert len(all_users) == len(users)
216
-
217
-
218
- def test_enum(sdk: mtds.Looker40SDK):
219
- # TODO: there is currently no example in the Looker API of a "bare"
220
- # ForwardRef property on a model that is returned by the API. We
221
- # have unittests deserializing into "bare" ForwardRef properties,
222
- # that will have to do for now.
223
- query = ml.WriteQuery(
224
- model="system__activity",
225
- view="dashboard",
226
- fields=["dashboard.id", "dashboard.title", "dashboard.count"],
227
- )
228
- query_id = sdk.create_query(query).id
229
- assert query_id
230
- task = ml.WriteCreateQueryTask(
231
- query_id=query_id, source="test", result_format=ml.ResultFormat.csv
232
- )
233
- created = sdk.create_query_task(task)
234
- # created.result_format is type str, not ResultFormat.csv
235
- assert ml.ResultFormat.csv.value == created.result_format
236
-
237
-
238
- @pytest.mark.usefixtures("test_users")
239
- def test_it_matches_email_domain_and_returns_sorted(
240
- sdk: mtds.Looker40SDK, email_domain: str, users: List[Dict[str, str]]
241
- ):
242
- """search_users_names() should search users matching a given pattern and return
243
- sorted results if sort fields are specified.
244
- """
245
- search_results = sdk.search_users_names(
246
- pattern=f"%{email_domain}", sorts="last_name, first_name"
247
- )
248
- assert len(search_results) == len(users)
249
- sorted_test_data: List[Dict[str, str]] = sorted(
250
- users, key=itemgetter("last_name", "first_name")
251
- )
252
- for actual, expected in zip(search_results, sorted_test_data):
253
- assert actual.first_name == expected["first_name"]
254
- assert actual.last_name == expected["last_name"]
255
-
256
-
257
- @pytest.mark.usefixtures("test_users")
258
- def test_delim_sequence(
259
- sdk: mtds.Looker40SDK, email_domain: str, users: List[Dict[str, str]]
260
- ):
261
- search_results = sdk.search_users_names(pattern=f"%{email_domain}")
262
- assert len(search_results) == len(users)
263
- delim_ids = ml.DelimSequence([cast(int, u.id) for u in search_results])
264
- all_users = sdk.all_users(ids=delim_ids)
265
- assert len(all_users) == len(users)
266
-
267
-
268
- def test_it_retrieves_session(sdk: mtds.Looker40SDK):
269
- """session() should return the current session."""
270
- current_session = sdk.session()
271
- assert current_session.workspace_id == "production"
272
-
273
-
274
- def test_it_updates_session(sdk: mtds.Looker40SDK):
275
- """update_session() should allow us to change the current workspace."""
276
- # Switch workspace to dev mode
277
- sdk.update_session(ml.WriteApiSession(workspace_id="dev"))
278
- current_session = sdk.session()
279
-
280
- assert isinstance(current_session, ml.ApiSession)
281
- assert current_session.workspace_id == "dev"
282
-
283
- # Switch workspace back to production
284
- current_session = sdk.update_session(ml.WriteApiSession(workspace_id="production"))
285
-
286
- assert isinstance(current_session, ml.ApiSession)
287
- assert current_session.workspace_id == "production"
288
-
289
-
290
- TQueries = List[Dict[str, Union[str, List[str], Dict[str, str]]]]
291
-
292
-
293
- def test_it_creates_and_runs_query(
294
- sdk: mtds.Looker40SDK, queries_system_activity: TQueries
295
- ):
296
- """create_query() creates a query and run_query() returns its result."""
297
- for q in queries_system_activity:
298
- limit = cast(str, q["limit"]) or "10"
299
- request = create_query_request(q, limit)
300
- query = sdk.create_query(request)
301
- assert isinstance(query, ml.Query)
302
- assert query.id
303
- assert isinstance(query.id, str)
304
- assert query.id != '0'
305
-
306
- sql = sdk.run_query(query.id, "sql")
307
- assert "SELECT" in sql
308
-
309
- json_ = sdk.run_query(query.id, "json")
310
- assert isinstance(json_, str)
311
- json_ = json.loads(json_)
312
- assert isinstance(json_, list)
313
- assert len(json_) == int(limit)
314
- row = json_[0]
315
- if q.get("fields"):
316
- for field in q["fields"]:
317
- assert field in row.keys()
318
-
319
- csv = sdk.run_query(query.id, "csv")
320
- assert isinstance(csv, str)
321
- assert len(re.findall(r"\n", csv)) == int(limit) + 1
322
-
323
-
324
- def test_it_runs_inline_query(sdk: mtds.Looker40SDK, queries_system_activity: TQueries):
325
- """run_inline_query() should run a query and return its results."""
326
- for q in queries_system_activity:
327
- limit = cast(str, q["limit"]) or "10"
328
- request = create_query_request(q, limit)
329
-
330
- json_resp = sdk.run_inline_query("json", request)
331
- assert isinstance(json_resp, str)
332
- json_: List[Dict[str, Any]] = json.loads(json_resp)
333
- assert len(json_) == int(limit)
334
-
335
- row = json_[0]
336
- if q.get("fields"):
337
- for field in q["fields"]:
338
- assert field in row.keys()
339
-
340
- csv = sdk.run_inline_query("csv", request)
341
- assert isinstance(csv, str)
342
- assert len(re.findall(r"\n", csv)) == int(limit) + 1
343
-
344
-
345
- @pytest.mark.usefixtures("remove_test_looks")
346
- def test_crud_look(sdk: mtds.Looker40SDK, looks):
347
- """Test creating, retrieving, updating and deleting a look."""
348
- for l in looks:
349
- request = create_query_request(l["query"][0], "10")
350
- query = sdk.create_query(request)
351
-
352
- look = sdk.create_look(
353
- ml.WriteLookWithQuery(
354
- title=l.get("title"),
355
- description=l.get("description"),
356
- deleted=l.get("deleted"),
357
- is_run_on_load=l.get("is_run_on_load"),
358
- public=l.get("public"),
359
- query_id=query.id,
360
- folder_id=l.get("folder_id") or str(sdk.me().personal_folder_id),
361
- )
362
- )
363
-
364
- assert isinstance(look, ml.LookWithQuery)
365
- assert look.title == l.get("title")
366
- assert look.description == l.get("description")
367
- assert look.deleted == l.get("deleted")
368
- assert look.is_run_on_load == l.get("is_run_on_load")
369
- # TODO this is broken for local dev but works for CI...
370
- # assert look.public == l.get("public")
371
- assert look.query_id == query.id
372
- assert look.folder_id == l.get("folder_id") or sdk.me().home_folder_id
373
- assert look.user_id == l.get("user_id") or sdk.me().id
374
-
375
- # Update
376
- assert isinstance(look.id, str)
377
- updated_look = sdk.update_look(look.id, ml.WriteLookWithQuery(deleted=True))
378
- assert updated_look.deleted
379
- assert updated_look.title == look.title
380
-
381
- look = sdk.update_look(look.id, ml.WriteLookWithQuery(deleted=False))
382
- assert not look.deleted
383
-
384
-
385
- def test_png_svg_downloads(sdk: mtds.Looker40SDK):
386
- """content_thumbnail() should return a binary or string response based on the specified format."""
387
- looks = sdk.search_looks(limit=1)
388
- resource_id: str
389
- if looks:
390
- resource_type = "look"
391
- resource_id = str(looks[0].id)
392
- else:
393
- dashboards = sdk.search_dashboards(limit=1)
394
- if dashboards:
395
- resource_type = "dashboard"
396
- resource_id = cast(str, dashboards[0].id)
397
-
398
- png = sdk.content_thumbnail(
399
- type=resource_type, resource_id=resource_id, format="png"
400
- )
401
- assert isinstance(png, bytes)
402
- try:
403
- Image.open(io.BytesIO(png))
404
- except IOError:
405
- raise AssertionError("png format failed to return an image")
406
-
407
- svg = sdk.content_thumbnail(
408
- type=resource_type, resource_id=resource_id, format="svg"
409
- )
410
- assert isinstance(svg, str)
411
- assert "<?xml" in svg
412
-
413
-
414
- def test_setting_default_color_collection(sdk: mtds.Looker40SDK):
415
- """Given a color collection id, set_default_color_collection() should change the default collection."""
416
- original = sdk.default_color_collection()
417
- assert isinstance(original, ml.ColorCollection)
418
- assert isinstance(original.id, str)
419
- color_collections = sdk.all_color_collections()
420
- other: ml.ColorCollection = next(
421
- filter(lambda c: c.id != original.id, color_collections)
422
- )
423
- assert isinstance(other.id, str)
424
- actual = sdk.set_default_color_collection(other.id)
425
- assert actual.id == other.id
426
- updated = sdk.set_default_color_collection(original.id)
427
- assert updated.id == original.id
428
-
429
-
430
- def test_search_looks_returns_looks(sdk: mtds.Looker40SDK):
431
- """search_looks() should return a list of looks."""
432
- search_results = sdk.search_looks()
433
- assert isinstance(search_results, list)
434
- assert len(search_results) > 0
435
- look = search_results[0]
436
- assert isinstance(look, ml.Look)
437
- assert look.title != ""
438
- assert look.created_at is not None
439
-
440
-
441
- def test_search_looks_fields_filter(sdk: mtds.Looker40SDK):
442
- """search_looks() should only return the requested fields passed in the fields
443
- argument of the request.
444
- """
445
- search_results = sdk.search_looks(fields="id, title, description")
446
- assert isinstance(search_results, list)
447
- assert len(search_results) > 0
448
- look = search_results[0]
449
- assert isinstance(look, ml.Look)
450
- assert look.title is not None
451
- assert look.created_at is None
452
-
453
-
454
- def test_search_looks_title_fields_filter(sdk: mtds.Looker40SDK):
455
- """search_looks() should be able to filter on title."""
456
- search_results = sdk.search_looks(title="An SDK%", fields="id, title")
457
- assert isinstance(search_results, list)
458
- assert len(search_results) > 0
459
- look = search_results[0]
460
- assert isinstance(look.id, str)
461
- assert look.id != "0"
462
- assert "SDK" in look.title
463
- assert look.description is None
464
-
465
-
466
- def test_search_look_and_run(sdk: mtds.Looker40SDK):
467
- """run_look() should return CSV and JSON
468
- CSV will use column descriptions
469
- JSON will use column names
470
- JSON_LABEL will use column descriptions
471
- """
472
- search_results = sdk.search_looks(title="An SDK Look", fields="id, title")
473
- assert isinstance(search_results, list)
474
- assert len(search_results) > 0
475
- look = search_results[0]
476
- assert isinstance(look.id, str)
477
- assert look.id != "0"
478
- assert "SDK" in look.title
479
- assert look.description is None
480
- actual = sdk.run_look(look_id=look.id, result_format="csv")
481
- assert "Dashboard Count" in actual
482
- assert "Dashboard ID" in actual
483
- actual = sdk.run_look(look_id=look.id, result_format="json")
484
- assert "dashboard.count" in actual
485
- assert "dashboard.id" in actual
486
- actual = sdk.run_look(look_id=look.id, result_format="json_label")
487
- assert "Dashboard Count" in actual
488
- assert "Dashboard ID" in actual
489
-
490
-
491
- def create_query_request(q, limit: Optional[str] = None) -> ml.WriteQuery:
492
- return ml.WriteQuery(
493
- model=q.get("model"),
494
- view=q.get("view"),
495
- fields=q.get("fields"),
496
- pivots=q.get("pivots"),
497
- fill_fields=q.get("fill_fields"),
498
- filters=q.get("filters"),
499
- filter_expression=q.get("filter_expressions"),
500
- sorts=q.get("sorts"),
501
- limit=q.get("limit") or limit,
502
- column_limit=q.get("column_limit"),
503
- total=q.get("total"),
504
- row_total=q.get("row_total"),
505
- subtotals=q.get("subtotal"),
506
- vis_config=q.get("vis_config"),
507
- filter_config=q.get("filter_config"),
508
- visible_ui_sections=q.get("visible_ui_sections"),
509
- dynamic_fields=q.get("dynamic_fields"),
510
- client_id=q.get("client_id"),
511
- query_timezone=q.get("query_timezone"),
512
- )
513
-
514
-
515
- @pytest.mark.usefixtures("remove_test_dashboards")
516
- def test_crud_dashboard(sdk: mtds.Looker40SDK, queries_system_activity, dashboards):
517
- """Test creating, retrieving, updating and deleting a dashboard."""
518
- qhash: Dict[Union[str, int], ml.Query] = {}
519
- for idx, q in enumerate(queries_system_activity):
520
- limit = "10"
521
- request = create_query_request(q, limit)
522
- key = q.get("id") or str(idx)
523
- qhash[key] = sdk.create_query(request)
524
-
525
- for d in dashboards:
526
- dashboard = sdk.create_dashboard(
527
- ml.WriteDashboard(
528
- description=d.get("description"),
529
- hidden=d.get("hidden"),
530
- query_timezone=d.get("query_timezone"),
531
- refresh_interval=d.get("refresh_interval"),
532
- title=d.get("title"),
533
- background_color=d.get("background_color"),
534
- load_configuration=d.get("load_configuration"),
535
- lookml_link_id=d.get("lookml_link_id"),
536
- show_filters_bar=d.get("show_filters_bar"),
537
- show_title=d.get("show_title"),
538
- slug=d.get("slug"),
539
- folder_id=d.get("folder_id") or sdk.me().home_folder_id,
540
- text_tile_text_color=d.get("text_tile_text_color"),
541
- tile_background_color=d.get("tile_background_color"),
542
- tile_text_color=d.get("tile_text_color"),
543
- title_color=d.get("title_color"),
544
- )
545
- )
546
-
547
- assert isinstance(dashboard, ml.Dashboard)
548
- assert isinstance(dashboard.created_at, datetime.datetime)
549
-
550
- if d.get("background_color"):
551
- assert d["background_color"] == dashboard.background_color
552
-
553
- if d.get("text_tile_text_color"):
554
- assert d["text_tile_text_color"] == dashboard.text_tile_text_color
555
-
556
- if d.get("tile_background_color"):
557
- assert d["tile_background_color"] == dashboard.tile_background_color
558
-
559
- if d.get("tile_text_color"):
560
- assert d["tile_text_color"] == dashboard.tile_text_color
561
-
562
- if d.get("title_color"):
563
- assert d["title_color"] == dashboard.title_color
564
-
565
- # Update dashboard
566
- assert isinstance(dashboard.id, str)
567
- update_response = sdk.update_dashboard(
568
- dashboard.id, ml.WriteDashboard(deleted=True)
569
- )
570
- assert update_response.deleted
571
- assert update_response.title == dashboard.title
572
-
573
- dashboard = sdk.update_dashboard(dashboard.id, ml.WriteDashboard(deleted=False))
574
- assert isinstance(dashboard.id, str)
575
- assert not dashboard.deleted
576
-
577
- if d.get("filters"):
578
- for f in d["filters"]:
579
- filter = sdk.create_dashboard_filter(
580
- ml.WriteCreateDashboardFilter(
581
- dashboard_id=dashboard.id,
582
- name=f.get("name"),
583
- title=f.get("title"),
584
- type=f.get("type"),
585
- default_value=f.get("default_value"),
586
- model=f.get("model"),
587
- explore=f.get("explore"),
588
- dimension=f.get("dimension"),
589
- row=f.get("row"),
590
- listens_to_filters=f.get("listens_to_filters"),
591
- allow_multiple_values=f.get("allow_multiple_values"),
592
- required=f.get("required"),
593
- )
594
- )
595
- assert isinstance(filter, ml.DashboardFilter)
596
- assert filter.name == f.get("name")
597
- assert filter.title == f.get("title")
598
- assert filter.type == f.get("type")
599
- assert filter.default_value == f.get("default_value")
600
- assert filter.model == f.get("model")
601
- assert filter.explore == f.get("explore")
602
- assert filter.dimension == f.get("dimension")
603
- assert filter.row == f.get("row")
604
- assert filter.allow_multiple_values == f.get(
605
- "allow_multiple_values", False
606
- )
607
- assert filter.required == f.get("required", False)
608
-
609
- if d.get("tiles"):
610
- for t in d["tiles"]:
611
- tile = sdk.create_dashboard_element(
612
- ml.WriteDashboardElement(
613
- body_text=t.get("body_text"),
614
- dashboard_id=dashboard.id,
615
- look=t.get("look"),
616
- look_id=t.get("look_id"),
617
- merge_result_id=t.get("merge_result_id"),
618
- note_display=t.get("note_display"),
619
- note_state=t.get("note_state"),
620
- note_text=t.get("note_text"),
621
- query=t.get("query"),
622
- query_id=get_query_id(qhash, t.get("query_id")),
623
- refresh_interval=t.get("refresh_interval"),
624
- subtitle_text=t.get("subtitle_text"),
625
- title=t.get("title"),
626
- title_hidden=t.get("title_hidden"),
627
- type=t.get("type"),
628
- )
629
- )
630
-
631
- assert isinstance(tile, ml.DashboardElement)
632
- assert tile.dashboard_id == dashboard.id
633
- assert tile.title == t.get("title")
634
- assert tile.type == t.get("type")
635
-
636
-
637
- def get_query_id(
638
- qhash: Dict[Union[str, int], ml.Query], id: Union[str, int]
639
- ) -> Optional[int]:
640
- if isinstance(id, str) and id.startswith("#"):
641
- id = id[1:]
642
- # if id is invalid, default to first query. test data is bad
643
- query = qhash.get(id) or list(qhash.values())[0]
644
- query_id = query.id
645
- elif (isinstance(id, str) and id.isdigit()) or isinstance(id, int):
646
- query_id = int(id)
647
- else:
648
- query_id = None
649
- return query_id
650
-
651
- @pytest.mark.skip(reason="TODO: This breaks CI right now")
652
- def test_validate_theme(sdk: mtds.Looker40SDK):
653
-
654
- valid_theme_response = sdk.validate_theme(
655
- body = ml.WriteTheme(
656
- name = 'valid_theme',
657
- settings = ml.ThemeSettings(
658
- show_filters_bar = False,
659
- show_title = False,
660
- tile_shadow = False,
661
- font_family = 'Arial',
662
- )
663
- )
664
- )
665
- assert valid_theme_response == ""
666
-
667
- try:
668
- sdk.validate_theme(
669
- body = ml.WriteTheme(
670
- settings = ml.ThemeSettings(
671
- show_filters_bar = False,
672
- show_title = False,
673
- tile_shadow = False,
674
- font_family = 'Arial;',
675
- )
676
- )
677
- )
678
- except Exception as e:
679
- assert e.message is not None
680
- assert e.message != ""
681
- assert len(e.errors) == 3