Author: bryantbhowell

Tableau and Behold! at TC17

I’ll be working at Tableau Doctor during the day on Tuesday and Thursday at TC17. Come by and ask for the “Tableau and Behold blog guy”. Hopefully they won’t take away my Tableau Doctor’s license for some of my “remedies”.

As they say, Viva Las Vegas!


Republishing Extracts from One Site (or Server) to Another with tableau_tools

Imagine you have a Data Source (in a workbook or outside of one) which is an extract, refreshing on a schedule. But that same data could be used on a different site, or a different server. There are lots of reasons to have logical partitions that basically need a copy of data, particularly related to security. You might have an internal server that connects to data sources allowing the refresh, but want to push that content to a server that eventually connects to the public Internet.

The REST API allow for this fairly easily — you simply download the first workbook, then republish to a different site with the Save Credentials options set to “False”. No credentials means the extract can’t update, but that’s exactly the idea behind this exercise — you want no way to access the database.

Note: The Tableau workbook and data source files will still contain some information about the original live data source that the extract was created from, but no passwords (no credentials are passed to the second site/server). If you need complete lock-down security, I can try and explore how much you can blank out of the XML while still publishing successfully.

This is very easily accomplished via tableau_tools:

# -*- coding: utf-8 -*-

from tableau_tools.tableau_rest_api import *
from tableau_tools import *
import time

o_server = u'http://'
o_username = u''
o_password = u''
o_site_content_url = u''

logger = Logger(u'move.log')

d_server = u'http://'
d_username = u''
d_password = u''
d_site_content_url = u''

t = TableauRestApiConnection26(o_server, o_username, o_password, o_site_content_url)
downloaded_filename = u'File Name'
wb_name_on_server = u'WB Name on Server'
proj_name = u'Default'
t.download_workbook(wb_name_on_server, downloaded_filename, proj_name_or_luid=proj_name)

d = TableauRestApiConnection26(d_server, d_username, d_password, d_site_content_url)
proj = d.query_project(u'Default')
d.publish_workbook(u'{}.twbx'.format(downloaded_filename), wb_name_on_server, proj, save_credentials=False, overwrite=True)



Killing a Tableau Server Session

Within an embedded application, it can be difficult to make sure that sign-out is achieved in both the application and Tableau Server. Tableau Server supports SAML signout commands, but for all sorts of reasons, this might not always work.

Luckily, it is possible to use the REST API to kill any session programmatically, but you need the session identifier from the Tableau Repository. The question is, how do you know what session belongs to a user? There is a sessions view, but you need a little bit more to get filtering down to the username level:

sessions.shared_vizql_write, AS user_name,
FROM sessions
JOIN users ON sessions.user_id =
JOIN system_users ON users.system_user_id =
WHERE = '{username}'

Once you have the session ID, you can send a REST API sign out command.

tableau_tools has both of these commands wrapped in a simple interface.

server = ''
username = ''
password = ''
readonly_user_password = ""
d = TableauRestApiConnection25(server, username, password)
tab_rep = TableauRepository(server, readonly_user_password)
uname = 'some_username'
sessions_cur = tab_rep.query_sessions(username=uname)
for row in sessions_cur:
    d.token = row[0]

The token property of the TableauRestApiConnection uses the REST API session token on when you do the signin() method, but you can replace the token with any session ID from the repository and then the signout() method will be sending the correct method to sign-out.

tableau_tools version 4.2.0 released – now Python 3 compatible!

Update: Hot on the heels of 4.1.0, tableau_tools 4.2.0 is now available with full Python 3 compatibility!

