10000 Merge pull request #128 from tableau/development · cycoo618/server-client-python@8e6c907 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8e6c907

Browse files
author
Russell Hay
authored
Merge pull request tableau#128 from tableau/development
Release 0.3
2 parents 05974c3 + aa56523 commit 8e6c907

33 files changed

+500
-87
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ python:
44
- "3.3"
55
- "3.4"
66
- "3.5"
7+
- "3.6"
78
- "pypy"
89
# command to install dependencies
910
install:
@@ -14,4 +15,4 @@ script:
1415
# Tests
1516
- python setup.py test
1617
# pep8 - disabled for now until we can scrub the files to make sure we pass before turning it on
17-
- pycodestyle .
18+
- pycodestyle tableauserverclient test

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
## 0.3 (11 January 2017)
2+
3+
* Return DateTime objects instead of strings (#102)
4+
* UserItem now is compatible with Pager (#107, #109)
5+
* Deprecated site in favor of site_id (#97)
6+
* Improved handling of large downloads (#105, #111)
7+
* Added support for oAuth when publishing (#117)
8+
* Added Testing against Py36 (#122, #123)
9+
* Added Version Checking to use highest supported REST api version (#100)
10+
* Added Infrastructure for throwing error if trying to do something that is not supported by REST api version (#124)
11+
* Various Code Cleanup
12+
* Added Documentation (#98)
13+
* Improved Test Infrastructure (#91)
14+
115
## 0.2 (02 November 2016)
216

317
* Added Initial Schedules Support (#48)

CONTRIBUTORS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ The following people have contributed to this project to make it possible, and w
55
## Contributors
66

77
* [geordielad](https://github.com/geordielad)
8+
* [Hugo Stijns)(https://github.com/hugoboos)
89
* [kovner](https://github.com/kovner)
910

1011

@@ -14,3 +15,5 @@ The following people have contributed to this project to make it possible, and w
1415
* [lgraber](https://github.com/lgraber)
1516
* [t8y8](https://github.com/t8y8)
1617
* [RussTheAerialist](https://github.com/RussTheAerialist)
18+
* [Ben Lower](https://github.com/benlower)
19+
* [Jared Dominguez](https://github.com/jdomingu)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ This repository contains Python source code and sample files.
1111
For more information on installing and using TSC, see the documentation:
1212

1313
<https://tableau.github.io/server-client-python/docs/>
14+

samples/initialize_server.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
####
2+
# This script sets up a server. It uploads datasources and workbooks from the local filesystem.
3+
#
4+
# By default, all content is published to the Default project on the Default site.
5+
####
6+
7+
import tableauserverclient as TSC
8+
import argparse
9+
import getpass
10+
import logging
11+
import glob
12+
13+
14+
def main():
15+
parser = argparse.ArgumentParser(description='Initialize a server with content.')
16+
parser.add_argument('--server', '-s', required=True, help='server address')
17+
parser.add_argument('--datasources-folder', '-df', required=True, help='folder containing datasources')
18+
parser.add_argument('--workbooks-folder', '-wf', required=True, help='folder containing workbooks')
19+
parser.add_argument('--site', '-si', required=False, default='Default', help='site to use')
20+
parser.add_argument('--project', '-p', required=False, default='Default', help='project to use')
21+
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
22+
parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
23+
help='desired logging level (set to error by default)')
24+
args = parser.parse_args()
25+
26+
password = getpass.getpass("Password: ")
27+
28+
# Set logging level based on user input, or error by default
29+
logging_level = getattr(logging, args.logging_level.upper())
30+
logging.basicConfig(level=logging_level)
31+
32+
################################################################################
33+
# Step 1: Sign in to server.
34+
################################################################################
35+
tableau_auth = TSC.TableauAuth(args.username, password)
36+
server = TSC.Server(args.server)
37+
38+
with server.auth.sign_in(tableau_auth):
39+
40+
################################################################################
41+
# Step 2: Create the site we need only if it doesn't exist
42+
################################################################################
43+
print("Checking to see if we need to create the site...")
44+
45+
all_sites, _ = server.sites.get()
46+
existing_site = next((s for s in all_sites if s.name == args.site), None)
47+
48+
# Create the site if it doesn't exist
49+
if existing_site is None:
50+
print("Site not found: {0} Creating it...").format(args.site)
51+
new_site = TSC.SiteItem(name=args.site, content_url=args.site.replace(" ", ""),
52+
admin_mode=TSC.SiteItem.AdminMode.ContentAndUsers)
53+
server.sites.create(new_site)
54+
else:
55+
print("Site {0} exists. Moving on...").format(args.site)
56+
57+
################################################################################
58+
# Step 3: Sign-in to our target site
59+
################################################################################
60+
print("Starting our content upload...")
61+
server_upload = TSC.Server(args.server)
62+
tableau_auth.site = args.site
63+
64+
with server_upload.auth.sign_in(tableau_auth):
65+
66+
################################################################################
67+
# Step 4: Create the project we need only if it doesn't exist
68+
################################################################################
69+
all_projects, _ = server_upload.projects.get()
70+
project = next((p for p in all_projects if p.name == args.project), None)
71+
72+
# Create our project if it doesn't exist
73+
if project is None:
74+
print("Project not found: {0} Creating it...").format(args.project)
75+
new_project = TSC.ProjectItem(name=args.project)
76+
project = server_upload.projects.create(new_project)
77+
78+
################################################################################
79+
# Step 5: Set up our content
80+
# Publish datasources to our site and project
81+
# Publish workbooks to our site and project
82+
################################################################################
83+
publish_datasources_to_site(server_upload, project, args.datasources_folder)
84+
publish_workbooks_to_site(server_upload, project, args.workbooks_folder)
85+
86+
87+
def publish_datasources_to_site(server_object, project, folder):
88+
path = folder + '/*.tds*'
89+
90+
for fname in glob.glob(path):
91+
new_ds = TSC.DatasourceItem(project.id)
92+
new_ds = server_object.datasources.publish(new_ds, fname, server_object.PublishMode.Overwrite)
93+
print("Datasource published. ID: {0}".format(new_ds.id))
94+
95+
96+
def publish_workbooks_to_site(server_object, project, folder):
97+
path = folder + '/*.twb*'
98+
99+
for fname in glob.glob(path):
100+
new_workbook = TSC.WorkbookItem(project.id)
101+
new_workbook.show_tabs = True
102+
new_workbook = server_object.workbooks.publish(new_workbook, fname, server_object.PublishMode.Overwrite)
103+
print("Workbook published. ID: {0}".format(new_workbook.id))
104+
105+
106+
if __name__ == "__main__":
107+
main()

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()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setup(
77
name='tableauserverclient',
8-
version='0.2',
8+
version='0.3',
99
author='Tableau',
1010
author_email='github@tableau.com',
1111
url='https://github.com/tableau/server-client-python',
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/connection_credentials.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ class ConnectionCredentials(object):
99
1010
"""
1111

12-
def __init__(self, name, password, embed=True):
12+
def __init__(self, name, password, embed=True, oauth=False):
1313
self.name = name
1414
self.password = password
1515
self.embed = embed
16+
self.oauth = oauth
1617

1718
@property
1819
def embed(self):
@@ -22,3 +23,12 @@ def embed(self):
2223
@property_is_boolean
2324
def embed(self, value):
2425
self._embed = value
26+
27+
@property
28+
def oauth(self):
29+
return self._oauth
30+
31+
@oauth.setter
32+
@property_is_boolean
33+
def oauth(self, value):
34+
self._oauth = value

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)

0 commit comments

Comments
 (0)
0