Skip to content

Commit 2d0e4e3

Browse files
authored
Jac/repr for models (#1191)
* add repr to several models * test all model classes for __repr__ add a dumb listing of all existing model classes, and a test that iterates over the whole list. Uses subtests so we get the whole list. Test is skipped because we know they don't all have it yet. Will update to skip known not-implemented models instead.
1 parent b184ba1 commit 2d0e4e3

File tree

11 files changed

+138
-7
lines changed

11 files changed

+138
-7
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ classifiers = [
3030
repository = "https://github.com/tableau/server-client-python"
3131

3232
[project.optional-dependencies]
33-
test = ["argparse", "black", "mock", "mypy", "pytest>=7.0", "requests-mock>=1.0,<2.0"]
33+
test = ["argparse", "black", "mock", "mypy", "pytest>=7.0", "pytest-subtests", "requests-mock>=1.0,<2.0"]
3434

3535
[tool.black]
3636
line-length = 120

tableauserverclient/models/datasource_item.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ class AskDataEnablement:
2424
Disabled = "Disabled"
2525
SiteDefault = "SiteDefault"
2626

27+
def __repr__(self):
28+
return "<Datasource {0} '{1}' ({2} parent={3} >".format(
29+
self._id,
30+
self.name,
31+
self.description or "No Description",
32+
self.project_id,
33+
)
34+
2735
def __init__(self, project_id: str, name: Optional[str] = None) -> None:
2836
self._ask_data_enablement = None
2937
self._certified = None

tableauserverclient/models/flow_item.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515

1616

1717
class FlowItem(object):
18+
def __repr__(self):
19+
return "<Flow {0} '{1}' ({2}) Project={3} createdAt={4}".format(
20+
self._id, self.name, self.description, self.project_id, self.created_at
21+
)
22+
1823
def __init__(self, project_id: str, name: Optional[str] = None) -> None:
1924
self._webpage_url: Optional[str] = None
2025
self._created_at: Optional[datetime.datetime] = None

tableauserverclient/models/project_item.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ class ContentPermissions:
1414
ManagedByOwner: str = "ManagedByOwner"
1515
LockedToProjectWithoutNested: str = "LockedToProjectWithoutNested"
1616

17+
def __repr__(self):
18+
return "<Project {0} {1} parent={2} permissions={3}>".format(
19+
self._id, self.name, self.parent_id or "None (Top level)", self.content_permissions or "Not Set"
20+
)
21+
1722
def __init__(
1823
self,
1924
name: str,

tableauserverclient/models/tableau_auth.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ def site(self, value):
5353

5454
class PersonalAccessTokenAuth(Credentials):
5555
def __init__(self, token_name, personal_access_token, site_id=None):
56+
if personal_access_token is None or token_name is None:
57+
raise TabError("Must provide a token and token name when using PAT authentication")
5658
super().__init__(site_id=site_id)
5759
self.token_name = token_name
5860
self.personal_access_token = personal_access_token

tableauserverclient/models/view_item.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ def __init__(self) -> None:
3131
self._permissions: Optional[Callable[[], List[PermissionsRule]]] = None
3232
self.tags: Set[str] = set()
3333

34+
def __repr__(self):
35+
return "<ViewItem {0} '{1}' contentUrl='{2}' project={3}>".format(
36+
self._id, self.name, self.content_url, self.project_id
37+
)
38+
3439
def _set_preview_image(self, preview_image):
3540
self._preview_image = preview_image
3641

tableauserverclient/models/workbook_item.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ def __init__(self, project_id: str, name: Optional[str] = None, show_tabs: bool
5252

5353
return None
5454

55+
def __repr__(self):
56+
return "<WorkbookItem {0} '{1}' contentUrl='{2}' project={3}>".format(
57+
self._id, self.name, self.content_url, self.project_id
58+
)
59+
5560
@property
5661
def connections(self) -> List[ConnectionItem]:
5762
if self._connections is None:

tableauserverclient/server/endpoint/endpoint.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,16 @@ def _make_request(
7878
self.parent_srv.http_options, auth_token, content, content_type, parameters
7979
)
8080

81-
logger.debug("request {}, url: {}".format(method, url))
81+
logger.debug("request method {}, url: {}".format(method.__name__, url))
8282
if content:
8383
redacted = helpers.strings.redact_xml(content[:1000])
84-
logger.debug("request content: {}".format(redacted))
84+
# logger.debug("request content: {}".format(redacted))
8585

8686
server_response = method(url, **parameters)
8787
self._check_status(server_response, url)
8888

8989
loggable_response = self.log_response_safely(server_response)
90-
logger.debug("Server response from {0}:\n\t{1}".format(url, loggable_response))
90+
# logger.debug("Server response from {0}:\n\t{1}".format(url, loggable_response))
9191

9292
if content_type == "application/xml":
9393
self.parent_srv._namespace.detect(server_response.content)
@@ -258,7 +258,7 @@ def all(self, *args, **kwargs):
258258
return queryset
259259

260260
@api(version="2.0")
261-
def filter(self, *_, **kwargs):
261+
def filter(self, *_, **kwargs) -> QuerySet:
262262
if _:
263263
raise RuntimeError("Only keyword arguments accepted.")
264264
queryset = QuerySet(self).filter(**kwargs)

tableauserverclient/server/server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"9.0": "2.0",
4949
}
5050
minimum_supported_server_version = "2.3"
51-
default_server_version = "2.3"
51+
default_server_version = "3.0" # at least use the current major version
5252

5353

5454
class Server(object):
@@ -114,7 +114,7 @@ def validate_connection_settings(self):
114114
raise ValueError("Server connection settings not valid", req_ex)
115115

116116
def __repr__(self):
117-
return "<TableauServerClient> [Connection: {}, {}]".format(self.baseurl, self.server_info.serverInfo)
117+
return "<TableauServerClient [Connection: {}, {}]>".format(self.baseurl, self.server_info.serverInfo)
118118

119119
def add_http_options(self, options_dict: dict):
120120
try:

test/models/_models.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from tableauserverclient import *
2+
3+
# mmm. why aren't these available in the tsc namespace?
4+
from tableauserverclient.models import (
5+
DataAccelerationReportItem,
6+
FavoriteItem,
7+
Credentials,
8+
ServerInfoItem,
9+
Resource,
10+
TableauItem,
11+
plural_type,
12+
)
13+
14+
15+
def get_defined_models():
16+
# not clever: copied from tsc/models/__init__.py
17+
return [
18+
ColumnItem,
19+
ConnectionCredentials,
20+
ConnectionItem,
21+
DataAccelerationReportItem,
22+
DataAlertItem,
23+
DatabaseItem,
24+
DatasourceItem,
25+
DQWItem,
26+
UnpopulatedPropertyError,
27+
FavoriteItem,
28+
FlowItem,
29+
FlowRunItem,
30+
GroupItem,
31+
IntervalItem,
32+
DailyInterval,
33+
WeeklyInterval,
34+
MonthlyInterval,
35+
HourlyInterval,
36+
JobItem,
37+
BackgroundJobItem,
38+
MetricItem,
39+
PaginationItem,
40+
PermissionsRule,
41+
Permission,
42+
ProjectItem,
43+
RevisionItem,
44+
ScheduleItem,
45+
ServerInfoItem,
46+
SiteItem,
47+
SubscriptionItem,
48+
TableItem,
49+
Credentials,
50+
TableauAuth,
51+
PersonalAccessTokenAuth,
52+
Resource,
53+
TableauItem,
54+
plural_type,
55+
Target,
56+
TaskItem,
57+
UserItem,
58+
ViewItem,
59+
WebhookItem,
60+
WorkbookItem,
61+
]

0 commit comments

Comments
 (0)