Skip to main content

Python equivalent of Cluster Yield CI's Scala plan-extractor

Project description

cy-py — Cluster Yield CI for Python

The Python equivalent of the Scala plan-extractor. Extracts Spark physical plans from PySpark pipelines so Cluster Yield CI can diff them on every PR — same JSON format, same deterministic Spark config, same GitHub Action.

30-Second Setup

1. Add the dependency

Poetry:

poetry add --group dev cy-python

pip:

# requirements.txt or pyproject.toml
cy-python

2. Extend SparkPipeline in your pipeline

from cy_py import SparkPipeline
from pyspark.sql import DataFrame, SparkSession

# Just add SparkPipeline as a base class — nothing else changes
class DailyOrderSummary(SparkPipeline):
    def build(self, spark: SparkSession) -> DataFrame:
        # ... your existing pipeline code ...

3. Add the GitHub Action

# .github/workflows/spark-plan-check.yml
name: Spark Plan Check
on:
  pull_request:
    branches: [main]
jobs:
  plan-check:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    steps:
      - uses: actions/setup-python@v5
        with: { python-version: '3.12' }
      - uses: actions/setup-java@v4
        with: { java-version: '11', distribution: 'temurin' }
      - uses: clusteryieldanalytics/cluster-yield-ci@v1
        with:
          pipeline-class: my_package.pipelines:DailyOrderSummary
          github-token: ${{ secrets.GITHUB_TOKEN }}

That's it. The action detects your Python build tool (Poetry or pip), installs dependencies, calls your build() method, extracts the plan, diffs it against the baseline from main, and posts findings on your PR.

How It Works

The pipeline-class input takes a Python import path. Under the hood:

  1. The action detects your build tool (pyproject.toml with Poetry, or pip)
  2. Installs your project (poetry install or pip install -e .)
  3. Runs cy-py my_package.pipelines:DailyOrderSummary on both branches
  4. cy-py imports your class, calls build(spark), exports the physical plan as JSON
  5. cluster-yield-ci diffs the plans and posts findings

Scala ↔ Python Mapping

cy-py is a 1-1 port of the Scala library. Every component has a direct equivalent:

Scala Python Purpose
SparkPipeline trait SparkPipeline ABC Contract: build(spark) -> DataFrame
PlanExtractor.exportPlan() export_plan() Export physical plan as JSON
PlanExtractor.exportCatalog() export_catalog() Export table statistics
PlanExtractor.createExtractionSession() create_extraction_session() Deterministic SparkSession for CI
ExtractRunner (reflection) extract_runner (import + getattr) CLI that resolves and invokes pipelines
com.example.MyPipeline my_package.module:MyPipeline Pipeline identification syntax
MyPipeline#run my_package.module:MyPipeline#run Custom method override

The output JSON is identical — plan.toJSON() from Spark's JVM, so the same analyzer works for both Scala and Python pipelines.

API

SparkPipeline base class

The contract your pipeline implements. Just one method:

from cy_py import SparkPipeline

class MyPipeline(SparkPipeline):
    def build(self, spark: SparkSession) -> DataFrame:
        ...

The base class is optional — cy-py also works with any class that has a build(self, spark) method, or even a plain function. The base class provides IDE autocompletion and type checking.

Custom method names

If your method isn't called build, append #methodName:

pipeline-class: my_package.pipelines:MyPipeline#run

Direct usage

For advanced workflows (multiple pipelines, custom Spark configs):

from cy_py import create_extraction_session, export_plan, export_catalog

spark = create_extraction_session()
df = MyPipeline().build(spark)
export_plan(df, "plans/current.json")
export_catalog(spark, ["db.orders", "db.customers"], "plans/catalog.json")
Function Description
export_plan(df, path) Export physical plan as JSON (does not execute the query)
export_catalog(spark, tables, path) Export catalog statistics for --catalog flag
create_extraction_session() SparkSession with deterministic CI settings

Deterministic Spark settings

create_extraction_session() configures Spark for reproducible plans:

  • spark.sql.adaptive.enabled = false — pre-AQE plan reflects code, not data
  • spark.sql.autoBroadcastJoinThreshold = -1 — simulates production table sizes
  • local[1] master, UI disabled, 200 shuffle partitions

These match the Scala extractor exactly, so plans are comparable across languages.

CLI

# Standard (method defaults to "build")
cy-py my_package.pipelines:DailyOrderSummary

# Custom output path
cy-py my_package.pipelines:DailyOrderSummary plans/current.json

# Custom method name
cy-py my_package.pipelines:DailyOrderSummary#run plans/current.json

Outputs plans/current.json (plan array) and plans/current.txt (human-readable tree).

Compatibility

PySpark Python Java Status
3.3.x 3.10+ 8+ Supported
3.4.x 3.10+ 8+ Supported
3.5.x 3.10+ 11+ Supported

PySpark is pinned to >=3.3,<4. Uses only stable Spark APIs via the JVM bridge.

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

cy_python-0.1.0.tar.gz (10.4 kB view details)

Uploaded Source

Built Distribution

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

cy_python-0.1.0-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

Details for the file cy_python-0.1.0.tar.gz.

File metadata

  • Download URL: cy_python-0.1.0.tar.gz
  • Upload date:
  • Size: 10.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cy_python-0.1.0.tar.gz
Algorithm Hash digest
SHA256 91a572f2009b68af30a7cf1c6dcb2c0140aaf4b3a9fa190d0ab6fb9d9d53427e
MD5 c9da1630fe4d8f3cc788da8d8c466341
BLAKE2b-256 87833ee98f2c8dcde4e15e2fd7c359d0a0e786f10fa202b6db7496d9121d32ee

See more details on using hashes here.

Provenance

The following attestation bundles were made for cy_python-0.1.0.tar.gz:

Publisher: publish.yml on clusteryieldanalytics/cy-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cy_python-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: cy_python-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cy_python-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fc2613f7e97a7d0d4bd0186d767e57ca1af211b09fc98c873184befe960d27c0
MD5 fc2bcf2a43a3fee863af14f2d80a34d5
BLAKE2b-256 8dfe47d8fdc52328719134cd27986d14604f160e53d429310bc55f8a257694a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for cy_python-0.1.0-py3-none-any.whl:

Publisher: publish.yml on clusteryieldanalytics/cy-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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