8000 Merge pull request #103 from tableau/feature-102-datetimes · delphinium/server-client-python@e853d7c · GitHub
[go: up one dir, main page]

Skip to content

Commit e853d7c

Browse files
author
Russell Hay
authored
Merge pull request tableau#103 from tableau/feature-102-datetimes
Initial implementation to address tableau#102 and provide datetime objects
2 parents 39f4b22 + db0dac1 commit e853d7c

17 files changed

+140
-60
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ script:
1414
# Tests
1515
- python setup.py test
1616
# pep8 - disabled for now until we can scrub the files to make sure we pass before turning it on
17-
- pycodestyle .
17+
- pycodestyle tableauserverclient test

samples/initialize_server.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import logging
1111
import glob
1212

13+
1314
def main():
1415
parser = argparse.ArgumentParser(description='Initialize a server with content.')
1516
parser.add_argument('--server', '-s', required=True, help='server address')
@@ -47,12 +48,12 @@ def main():
4748
# Create the site if it doesn't exist
4849
if existing_site is None:
4950
print("Site not found: {0} Creating it...").format(args.site)
50-
new_site = TSC.SiteItem(name=args.site, content_url=args.site.replace(" ", ""), admin_mode=TSC.SiteItem.AdminMode.ContentAndUsers)
51+
new_site = TSC.SiteItem(name=args.site, content_url=args.site.replace(" ", ""),
52+
admin_mode=TSC.SiteItem.AdminMode.ContentAndUsers)
5153
server.sites.create(new_site)
5254
else:
5355
print("Site {0} exists. Moving on...").format(args.site)
5456

55-
5657
################################################################################
5758
# Step 3: Sign-in to our target site
5859
################################################################################
@@ -82,6 +83,7 @@ def main():
8283
publish_datasources_to_site(server_upload, project, args.datasources_folder)
8384
publish_workbooks_to_site(server_upload, project, args.workbooks_folder)
8485

86+
8587
def publish_datasources_to_site(server_object, project, folder):
8688
path = folder + '/*.tds*'
8789

samples/pagination_sample.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,6 @@ def main():
6666
# >>> request_options = TSC.RequestOptions(pagesize=1000)
6767
# >>> all_workbooks = list(TSC.Pager(server.workbooks, request_options))
6868

69+
6970
if __name__ == '__main__':
7071
main()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import datetime
2+
3+
4+
# This code below is from the python documentation for tzinfo: https://docs.python.org/2.3/lib/datetime-tzinfo.html
5+
ZERO = datetime.timedelta(0)
6+
HOUR = datetime.timedelta(hours=1)
7+
8+
# A UTC class.
9+
10+
11+
class UTC(datetime.tzinfo):
12+
"""UTC"""
13+
14+
def utcoffset(self, dt):
15+
return ZERO
16+
17+
def tzname(self, dt):
18+
return "UTC"
19+
20+
def dst(self, dt):
21+
return ZERO
22+
23+
24+
utc = UTC()
25+
26+
TABLEAU_DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
27+
28+
29+
def parse_datetime(date):
30+
if date is None:
31+
return None
32+
33+
return datetime.datetime.strptime(date, TABLEAU_DATE_FORMAT).replace(tzinfo=utc)
34+
35+
36+
def format_datetime(date):
37+
return date.astimezone(tz=utc).strftime(TABLEAU_DATE_FORMAT)

tableauserverclient/models/datasource_item.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .property_decorators import property_not_nullable
44
from .tag_item import TagItem
55
from .. import NAMESPACE
6+
from ..datetime_helpers import parse_datetime
67

78

89
class DatasourceItem(object):
@@ -118,8 +119,8 @@ def _parse_element(datasource_xml):
118119
name = datasource_xml.get('name', None)
119120
datasource_type = datasource_xml.get('type', None)
120121
content_url = datasource_xml.get('contentUrl', None)
121-
created_at = datasource_xml.get('createdAt', None)
122-
updated_at = datasource_xml.get('updatedAt', None)
122+
created_at = parse_datetime(datasource_xml.get('createdAt', None))
123+
updated_at = parse_datetime(datasource_xml.get('updatedAt', None))
123124

124125
tags = None
125126
tags_elem = datasource_xml.find('.//t:tags', namespaces=NAMESPACE)

