Skip to main content

Convert Tableau Prep Flow files to Python/pandas scripts

Project description

TFL Decompiler

Convert Tableau Prep Flow files (.tfl) to Python/pandas scripts.

PyPI version Python License: MIT

Say goodbye to Tableau Prep's proprietary flows. Transform your data transformations into portable, version-controlled, scalable Python code.


Table of Contents


Installation

pip install tfl-decompiler

With optional database connectors:

# PostgreSQL
pip install "tfl-decompiler[postgresql]"

# MySQL
pip install "tfl-decompiler[mysql]"

# SAP HANA
pip install "tfl-decompiler[saphana]"

# All database connectors
pip install "tfl-decompiler[all]"

Requirements: Python 3.9+


Quick Start

tfl-decompile my_flow.tfl -o my_flow.py
python my_flow.py

Usage

Command Line

After installation, the tfl-decompile command is available on your PATH.

# Convert a flow to Python (save to file)
tfl-decompile my_flow.tfl -o my_flow.py

# Print generated code to stdout
tfl-decompile my_flow.tfl

# Analyze flow structure without generating code
tfl-decompile my_flow.tfl --analyze

# Batch convert all flows in a directory
for f in *.tfl; do tfl-decompile "$f" -o "${f%.tfl}.py"; done

You can also run it as a module:

python -m tfl_decompiler my_flow.tfl -o my_flow.py

Python API

from tfl_decompiler import decompile

# Generate Python code string
code = decompile("my_flow.tfl")
print(code)

# Generate and save to file
decompile("my_flow.tfl", output_path="my_flow.py")

# Inspect the flow structure
from tfl_decompiler import TFLExtractor

extractor = TFLExtractor("my_flow.tfl")
content = extractor.extract()
summary = extractor.get_flow_summary(content)
print(summary)

# Fine-grained control
from tfl_decompiler import FlowParser, CodeGenerator

parser = FlowParser(content)
graph = parser.build_graph()
generator = CodeGenerator(graph)
code = generator.generate()

Example Output

Given a Tableau Prep flow that reads a CSV, renames columns, filters rows, aggregates, and writes output:

#!/usr/bin/env python3
"""
Auto-generated from: sales_flow.tfl
Generated by: TFL Decompiler
"""

import pandas as pd
import numpy as np
import os
from pathlib import Path


def main(input_sales: str = "data/sales.csv", output_results: str = "output/results.csv"):
    """Execute the data transformation flow."""

    # Step 1: Load data from CSV file
    df_input_sales = pd.read_csv(input_sales)

    # Step 2: Clean step (3 operations): rename, changetype, filter
    df_clean_transform = df_input_sales.copy()
    df_clean_transform = df_clean_transform.rename(columns={"old_name": "new_name"})
    df_clean_transform["amount"] = df_clean_transform["amount"].astype(float)
    df_clean_transform = df_clean_transform[df_clean_transform["status"] == "active"]

    # Step 3: Aggregate by [product_category]
    df_agg_summary = df_clean_transform.groupby("product_category").agg(
        {"amount": "sum", "quantity": "mean"}
    ).reset_index()

    # Step 4: Output to CSV
    os.makedirs(Path(output_results).parent, exist_ok=True)
    df_agg_summary.to_csv(output_results, index=False)

    return df_agg_summary


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="Decompiled Tableau Prep flow")
    parser.add_argument("--input_sales", default="data/sales.csv")
    parser.add_argument("--output_results", default="output/results.csv")
    args = parser.parse_args()
    result = main(input_sales=args.input_sales, output_results=args.output_results)
    print(f"Processing complete. Output shape: {result.shape}")

Supported Transformations

Node Types

Node Description
Input CSV, Excel, JSON, PostgreSQL, MySQL, SAP HANA
Clean / Transform Rename, filter, calculate, type conversion, and more
Pivot Columns-to-rows (melt) and rows-to-columns (pivot_table)
Aggregate groupby with all common aggregations
Join Inner, left, right, full outer
Union Vertical concatenation
Filter Boolean conditions
Output CSV, Excel, databases

Input Sources

Tableau Pandas
CSV File pd.read_csv()
Excel File pd.read_excel()
JSON File pd.read_json()
PostgreSQL pd.read_sql() with psycopg2
MySQL pd.read_sql() with mysql-connector
SAP HANA pd.read_sql() with hdbcli

