I have a Python package with a module containing UDF's to be used in a PySpark setting. I've worked out a way to initialize and shut down a Spark session when running the unit tests, but I'm having an issue creating the docs. I'm using Sphinx docs so I'm simply running make clean docs and running into this error:
File "/usr/local/lib/python3.9/site-packages/pyspark/sql/pandas/functions.py", line 432, in _create_pandas_udf
return _create_udf(f, returnType, evalType)
File "/usr/local/lib/python3.9/site-packages/pyspark/sql/udf.py", line 43, in _create_udf
return udf_obj._wrapped()
File "/usr/local/lib/python3.9/site-packages/pyspark/sql/udf.py", line 206, in _wrapped
wrapper.returnType = self.returnType
File "/usr/local/lib/python3.9/site-packages/pyspark/sql/udf.py", line 96, in returnType
self._returnType_placeholder = _parse_datatype_string(self._returnType)
File "/usr/local/lib/python3.9/site-packages/pyspark/sql/types.py", line 843, in _parse_datatype_string
raise e
File "/usr/local/lib/python3.9/site-packages/pyspark/sql/types.py", line 833, in _parse_datatype_string
return from_ddl_schema(s)
File "/usr/local/lib/python3.9/site-packages/pyspark/sql/types.py", line 825, in from_ddl_schema
sc._jvm.org.apache.spark.sql.types.StructType.fromDDL(type_str).json())
AttributeError: 'NoneType' object has no attribute '_jvm'
The error is of course being caused by trying to load a module containing a UDF defined as such:
import pyspark.sql.functions as F
@F.pandas_udf(returnType='string')
def some_udf(col):
return col
As I understand, the issue is the pandas_udf can't be created because there is no Spark session available when I run make clean docs. This library is imported in used in our Databricks cluster so the Spark session is already created and exists for you when the library is loaded. I've made some other UDF's which accept both static values and column arguments as such:
import pyspark.sql.functions as F
def outer_function(column_arg, integer_arg):
@F.pandas_udf(returnType='string')
def inner_function(column_arg):
return do_something_with(column_arg, integer_arg)
return inner_function(column_arg)
Should I refactor all my UDF's to work like this? Seems overkill.