The version 4.0 series of tableau_tools was always intended to allow for Python 3 compatibility, and with version 4.2.0, installing from PyPi (or invokes automatic 2to3 conversion that should work without any additional changes. The short lived 4.1.0 release moved from urllib2 to requests as the library for making the actual HTTP calls in the backend, and 4.2.0 finishes off the work by moving everything to Unicode internally, while writing all text files out in UTF-8 encoding.

This means there is now a requirement for the requests library, but since every other Python package in the world now uses requests, I don’t think it should cause anyone any harm. Please do report any bugs that you see, as there might be a few quirky corner cases where something that was necessary before requests is causing an issue.

The Tableau SDK itself is only Python 2.7 compatible, so the TDE Extract Generation / Conversion from TDS to TDSX functionality won’t work in Python 3, but everything else should be completely compatible.


tableau_tools 4.0.0 is released!

I’m very excited to announce the release of tableau_tools 4.0.0, available now on GitHub and PyPi! tableau_tools is a single library to make administrating a Tableau Server and the content on that server as simple as possible. It is written in Python 2.7 with the aim to eventually become compatible with Python 3. It is also intended to server all versions of Tableau Server from 9.0 – current release.

The 4.0 release is almost a complete rewrite, with a focus on full implementation of the Tableau Server REST API through API Version 2.6, simplification of methods throughout, and advanced capabilities for publishing from templates. The capabilities of tableau_tools are beyond the current capabilities of the Tableau Server-Client Library and Document API, and I recommend you use it over them at this time.

4.0 is different enough from the previous versions that all previous versions of tableau_tools are now deprecated, and I will be removing their documentation from the website to remove any confusion.

There are plenty of example scripts included in the package, which you can see at GitHub…

The README is a full guide to using the library, and should be read when beginning. As before, tableau_tools was programmed using PyCharm and is designed to provide optimal code completion when using PyCharm. Your life will be a lot easier if you do.

tableau_tools README

A list of all the major changes, which won’t matter if you are just getting started:


tableau_tools 4.0 is coming soon

I don’t normally post about things before they are ready, but tableau_tools 4.0 is getting close to release, and I am excited about how much it has improved. This is the big one, and if will probably break all your old scripts, so get ready for some cleanup, but I promise it is worth it.

The 4.0.0 branch is available on GitHub, and you can preview the README files now

tableau_rest_api README

Here are all the big changes:

  • Up to date for version 10.3 / API version 2.6: All methods from all versions are now supported
  • tableau_documents updated to handle version 10 style data sources with cross-database connections.
    • Vastly simplified model of: TableauFile->TableauDocument (Datasource or Workbook)->Datasources->Connections
    • Most getter/setters replaced with properties
    • Merging of the DatasourceGenerator with the actual TableauDatasource class so that single class can work with existing datasources to modify or build one entirely from scratch
    • Improved handling of large workbooks and datasources
  • Massive cleanup of all REST API methods: There is now one method to do anything related to that action, with optional parameters if you need more specificity.
  • Name vs. LUID lookup built in: Every method that can autodetects whether a LUID is being passed, and if not, does a name lookup automatically. You can use real names in almost every method without having to do the lookup first
  • Versioning handled by subclass inheritance. “What is this?” you may be asking. Basically, tableau_tools now implements each new version of the Tableau REST API as a subclass of the previous class, so it retains all features of the older versions, while adding new methods and updating those that have new features. Subclasses for versions are named like: TableauRestApiConnection23 or TableauRestApiConnection26
  • All permissions are handled through the PublishedContent classes: Project, Workbook, Datasource
    • All work on Projects is handled through a Project object.
    • Workbooks and Datasources still require requesting their PublishedContent objects
    • GranteeCapabilities object renamed to Permissions
    • Changes to Permissions must be accomplished via Permissions object
  • lxml removed and replaced fully with Python standard library ElementTree. No more need to install lxml binaries on Windows!
  • All XML requests are now built via ElementTree rather than as text strings
  • docstring typing for all parameters and returns. If there’s no docstring, the method hasn’t been updated yet. This means PyCharm or your other IDE can tell if you are passing in the right types to a given method. Some people will complain this is less Pythonic, but I promise type-safety is incredibly useful

Future goals for the 4.X series:

  • Python 3.3 compatibility
  • Using the requests library for HTTP calls (if there is any benefit, might be worth it for Python 3)

Behold! Emailer 1.2 Introduces Bulk E-mail Mode

The original release of Behold! Emailer was focused on the need of Tableau Server users who wanted to schedule e-mail reports of a PDF from a full workbook. In version 1.2.0, available on GitHub, a Bulk tab has been added to allow for running through lists of jobs to send out to any users. This is useful when you need to push out static results, perhaps filtered on certain factors, to sets of users who are not on the Tableau Server. As long as the output is a static PDF or CSV and not a TWBX, this falls within the Tableau EULA (at the time of writing).

How does it work? Create a CSV file (including the headers) on the following pattern:

To:,CC:,BCC:,Site,View Location,Filter Field Name 1,Filter Values 1,Filter Field Name 2,Filter Values 2,Filter Name 3,Filter Values 3,...

You’ll notice the ellipses at the end (don’t actually include them). That signals that you can make as many slots for additional parameters and filters as you need (up to 25). Just follow the naming convention for the additional fields.

To include multiple items for filtering, separate them with a semi-colon (“;”), like the following:

To:,CC:,BCC:,Site,View Location,Filter Field Name 1,Filter Values 1,Filter Field Name 2,Filter Values 2,Filter Name 3,Filter Values 3,,,default,BasicSuperstoreSQLServer/Sheet1,Category,Technology;Office Supplies,YEAR(Order Date),2013;2014,,

The program will automatically convert things into lists or change the semi-colons into the right separators. All URL encoding is handled automatically — just make the CSV and load it in. Reference things exactly as you would in Tableau (notice the YEAR(Order Date) example above), with no spaces between the commas.