Clean Operations

Tableau Pandas
Rename df.rename(columns={})
Remove Field df.drop(columns=[])
Change Type df.astype() / pd.to_datetime()
Filter df[condition]
Replace Values df.replace()
Split Field df[col].str.split()
Merge Fields String concatenation
Fill Nulls df.fillna()
Remove Nulls df.dropna()
Calculated Field New column assignment
Trim df[col].str.strip()
Case Conversion str.upper() / str.lower()

Pivot Operations

Tableau Pandas
Columns to Rows pd.melt()
Rows to Columns df.pivot_table()

Aggregations

Tableau Pandas
SUM sum
AVG mean
COUNT count
COUNTD nunique
MIN min
MAX max
MEDIAN median
STDEV std

Joins

Tableau Pandas
Inner pd.merge(how='inner')
Left pd.merge(how='left')
Right pd.merge(how='right')
Full Outer pd.merge(how='outer')

Tableau Expression Syntax

Tableau Pandas
[Field Name] df['Field Name']
IF...THEN...ELSE...END np.where()
CONTAINS([Field], 'x') df['Field'].str.contains('x')
LEFT([Field], n) df['Field'].str[:n]
UPPER([Field]) df['Field'].str.upper()
ZN([Field]) df['Field'].fillna(0)
IFNULL([Field], val) df['Field'].fillna(val)
YEAR([Date]) df['Date'].dt.year

Architecture

tfl_decompiler/
├── __init__.py           # Public API exports
├── __main__.py           # python -m tfl_decompiler entry point
├── main.py               # CLI entry point (tfl-decompile command)
├── extractor.py          # .tfl ZIP extraction and JSON parsing
├── flow_parser.py        # Flow graph construction + topological sort
├── node_registry.py      # Node type → handler mapping
├── code_generator.py     # Python code generation
├── expression_parser.py  # Tableau calc → pandas expression translator
├── db_connectors.py      # Database connection helpers
├── utils.py              # Utility functions
├── nodes/
│   ├── base.py           # Abstract base node
│   ├── input_node.py     # Data source handlers
│   ├── clean_node.py     # Transform handlers
│   ├── pivot_node.py     # Pivot handlers
│   ├── aggregate_node.py # Aggregation handlers
│   ├── join_node.py      # Join handlers
│   ├── union_node.py     # Union handlers
│   ├── filter_node.py    # Filter handlers
│   └── output_node.py    # Output handlers
└── builder/
    ├── flow_builder.py   # High-level flow assembly
    └── node_builders.py  # Per-node code builders

Why Replace Tableau Prep?

Tableau Prep Python / pandas
Proprietary format Plain text, version-controlled
GUI-only Scriptable and automatable
License required Free and open source
Limited scalability Scale to any size
Black box Full transparency
Desktop only Runs anywhere

Contributing

Contributions are welcome. Areas of interest:

  • Additional node types
  • More Tableau functions in the expression parser
  • Additional database connectors
  • Test cases with real .tfl files

Please open an issue or pull request on GitHub.


License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tfl_decompiler-1.0.0.tar.gz (68.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tfl_decompiler-1.0.0-py3-none-any.whl (79.5 kB view details)

Uploaded Python 3

File details

Details for the file tfl_decompiler-1.0.0.tar.gz.

File metadata

  • Download URL: tfl_decompiler-1.0.0.tar.gz
  • Upload date:
  • Size: 68.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for tfl_decompiler-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3c448016796ca90b9b55f7bbb81b94ca73d467b1b27a19d7c539e55f9be49df3
MD5 5ba2336758d2068bec1bcb8b7a33f3c7
BLAKE2b-256 3aeb3b0ee150ac56054e4684f90b44aa9d749df1468d8c452c6c34c7e1066f96

See more details on using hashes here.

File details

Details for the file tfl_decompiler-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: tfl_decompiler-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 79.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for tfl_decompiler-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e7b3cd825e8da2483d0677cbd8be78b5d74cbc6c801755ca430f309223fb0d6d
MD5 3015b23074f530e91592ba2c4372224d
BLAKE2b-256 9ed1d3925f0beae8ca331eee955f487ea97dbe05fea652923a0dd754a675561f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page