Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions .github/workflows/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,6 @@ jobs:
fail-fast: false
matrix:
include:
- PYSPARK_VERSION: "3.1.3"
PYTHON_VERSION: "3.9"
JAVA_VERSION: "11"
- PYSPARK_VERSION: "3.2"
PYTHON_VERSION: "3.9"
JAVA_VERSION: "11"
- PYSPARK_VERSION: "3.3"
PYTHON_VERSION: "3.9"
JAVA_VERSION: "11"
- PYSPARK_VERSION: "3.5"
PYTHON_VERSION: "3.9"
JAVA_VERSION: "17"
Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install -y software-properties-common
RUN add-apt-repository ppa:deadsnakes/ppa
RUN apt-get install -y python3.8 python3-pip
RUN apt-get install -y python3.8-distutils
RUN apt-get install -y openjdk-11-jdk
RUN apt-get install -y python3.9 python3-pip
RUN apt-get install -y python3.9-distutils
RUN apt-get install -y openjdk-17-jdk

# Update symlink to point to latest
RUN rm /usr/bin/python3 && ln -s /usr/bin/python3.8 /usr/bin/python3
RUN rm /usr/bin/python3 && ln -s /usr/bin/python3.9 /usr/bin/python3
RUN python3 --version
RUN pip3 --version
RUN java -version
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ You can install [PyDeequ via pip](https://pypi.org/project/pydeequ/).
pip install pydeequ
```

> **Supported Spark version:** PyDeequ tracks the Deequ 2.0.21 JVM library, which is published for **Spark 3.5 only**. If you are on Spark 3.1/3.2/3.3, use PyDeequ 1.6.0 (Deequ 2.0.8).

### Set up a PySpark session
```python
from pyspark.sql import SparkSession, Row
Expand Down Expand Up @@ -214,8 +216,8 @@ Install Java Now open favourite terminal and enter the following:
List the Apache Spark versions:
$ sdk list spark

To install For Spark 3
$ sdk install spark 3.0.2
To install For Spark 3.5
$ sdk install spark 3.5.1
```

### Poetry
Expand Down Expand Up @@ -246,8 +248,8 @@ $ poetry run pytest
If you have issues installing the dependencies listed above, another way to run the tests and verify your changes is through Docker. There is a Dockerfile that will install the required dependencies and run the tests in a container.

```
docker build . -t spark-3.3-docker-test
docker run spark-3.3-docker-test
docker build . -t spark-3.5-docker-test
docker run spark-3.5-docker-test
```

## Contributing
Expand Down
7 changes: 3 additions & 4 deletions pydeequ/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
import re


# Deequ 2.0.10+ only publishes a spark-3.5 build; support for Spark 3.1/3.2/3.3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DESIGN: The dependency constraint pyspark >=2.4.7,<4.0.0 no longer reflects the Spark-3.5-only support; users on Spark 3.1–3.4 will encounter an import-time RuntimeError with no pip-level guard.

configs.py lines 42-43 run at module import; lines 34-39 raise RuntimeError for non-"3.5" versions. pyproject declares pyspark = ">=2.4.7,<4.0.0" (unchanged by diff). A user on Spark 3.3 installing pydeequ will hit RuntimeError at import pydeequ.

Refutation trail (why this survived the Critic's disprove pass)

Hypothesis (Investigator): Dropping all keys except "3.5" leaves the declared pyspark = ">=2.4.7,<4.0.0" dependency floor inconsistent with actual runtime support, so installs on Spark <3.5 import-fail with RuntimeError.

Disprove attempt (Critic): The pyproject shows pyspark = { version = ">=2.4.7,<4.0.0", optional = true }, unchanged by the diff. configs.py lines 32-39 now raise RuntimeError for any Spark version whose major.minor != "3.5". So a user on an allowed pyspark (e.g. 3.3) hits a hard RuntimeError at import pydeequ (line 43 executes at module load). The dependency metadata and the coord map now disagree; the PR narrows runtime support without narrowing the declared pyspark range.

The Critic's default verdict is OVERTURNED. UPHELD findings are those it tried — and failed — to refute.

# was dropped upstream, so pydeequ tracks Spark 3.5 only on Deequ 2.0.21.
SPARK_TO_DEEQU_COORD_MAPPING = {
"3.5": "com.amazon.deequ:deequ:2.0.8-spark-3.5",
"3.3": "com.amazon.deequ:deequ:2.0.8-spark-3.3",
"3.2": "com.amazon.deequ:deequ:2.0.8-spark-3.2",
"3.1": "com.amazon.deequ:deequ:2.0.8-spark-3.1"
"3.5": "com.amazon.deequ:deequ:2.0.21-spark-3.5",
}


Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ classifiers = [
python = ">=3.9,<4"
numpy = ">=1.14.1"
pandas = ">=0.23.0"
pyspark = { version = ">=2.4.7,<4.0.0", optional = true }
pyspark = { version = ">=3.5,<3.6", optional = true }

[tool.poetry.dev-dependencies]
pytest = "^8.0"
Expand Down
5 changes: 5 additions & 0 deletions tests/test_analyzers.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ def test_fail_Histogram(self):
)

def test_Histogram_maxBins(self):
# Deequ 2.0.10+ emits a trailing Histogram.tailCount metric when the
# number of distinct values (3) exceeds maxDetailBins (2): tailCount =
# 3 - 2 = 1, so the final Row(value=1.0) is the rolled-up tail.
self.assertEqual(
self.Histogram_maxBins("b", maxDetailBins=2),
[
Expand All @@ -419,6 +422,7 @@ def test_Histogram_maxBins(self):
Row(value=0.3333333333333333),
Row(value=1.0),
Row(value=0.3333333333333333),
Row(value=1.0),
],
)
self.assertEqual(
Expand All @@ -429,6 +433,7 @@ def test_Histogram_maxBins(self):
Row(value=0.3333333333333333),
Row(value=1.0),
Row(value=0.3333333333333333),
Row(value=1.0),
],
)

Expand Down
15 changes: 0 additions & 15 deletions tests/test_anomaly_detection.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
import os
import unittest

import pytest
Expand Down Expand Up @@ -282,13 +281,6 @@ def HoltWinters(self, analyzer_func, test, df_prev, df_curr=None):
print(df.collect())
return df.select("check_status").collect()

@pytest.mark.xfail(
os.environ.get("SPARK_VERSION", "").startswith(("3.1", "3.2")),
reason=(
"Not supported in Spark < 3.3: breeze.stats.DescriptiveStats "
"is in unnamed module of loader 'app'"
)
)
def test_BatchNormalStrategy(self):

# Interval is inclusive, so meet the requirements upper value is up to 9
Expand Down Expand Up @@ -357,13 +349,6 @@ def test_OnlineNormalStrategy(self):
[Row(check_status="Success")],
)

@pytest.mark.xfail(
os.environ.get("SPARK_VERSION", "").startswith(("3.1", "3.2")),
reason=(
"Not supported in Spark < 3.3: breeze.stats.DescriptiveStats "
"is in unnamed module of loader 'app'"
)
)
def test_holtWinters(self):
# must have 15 points of data
self.assertEqual(self.HoltWinters(Size(), 1, self.df_1), [Row(check_status="Success")])
Expand Down
28 changes: 27 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import pytest
from pydeequ.configs import _extract_major_minor_versions
from pydeequ.configs import (
_extract_major_minor_versions,
_get_deequ_maven_config,
_get_spark_version,
)


@pytest.mark.parametrize(
Expand All @@ -13,3 +17,25 @@
)
def test_extract_major_minor_versions(full_version, major_minor_version):
assert _extract_major_minor_versions(full_version) == major_minor_version


def test_supported_spark_resolves_to_deequ_coord(monkeypatch):
# _get_spark_version is lru_cached and reads SPARK_VERSION at call time.
monkeypatch.setenv("SPARK_VERSION", "3.5")
_get_spark_version.cache_clear()
try:
assert _get_deequ_maven_config() == "com.amazon.deequ:deequ:2.0.21-spark-3.5"
finally:
_get_spark_version.cache_clear()


@pytest.mark.parametrize("unsupported", ["3.3", "3.2", "3.1", "3.4"])
def test_unsupported_spark_raises(monkeypatch, unsupported):
# Spark versions Deequ no longer publishes a build for must fail loudly.
monkeypatch.setenv("SPARK_VERSION", unsupported)
_get_spark_version.cache_clear()
try:
with pytest.raises(RuntimeError, match="incompatible Spark version"):
_get_deequ_maven_config()
finally:
_get_spark_version.cache_clear()
Loading