tableauserverclient 0.25__py3-none-any.whl → 0.27.post0.dev1__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 (77) hide show
  1. tableauserverclient/__init__.py +42 -1
  2. tableauserverclient/_version.py +4 -4
  3. tableauserverclient/config.py +13 -0
  4. tableauserverclient/datetime_helpers.py +4 -0
  5. tableauserverclient/helpers/logging.py +4 -0
  6. tableauserverclient/models/__init__.py +1 -1
  7. tableauserverclient/models/column_item.py +3 -0
  8. tableauserverclient/models/connection_credentials.py +7 -0
  9. tableauserverclient/models/connection_item.py +1 -1
  10. tableauserverclient/models/custom_view_item.py +5 -0
  11. tableauserverclient/models/data_acceleration_report_item.py +3 -0
  12. tableauserverclient/models/datasource_item.py +10 -54
  13. tableauserverclient/models/favorites_item.py +56 -40
  14. tableauserverclient/models/fileupload_item.py +2 -2
  15. tableauserverclient/models/flow_item.py +30 -25
  16. tableauserverclient/models/group_item.py +1 -4
  17. tableauserverclient/models/interval_item.py +12 -0
  18. tableauserverclient/models/job_item.py +10 -1
  19. tableauserverclient/models/metric_item.py +36 -29
  20. tableauserverclient/models/pagination_item.py +3 -0
  21. tableauserverclient/models/permissions_item.py +8 -5
  22. tableauserverclient/models/project_item.py +11 -13
  23. tableauserverclient/models/schedule_item.py +6 -7
  24. tableauserverclient/models/server_info_item.py +2 -2
  25. tableauserverclient/models/site_item.py +3 -0
  26. tableauserverclient/models/subscription_item.py +8 -0
  27. tableauserverclient/models/table_item.py +6 -0
  28. tableauserverclient/models/tableau_auth.py +41 -6
  29. tableauserverclient/models/tableau_types.py +4 -2
  30. tableauserverclient/models/user_item.py +5 -1
  31. tableauserverclient/models/view_item.py +39 -36
  32. tableauserverclient/models/workbook_item.py +14 -43
  33. tableauserverclient/server/__init__.py +1 -3
  34. tableauserverclient/server/endpoint/__init__.py +1 -5
  35. tableauserverclient/server/endpoint/auth_endpoint.py +29 -8
  36. tableauserverclient/server/endpoint/custom_views_endpoint.py +1 -1
  37. tableauserverclient/server/endpoint/data_acceleration_report_endpoint.py +1 -1
  38. tableauserverclient/server/endpoint/data_alert_endpoint.py +1 -1
  39. tableauserverclient/server/endpoint/databases_endpoint.py +1 -1
  40. tableauserverclient/server/endpoint/datasources_endpoint.py +21 -15
  41. tableauserverclient/server/endpoint/default_permissions_endpoint.py +1 -1
  42. tableauserverclient/server/endpoint/dqw_endpoint.py +1 -1
  43. tableauserverclient/server/endpoint/endpoint.py +98 -11
  44. tableauserverclient/server/endpoint/exceptions.py +1 -5
  45. tableauserverclient/server/endpoint/favorites_endpoint.py +71 -29
  46. tableauserverclient/server/endpoint/fileuploads_endpoint.py +11 -10
  47. tableauserverclient/server/endpoint/flow_runs_endpoint.py +1 -1
  48. tableauserverclient/server/endpoint/flows_endpoint.py +5 -5
  49. tableauserverclient/server/endpoint/groups_endpoint.py +5 -2
  50. tableauserverclient/server/endpoint/jobs_endpoint.py +1 -1
  51. tableauserverclient/server/endpoint/metadata_endpoint.py +1 -1
  52. tableauserverclient/server/endpoint/metrics_endpoint.py +1 -1
  53. tableauserverclient/server/endpoint/permissions_endpoint.py +1 -1
  54. tableauserverclient/server/endpoint/projects_endpoint.py +3 -1
  55. tableauserverclient/server/endpoint/resource_tagger.py +3 -3
  56. tableauserverclient/server/endpoint/schedules_endpoint.py +2 -1
  57. tableauserverclient/server/endpoint/server_info_endpoint.py +2 -4
  58. tableauserverclient/server/endpoint/sites_endpoint.py +1 -1
  59. tableauserverclient/server/endpoint/subscriptions_endpoint.py +1 -1
  60. tableauserverclient/server/endpoint/tables_endpoint.py +1 -1
  61. tableauserverclient/server/endpoint/tasks_endpoint.py +12 -1
  62. tableauserverclient/server/endpoint/users_endpoint.py +1 -1
  63. tableauserverclient/server/endpoint/views_endpoint.py +1 -1
  64. tableauserverclient/server/endpoint/webhooks_endpoint.py +1 -1
  65. tableauserverclient/server/endpoint/workbooks_endpoint.py +4 -2
  66. tableauserverclient/server/exceptions.py +8 -1
  67. tableauserverclient/server/filter.py +5 -1
  68. tableauserverclient/server/request_factory.py +56 -12
  69. tableauserverclient/server/request_options.py +4 -2
  70. tableauserverclient/server/server.py +12 -13
  71. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/METADATA +12 -10
  72. tableauserverclient-0.27.post0.dev1.dist-info/RECORD +97 -0
  73. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/WHEEL +1 -1
  74. tableauserverclient-0.25.dist-info/RECORD +0 -95
  75. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/LICENSE +0 -0
  76. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/LICENSE.versioneer +0 -0
  77. {tableauserverclient-0.25.dist-info → tableauserverclient-0.27.post0.dev1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,47 @@
1
1
  from ._version import get_versions
2
2
  from .namespace import NEW_NAMESPACE as DEFAULT_NAMESPACE
3
- from .models import *
3
+ from .models import (
4
+ BackgroundJobItem,
5
+ ColumnItem,
6
+ ConnectionCredentials,
7
+ ConnectionItem,
8
+ CustomViewItem,
9
+ DQWItem,
10
+ DailyInterval,
11
+ DataAlertItem,
12
+ DatabaseItem,
13
+ DatasourceItem,
14
+ FavoriteItem,
15
+ FlowItem,
16
+ FlowRunItem,
17
+ FileuploadItem,
18
+ GroupItem,
19
+ HourlyInterval,
20
+ IntervalItem,
21
+ JobItem,
22
+ JWTAuth,
23
+ MetricItem,
24
+ MonthlyInterval,
25
+ PaginationItem,
26
+ Permission,
27
+ PermissionsRule,
28
+ PersonalAccessTokenAuth,
29
+ ProjectItem,
30
+ RevisionItem,
31
+ ScheduleItem,
32
+ SiteItem,
33
+ ServerInfoItem,
34
+ SubscriptionItem,
35
+ TableItem,
36
+ TableauAuth,
37
+ Target,
38
+ TaskItem,
39
+ UserItem,
40
+ ViewItem,
41
+ WebhookItem,
42
+ WeeklyInterval,
43
+ WorkbookItem,
44
+ )
4
45
  from .server import (
5
46
  CSVRequestOptions,
6
47
  ExcelRequestOptions,
@@ -1,5 +1,5 @@
1
1
 
2
- # This file was generated by 'versioneer.py' (0.28) from
2
+ # This file was generated by 'versioneer.py' (0.29) from
3
3
  # revision-control system data, or from the parent directory name of an
4
4
  # unpacked source archive. Distribution tarballs contain a pre-generated copy
5
5
  # of this file.
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2023-03-16T11:05:21-0700",
11
+ "date": "2023-10-04T00:33:03-0700",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "e4fbe41560fbd2314c9c7b8b8a169164dd15185f",
15
- "version": "0.25"
14
+ "full-revisionid": "72eb3c8500193e4f20defa20c8a6f8bbf34b2f43",
15
+ "version": "0.27.post0.dev1"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -0,0 +1,13 @@
1
+ # TODO: check for env variables, else set default values
2
+
3
+ ALLOWED_FILE_EXTENSIONS = ["tds", "tdsx", "tde", "hyper", "parquet"]
4
+
5
+ BYTES_PER_MB = 1024 * 1024
6
+
7
+ # For when a datasource is over 64MB, break it into 5MB(standard chunk size) chunks
8
+ CHUNK_SIZE_MB = 5 * 10 # 5MB felt too slow, upped it to 50
9
+
10
+ DELAY_SLEEP_SECONDS = 10
11
+
12
+ # The maximum size of a file that can be published in a single request is 64MB
13
+ FILESIZE_LIMIT_MB = 64
@@ -5,6 +5,10 @@ ZERO = datetime.timedelta(0)
5
5
  HOUR = datetime.timedelta(hours=1)
6
6
 
7
7
 
8
+ def timestamp():
9
+ return datetime.datetime.now().strftime("%H:%M:%S")
10
+
11
+
8
12
  # This class is a concrete implementation of the abstract base class tzinfo
9
13
  # docs: https://docs.python.org/2.3/lib/datetime-tzinfo.html
10
14
  class UTC(datetime.tzinfo):
@@ -0,0 +1,4 @@
1
+ import logging
2
+
3
+ # TODO change: this defaults to logging *everything* to stdout
4
+ logger = logging.getLogger("TSC")
@@ -31,7 +31,7 @@ from .server_info_item import ServerInfoItem
31
31
  from .site_item import SiteItem
32
32
  from .subscription_item import SubscriptionItem
33
33
  from .table_item import TableItem
34
- from .tableau_auth import Credentials, TableauAuth, PersonalAccessTokenAuth
34
+ from .tableau_auth import Credentials, TableauAuth, PersonalAccessTokenAuth, JWTAuth
35
35
  from .tableau_types import Resource, TableauItem, plural_type
36
36
  from .tag_item import TagItem
37
37
  from .target import Target
@@ -9,6 +9,9 @@ class ColumnItem(object):
9
9
  self.description = description
10
10
  self.name = name
11
11
 
12
+ def __repr__(self):
13
+ return f"<{self.__class__.__name__} {self._id} {self.name} {self.description}>"
14
+
12
15
  @property
13
16
  def id(self):
14
17
  return self._id
@@ -15,6 +15,13 @@ class ConnectionCredentials(object):
15
15
  self.embed = embed
16
16
  self.oauth = oauth
17
17
 
18
+ def __repr__(self):
19
+ if self.password:
20
+ print = "redacted"
21
+ else:
22
+ print = "None"
23
+ return f"<{self.__class__.__name__} name={self.name} password={print} embed={self.embed} oauth={self.oauth} >"
24
+
18
25
  @property
19
26
  def embed(self):
20
27
  return self._embed
@@ -5,6 +5,7 @@ from defusedxml.ElementTree import fromstring
5
5
 
6
6
  from .connection_credentials import ConnectionCredentials
7
7
  from .property_decorators import property_is_boolean
8
+ from tableauserverclient.helpers.logging import logger
8
9
 
9
10
 
10
11
  class ConnectionItem(object):
@@ -46,7 +47,6 @@ class ConnectionItem(object):
46
47
  def query_tagging(self, value: Optional[bool]):
47
48
  # if connection type = hyper, Snowflake, or Teradata, we can't change this value: it is always true
48
49
  if self._connection_type in ["hyper", "snowflake", "teradata"]:
49
- logger = logging.getLogger("tableauserverclient.models.connection_item")
50
50
  logger.debug(
51
51
  "Cannot update value: Query tagging is always enabled for {} connections".format(self._connection_type)
52
52
  )
@@ -134,6 +134,7 @@ class CustomViewItem(object):
134
134
  cv_item._content_url = custom_view_xml.get("contentUrl", None)
135
135
  cv_item._id = custom_view_xml.get("id", None)
136
136
  cv_item._name = custom_view_xml.get("name", None)
137
+ cv_item._shared = string_to_bool(custom_view_xml.get("shared", None))
137
138
 
138
139
  if owner_elem is not None:
139
140
  parsed_owners = UserItem.from_response_as_owner(tostring(custom_view_xml), ns)
@@ -154,3 +155,7 @@ class CustomViewItem(object):
154
155
 
155
156
  all_view_items.append(cv_item)
156
157
  return all_view_items
158
+
159
+
160
+ def string_to_bool(s: Optional[str]) -> bool:
161
+ return (s or "").lower() == "true"
@@ -46,6 +46,9 @@ class DataAccelerationReportItem(object):
46
46
  def __init__(self, comparison_records):
47
47
  self._comparison_records = comparison_records
48
48
 
49
+ def __repr__(self):
50
+ return f"<(deprecated)DataAccelerationReportItem site={self.site} sheet={sheet_uri}>"
51
+
49
52
  @property
50
53
  def comparison_records(self):
51
54
  return self._comparison_records
@@ -32,7 +32,7 @@ class DatasourceItem(object):
32
32
  self.project_id,
33
33
  )
34
34
 
35
- def __init__(self, project_id: str, name: Optional[str] = None) -> None:
35
+ def __init__(self, project_id: Optional[str] = None, name: Optional[str] = None) -> None:
36
36
  self._ask_data_enablement = None
37
37
  self._certified = None
38
38
  self._certification_note = None
@@ -135,12 +135,11 @@ class DatasourceItem(object):
135
135
  return self._id
136
136
 
137
137
  @property
138
- def project_id(self) -> str:
138
+ def project_id(self) -> Optional[str]:
139
139
  return self._project_id
140
140
 
141
141
  @project_id.setter
142
- @property_not_nullable
143
- def project_id(self, value: str):
142
+ def project_id(self, value: Optional[str]):
144
143
  self._project_id = value
145
144
 
146
145
  @property
@@ -306,50 +305,16 @@ class DatasourceItem(object):
306
305
  all_datasource_xml = parsed_response.findall(".//t:datasource", namespaces=ns)
307
306
 
308
307
  for datasource_xml in all_datasource_xml:
309
- (
310
- ask_data_enablement,
311
- certified,
312
- certification_note,
313
- content_url,
314
- created_at,
315
- datasource_type,
316
- description,
317
- encrypt_extracts,
318
- has_extracts,
319
- id_,
320
- name,
321
- owner_id,
322
- project_id,
323
- project_name,
324
- tags,
325
- updated_at,
326
- use_remote_query_agent,
327
- webpage_url,
328
- ) = cls._parse_element(datasource_xml, ns)
329
- datasource_item = cls(project_id)
330
- datasource_item._set_values(
331
- ask_data_enablement,
332
- certified,
333
- certification_note,
334
- content_url,
335
- created_at,
336
- datasource_type,
337
- description,
338
- encrypt_extracts,
339
- has_extracts,
340
- id_,
341
- name,
342
- owner_id,
343
- None,
344
- project_name,
345
- tags,
346
- updated_at,
347
- use_remote_query_agent,
348
- webpage_url,
349
- )
308
+ datasource_item = cls.from_xml(datasource_xml, ns)
350
309
  all_datasource_items.append(datasource_item)
351
310
  return all_datasource_items
352
311
 
312
+ @classmethod
313
+ def from_xml(cls, datasource_xml, ns):
314
+ datasource_item = cls()
315
+ datasource_item._set_values(*cls._parse_element(datasource_xml, ns))
316
+ return datasource_item
317
+
353
318
  @staticmethod
354
319
  def _parse_element(datasource_xml: ET.Element, ns: Dict) -> Tuple:
355
320
  id_ = datasource_xml.get("id", None)
@@ -361,17 +326,8 @@ class DatasourceItem(object):
361
326
  updated_at = parse_datetime(datasource_xml.get("updatedAt", None))
362
327
  certification_note = datasource_xml.get("certificationNote", None)
363
328
  certified = str(datasource_xml.get("isCertified", None)).lower() == "true"
364
- certification_note = datasource_xml.get("certificationNote", None)
365
- certified = str(datasource_xml.get("isCertified", None)).lower() == "true"
366
- content_url = datasource_xml.get("contentUrl", None)
367
- created_at = parse_datetime(datasource_xml.get("createdAt", None))
368
- datasource_type = datasource_xml.get("type", None)
369
- description = datasource_xml.get("description", None)
370
329
  encrypt_extracts = datasource_xml.get("encryptExtracts", None)
371
330
  has_extracts = datasource_xml.get("hasExtracts", None)
372
- id_ = datasource_xml.get("id", None)
373
- name = datasource_xml.get("name", None)
374
- updated_at = parse_datetime(datasource_xml.get("updatedAt", None))
375
331
  use_remote_query_agent = datasource_xml.get("useRemoteQueryAgent", None)
376
332
  webpage_url = datasource_xml.get("webpageUrl", None)
377
333
 
@@ -1,74 +1,90 @@
1
1
  import logging
2
2
 
3
3
  from defusedxml.ElementTree import fromstring
4
+ from .tableau_types import TableauItem
4
5
 
5
6
  from .datasource_item import DatasourceItem
6
7
  from .flow_item import FlowItem
7
8
  from .project_item import ProjectItem
9
+ from .metric_item import MetricItem
8
10
  from .view_item import ViewItem
9
11
  from .workbook_item import WorkbookItem
12
+ from typing import Dict, List
10
13
 
11
- logger = logging.getLogger("tableau.models.favorites_item")
12
-
14
+ from tableauserverclient.helpers.logging import logger
13
15
  from typing import Dict, List, Union
14
16
 
15
17
  FavoriteType = Dict[
16
18
  str,
17
- List[
18
- Union[
19
- DatasourceItem,
20
- ProjectItem,
21
- FlowItem,
22
- ViewItem,
23
- WorkbookItem,
24
- ]
25
- ],
19
+ List[TableauItem],
26
20
  ]
27
21
 
28
22
 
29
23
  class FavoriteItem:
30
- class Type:
31
- Workbook: str = "workbook"
32
- Datasource: str = "datasource"
33
- View: str = "view"
34
- Project: str = "project"
35
- Flow: str = "flow"
36
-
37
24
  @classmethod
38
25
  def from_response(cls, xml: str, namespace: Dict) -> FavoriteType:
39
26
  favorites: FavoriteType = {
40
27
  "datasources": [],
41
28
  "flows": [],
42
29
  "projects": [],
30
+ "metrics": [],
43
31
  "views": [],
44
32
  "workbooks": [],
45
33
  }
46
-
47
34
  parsed_response = fromstring(xml)
48
- for workbook in parsed_response.findall(".//t:favorite/t:workbook", namespace):
49
- fav_workbook = WorkbookItem("")
50
- fav_workbook._set_values(*fav_workbook._parse_element(workbook, namespace))
51
- if fav_workbook:
52
- favorites["workbooks"].append(fav_workbook)
53
- for view in parsed_response.findall(".//t:favorite[t:view]", namespace):
54
- fav_views = ViewItem.from_xml_element(view, namespace)
55
- if fav_views:
56
- for fav_view in fav_views:
57
- favorites["views"].append(fav_view)
58
- for datasource in parsed_response.findall(".//t:favorite/t:datasource", namespace):
59
- fav_datasource = DatasourceItem("")
60
- fav_datasource._set_values(*fav_datasource._parse_element(datasource, namespace))
35
+
36
+ datasources_xml = parsed_response.findall(".//t:favorite/t:datasource", namespace)
37
+ flows_xml = parsed_response.findall(".//t:favorite/t:flow", namespace)
38
+ metrics_xml = parsed_response.findall(".//t:favorite/t:metric", namespace)
39
+ projects_xml = parsed_response.findall(".//t:favorite/t:project", namespace)
40
+ views_xml = parsed_response.findall(".//t:favorite/t:view", namespace)
41
+ workbooks_xml = parsed_response.findall(".//t:favorite/t:workbook", namespace)
42
+
43
+ logger.debug(
44
+ "ds: {}, flows: {}, metrics: {}, projects: {}, views: {}, wbs: {}".format(
45
+ len(datasources_xml),
46
+ len(flows_xml),
47
+ len(metrics_xml),
48
+ len(projects_xml),
49
+ len(views_xml),
50
+ len(workbooks_xml),
51
+ )
52
+ )
53
+ for datasource in datasources_xml:
54
+ fav_datasource = DatasourceItem.from_xml(datasource, namespace)
61
55
  if fav_datasource:
56
+ logger.debug(fav_datasource)
62
57
  favorites["datasources"].append(fav_datasource)
63
- for project in parsed_response.findall(".//t:favorite/t:project", namespace):
64
- fav_project = ProjectItem("p")
65
- fav_project._set_values(*fav_project._parse_element(project))
66
- if fav_project:
67
- favorites["projects"].append(fav_project)
68
- for flow in parsed_response.findall(".//t:favorite/t:flow", namespace):
69
- fav_flow = FlowItem("flows")
70
- fav_flow._set_values(*fav_flow._parse_element(flow, namespace))
58
+
59
+ for flow in flows_xml:
60
+ fav_flow = FlowItem.from_xml(flow, namespace)
71
61
  if fav_flow:
62
+ logger.debug(fav_flow)
72
63
  favorites["flows"].append(fav_flow)
73
64
 
65
+ for metric in metrics_xml:
66
+ fav_metric = MetricItem.from_xml(metric, namespace)
67
+ if fav_metric:
68
+ logger.debug(fav_metric)
69
+ favorites["metrics"].append(fav_metric)
70
+
71
+ for project in projects_xml:
72
+ fav_project = ProjectItem.from_xml(project, namespace)
73
+ if fav_project:
74
+ logger.debug(fav_project)
75
+ favorites["projects"].append(fav_project)
76
+
77
+ for view in views_xml:
78
+ fav_view = ViewItem.from_xml(view, namespace)
79
+ if fav_view:
80
+ logger.debug(fav_view)
81
+ favorites["views"].append(fav_view)
82
+
83
+ for workbook in workbooks_xml:
84
+ fav_workbook = WorkbookItem.from_xml(workbook, namespace)
85
+ if fav_workbook:
86
+ logger.debug(fav_workbook)
87
+ favorites["workbooks"].append(fav_workbook)
88
+
89
+ logger.debug(favorites)
74
90
  return favorites
@@ -11,8 +11,8 @@ class FileuploadItem(object):
11
11
  return self._upload_session_id
12
12
 
13
13
  @property
14
- def file_size(self):
15
- return self._file_size
14
+ def file_size(self) -> int:
15
+ return int(self._file_size)
16
16
 
17
17
  @classmethod
18
18
  def from_response(cls, resp, ns):
@@ -176,34 +176,39 @@ class FlowItem(object):
176
176
  all_flow_xml = parsed_response.findall(".//t:flow", namespaces=ns)
177
177
 
178
178
  for flow_xml in all_flow_xml:
179
- (
180
- id_,
181
- name,
182
- description,
183
- webpage_url,
184
- created_at,
185
- updated_at,
186
- tags,
187
- project_id,
188
- project_name,
189
- owner_id,
190
- ) = cls._parse_element(flow_xml, ns)
191
- flow_item = cls(project_id)
192
- flow_item._set_values(
193
- id_,
194
- name,
195
- description,
196
- webpage_url,
197
- created_at,
198
- updated_at,
199
- tags,
200
- None,
201
- project_name,
202
- owner_id,
203
- )
179
+ flow_item = cls.from_xml(flow_xml, ns)
204
180
  all_flow_items.append(flow_item)
205
181
  return all_flow_items
206
182
 
183
+ @classmethod
184
+ def from_xml(cls, flow_xml, ns) -> "FlowItem":
185
+ (
186
+ id_,
187
+ name,
188
+ description,
189
+ webpage_url,
190
+ created_at,
191
+ updated_at,
192
+ tags,
193
+ project_id,
194
+ project_name,
195
+ owner_id,
196
+ ) = cls._parse_element(flow_xml, ns)
197
+ flow_item = cls(project_id)
198
+ flow_item._set_values(
199
+ id_,
200
+ name,
201
+ description,
202
+ webpage_url,
203
+ created_at,
204
+ updated_at,
205
+ tags,
206
+ None,
207
+ project_name,
208
+ owner_id,
209
+ )
210
+ return flow_item
211
+
207
212
  @staticmethod
208
213
  def _parse_element(flow_xml, ns):
209
214
  id_ = flow_xml.get("id", None)
@@ -26,11 +26,9 @@ class GroupItem(object):
26
26
  self.name: Optional[str] = name
27
27
  self.domain_name: Optional[str] = domain_name
28
28
 
29
- def __str__(self):
29
+ def __repr__(self):
30
30
  return "{}({!r})".format(self.__class__.__name__, self.__dict__)
31
31
 
32
- __repr__ = __str__
33
-
34
32
  @property
35
33
  def domain_name(self) -> Optional[str]:
36
34
  return self._domain_name
@@ -48,7 +46,6 @@ class GroupItem(object):
48
46
  return self._name
49
47
 
50
48
  @name.setter
51
- @property_not_empty
52
49
  def name(self, value: str) -> None:
53
50
  self._name = value
54
51
 
@@ -31,6 +31,9 @@ class HourlyInterval(object):
31
31
  self.end_time = end_time
32
32
  self.interval = interval_value
33
33
 
34
+ def __repr__(self):
35
+ return f"<{self.__class__.__name__} start={self.start_time} end={self.end_time} interval={self.interval}>"
36
+
34
37
  @property
35
38
  def _frequency(self):
36
39
  return IntervalItem.Frequency.Hourly
@@ -86,6 +89,9 @@ class DailyInterval(object):
86
89
  self.start_time = start_time
87
90
  self.interval = interval_values
88
91
 
92
+ def __repr__(self):
93
+ return f"<{self.__class__.__name__} start={self.start_time} interval={self.interval}>"
94
+
89
95
  @property
90
96
  def _frequency(self):
91
97
  return IntervalItem.Frequency.Daily
@@ -114,6 +120,9 @@ class WeeklyInterval(object):
114
120
  self.start_time = start_time
115
121
  self.interval = interval_values
116
122
 
123
+ def __repr__(self):
124
+ return f"<{self.__class__.__name__} start={self.start_time} interval={self.interval}>"
125
+
117
126
  @property
118
127
  def _frequency(self):
119
128
  return IntervalItem.Frequency.Weekly
@@ -148,6 +157,9 @@ class MonthlyInterval(object):
148
157
  self.start_time = start_time
149
158
  self.interval = str(interval_value)
150
159
 
160
+ def __repr__(self):
161
+ return f"<{self.__class__.__name__} start={self.start_time} interval={self.interval}>"
162
+
151
163
  @property
152
164
  def _frequency(self):
153
165
  return IntervalItem.Frequency.Monthly
@@ -117,12 +117,15 @@ class JobItem(object):
117
117
  def updated_at(self) -> Optional[datetime.datetime]:
118
118
  return self._updated_at
119
119
 
120
- def __repr__(self):
120
+ def __str__(self):
121
121
  return (
122
122
  "<Job#{_id} {_type} created_at({_created_at}) started_at({_started_at}) updated_at({_updated_at}) completed_at({_completed_at})"
123
123
  " progress ({_progress}) finish_code({_finish_code})>".format(**self.__dict__)
124
124
  )
125
125
 
126
+ def __repr__(self):
127
+ return self.__str__() + " { " + ", ".join(" % s: % s" % item for item in vars(self).items()) + "}"
128
+
126
129
  @classmethod
127
130
  def from_response(cls, xml, ns) -> List["JobItem"]:
128
131
  parsed_response = fromstring(xml)
@@ -202,6 +205,12 @@ class BackgroundJobItem(object):
202
205
  self._title = title
203
206
  self._subtitle = subtitle
204
207
 
208
+ def __str__(self):
209
+ return f"<{self.__class__.name} {self._id} {self._type}>"
210
+
211
+ def __repr__(self):
212
+ return self.__str__() + " { " + ", ".join(" % s: % s" % item for item in vars(self).items()) + "}"
213
+
205
214
  @property
206
215
  def id(self) -> str:
207
216
  return self._id