Changing database connections in TWBX and TDSX files i.e. Publishing extracts from a template

This post coincides with v1.3.0 of the tableau_rest_api library, which you should promptly be upgrading to for all the excellent functionality it provides

As shown previously, it’s not tremendously difficult to change the database/schema name (or port) in the XML of a TWB or TDS file — easy enough that we were able to add programmatic facilities for it to the tableau_rest_api library. Live connections aren’t the only side of Tableau though; extracts are an essential aspect of the Tableau experience. When we want to publish extracts, we end up using the Packaged File types – TWBX and TDSX (you may not be saving your stand alone extracts as a TDSX, but you should — a TDE file by itself stores no information about the datasource from whence it sprung, while a TDSX holds both the originating TDS and the TDE.

Packaged files are just plain ZIP files with a bit of structure (try it — you can unzip them, or ZIP up a TDS and rename the .zip to .tdsx and it will work). The main XML file (TWB or TDS) lives in the lowest level, and then data and other files exist in sub-directories. These sub-directories are not always the same, so it’s hard to generically say what will be inside. Since all we’re worried about is changing the XML file, we’ll just copy whatever we find in the sub-directories as is and hope for the best [this is a fundamental strategy in the rest_api_library : edit the least necessary pieces and copy the rest].

Using the TableauPackagedFIle class

Given the previous information about the packaged workbooks, there is a new class starting in tableau_rest_api v1.3.0 called TableauPackagedFile which can be instantiated from a file-like object of a ZIP file. It actually can determine whether it is a TDSX or a TWBX based on the files packaged inside, which can be checked via TableauPackagedFile.get_type(). The two other essential methods are get_tableau_object() which will return either a TableauDatasource object or a TableauWorkbook object, depending on if you are dealing with a TWBX or TDS. Any manipulation you do in the objects to their internal TableauConnection object(s) will be saved when you do a save_new_packaged_file(new_filename_no_extension) .

But wait, there is more! You can pass a TableauPackagedFile object directly into the publish_ methods in the place of the filename, and the new resulting file will be brought down temporarily and then published up to the server.

Example


from tableau_rest_api.tableau_rest_api import *
import urllib2

username = ''
password = ''
server = 'http://127.0.0.1'

logger = Logger('switch.log')

# Modifying the TDSX
tdsx_filename = "somefile.tdsx"
fh = open(tdsx_filename, 'rb')
pfile = TableauPackagedFile(fh, logger)
if pfile.get_type() == 'tdsx':
ds = pfile.get_tableau_object()
ds.connection.set_dbname('Super Store')
pfile.save_new_packaged_file('new_file')

fh.close()

# Publishing the modified TDSX
default = TableauRestApi(server, username, password)
default.signin()
proj_luid = default.query_project_luid_by_name('default')
default.publish_datasource('new_file.tdsx', 'Changed DS 2', proj_luid, True)

# Modifying a TWBX
twbx_filename = "some workbook.twbx"
fh = open(twbx_filename, 'rb')
pfile = TableauPackagedFile(fh, logger)
if pfile.get_type() == 'twbx':
wb = pfile.get_tableau_object()
datasources = wb.get_datasources()
for ds in datsources:
ds.connection.set_dbname('New Database')
fh.close()

proj_luid = default.query_project_luid_by_name('default')
default.publish_datasource(pfile, 'Changed TWBX', proj_luid, True)

How IT WOrks

The zipfile module in the standard Python library actually handles all the functionality we need. If you are re-implementing in another language, there’s not much going on. My algorithm is just to ignore anything that has a sub-directory as part of its filename, then look for the .twb or .tds. After that, I just copy all content from the sub-directories into the new file, as is.

The XML file gets represented as its appropriate class– since the library already has classes that represent the hierarchy, it just piggybacks on the existing capabilities to work with TDS and TWB files.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s