tableauserverclient/models/property_decorators.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
import datetime
12
import re
23
from functools import wraps
4+
from ..datetime_helpers import parse_datetime
5+
try:
6+
basestring
7+
except NameError:
8+
# In case we are in python 3 the string check is different
9+
basestring = str
310

411

512
def property_is_enum(enum_type):
@@ -99,3 +106,25 @@ def validate_regex_decorator(self, value):
99106
return func(self, value)
100107
return validate_regex_decorator
101108
return wrapper
109+
110+
111+
def property_is_datetime(func):
112+
""" Takes the following datetime format and turns it into a datetime object:
113+
114+
2016-08-18T18:25:36Z
115+
116+
Because we return everything with Z as the timezone, we assume everything is in UTC and create
117+
a timezone aware datetime.
118+
"""
119+
120+
@wraps(func)
121+
def wrapper(self, value):
122+
if isinstance(value, datetime.datetime):
123+
return func(self, value)
124+
if not isinstance(value, basestring):
125+
raise ValueError("Cannot convert {} into a datetime, cannot update {}".format(value.__class__.__name__,
126+
func.__name__))
127+
128+
dt = parse_datetime(value)
129+
return func(self, dt)
130+
return wrapper

tableauserverclient/models/schedule_item.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .interval_item import IntervalItem, HourlyInterval, DailyInterval, WeeklyInterval, MonthlyInterval
55
from .property_decorators import property_is_enum, property_not_nullable, property_is_int
66
from .. import NAMESPACE
7+
from ..datetime_helpers import parse_datetime
78

89

910
class ScheduleItem(object):
@@ -208,12 +209,12 @@ def _parse_element(schedule_xml):
208209
id = schedule_xml.get('id', None)
209210
name = schedule_xml.get('name', None)
210211
state = schedule_xml.get('state', None)
211-
created_at = schedule_xml.get('createdAt', None)
212-
updated_at = schedule_xml.get('updatedAt', None)
212+
created_at = parse_datetime(schedule_xml.get('createdAt', None))
213+
updated_at = parse_datetime(schedule_xml.get('updatedAt', None))
213214
schedule_type = schedule_xml.get('type', None)
214215
frequency = schedule_xml.get('frequency', None)
215-
next_run_at = schedule_xml.get('nextRunAt', None)
216-
end_schedule_at = schedule_xml.get('endScheduleAt', None)
216+
next_run_at = parse_datetime(schedule_xml.get('nextRunAt', None))
217+
end_schedule_at = parse_datetime(schedule_xml.get('endScheduleAt', None))
217218
execution_order = schedule_xml.get('executionOrder', None)
218219

219220
priority = schedule_xml.get('priority', None)

tableauserverclient/models/user_item.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .exceptions import UnpopulatedPropertyError
33
from .property_decorators import property_is_enum, property_not_empty, property_not_nullable
44
from .. import NAMESPACE
5+
from ..datetime_helpers import parse_datetime
56

67

78
class UserItem(object):
@@ -135,7 +136,7 @@ def _parse_element(user_xml):
135136
id = user_xml.get('id', None)
136137
name = user_xml.get('name', None)
137138
site_role = user_xml.get('siteRole', None)
138-
last_login = user_xml.get('lastLogin', None)
139+
last_login = parse_datetime(user_xml.get('lastLogin', None))
139140
external_auth_user_id = user_xml.get('externalAuthUserId', None)
140141
fullname = user_xml.get('fullName', None)
141142
email = user_xml.get('email', None)

tableauserverclient/models/workbook_item.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from .tag_item import TagItem
55
from .view_item import ViewItem
66
from .. import NAMESPACE
7+
from ..datetime_helpers import parse_datetime
78
import copy
89

910

@@ -163,8 +164,8 @@ def _parse_element(workbook_xml):
163164
id = workbook_xml.get('id', None)
164165
name = workbook_xml.get('name', None)
165166
content_url = workbook_xml.get('contentUrl', None)
166-
created_at = workbook_xml.get('createdAt', None)
167-
updated_at = workbook_xml.get('updatedAt', None)
167+
created_at = parse_datetime(workbook_xml.get('createdAt', None))
168+
updated_at = parse_datetime(workbook_xml.get('updatedAt', None))
168169

169170
size = workbook_xml.get('size', None)
170171
if size:

tableauserverclient/server/request_factory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from ..datetime_helpers import format_datetime
12
import xml.etree.ElementTree as ET
23

34
from requests.packages.urllib3.fields import RequestField

0 commit comments

Comments
 (0)
0