-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-25003][PYSPARK] Use SessionExtensions in Pyspark #21990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
84c2513
def4f3e
67d9772
4ddaff8
d9b2a55
3629c78
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3563,6 +3563,48 @@ def test_query_execution_listener_on_collect_with_arrow(self): | |
| "The callback from the query execution listener should be called after 'toPandas'") | ||
|
|
||
|
|
||
| class SparkExtensionsTest(unittest.TestCase, SQLTestUtils): | ||
|
||
| # These tests are separate because it uses 'spark.sql.extensions' which is | ||
| # static and immutable. This can't be set or unset, for example, via `spark.conf`. | ||
|
|
||
| @classmethod | ||
| def setUpClass(cls): | ||
| import glob | ||
| from pyspark.find_spark_home import _find_spark_home | ||
|
|
||
| SPARK_HOME = _find_spark_home() | ||
| filename_pattern = ( | ||
| "sql/core/target/scala-*/test-classes/org/apache/spark/sql/" | ||
| "SparkSessionExtensionSuite.class") | ||
| if not glob.glob(os.path.join(SPARK_HOME, filename_pattern)): | ||
| raise unittest.SkipTest( | ||
| "'org.apache.spark.sql.SparkSessionExtensionSuite' is not " | ||
| "available. Will skip the related tests.") | ||
|
|
||
| # Note that 'spark.sql.extensions' is a static immutable configuration. | ||
| cls.spark = SparkSession.builder \ | ||
| .master("local[4]") \ | ||
| .appName(cls.__name__) \ | ||
| .config( | ||
| "spark.sql.extensions", | ||
| "org.apache.spark.sql.MyExtensions") \ | ||
RussellSpitzer marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .getOrCreate() | ||
|
|
||
| @classmethod | ||
| def tearDownClass(cls): | ||
| cls.spark.stop() | ||
|
|
||
| def test_use_custom_class_for_extensions(self): | ||
| self.assertTrue( | ||
| self.spark._jsparkSession.sessionState().planner().strategies().contains( | ||
| self.spark._jvm.org.apache.spark.sql.MySparkStrategy(self.spark._jsparkSession)), | ||
| "MySparkStrategy not found in active planner strategies") | ||
| self.assertTrue( | ||
| self.spark._jsparkSession.sessionState().analyzer().extendedResolutionRules().contains( | ||
| self.spark._jvm.org.apache.spark.sql.MyRule(self.spark._jsparkSession)), | ||
| "MyRule not found in extended resolution rules") | ||
|
|
||
|
|
||
| class SparkSessionTests(PySparkTestCase): | ||
|
|
||
| # This test is separate because it's closely related with session's start and stop. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,6 +86,7 @@ class SparkSession private( | |
|
|
||
| private[sql] def this(sc: SparkContext) { | ||
RussellSpitzer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| this(sc, None, None, new SparkSessionExtensions) | ||
| SparkSession.applyExtensionsFromConf(sc.getConf, this.extensions) | ||
|
||
| } | ||
|
|
||
| sparkContext.assertNotStopped() | ||
|
|
@@ -935,23 +936,7 @@ object SparkSession extends Logging { | |
| // Do not update `SparkConf` for existing `SparkContext`, as it's shared by all sessions. | ||
| } | ||
|
|
||
| // Initialize extensions if the user has defined a configurator class. | ||
| val extensionConfOption = sparkContext.conf.get(StaticSQLConf.SPARK_SESSION_EXTENSIONS) | ||
| if (extensionConfOption.isDefined) { | ||
| val extensionConfClassName = extensionConfOption.get | ||
| try { | ||
| val extensionConfClass = Utils.classForName(extensionConfClassName) | ||
| val extensionConf = extensionConfClass.newInstance() | ||
| .asInstanceOf[SparkSessionExtensions => Unit] | ||
| extensionConf(extensions) | ||
| } catch { | ||
| // Ignore the error if we cannot find the class or when the class has the wrong type. | ||
| case e @ (_: ClassCastException | | ||
| _: ClassNotFoundException | | ||
| _: NoClassDefFoundError) => | ||
| logWarning(s"Cannot use $extensionConfClassName to configure session extensions.", e) | ||
| } | ||
| } | ||
| applyExtensionsFromConf(sparkContext.conf, extensions) | ||
|
|
||
| session = new SparkSession(sparkContext, None, None, extensions) | ||
| options.foreach { case (k, v) => session.initialSessionOptions.put(k, v) } | ||
|
|
@@ -1136,4 +1121,27 @@ object SparkSession extends Logging { | |
| SparkSession.clearDefaultSession() | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Initialize extensions if the user has defined a configurator class in their SparkConf. | ||
| * This class will be applied to the extensions passed into this function. | ||
| */ | ||
| private[sql] def applyExtensionsFromConf(conf: SparkConf, extensions: SparkSessionExtensions) { | ||
|
||
| val extensionConfOption = conf.get(StaticSQLConf.SPARK_SESSION_EXTENSIONS) | ||
|
||
| if (extensionConfOption.isDefined) { | ||
| val extensionConfClassName = extensionConfOption.get | ||
| try { | ||
| val extensionConfClass = Utils.classForName(extensionConfClassName) | ||
| val extensionConf = extensionConfClass.newInstance() | ||
| .asInstanceOf[SparkSessionExtensions => Unit] | ||
| extensionConf(extensions) | ||
| } catch { | ||
| // Ignore the error if we cannot find the class or when the class has the wrong type. | ||
| case e@(_: ClassCastException | | ||
| _: ClassNotFoundException | | ||
| _: NoClassDefFoundError) => | ||
| logWarning(s"Cannot use $extensionConfClassName to configure session extensions.", e) | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh haha, let's get rid of this change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm addicted to whitespace apparently