8000 Merge pull request #316 from RussTheAerialist/master · tableau/server-client-python@b7b544e · GitHub
[go: up one dir, main page]

Skip to content

Commit b7b544e

Browse files
author
Russell Hay
authored
Merge pull request #316 from RussTheAerialist/master
Merge in v0.7 from development.
2 parents 5e88a41 + 02e0111 commit b7b544e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+885
-83
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
## 0.7 (2 Jul 2018)
2+
3+
* Added cancel job (#299)
4+
* Added Get background jobs (#298)
5+
* Added Multi-credential support (#276)
6+
* Added Update Groups (#279)
7+
* Adding project_id to view (#285)
8+
* Added ability to rename workbook using `update workbook` (#284)
9+
* Added Sample for exporting full pdf using pdf page combining (#267)
10+
* Added Sample for exporting data, images, and single view pdfs (#263)
11+
* Added view filters to the populate request options (#260)
12+
* Add Async publishing for workbook and datasource endpoints (#311)
13+
* Fixed ability to update datasource server connection port (#283)
14+
* Fixed next project handling (#267)
15+
* Cleanup debugging output to strip out non-xml response
16+
* Improved refresh sample for readability (#288)
17+
118
## 0.6.1 (26 Jan 2018)
219

320
* Fixed #257 where refreshing extracts does not work due to a missing "self"

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ The following people have contributed to this project to make it possible, and w
1515
* [William Lang](https://github.com/williamlang)
1616
* [Jim Morris](https://github.com/jimbodriven)
1717
* [BingoDinkus](https://github.com/BingoDinkus)
18+
* [Sergey Sotnichenko](https://github.com/sotnich)
1819

1920
## Core Team
2021

docs/docs/api-ref.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,52 @@ Error | Description
849849
<br>
850850
<br>
851851

852+
#### groups.update
853+
854+
```py
855+
groups.update(group_item, default_site_role=UserItem.Roles.Unlicensed)
856+
```
857+
858+
Updates the group on the site.
859+
If domain_name = 'local' then update only the name of the group.
860+
If not - update group from the Active Directory with domain_name.
861+
862+
REST API: [Update Group](http://onlinehelp.tableau.com/current/api/rest_api/en-us/help.htm#REST/rest_api_ref.htm#Update_Group%3FTocPath%3DAPI%2520Reference%7C_____95){:target="_blank"}
863+
864+
865+
**Parameters**
866+
867+
Name | Description
868+
:--- | :---
869+
`group_item` | the group_item specifies the group to update.
870+
`default_site_role` | if group updates from Active Directory then this is the default role for the new users.
871+
872+
873+
**Exceptions**
874+
875+
Error | Description
876+
:--- | :---
877+
`Group item missing ID` | Raises an exception if a valid `group_item.id` is not provided.
878+
879+
880+
**Example**
881+
882+
```py
883+
# Update a group
884+
885+
# import tableauserverclient as TSC
886+
# tableau_auth = TSC.TableauAuth('USERNAME', 'PASSWORD')
887+
# server = TSC.Server('http://SERVERURL')
888+
889+
with server.auth.sign_in(tableau_auth):
890+
all_groups, pagination_item = server.groups.get()
891+
892+
for group in all_groups:
893+
server.groups.update(group)
894+
```
895+
<br>
896+
<br>
897+
852898
#### groups.get
853899

854900
```py

samples/download_view_image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def main():
4343
tableau_auth = TSC.TableauAuth(args.username, password, site_id=site_id)
4444
server = TSC.Server(args.server)
4545
# The new endpoint was introduced in Version 2.5
46-
server.version = 2.5
46+
server.version = "2.5"
4747

4848
with server.auth.sign_in(tableau_auth):
4949
# Step 2: Query for the view that we want an image of

samples/export.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import argparse
2+
import getpass
3+
import logging
4+
5+
import tableauserverclient as TSC
6+
7+
8+
def main():
9+
parser = argparse.ArgumentParser(description='Export a view as an image, pdf, or csv')
10+
parser.add_argument('--server', '-s', required=True, help='server address')
11+
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
12+
parser.add_argument('--site', '-S', default=None)
13+
parser.add_argument('-p', default=None)
14+
15+
parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
16+
help='desired logging level (set to error by default)')
17+
group = parser.add_mutually_exclusive_group(required=True)
18+
group.add_argument('--pdf', dest='type', action='store_const', const=('populate_pdf', 'PDFRequestOptions', 'pdf',
19+
'pdf'))
20+
group.add_argument('--png', dest='type', action='store_const', const=('populate_image', 'ImageRequestOptions',
21+
'image', 'png'))
22+
group.add_argument('--csv', dest='type', action='store_const', const=('populate_csv', 'CSVRequestOptions', 'csv',
23+
'csv'))
24+
25+
parser.add_argument('--file', '-f', help='filename to store the exported data')
26+
parser.add_argument('--filter', '-vf', metavar='COLUMN:VALUE',
27+
help='View filter to apply to the view')
28+
parser.add_argument('resource_id', help='LUID for the view')
29+
30+
args = parser.parse_args()
31+
32+
if args.p is None:
33+
password = getpass.getpass("Password: ")
34+
else:
35+
password = args.p
36+
37+
# Set logging level based on user input, or error by default
38+
logging_level = getattr(logging, args.logging_level.upper())
39+
logging.basicConfig(level=logging_level)
40+
41+
tableau_auth = TSC.TableauAuth(args.username, password, args.site)
42+
server = TSC.Server(args.server, use_server_version=True)
43+
with server.auth.sign_in(tableau_auth):
44+
views = filter(lambda x: x.id == args.resource_id,
45+
TSC.Pager(server.views.get))
46+
view = views.pop()
47+
48+
# We have a number of different types and functions for each different export type.
49+
# We encode that information above in the const=(...) parameter to the add_argument function to make
50+
# the code automatically adapt for the type of export the user is doing.
51+
# We unroll that information into methods we can call, or objects we can create by using getattr()
52+
(populate_func_name, option_factory_name, member_name, extension) = args.type
53+
populate = getattr(server.views, populate_func_name)
54+
option_factory = getattr(TSC, option_factory_name)
55+
56+
if args.filter:
57+
options = option_factory().vf(*args.filter.split(':'))
58+
else:
59+
options = None
60+
if args.file:
61+
filename = args.file
62+
else:
63+
filename = 'out.{}'.format(extension)
64+
65+
populate(view, options)
66+
with file(filename, 'wb') as f:
67+
if member_name == 'csv':
68+
f.writelines(getattr(view, member_name))
69+
else:
70+
f.write(getattr(view, member_name))
71+
72+
73+
if __name__ == '__main__':
74+
main()

samples/export_wb.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#
2+
# This sample uses the PyPDF2 library for combining pdfs together to get the full pdf for all the views in a
3+
# workbook.
4+
#
5+
# You will need to do `pip install PyPDF2` to use this sample.
6+
#
7+
8+
import argparse
9+
import getpass
10+
import logging
11+
import tempfile
12+
import shutil
13+
import functools
14+
import os.path
15+
16+
import tableauserverclient as TSC
17+
try:
18+
import PyPDF2
19+
except ImportError:
20+
print('Please `pip install PyPDF2` to use this sample')
21+
import sys
22+
sys.exit(1)
23+
24+
25+
def get_views_for_workbook(server, workbook_id): # -> Iterable of views
26+
workbook = server.workbooks.get_by_id(workbook_id)
27+
server.workbooks.populate_views(workbook)
28+
return workbook.views
29+
30+
31+
def download_pdf(server, tempdir, view): # -> Filename to downloaded pdf
32+
logging.info("Exporting {}".format(view.id))
33+
destination_filename = os.path.join(tempdir, view.id)
34+
server.views.populate_pdf(view)
35+
with file(destination_filename, 'wb') as f:
36+
f.write(view.pdf)
37+
38+
return destination_filename
39+
40+
41+
def combine_into(dest_pdf, filename): # -> None
42+
dest_pdf.append(filename)
43+
return dest_pdf
44+
45+
46+
def cleanup(tempdir):
47+
shutil.rmtree(tempdir)
48+
49+
50+
def main():
51+
parser = argparse.ArgumentParser(description='Export to PDF all of the views in a workbook')
52+
parser.add_argument('--server', '-s', required=True, help='server address')
53+
parser.add_argument('--site', '-S', default=None, help='Site to log into, do not specify for default site')
54+
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
55+
parser.add_argument('--password', '-p', default=None, help='password for the user')
56+
57+
parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
58+
help='desired logging level (set to error by default)')
59+
parser.add_argument('--file', '-f', default='out.pdf', help='filename to store the exported data')
60+
parser.add_argument('resource_id', help='LUID for the workbook')
61+
62+
args = parser.parse_args()
63+
64+
if args.password is None:
65+
password = getpass.getpass("Password: ")
66+
else:
67+
password = args.password
68+
69+
# Set logging level based on user input, or error by default
70+
logging_level = getattr(logging, args.logging_level.upper())
71+
logging.basicConfig(level=logging_level)
72+
73+
tempdir = tempfile.mkdtemp('tsc')
74+
logging.debug("Saving to tempdir: %s", tempdir)
75+
76+
tableau_auth = TSC.TableauAuth(args.username, password, args.site)
77+
server = TSC.Server(args.server, use_server_version=True)
78+
try:
79+
with server.auth.sign_in(tableau_auth):
80+
get_list = functools.partial(get_views_for_workbook, server)
81+
download = functools.partial(download_pdf, server, tempdir)
82+
83+
downloaded = (download(x) for x in get_list(args.resource_id))
84+
output = reduce(combine_into, downloaded, PyPDF2.PdfFileMerger())
85+
with file(args.file, 'wb') as f:
86+
output.write(f)
87+
finally:
88+
cleanup(tempdir)
89+
90+
91+
if __name__ == '__main__':
92+
main()

samples/kill_all_jobs.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
####
2+
# This script demonstrates how to kill all of the running jobs
3+
#
4+
# To run the script, you must have installed Python 2.7.X or 3.3 and later.
5+
####
6+
7+
import argparse
8+
import getpass
9+
import logging
10+
11+
import tableauserverclient as TSC
12+
13+
14+
def main():
15+
parser = argparse.ArgumentParser(description='Cancel all of the running background jobs')
16+
parser.add_argument('--server', '-s', required=True, help='server address')
17+
parser.add_argument('--site', '-S', default=None, help='site to log into, do not specify for default site')
18+
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
19+
parser.add_argument('--password', '-p', default=None, help='password for the user')
20+
21+
parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
22+
help='desired logging level (set to error by default)')
23+
24+
args = parser.parse_args()
25+
26+
if args.password is None:
27+
password = getpass.getpass("Password: ")
28+
else:
29+
password = args.password
30+
31+
# Set logging level based on user input, or error by default
32+
logging_level = getattr(logging, args.logging_level.upper())
33+
logging.basicConfig(level=logging_level)
34+
35+
# SIGN IN
36+
tableau_auth = TSC.TableauAuth(args.username, password, args.site)
37+
server = TSC.Server(args.server, use_server_version=True)
38+
with server.auth.sign_in(tableau_auth):
39+
req = TSC.RequestOptions()
40+
41+
req.filter.add(TSC.Filter("progress", TSC.RequestOptions.Operator.LessThanOrEqual, 0))
42+
for job in TSC.Pager(server.jobs, request_opts=req):
43+
print(server.jobs.cancel(job.id), job.id, job.status, job.type)
44+
45+
46+
if __name__ == '__main__':
47+
main()

samples/list.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,23 @@
1212

1313

1414
def main():
15-
parser = argparse.ArgumentParser(description='Get all of the refresh tasks available on a server')
15+
parser = argparse.ArgumentParser(description='List out the names and LUIDs for different resource types')
1616
parser.add_argument('--server', '-s', required=True, help='server address')
17+
parser.add_argument('--site', '-S', default=None, help='site to log into, do not specify for default site')
1718
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
18-
parser.add_argument('--site', '-S', default=None)
19-
parser.add_argument('-p', default=None)
19+
parser.add_argument('--password', '-p', default=None, help='password for the user')
2020

2121
parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
2222
help='desired logging level (set to error by default)')
2323

24-
parser.add_argument('resource_type', choices=['workbook', 'datasource'])
24+
parser.add_argument('resource_type', choices=['workbook', 'datasource', 'project', 'view', 'job'])
2525

2626
args = parser.parse_args()
2727

28-
if args.p is None:
28+
if args.password is None:
2929
password = getpass.getpass("Password: ")
3030
else:
31-
password = args.p
31+
password = args.password
3232

3333
# Set logging level based on user input, or error by default
3434
logging_level = getattr(logging, args.logging_level.upper())
@@ -40,7 +40,10 @@ def main():
4040
with server.auth.sign_in(tableau_auth):
4141
endpoint = {
4242
'workbook': server.workbooks,
43-
'datasource': server.datasources
43+
'datasource': server.datasources,
44+
'view': server.views,
45+
'job': server.jobs,
46+
'project': server.projects,
4447
}.get(args.resource_type)
4548

4649
for resource in TSC.Pager(endpoint.get):

samples/publish_workbook.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import logging
2020

2121
import tableauserverclient as TSC
22+
from tableauserverclient import ConnectionCredentials, ConnectionItem
2223

2324

2425
def main():
@@ -51,14 +52,29 @@ def main():
5152
all_projects, pagination_item = server.projects.get()
5253
default_project = next((project for project in all_projects if project.is_default()), None)
5354

55+
connection1 = ConnectionItem()
56+
connection1.server_address = "mssql.test.com"
57+
connection1.connection_credentials = ConnectionCredentials("test", "password", True)
58+
59+
connection2 = ConnectionItem()
60+
connection2.server_address = "postgres.test.com"
61+
connection2.server_port = "5432"
62+
connection2.connection_credentials = ConnectionCredentials("test", "password", True)
63+
64+
all_connections = list()
65+
all_connections.append(connection1)
66+
all_connections.append(connection2)
67+
5468
# Step 3: If default project is found, form a new workbook item and publish.
5569
if default_project is not None:
5670
new_workbook = TSC.WorkbookItem(default_project.id)
5771
if args.as_job:
58-
new_job = server.workbooks.publish(new_workbook, args.filepath, overwrite_true, as_job=args.as_job)
72+
new_job = server.workbooks.publish(new_workbook, args.filepath, overwrite_true,
73+
connections=all_connections, as_job=args.as_job)
5974
print("Workbook published. JOB ID: {0}".format(new_job.id))
6075
else:
61-
new_workbook = server.workbooks.publish(new_workbook, args.filepath, overwrite_true, as_job=args.as_job)
76+
new_workbook = server.workbooks.publish(new_workbook, args.filepath, overwrite_true,
77+
connections=all_connections, as_job=args.as_job)
6278
print("Workbook published. ID: {0}".format(new_workbook.id))
6379
else:
6480
error = "The default project could not be found."

0 commit comments

Comments
 (0)
0