tableau_tools 5.0 : Python 3 for 2020 (and so much more!)

Just in time for 2020, tableau_tools has gone a thorough upgrade to bring it into the Python 3 era. While the 4 series of tableau_tools was Python 3 compatible, tableau_tools 5.0 and beyond are Python 3 native, dropping support for 2.7 entirely. It also drops support for any version of Tableau before 10.3, which matches Tableau’s official support policy at this point.

In the process, the source has also been completely refactored for anyone who wants to join in and help with the project or just is tracking down a bug or strange behavior. It’s far easier now to find where everything is implemented, understand the logic of it, and make suggestions or changes.

Update to Python 3.6 or better, and then use PIP to install the latest version from PyPi. For all the good details, read more…

TableauServerRest classes with better organization

There’s a lot of changes under the hood (discussed below) but all those internal improvements result in the most visible change to the user: the TableauServerRest classes, with much better organization and discovery of the available methods.

In all previous versions of tableau_tools, you would use the TableauRestApiConnection classes, which had all the available REST API methods attached directly to them:


t = TableauRestApiConnection(server=server, username=username, password=password,
site_content_url=new_site_content_url)
t.signin()
logger = Logger('log.log')
# Enable logging after sign-in to hide credentials
t.enable_logging(logger)

# Create some groups
groups_to_create = ['Administrators', 'Executives', 'Managers', 'Line Level Workers']

for group in groups_to_create:
t.create_group(group_name=group)

time.sleep(4)
default_proj = t.query_project(project_name_or_luid='Default')

 

 

With TableauServerRest, methods for the different aspects (projects, users, workbooks, etc.) are accessible through a sub-object named as such. Methods that affect the whole REST API connection, or are useful to any type of endpoint, remain available on the main object. Here’s the same code using TableauServerRest:


t = TableauServerRest(server=server, username=username, password=password,
site_content_url=new_site_content_url)
t.signin()
logger = Logger('log.log')
# Enable logging after sign-in to hide credentials
t.enable_logging(logger)

# Create some groups
groups_to_create = ['Administrators', 'Executives', 'Managers', 'Line Level Workers']

for group in groups_to_create:
t.groups.create_group(group_name=group)

time.sleep(4)
default_proj = t.projects.query_project(project_name_or_luid='Default')

 

 

You’ll notice the only real change is the additional .projects or .groups to get to the methods related to them. Under the hood, both object types implement the exact same methods, they just do so in slightly different ways, so neither class type has more or less features than the other — they are just organized differently.

TableauServerRest should be a little easier if you are just getting started with tableau_tools, but you can keep using the TableauRestApiConnection classes for any existing scripts you have, and there should be “complete backward compatibility” (quotes because you should only be using tableau_tools 5+ with Tableau Server 10.3 or above, and there’s always the chance of slight changes to reflect real improvements).

Explicit Type Hinting

The other big improvement is real Python 3-style type hinting on every single method in the entire package. Python lets you write without explicit typing, but when dealing with the kind of complexity that XML or the tableau_documents objects, it is very useful to know exactly what you are expected to put into a function and what you’ll get back. If you are using PyCharm (or presumably another high-quality IDE), pay attention if you get a message or underline signaling you are sending the wrong type into a method, or doing a method that is not allowed on the returned variable.

Due to the type hinting throughout, your IDE should always be able to tell you the available methods on anything you get back from any method in tableau_tools, or what is expected of parameters into a method.

tableau_documents Improvements and Changes

The tableau_documents sub-package has been remodeled, so if you are using it you may have to change your code up just a bit. See the updated examples and README for what the current methods look like.

The biggest change is that the previous TableauFile class has changed into TableauFileManager, which contains static methods for opening things. So rather than TableauFile(filename=’some file’), you would now use TableauFileManager.open(filename=’some file’).

The second change is that all of the file types that might contain TableauDatasource objects now present the list of TableauDatasource objects at the top level, by all inheriting the DatasourceFileInterface class. This way you can open up a whole directory of files without worrying about if they are TWBs, TWBXs, TDSs, or TDSXs.

