From 71b9481d76196f8c0558c5b34530d1d7252a24b5 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Wed, 14 Feb 2018 08:46:03 -0800 Subject: [PATCH 1/4] Adding export sample/tool --- samples/export.py | 69 +++++++++++++++++++++++++++++++++++++++++++++++ samples/list.py | 6 +++-- 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 samples/export.py diff --git a/samples/export.py b/samples/export.py new file mode 100644 index 000000000..773d2f221 --- /dev/null +++ b/samples/export.py @@ -0,0 +1,69 @@ +import argparse +import getpass +import logging + +import tableauserverclient as TSC + + +def main(): + parser = argparse.ArgumentParser(description='Get all of the refresh tasks available on a server') + 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() + (populate_name, option_factory_name, member_name, extension) = args.type + populate = getattr(server.views, populate_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() diff --git a/samples/list.py b/samples/list.py index ec2ff9a6b..2e7307afb 100644 --- a/samples/list.py +++ b/samples/list.py @@ -7,6 +7,7 @@ import argparse import getpass import logging +import requests import tableauserverclient as TSC @@ -21,7 +22,7 @@ def main(): 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', 'view']) args = parser.parse_args() @@ -40,7 +41,8 @@ def main(): with server.auth.sign_in(tableau_auth): endpoint = { 'workbook': server.workbooks, - 'datasource': server.datasources + 'datasource': server.datasources, + 'view': server.views }.get(args.resource_type) for resource in TSC.Pager(endpoint.get): From c4b4b6d7608ba5ed18f9185a93437861f45fcab1 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Wed, 14 Feb 2018 08:57:02 -0800 Subject: [PATCH 2/4] Removing unused import --- samples/list.py | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/list.py b/samples/list.py index 2e7307afb..9c22fc7fd 100644 --- a/samples/list.py +++ b/samples/list.py @@ -7,7 +7,6 @@ import argparse import getpass import logging -import requests import tableauserverclient as TSC From 1c4478a469580d4635bc9b07d08ad0e51ae0a77d Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Thu, 15 Feb 2018 13:35:30 -0800 Subject: [PATCH 3/4] Addressing code review feedback --- samples/export.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/samples/export.py b/samples/export.py index 773d2f221..67b3319a8 100644 --- a/samples/export.py +++ b/samples/export.py @@ -6,7 +6,7 @@ def main(): - parser = argparse.ArgumentParser(description='Get all of the refresh tasks available on a server') + 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) @@ -44,8 +44,13 @@ def main(): views = filter(lambda x: x.id == args.resource_id, TSC.Pager(server.views.get)) view = views.pop() - (populate_name, option_factory_name, member_name, extension) = args.type - populate = getattr(server.views, populate_name) + + # 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: From 7168309a5381b718043969ddf4ed816acb38dc09 Mon Sep 17 00:00:00 2001 From: Russell Hay Date: Thu, 15 Feb 2018 13:36:50 -0800 Subject: [PATCH 4/4] Missed one description --- samples/list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/list.py b/samples/list.py index 9c22fc7fd..b53795d1a 100644 --- a/samples/list.py +++ b/samples/list.py @@ -12,7 +12,7 @@ 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('--username', '-u', required=True, help='username to sign into server') parser.add_argument('--site', '-S', default=None)