Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## 0.7 (2 Jul 2018)

* Added cancel job (#299)
* Added Get background jobs (#298)
* Added Multi-credential support (#276)
* Added Update Groups (#279)
* Adding project_id to view (#285)
* Added ability to rename workbook using `update workbook` (#284)
* Added Sample for exporting full pdf using pdf page combining (#267)
* Added Sample for exporting data, images, and single view pdfs (#263)
* Added view filters to the populate request options (#260)
* Add Async publishing for workbook and datasource endpoints (#311)
* Fixed ability to update datasource server connection port (#283)
* Fixed next project handling (#267)
* Cleanup debugging output to strip out non-xml response
* Improved refresh sample for readability (#288)

## 0.6.1 (26 Jan 2018)

* Fixed #257 where refreshing extracts does not work due to a missing "self"
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The following people have contributed to this project to make it possible, and w
* [William Lang](https://github.com/williamlang)
* [Jim Morris](https://github.com/jimbodriven)
* [BingoDinkus](https://github.com/BingoDinkus)
* [Sergey Sotnichenko](https://github.com/sotnich)

## Core Team

Expand Down
46 changes: 46 additions & 0 deletions docs/docs/api-ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,52 @@ Error | Description
<br>
<br>

#### groups.update

```py
groups.update(group_item, default_site_role=UserItem.Roles.Unlicensed)
```

Updates the group on the site.
If domain_name = 'local' then update only the name of the group.
If not - update group from the Active Directory with domain_name.

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"}


**Parameters**

Name | Description
:--- | :---
`group_item` | the group_item specifies the group to update.
`default_site_role` | if group updates from Active Directory then this is the default role for the new users.


**Exceptions**

Error | Description
:--- | :---
`Group item missing ID` | Raises an exception if a valid `group_item.id` is not provided.


**Example**

```py
# Update a group

# import tableauserverclient as TSC
# tableau_auth = TSC.TableauAuth('USERNAME', 'PASSWORD')
# server = TSC.Server('http://SERVERURL')

with server.auth.sign_in(tableau_auth):
all_groups, pagination_item = server.groups.get()

for group in all_groups:
server.groups.update(group)
```
<br>
<br>

#### groups.get

```py
Expand Down
2 changes: 1 addition & 1 deletion samples/download_view_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def main():
tableau_auth = TSC.TableauAuth(args.username, password, site_id=site_id)
server = TSC.Server(args.server)
# The new endpoint was introduced in Version 2.5
server.version = 2.5
server.version = "2.5"

with server.auth.sign_in(tableau_auth):
# Step 2: Query for the view that we want an image of
Expand Down
74 changes: 74 additions & 0 deletions samples/export.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import argparse
import getpass
import logging

import tableauserverclient as TSC


def main():
parser = argparse.ArgumentParser(description='Export a view as an image, pdf, or csv')
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
parser.add_argument('--site', '-S', default=None)
parser.add_argument('-p', default=None)

parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
help='desired logging level (set to error by default)')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--pdf', dest='type', action='store_const', const=('populate_pdf', 'PDFRequestOptions', 'pdf',
'pdf'))
group.add_argument('--png', dest='type', action='store_const', const=('populate_image', 'ImageRequestOptions',
'image', 'png'))
group.add_argument('--csv', dest='type', action='store_const', const=('populate_csv', 'CSVRequestOptions', 'csv',
'csv'))

parser.add_argument('--file', '-f', help='filename to store the exported data')
parser.add_argument('--filter', '-vf', metavar='COLUMN:VALUE',
help='View filter to apply to the view')
parser.add_argument('resource_id', help='LUID for the view')

args = parser.parse_args()

if args.p is None:
password = getpass.getpass("Password: ")
else:
password = args.p

# Set logging level based on user input, or error by default
logging_level = getattr(logging, args.logging_level.upper())
logging.basicConfig(level=logging_level)

tableau_auth = TSC.TableauAuth(args.username, password, args.site)
server = TSC.Server(args.server, use_server_version=True)
with server.auth.sign_in(tableau_auth):
views = filter(lambda x: x.id == args.resource_id,
TSC.Pager(server.views.get))
view = views.pop()

# We have a number of different types and functions for each different export type.
# We encode that information above in the const=(...) parameter to the add_argument function to make
# the code automatically adapt for the type of export the user is doing.
# We unroll that information into methods we can call, or objects we can create by using getattr()
(populate_func_name, option_factory_name, member_name, extension) = args.type
populate = getattr(server.views, populate_func_name)
option_factory = getattr(TSC, option_factory_name)

if args.filter:
options = option_factory().vf(*args.filter.split(':'))
else:
options = None
if args.file:
filename = args.file
else:
filename = 'out.{}'.format(extension)

populate(view, options)
with file(filename, 'wb') as f:
if member_name == 'csv':
f.writelines(getattr(view, member_name))
else:
f.write(getattr(view, member_name))


if __name__ == '__main__':
main()
92 changes: 92 additions & 0 deletions samples/export_wb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#
# This sample uses the PyPDF2 library for combining pdfs together to get the full pdf for all the views in a
# workbook.
#
# You will need to do `pip install PyPDF2` to use this sample.
#

import argparse
import getpass
import logging
import tempfile
import shutil
import functools
import os.path

import tableauserverclient as TSC
try:
import PyPDF2
except ImportError:
print('Please `pip install PyPDF2` to use this sample')
import sys
sys.exit(1)


def get_views_for_workbook(server, workbook_id): # -> Iterable of views
workbook = server.workbooks.get_by_id(workbook_id)
server.workbooks.populate_views(workbook)
return workbook.views


def download_pdf(server, tempdir, view): # -> Filename to downloaded pdf
logging.info("Exporting {}".format(view.id))
destination_filename = os.path.join(tempdir, view.id)
server.views.populate_pdf(view)
with file(destination_filename, 'wb') as f:
f.write(view.pdf)

return destination_filename


def combine_into(dest_pdf, filename): # -> None
dest_pdf.append(filename)
return dest_pdf


def cleanup(tempdir):
shutil.rmtree(tempdir)


def main():
parser = argparse.ArgumentParser(description='Export to PDF all of the views in a workbook')
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--site', '-S', default=None, help='Site to log into, do not specify for default site')
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
parser.add_argument('--password', '-p', default=None, help='password for the user')

parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error',
help='desired logging level (set to error by default)')
parser.add_argument('--file', '-f', default='out.pdf', help='filename to store the exported data')
parser.add_argument('resource_id', help='LUID for the workbook')

args = parser.parse_args()

if args.password is None:
password = getpass.getpass("Password: ")
else:
password = args.password

# Set logging level based on user input, or error by default
logging_level = getattr(logging, args.logging_level.upper())
logging.basicConfig(level=logging_level)

tempdir = tempfile.mkdtemp('tsc')
logging.debug("Saving to tempdir: %s", tempdir)

tableau_auth = TSC.TableauAuth(args.username, password, args.site)
server = TSC.Server(args.server, use_server_version=True)
try:
with server.auth.sign_in(tableau_auth):
get_list = functools.partial(get_views_for_workbook, server)
download = functools.partial(download_pdf, server, tempdir)

downloaded = (download(x) for x in get_list(args.resource_id))
output = reduce(combine_into, downloaded, PyPDF2.PdfFileMerger())
with file(args.file, 'wb') as f:
output.write(f)
finally:
cleanup(tempdir)


if __name__ == '__main__':
main()
47 changes: 47 additions & 0 deletions samples/kill_all_jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
####
# This script demonstrates how to kill all of the running jobs
#
# To run the script, you must have installed Python 2.7.X or 3.3 and later.
####

import argparse
import getpass
import logging

import tableauserverclient as TSC


def main():
parser = argparse.ArgumentParser(description='Cancel all of the running background jobs')
parser.add_argument('--server', '-s', required=True, help='server address')
parser.add_argument('--site', '-S', default=None, help='site to log into, do not specify for default site')
parser.add_argument('--username', '-u', required=True, help='username to sign into server')
parser.add_argument('--password', '-p', default=None, help='password for the user')

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

args = parser.parse_args()

if args.password is None:
password = getpass.getpass("Password: ")
else:
password = args.password

# Set logging level based on user input, or error by default
logging_level = getattr(logging, args.logging_level.upper())
logging.basicConfig(level=logging_level)

# SIGN IN
tableau_auth = TSC.TableauAuth(args.username, password, args.site)
server = TSC.Server(args.server, use_server_version=True)
with server.auth.sign_in(tableau_auth):
req = TSC.RequestOptions()

req.filter.add(TSC.Filter("progress", TSC.RequestOptions.Operator.LessThanOrEqual, 0))
for job in TSC.Pager(server.jobs, request_opts=req):
print(server.jobs.cancel(job.id), job.id, job.status, job.type)


if __name__ == '__main__':
main()
17 changes: 10 additions & 7 deletions samples/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@


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

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

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

args = parser.parse_args()

if args.p is None:
if args.password is None:
password = getpass.getpass("Password: ")
else:
password = args.p
password = args.password

# Set logging level based on user input, or error by default
logging_level = getattr(logging, args.logging_level.upper())
Expand All @@ -40,7 +40,10 @@ def main():
with server.auth.sign_in(tableau_auth):
endpoint = {
'workbook': server.workbooks,
'datasource': server.datasources
'datasource': server.datasources,
'view': server.views,
'job': server.jobs,
'project': server.projects,
}.get(args.resource_type)

for resource in TSC.Pager(endpoint.get):
Expand Down
20 changes: 18 additions & 2 deletions samples/publish_workbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import logging

import tableauserverclient as TSC
from tableauserverclient import ConnectionCredentials, ConnectionItem


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

connection1 = ConnectionItem()
connection1.server_address = "mssql.test.com"
connection1.connection_credentials = ConnectionCredentials("test", "password", True)

connection2 = ConnectionItem()
connection2.server_address = "postgres.test.com"
connection2.server_port = "5432"
connection2.connection_credentials = ConnectionCredentials("test", "password", True)

all_connections = list()
all_connections.append(connection1)
all_connections.append(connection2)

# Step 3: If default project is found, form a new workbook item and publish.
if default_project is not None:
new_workbook = TSC.WorkbookItem(default_project.id)
if args.as_job:
new_job = server.workbooks.publish(new_workbook, args.filepath, overwrite_true, as_job=args.as_job)
new_job = server.workbooks.publish(new_workbook, args.filepath, overwrite_true,
connections=all_connections, as_job=args.as_job)
print("Workbook published. JOB ID: {0}".format(new_job.id))
else:
new_workbook = server.workbooks.publish(new_workbook, args.filepath, overwrite_true, as_job=args.as_job)
new_workbook = server.workbooks.publish(new_workbook, args.filepath, overwrite_true,
connections=all_connections, as_job=args.as_job)
print("Workbook published. ID: {0}".format(new_workbook.id))
else:
error = "The default project could not be found."
Expand Down
Loading