Skip to main content

SparkShift

CI PyPI Python License: Apache-2.0

Convert SQL and SAS programs into readable, idiomatic, tested PySpark DataFrame code.

Try it in your browser: nothing to install, and your code never leaves your browser.

Status: first release (0.1). SparkShift converts SELECT queries, including joins, aggregation, ordering, window functions and QUALIFY, CTEs, set operations, and subqueries, from generic SQL and six dialects (T-SQL, PostgreSQL, MySQL, Snowflake, BigQuery, and Oracle), and a documented subset of SAS: DATA steps and PROC SORT, MEANS, SUMMARY, FREQ, and SQL. Everything else is rejected with a clear error. See ROADMAP.md for what is planned.

Why SparkShift

  • Readable output. The code looks like what a data engineer would write by hand: one chained DataFrame expression per query, named variables for CTEs and SAS data sets, and only the imports it needs.
  • It rejects instead of guessing. When a construct means something different in Spark, or only the table schema would tell what it means, SparkShift says so, names the construct, and suggests a rewrite. Every issue in a query is listed at once.
  • Proven on real engines. Every supported construct is tested by running the original SQL and the generated PySpark on Apache Spark and comparing the results; PostgreSQL and MySQL queries also run on real servers in CI, the Spark tests also run through Spark Connect, and the examples have been run on Databricks. See How correctness is verified.

Install

SparkShift needs Python 3.11 or later:

pip install sparkshift

It depends only on SQLGlot: converting needs neither Spark nor Java. The generated code runs on PySpark 4.

Usage

import sparkshift

result = sparkshift.convert(
    "SELECT order_id, amount * 1.10 AS with_tax FROM sales.orders"
)
print(result.code)
from pyspark.sql import functions as F

result = (
    spark.table("sales.orders")
    .select(
        F.col("order_id"),
        (F.col("amount") * F.lit("1.10").cast("decimal(3,2)")).alias("with_tax"),
    )
)

The generated code imports what it uses, expects a SparkSession named spark (as in a Databricks notebook), and assigns the final DataFrame to result. Pass dialect= for non-generic SQL: tsql, postgres, mysql, snowflake, bigquery, or oracle.

Queries SparkShift cannot translate safely raise UnsupportedSQLError, listing every unsupported construct:

UnsupportedSQLError: 2 unsupported constructs:
  - function MY_UDF: MY_UDF(score)
  - OFFSET clause: OFFSET 20

See the Python API for the result, warnings, and errors.

Command line

sparkshift convert query.sql --dialect tsql       # print the PySpark code
sparkshift convert queries/ -o pyspark/           # every .sql and .sas file in a directory
sparkshift report queries/ --dialect snowflake    # how much of a workload converts, and what blocks the rest
sparkshift upload jobs/ --to /Workspace/Users/you@example.com/migrated   # notebooks into Databricks

For example:

echo "SELECT TOP 3 name FROM customers ORDER BY name" | sparkshift convert - --dialect tsql
from pyspark.sql import functions as F

result = (
    spark.table("customers")
    .select(F.col("name"))
    .orderBy(F.col("name").asc())
    .limit(3)
)

The command-line guide covers every option, strict mode, the coverage report, and the exit codes.

SAS

A .sas file is converted as a SAS program:

data low_scores;
    set customers (keep=customer_id name score);
    where score < 3;
    rename name = customer_name;
run;
from pyspark.sql import functions as F

low_scores = (
    spark.table("customers")
    .select(
        F.col("customer_id"),
        F.col("name"),
        F.col("score"),
    )
    .where(F.col("score").isNull() | (F.col("score") < F.lit(3)))
    .withColumnRenamed("name", "customer_name")
)

result = low_scores

In SAS a missing number is smaller than every number, so score < 3 keeps rows whose score is missing; in SQL and Spark it would drop them, so the code says so explicitly. No SAS installation is available to test against: SAS support follows SAS's documented rules, with expected results written by hand. docs/sas.md lists what is supported, each rule with its source, and the limitations.

Databricks

sparkshift convert jobs/ --notebook -o notebooks/ --catalog main --schema sales
pip install "sparkshift[databricks]"
sparkshift upload jobs/ --to /Workspace/Users/you@example.com/migrated --catalog main --schema sales

--notebook writes Databricks notebooks, with catalog and schema boxes at the top that choose where tables are read from; upload imports them into a workspace, with credentials only from the Databricks SDK's environment variables or profiles. The generated code needs a PySpark 4 client: on serverless compute, environment version 4 or later. See the Databricks guide.

How correctness is verified

Supported translations are backed by automated equivalence tests that execute both the original SQL and the generated PySpark against the same datasets on real Apache Spark, then compare the results with SQL semantics in mind: row order is ignored unless the query orders it, duplicate rows must match in number, column names and types must match, and NULLs are compared as values. The test data deliberately includes duplicates, NULLs, empty strings, and other edge cases.

For dialects Spark cannot run, the reference is Spark SQL written to mean the same thing. PostgreSQL and MySQL queries are also run on real PostgreSQL and MySQL servers in CI and compared with the generated PySpark; T-SQL, Oracle, Snowflake, and BigQuery are not yet checked against their own databases.

The Spark tests also run through Spark Connect, the way Databricks serverless compute runs code, in a separate CI job. See docs/testing.md. The gallery examples have also been run on a Databricks workspace and matched local Spark; see docs/databricks-validation.md.

Documentation

  • Supported SQL — every construct, dialect difference, and known limitation
  • SAS — the supported subset of SAS, with the documented rules it follows
  • Command line — convert, report, and upload, with every option and exit code
  • Python API — convert, to_notebook, results, warnings, and errors
  • Databricks — notebooks, uploading, and running on Databricks
  • Examples — a realistic query in each dialect, and SAS programs, next to the PySpark generated for them
  • Playground — the in-browser converter: limits, privacy, and running it locally
  • Architecture, testing, and decision records — how SparkShift is built and why

Contributing and security

See CONTRIBUTING.md for the development setup and how to add a construct, and SECURITY.md for reporting a vulnerability and how SparkShift handles code and credentials.

License

Apache License 2.0

Metadata

Release files for sparkshift 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sparkshift 0.1.0
File Size Uploaded
sparkshift-0.1.0.tar.gz 444.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sparkshift 0.1.0
File Interpreter ABI Platform
sparkshift-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 562.9 kB

Release files / sparkshift-0.1.0.tar.gz

Download URL sparkshift-0.1.0.tar.gz
Size 444.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c0744c05ea607b43067854dfad5420c6c35a90494252fb1fb6653de0cdff8440
BLAKE2b-256 checksum
How to use checksums
26b8b97fda982f35bbfdd73f39fcd512b559ed262557020176fadf665b656a16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release files / sparkshift-0.1.0-py3-none-any.whl

Download URL sparkshift-0.1.0-py3-none-any.whl
Size 118.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4c34e11f0589fd56a4c2e4ebeaa0a8ad7a80df5c4a17e0d88955280e019d3d8d
BLAKE2b-256 checksum
How to use checksums
de81ee0e784e0723651af6707e8252026897117437c2c01142e012197f210a02
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page