Repository navigation
[SPARK-61178][CONNECT][PYTHON] Make StructType.fields the list of the struct, and the name, dataType and nullable of StructField assignable, so that their edits show in the struct, in the Python client as PySpark does - #375
Closed
HyukjinKwon wants to merge 1 commit into
Closed
HyukjinKwon wants to merge 1 commit into
HyukjinKwon wants to merge 1 commit into
Conversation
… struct, and the name, dataType and nullable of StructField assignable, so that their edits show in the struct, in the Python client as PySpark does PySpark's StructType keeps its fields in a list attribute, fields, and gives back the same list on each access. Its names are a separate list. The attributes name, dataType, nullable and metadata of StructField are plain attributes. The Python client built a new list of fields on each access and made the attributes read-only, so an edit of the fields of a struct, or of a field, did not reach the struct. Now fields and names are the lists that the struct holds. The fields are read from them on each use, and the attributes of StructField are assignable, as in PySpark. The types nested in a field (its dataType, the elementType of an array, the keyType and valueType of a map) are kept as Python objects, so they are the same object each time, and edits of them are seen by the outer type. Co-authored-by: Isaac <no-reply@databricks.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
SPARK-61178: PySpark's
StructTypeholds its fields in a list attribute,fields, and gives back the same list on each access. Itsnamesis a separate list, which__init__andaddset. The attributesname,dataType,nullableandmetadataofStructFieldare plain attributes.The Python client now mirrors this:
StructTypeholds itsfields(a list ofStructFieldobjects) and itsnames(a list of strings) as Python lists. The struct reads its fields from them each time, soappend, item assignment,pop,sortanddelonfieldschange the struct:simpleString(),json(),len, iteration and indexing. A list kept beforeadd()sees the new field.add()appends to both lists.fieldNames()returns a copy ofnames, so it does not follow an edit offields.__eq__also comparesnames.StructField.name,dataType,nullableandmetadataare assignable. An assignment is seen by the struct the field is in.StructField.dataType,ArrayType.elementType,MapType.keyTypeandMapType.valueTypekeep their Python object: the object given to the constructor or setter, or one made from the core type on first access. So they are the same object each time, and an edit of a nested type (in place, or through its parent) is seen by the outer type, in its json, simpleString, equality, hash, pickling,createDataFrameschemas and UDF return types._needConversionand_needSerializeAnyFieldare computed by__init__andadd, as in PySpark, so an edit of a field's type does not change them.createDataFrameschemas, UDF return types,json, equality,toDDL) is built from the live lists.Not mirrored: after a field is appended to
fields(not withadd()),createDataFrameon local data builds the rows from all the fields. PySpark raises there, because its row conversion usesnames. Pickling a struct keeps only the names of its fields, so a struct whosenamesdisagree with itsfieldsunpickles with the names of the fields.Why are the changes needed?
Each access to
fieldsbuilt a new list, and theStructFieldattributes were read-only. So edits in place were lost, and the common way to change nullability did not work:Does this PR introduce any user-facing change?
Yes.
StructType.fieldsis the same list on each access, and edits of it or of aStructField(name,dataType,nullable,metadata) change the struct, as in PySpark.fieldNames()andnameskeep the names that__init__andaddset, so they can disagree withfieldsafter a list edit, as in PySpark.How was this patch tested?
python/tests/test_dropin_offline.py:test_struct_type_fields_is_the_live_list_of_the_struct,test_struct_type_add_keeps_the_fields_list,test_struct_type_names_are_apart_from_fields,test_struct_field_attributes_are_assignable,test_struct_type_edits_reach_its_core_type,test_struct_type_nested_types_are_kept_as_pyspark_keeps_them. The first five fail on the code before this change, and pass with it. The same six tests pass unchanged against official PySpark 4.3.0. The nested test was not run on the build before this change. Its identity checks (dataType is dataType) were False on that build in the coordinator's probe.python/tests/test_dropin_e2e.py:test_create_dataframe_with_a_schema_edited_in_place. It edits nullability in place and adds a field withadd(), and checks the schema and rows ofcreateDataFrame. Official PySpark 4.3.0 gives the same schema and rows against the same server.-k "struct or schema or types"offline tests and the matching e2e tests pass.wasm-udf, the offline Python suites (2233 passed, 8 skipped), and the live drop-in and Arrow suites (211 passed) and live cases (11 passed) against a local Spark 4.3.0 server. Clippy reports no diagnostics in the changed lines.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Opus 5.5
This pull request and its description were written by Isaac.