From dfe6737efd1ab46c9076539b53c95126d5285925 Mon Sep 17 00:00:00 2001 From: Chris Shin Date: Wed, 8 Jul 2020 16:54:40 -0700 Subject: [PATCH 1/2] Adds a sample for publishing datasources --- samples/publish_datasource.py | 81 +++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 samples/publish_datasource.py diff --git a/samples/publish_datasource.py b/samples/publish_datasource.py new file mode 100644 index 000000000..d0af50f33 --- /dev/null +++ b/samples/publish_datasource.py @@ -0,0 +1,81 @@ +#### +# This script demonstrates how to use the Tableau Server Client +# to publish a datasource to a Tableau server. It will publish +# a specified datasource to the 'default' project of the provided site. +# +# Some optional arguments are provided to demonstrate async publishing, +# as well as providing connection credentials when publishing. If the +# provided datasource file is over 64MB in size, TSC will automatically +# publish the datasource using the chunking method. +# +# For more information, refer to the documentations: +# (https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_datasources.htm#publish_data_source) +# +# To run the script, you must have installed Python 3.5 or later. +#### + +import argparse +import getpass +import logging + +import tableauserverclient as TSC + + +def main(): + parser = argparse.ArgumentParser(description='Publish a datasource to server.') + parser.add_argument('--server', '-s', required=True, help='server address') + parser.add_argument('--site', '-i', help='site name') + parser.add_argument('--username', '-u', required=True, help='username to sign into server') + parser.add_argument('--filepath', '-f', required=True, help='filepath to the datasource to publish') + parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', + help='desired logging level (set to error by default)') + parser.add_argument('--as-job', '-a', help='Publishing asynchronously', action='store_true') + parser.add_argument('--conn-username', help='connection username') + parser.add_argument('--conn-password', help='connection password') + parser.add_argument('--conn-embed', help='embed connection password to datasource', action='store_true') + parser.add_argument('--conn-oauth', help='connection is configured to use oAuth', action='store_true') + + args = parser.parse_args() + + # Ensure that both the connection username and password are provided, or none at all + if (args.conn_username and not args.conn_password) or (not args.conn_username and args.conn_password): + parser.error("Both the connection username and password must be provided") + + password = getpass.getpass("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 to server + tableau_auth = TSC.TableauAuth(args.username, password, site=args.site) + server = TSC.Server(args.server, use_server_version=True) + with server.auth.sign_in(tableau_auth): + # Create a new datasource item to publish - empty project_id field + # will default the publish to the site's default project + new_datasource = TSC.DatasourceItem(project_id="") + + # Create a connection_credentials item if connection details are provided + new_conn_creds = None + if args.conn_username: + new_conn_creds = TSC.ConnectionCredentials(args.conn_username, args.conn_password, + embed=args.conn_embed, oauth=args.conn_oauth) + + # Define publish mode - Overwrite, Append, or CreateNew + publish_mode = TSC.Server.PublishMode.Overwrite + + # Publish datasource + if args.as_job: + # Async publishing, returns a job_item + new_job = server.datasources.publish(new_datasource, args.filepath, publish_mode, + connection_credentials=new_conn_creds, as_job=True) + print("Datasource published asynchronously. Job ID: {0}".format(new_job.id)) + else: + # Normal publishing, returns a datasource_item + new_datasource = server.datasources.publish(new_datasource, args.filepath, publish_mode, + connection_credentials=new_conn_creds) + print("Datasource published. Datasource ID: {0}".format(new_datasource.id)) + + +if __name__ == '__main__': + main() From 287e20933ebc6c8dbd58b58a076baa19a27d364f Mon Sep 17 00:00:00 2001 From: Chris Shin Date: Fri, 10 Jul 2020 13:01:19 -0700 Subject: [PATCH 2/2] Addresses feedback to use PAT and async flag --- samples/publish_datasource.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/samples/publish_datasource.py b/samples/publish_datasource.py index d0af50f33..fa0fe2a95 100644 --- a/samples/publish_datasource.py +++ b/samples/publish_datasource.py @@ -11,11 +11,14 @@ # For more information, refer to the documentations: # (https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref_datasources.htm#publish_data_source) # +# For signing into server, this script uses personal access tokens. For +# more information on personal access tokens, refer to the documentations: +# (https://help.tableau.com/current/server/en-us/security_personal_access_tokens.htm) +# # To run the script, you must have installed Python 3.5 or later. #### import argparse -import getpass import logging import tableauserverclient as TSC @@ -25,11 +28,14 @@ def main(): parser = argparse.ArgumentParser(description='Publish a datasource to server.') parser.add_argument('--server', '-s', required=True, help='server address') parser.add_argument('--site', '-i', help='site name') - parser.add_argument('--username', '-u', required=True, help='username to sign into server') + parser.add_argument('--token-name', '-p', required=True, + help='name of the personal access token used to sign into the server') + parser.add_argument('--token-value', '-v', required=True, + help='value of the personal access token used to sign into the server') parser.add_argument('--filepath', '-f', required=True, help='filepath to the datasource to publish') parser.add_argument('--logging-level', '-l', choices=['debug', 'info', 'error'], default='error', help='desired logging level (set to error by default)') - parser.add_argument('--as-job', '-a', help='Publishing asynchronously', action='store_true') + parser.add_argument('--async', '-a', help='Publishing asynchronously', dest='async_', action='store_true') parser.add_argument('--conn-username', help='connection username') parser.add_argument('--conn-password', help='connection password') parser.add_argument('--conn-embed', help='embed connection password to datasource', action='store_true') @@ -41,14 +47,12 @@ def main(): if (args.conn_username and not args.conn_password) or (not args.conn_username and args.conn_password): parser.error("Both the connection username and password must be provided") - password = getpass.getpass("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 to server - tableau_auth = TSC.TableauAuth(args.username, password, site=args.site) + tableau_auth = TSC.PersonalAccessTokenAuth(args.token_name, args.token_value, site_id=args.site) server = TSC.Server(args.server, use_server_version=True) with server.auth.sign_in(tableau_auth): # Create a new datasource item to publish - empty project_id field @@ -65,7 +69,7 @@ def main(): publish_mode = TSC.Server.PublishMode.Overwrite # Publish datasource - if args.as_job: + if args.async_: # Async publishing, returns a job_item new_job = server.datasources.publish(new_datasource, args.filepath, publish_mode, connection_credentials=new_conn_creds, as_job=True)