<br data-mce-bogus="1">

t_file = TableauFileManager.open(filename='some file.tdsx')<br data-mce-bogus="1">

for ds in t_file.datasources:<br data-mce-bogus="1">

# loop and do things<br data-mce-bogus="1">

 

 

TableauFileManager is actually returning a class representing the files themselves, either a TWB, TWBX, TDS, TDSX, TFL, or TFLX class. Each of these classes knows how to construct the correct TableauDocument class within it (nothing for the Prep Flow files yet) and how to save back a new file correctly. If it is a packaged file (ending in X), there is now a .tableau_xml_file property to access the inner TWB or TDS object. From a TWB or TDS, you can still access the TableauDocument object (either TableauWorkbook or TableauDatasource) which represents XML contained within the actual file as an editable object. Then when you want to save your changes to a new file, you call the outer-most object’s .save_new_file() method and it will handle all the behind-the-scenes magic.

The experimental functionality for creating a TDS file from scratch has been temporarily disabled (in the sense that it has not been reworked or fully tested in this first 5-series release). I expect it to return in some fashion.

The ability to “add an extract to a live data source” has been removed and will stay removed. After a lot of consideration, the best way to make a data source with an extract that you can use as a template is:

  1. Create your initial data source in Tableau Desktop
    1. Make an Extract
    2. Build out the workbook
    3. Add an Extract filter that will result in little to no records in the Extract
    4. Once the Extract has been built, remove the filter
  2. Use “Add to Saved Data Sources” and save as a TDSX file
  3. Open the resulting file using tableau_documents.TableauFileManager.open().
  4. Use the .datasources property to loop through the datasources and connections collections and make any changes
  5. Use the .save_new_file() method to get a new TDSX with the changes included
  6. Publish to Tableau Server using TableauServerRest.datasources.publish_datasource() or TableauServerRest.workbooks.publish_workbook()
  7. Using the returned LUID, use TableauServerRest.extracts.run_extract_refresh_for_datasource() or TableauServerRest.extracts.run_extract_refresh_for_workbook() 
  8. You can also then put the new file on an extract schedule using TableauServerRest.schedules.add_datasource_to_schedule() or TableauServerRest.schedules.add_workbook_to_schedule()

Full Set of Changes

  • tableau_tools 5.0 assumes that Tableau Server REST API 2.6 is the baseline (this represents Server 10.3).
    • This means that the numbering system now goes: TableauServerRest, TableauServerRest27, …, TableauServerRest36 and TableauRestApiConnection, TableauRestApiConnection27, …, TableauRestApiConnection36
    • This change also affected any of the object types that were numbered prior to 26. They’ve all been rolled into the base version, and then the numbering starts at 27.
  • As mentioned above, TableauServerRest classes are available with a different organizing principle than the flat organization of the TableauRestApiConnection classes
  • Also as mentioned above, Explicit Type Hinting on every method in the official Python 3.6 style
  • Internally, everything has been refactored in a major way. There is a new methods sub-module to tableau_rest_api, containing source files for all of the implementations of the various methods, organized by endpoint. These classes are versioned just like the others. Ex: GroupMethods, GroupMethods27,… GroupMethods36. This accomplishes two purposes:
    •  Enabling the same method implementations on both TableauServerRest and TableauRestApiConnection
    • Vastly easier to find any given method implementation in the code. Hopefully this allows for more contributors and reviewers over time
  • The rest_api_base classes now hold the basic aspects of the REST API connection, as well as any “abstract” implementations that might be used by sub-classes. This allows for centralization and simplification of a lot of different implementations.
  • tableau_documents has new object types and is a much more consistent model of how the files and XML all relate together
  • The ‘create extract from a live datasource’ capabilities have been removed or deprecated because it is better to create a known template in Desktop then modify using tableau_documents, then have Server recreate.
  • There is more explicit capabilities for swapping in externally generated files from the Hyper or Extract APIs into packaged workbooks, as a TDSX or TWBX is necessary for publishing to Tableau Server, especially with multi-table Hyper files.

 

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s